comparison src/log.c @ 11177:3924db2b1ca8

[gaim-migrate @ 13285] Performance optimizing the log set and screenname autocompletion code. committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Mon, 01 Aug 2005 04:08:27 +0000
parents 59a1ff5a4bae
children bb0d7b719af2
comparison
equal deleted inserted replaced
11176:6932df31225f 11177:3924db2b1ca8
41 char *name; 41 char *name;
42 GaimAccount *account; 42 GaimAccount *account;
43 }; 43 };
44 static GHashTable *logsize_users = NULL; 44 static GHashTable *logsize_users = NULL;
45 45
46 static GList *log_get_log_sets_common(); 46 static void log_get_log_sets_common(GHashTable *sets);
47 47
48 /************************************************************************** 48 /**************************************************************************
49 * PUBLIC LOGGING FUNCTIONS *********************************************** 49 * PUBLIC LOGGING FUNCTIONS ***********************************************
50 **************************************************************************/ 50 **************************************************************************/
51 51
240 GList*(*list)(GaimLogType type, const char*, GaimAccount*), 240 GList*(*list)(GaimLogType type, const char*, GaimAccount*),
241 char*(*read)(GaimLog*, GaimLogReadFlags*), 241 char*(*read)(GaimLog*, GaimLogReadFlags*),
242 int(*size)(GaimLog*), 242 int(*size)(GaimLog*),
243 int(*total_size)(GaimLogType type, const char *name, GaimAccount *account), 243 int(*total_size)(GaimLogType type, const char *name, GaimAccount *account),
244 GList*(*list_syslog)(GaimAccount *account), 244 GList*(*list_syslog)(GaimAccount *account),
245 GList*(*get_log_sets)(void)) 245 void(*get_log_sets)(GaimLogSetCallback cb, GHashTable *sets))
246 { 246 {
247 GaimLogLogger *logger = g_new0(GaimLogLogger, 1); 247 GaimLogLogger *logger = g_new0(GaimLogLogger, 1);
248 248
249 logger->create = create; 249 logger->create = create;
250 logger->write = write; 250 logger->write = write;
331 gint gaim_log_set_compare(gconstpointer y, gconstpointer z) 331 gint gaim_log_set_compare(gconstpointer y, gconstpointer z)
332 { 332 {
333 const GaimLogSet *a = y; 333 const GaimLogSet *a = y;
334 const GaimLogSet *b = z; 334 const GaimLogSet *b = z;
335 gint ret = 0; 335 gint ret = 0;
336 char *tmp;
337 336
338 /* This logic seems weird at first... 337 /* This logic seems weird at first...
339 * If either account is NULL, we pretend the accounts are 338 * If either account is NULL, we pretend the accounts are
340 * equal. This allows us to detect duplicates that will 339 * equal. This allows us to detect duplicates that will
341 * exist if one logger knows the account and another 340 * exist if one logger knows the account and another
342 * doesn't. */ 341 * doesn't. */
343 if (a->account != NULL && b->account != NULL) { 342 if (a->account != NULL && b->account != NULL) {
344 ret = gaim_utf8_strcasecmp(gaim_account_get_username(a->account), gaim_account_get_username(b->account)); 343 ret = strcmp(gaim_account_get_username(a->account), gaim_account_get_username(b->account));
345 if (ret != 0) 344 if (ret != 0)
346 return ret; 345 return ret;
347 } 346 }
348 347
349 tmp = g_strdup(gaim_normalize(a->account, a->name)); 348 ret = strcmp(a->normalized_name, b->normalized_name);
350 ret = gaim_utf8_strcasecmp(tmp, gaim_normalize(b->account, b->name));
351 g_free(tmp);
352 if (ret != 0) 349 if (ret != 0)
353 return ret; 350 return ret;
354 351
355 return (gint)b->type - (gint)a->type; 352 return (gint)b->type - (gint)a->type;
356 } 353 }
371 * make sense for those data types, but I wish the comparison 368 * make sense for those data types, but I wish the comparison
372 * functions were compatible. */ 369 * functions were compatible. */
373 return !gaim_log_set_compare(a, b); 370 return !gaim_log_set_compare(a, b);
374 } 371 }
375 372
376 void log_set_build_list(gpointer key, gpointer value, gpointer user_data) 373 void log_add_log_set_to_hash(GHashTable *sets, GaimLogSet *set)
377 { 374 {
378 *((GList **)user_data) = g_list_append(*((GList **)user_data), key); 375 GaimLogSet *existing_set = g_hash_table_lookup(sets, set);
379 } 376
380 377 if (existing_set == NULL)
381 GList *gaim_log_get_log_sets() 378 g_hash_table_insert(sets, set, set);
379 else if (existing_set->account == NULL && set->account != NULL)
380 g_hash_table_replace(sets, set, set);
381 else
382 gaim_log_set_free(set);
383 }
384
385 GHashTable *gaim_log_get_log_sets(void)
382 { 386 {
383 GSList *n; 387 GSList *n;
384 GList *sets = NULL; 388 GHashTable *sets = g_hash_table_new_full(log_set_hash, log_set_equal,
385 GList *set; 389 (GDestroyNotify)gaim_log_set_free, NULL);
386 GHashTable *sets_ht = g_hash_table_new(log_set_hash, log_set_equal);
387 390
388 /* Get the log sets from all the loggers. */ 391 /* Get the log sets from all the loggers. */
389 for (n = loggers; n; n = n->next) { 392 for (n = loggers; n; n = n->next) {
390 GaimLogLogger *logger = n->data; 393 GaimLogLogger *logger = n->data;
391 394
392 if (!logger->get_log_sets) 395 if (!logger->get_log_sets)
393 continue; 396 continue;
394 397
395 sets = g_list_concat(sets, logger->get_log_sets()); 398 logger->get_log_sets(log_add_log_set_to_hash, sets);
396 } 399 }
397 400
398 /* Get the log sets for loggers that use the common logger functions. */ 401 log_get_log_sets_common(sets);
399 sets = g_list_concat(sets, log_get_log_sets_common()); 402
400 403 /* Return the GHashTable of unique GaimLogSets. */
401 for (set = sets; set != NULL ; set = set->next) { 404 return sets;
402 GaimLogSet *existing_set = g_hash_table_lookup(sets_ht, set->data); 405 }
403 406
404 if (existing_set == NULL) { 407 void gaim_log_set_free(GaimLogSet *set)
405 g_hash_table_insert(sets_ht, set->data, set->data); 408 {
406 } else if (existing_set->account == NULL && ((GaimLogSet *)set->data)->account != NULL) { 409 g_return_if_fail(set != NULL);
407 /* The existing entry in the hash table has no account. 410
408 * This one does. We'll delete the old one and keep this one. */ 411 g_free(set->name);
409 g_hash_table_replace(sets_ht, set->data, set->data); 412 if (set->normalized_name != set->name)
410 g_free(existing_set->name); 413 g_free(set->normalized_name);
411 g_free(existing_set); 414 g_free(set);
412 } else {
413 g_free(((GaimLogSet *)set->data)->name);
414 g_free(set->data);
415 }
416 }
417 g_list_free(sets);
418
419 /* At this point, we've built a GHashTable of unique GaimLogSets.
420 * So, we build a list of those keys and destroy the GHashTable. */
421 sets = NULL;
422 g_hash_table_foreach(sets_ht, log_set_build_list, &sets);
423 g_hash_table_destroy(sets_ht);
424
425 return g_list_sort(sets, gaim_log_set_compare);
426 } 415 }
427 416
428 GList *gaim_log_get_system_logs(GaimAccount *account) 417 GList *gaim_log_get_system_logs(GaimAccount *account)
429 { 418 {
430 GList *logs = NULL; 419 GList *logs = NULL;
554 return st.st_size; 543 return st.st_size;
555 } 544 }
556 545
557 /* This will build log sets for all loggers that use the common logger 546 /* This will build log sets for all loggers that use the common logger
558 * functions because they use the same directory structure. */ 547 * functions because they use the same directory structure. */
559 static GList *log_get_log_sets_common() 548 static void log_get_log_sets_common(GHashTable *sets)
560 { 549 {
561 gchar *log_path = g_build_filename(gaim_user_dir(), "logs", NULL); 550 gchar *log_path = g_build_filename(gaim_user_dir(), "logs", NULL);
562 GDir *log_dir = g_dir_open(log_path, 0, NULL); 551 GDir *log_dir = g_dir_open(log_path, 0, NULL);
563 const gchar *protocol; 552 const gchar *protocol;
564 GList *sets = NULL;
565 553
566 if (log_dir == NULL) { 554 if (log_dir == NULL) {
567 g_free(log_path); 555 g_free(log_path);
568 return NULL; 556 return;
569 } 557 }
570 558
571 while ((protocol = g_dir_read_name(log_dir)) != NULL) { 559 while ((protocol = g_dir_read_name(log_dir)) != NULL) {
572 gchar *protocol_path = g_build_filename(log_path, protocol, NULL); 560 gchar *protocol_path = g_build_filename(log_path, protocol, NULL);
573 GDir *protocol_dir; 561 GDir *protocol_dir;
632 /* Get the (possibly new) length of name. */ 620 /* Get the (possibly new) length of name. */
633 len = strlen(name); 621 len = strlen(name);
634 622
635 set->account = account; 623 set->account = account;
636 set->name = name; 624 set->name = name;
625 set->normalized_name = g_strdup(gaim_normalize(account, name));
637 626
638 /* Chat for .chat or .system at the end of the name to determine the type. */ 627 /* Chat for .chat or .system at the end of the name to determine the type. */
639 set->type = GAIM_LOG_IM; 628 set->type = GAIM_LOG_IM;
640 if (len > 7) { 629 if (len > 7) {
641 gchar *tmp = &name[len - 7]; 630 gchar *tmp = &name[len - 7];
651 *tmp = '\0'; 640 *tmp = '\0';
652 } 641 }
653 } 642 }
654 643
655 /* Determine if this (account, name) combination exists as a buddy. */ 644 /* Determine if this (account, name) combination exists as a buddy. */
656 if (gaim_find_buddy(account, name) != NULL) 645 set->buddy = (gaim_find_buddy(account, name) != NULL);
657 set->buddy = TRUE; 646
658 else 647 log_add_log_set_to_hash(sets, set);
659 set->buddy = FALSE;
660
661 sets = g_list_append(sets, set);
662 } 648 }
663 g_free(username_path); 649 g_free(username_path);
664 g_dir_close(username_dir); 650 g_dir_close(username_dir);
665 } 651 }
666 g_free(protocol_path); 652 g_free(protocol_path);
667 g_dir_close(protocol_dir); 653 g_dir_close(protocol_dir);
668 } 654 }
669 g_free(log_path); 655 g_free(log_path);
670 g_dir_close(log_dir); 656 g_dir_close(log_dir);
671
672 return sets;
673 } 657 }
674 658
675 #if 0 /* Maybe some other time. */ 659 #if 0 /* Maybe some other time. */
676 /**************** 660 /****************
677 ** XML LOGGER ** 661 ** XML LOGGER **
1220 { 1204 {
1221 struct old_logger_data *data = log->logger_data; 1205 struct old_logger_data *data = log->logger_data;
1222 return data ? data->length : 0; 1206 return data ? data->length : 0;
1223 } 1207 }
1224 1208
1225 static GList *old_logger_get_log_sets() 1209 static void old_logger_get_log_sets(GaimLogSetCallback cb, GHashTable *sets)
1226 { 1210 {
1227 char *log_path = g_build_filename(gaim_user_dir(), "logs", NULL); 1211 char *log_path = g_build_filename(gaim_user_dir(), "logs", NULL);
1228 GDir *log_dir = g_dir_open(log_path, 0, NULL); 1212 GDir *log_dir = g_dir_open(log_path, 0, NULL);
1229 gchar *name; 1213 gchar *name;
1230 GList *sets = NULL;
1231 GaimBlistNode *gnode, *cnode, *bnode; 1214 GaimBlistNode *gnode, *cnode, *bnode;
1232 1215
1233 g_free(log_path); 1216 g_free(log_path);
1234 if (log_dir == NULL) 1217 if (log_dir == NULL)
1235 return NULL; 1218 return;
1236 1219
1237 /* Don't worry about the cast, name will be filled with a dynamically allocated data shortly. */ 1220 /* Don't worry about the cast, name will be filled with a dynamically allocated data shortly. */
1238 while ((name = (gchar *)g_dir_read_name(log_dir)) != NULL) { 1221 while ((name = (gchar *)g_dir_read_name(log_dir)) != NULL) {
1239 size_t len; 1222 size_t len;
1240 gchar *ext; 1223 gchar *ext;
1270 set->type = GAIM_LOG_CHAT; 1253 set->type = GAIM_LOG_CHAT;
1271 *tmp = '\0'; 1254 *tmp = '\0';
1272 } 1255 }
1273 } 1256 }
1274 1257
1275 set->name = name; 1258 set->name = set->normalized_name = name;
1276 1259
1277 /* Search the buddy list to find the account and to determine if this is a buddy. */ 1260 /* Search the buddy list to find the account and to determine if this is a buddy. */
1278 for (gnode = gaim_get_blist()->root; !found && gnode != NULL; gnode = gnode->next) 1261 for (gnode = gaim_get_blist()->root; !found && gnode != NULL; gnode = gnode->next)
1279 { 1262 {
1280 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) 1263 if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
1296 } 1279 }
1297 } 1280 }
1298 } 1281 }
1299 } 1282 }
1300 1283
1301 sets = g_list_append(sets, set); 1284 cb(sets, set);
1302 } 1285 }
1303 g_dir_close(log_dir); 1286 g_dir_close(log_dir);
1304
1305 return sets;
1306 } 1287 }
1307 1288
1308 static void old_logger_finalize(GaimLog *log) 1289 static void old_logger_finalize(GaimLog *log)
1309 { 1290 {
1310 struct old_logger_data *data = log->logger_data; 1291 struct old_logger_data *data = log->logger_data;