diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | ChangeLog.ja | 7 | ||||
-rw-r--r-- | libsylph/procmsg.c | 15 | ||||
-rw-r--r-- | libsylph/procmsg.h | 9 | ||||
-rw-r--r-- | libsylph/virtual.c | 243 | ||||
-rw-r--r-- | src/summary_search.c | 2 |
6 files changed, 257 insertions, 26 deletions
@@ -1,3 +1,10 @@ +2005-12-27 + + * libsylph/procmsg.[ch] + libsylph/virtual.c: cache search result to speed up on and after + the second search. + * src/summary_search.c: fixed a warning. + 2005-12-26 * version 2.2.0beta2 diff --git a/ChangeLog.ja b/ChangeLog.ja index 096d56be..ab4d398c 100644 --- a/ChangeLog.ja +++ b/ChangeLog.ja @@ -1,3 +1,10 @@ +2005-12-27 + + * libsylph/procmsg.[ch] + libsylph/virtual.c: 2回目以降の検索を高速化するために検索結果を + キャッシュするようにした。 + * src/summary_search.c: 警告を修正。 + 2005-12-26 * version 2.2.0beta2 diff --git a/libsylph/procmsg.c b/libsylph/procmsg.c index c2dd50a0..0adb215b 100644 --- a/libsylph/procmsg.c +++ b/libsylph/procmsg.c @@ -41,11 +41,6 @@ static GHashTable *procmsg_read_mark_file (FolderItem *item); static void procmsg_write_mark_file (FolderItem *item, GHashTable *mark_table); -static FILE *procmsg_open_data_file (const gchar *file, - guint version, - DataOpenMode mode, - gchar *buf, - size_t buf_size); static FILE *procmsg_open_cache_file_with_buffer(FolderItem *item, DataOpenMode mode, gchar *buf, @@ -119,7 +114,7 @@ GHashTable *procmsg_to_folder_hash_table_create(GSList *mlist) return msg_table; } -static gint procmsg_read_cache_data_str(FILE *fp, gchar **str) +gint procmsg_read_cache_data_str(FILE *fp, gchar **str) { gchar buf[BUFFSIZE]; gint ret = 0; @@ -155,9 +150,6 @@ static gint procmsg_read_cache_data_str(FILE *fp, gchar **str) } else ret = -1; - if (ret < 0) - g_warning("Cache data is corrupted\n"); - return ret; } @@ -767,9 +759,8 @@ static void procmsg_write_mark_file(FolderItem *item, GHashTable *mark_table) fclose(fp); } -static FILE *procmsg_open_data_file(const gchar *file, guint version, - DataOpenMode mode, - gchar *buf, size_t buf_size) +FILE *procmsg_open_data_file(const gchar *file, guint version, + DataOpenMode mode, gchar *buf, size_t buf_size) { FILE *fp; guint32 data_ver; diff --git a/libsylph/procmsg.h b/libsylph/procmsg.h index 0e7e1b10..a8125039 100644 --- a/libsylph/procmsg.h +++ b/libsylph/procmsg.h @@ -214,6 +214,9 @@ void procmsg_msg_hash_table_append (GHashTable *msg_table, GSList *mlist); GHashTable *procmsg_to_folder_hash_table_create (GSList *mlist); +gint procmsg_read_cache_data_str (FILE *fp, + gchar **str); + GSList *procmsg_read_cache (FolderItem *item, gboolean scan_file); void procmsg_set_flags (GSList *mlist, @@ -252,6 +255,12 @@ void procmsg_get_mark_sum (FolderItem *item, gint *max, gint first); +FILE *procmsg_open_data_file (const gchar *file, + guint version, + DataOpenMode mode, + gchar *buf, + size_t buf_size); + FILE *procmsg_open_cache_file (FolderItem *item, DataOpenMode mode); FILE *procmsg_open_mark_file (FolderItem *item, diff --git a/libsylph/virtual.c b/libsylph/virtual.c index 985215ee..5a2778d7 100644 --- a/libsylph/virtual.c +++ b/libsylph/virtual.c @@ -42,18 +42,43 @@ #include "utils.h" typedef struct _VirtualSearchInfo VirtualSearchInfo; +typedef struct _SearchCacheInfo SearchCacheInfo; struct _VirtualSearchInfo { FilterRule *rule; GSList *mlist; + GHashTable *search_cache_table; + FILE *fp; +}; + +struct _SearchCacheInfo { + FolderItem *folder; + guint msgnum; + off_t size; + time_t mtime; + MsgFlags flags; +}; + +enum +{ + SCACHE_NOT_EXIST = 0, + SCACHE_MATCHED = 1, + SCACHE_NOT_MATCHED = 2 }; static void virtual_folder_init (Folder *folder, const gchar *name, const gchar *path); -static GSList *virtual_search_folder (FilterRule *rule, - FolderItem *item); +static GHashTable *virtual_read_search_cache + (FolderItem *item); +static void virtual_write_search_cache (FILE *fp, + FolderItem *item, + MsgInfo *msginfo, + gint matched); + +static GSList *virtual_search_folder (VirtualSearchInfo *info, + FolderItem *item); static gboolean virtual_search_recursive_func (GNode *node, gpointer data); @@ -137,7 +162,148 @@ static void virtual_folder_init(Folder *folder, const gchar *name, folder_local_folder_init(folder, name, path); } -static GSList *virtual_search_folder(FilterRule *rule, FolderItem *item) +guint sinfo_hash(gconstpointer key) +{ + const SearchCacheInfo *sinfo = key; + guint h; + + h = (guint)sinfo->folder; + h ^= sinfo->msgnum; + h ^= (guint)sinfo->size; + h ^= (guint)sinfo->mtime; + h ^= (guint)sinfo->flags.tmp_flags; + h ^= (guint)sinfo->flags.perm_flags; + + /* g_print("path: %s, n = %u, hash = %u\n", + sinfo->folder->path, sinfo->msgnum, h); */ + + return h; +} + +gint sinfo_equal(gconstpointer v, gconstpointer v2) +{ + const SearchCacheInfo *s1 = v; + const SearchCacheInfo *s2 = v2; + + return (s1->folder == s2->folder && s1->msgnum == s2->msgnum && + s1->size == s2->size && s1->mtime == s2->mtime && + s1->flags.tmp_flags == s2->flags.tmp_flags && + s1->flags.perm_flags == s2->flags.perm_flags); +} + +#define READ_CACHE_DATA_INT(n, fp) \ +{ \ + guint32 idata; \ + \ + if (fread(&idata, sizeof(idata), 1, fp) != 1) { \ + g_warning("Cache data is corrupted\n"); \ + fclose(fp); \ + return table; \ + } else \ + n = idata; \ +} + +static GHashTable *virtual_read_search_cache(FolderItem *item) +{ + GHashTable *table; + gchar *path, *file; + FILE *fp; + gchar *id; + + g_return_val_if_fail(item != NULL, NULL); + + path = folder_item_get_path(item); + file = g_strconcat(path, G_DIR_SEPARATOR_S, "search_cache", NULL); + debug_print("reading search cache: %s\n", file); + fp = procmsg_open_data_file(file, 1, DATA_READ, NULL, 0); + g_free(file); + g_free(path); + if (!fp) + return NULL; + + table = g_hash_table_new(sinfo_hash, sinfo_equal); + + while (procmsg_read_cache_data_str(fp, &id) == 0) { + FolderItem *folder; + guint32 msgnum; + off_t size; + time_t mtime; + MsgFlags flags; + gint matched; + SearchCacheInfo *sinfo; + + folder = folder_find_item_from_identifier(id); + g_free(id); + + while (fread(&msgnum, sizeof(msgnum), 1, fp) == 1) { + if (msgnum == 0) + break; + + READ_CACHE_DATA_INT(size, fp); + READ_CACHE_DATA_INT(mtime, fp); + READ_CACHE_DATA_INT(flags.tmp_flags, fp); + READ_CACHE_DATA_INT(flags.perm_flags, fp); + READ_CACHE_DATA_INT(matched, fp); + + if (folder) { + sinfo = g_new(SearchCacheInfo, 1); + sinfo->folder = folder; + sinfo->msgnum = msgnum; + sinfo->size = size; + sinfo->mtime = mtime; + sinfo->flags = flags; + g_hash_table_insert(table, sinfo, + GINT_TO_POINTER(matched)); + } + } + } + + fclose(fp); + return table; +} + +static void virtual_write_search_cache(FILE *fp, FolderItem *item, + MsgInfo *msginfo, gint matched) +{ + if (!item && !msginfo) { + WRITE_CACHE_DATA_INT(0, fp); + return; + } + + if (item) { + gchar *id; + + id = folder_item_get_identifier(item); + if (id) { + WRITE_CACHE_DATA(id, fp); + g_free(id); + } + } + + if (msginfo) { + WRITE_CACHE_DATA_INT(msginfo->msgnum, fp); + WRITE_CACHE_DATA_INT(msginfo->size, fp); + WRITE_CACHE_DATA_INT(msginfo->mtime, fp); + WRITE_CACHE_DATA_INT(msginfo->flags.tmp_flags, fp); + WRITE_CACHE_DATA_INT(msginfo->flags.perm_flags, fp); + WRITE_CACHE_DATA_INT(matched, fp); + } +} + +static void search_cache_free_func(gpointer key, gpointer value, gpointer data) +{ + g_free(key); +} + +static void virtual_search_cache_free(GHashTable *table) +{ + if (table) { + g_hash_table_foreach(table, search_cache_free_func, NULL); + g_hash_table_destroy(table); + } +} + +static GSList *virtual_search_folder(VirtualSearchInfo *info, FolderItem *item) { GSList *match_list = NULL; GSList *mlist; @@ -147,7 +313,8 @@ static GSList *virtual_search_folder(FilterRule *rule, FolderItem *item) gint count = 1, total; GTimeVal tv_prev, tv_cur; - g_return_val_if_fail(rule != NULL, NULL); + g_return_val_if_fail(info != NULL, NULL); + g_return_val_if_fail(info->rule != NULL, NULL); g_return_val_if_fail(item != NULL, NULL); g_return_val_if_fail(item->path != NULL, NULL); @@ -165,7 +332,9 @@ static GSList *virtual_search_folder(FilterRule *rule, FolderItem *item) debug_print("start query search: %s\n", item->path); - full_headers = filter_rule_requires_full_headers(rule); + full_headers = filter_rule_requires_full_headers(info->rule); + + virtual_write_search_cache(info->fp, item, NULL, 0); for (cur = mlist; cur != NULL; cur = cur->next) { MsgInfo *msginfo = (MsgInfo *)cur->data; @@ -181,6 +350,32 @@ static GSList *virtual_search_folder(FilterRule *rule, FolderItem *item) } ++count; + if (info->search_cache_table) { + gint matched; + SearchCacheInfo sinfo; + + sinfo.folder = item; + sinfo.msgnum = msginfo->msgnum; + sinfo.size = msginfo->size; + sinfo.mtime = msginfo->mtime; + sinfo.flags = msginfo->flags; + + matched = (gint)g_hash_table_lookup + (info->search_cache_table, &sinfo); + if (matched == SCACHE_MATCHED) { + match_list = g_slist_prepend + (match_list, msginfo); + cur->data = NULL; + virtual_write_search_cache(info->fp, NULL, + msginfo, matched); + continue; + } else if (matched == SCACHE_NOT_MATCHED) { + virtual_write_search_cache(info->fp, NULL, + msginfo, matched); + continue; + } + } + fltinfo.flags = msginfo->flags; if (full_headers) { gchar *file; @@ -194,14 +389,20 @@ static GSList *virtual_search_folder(FilterRule *rule, FolderItem *item) if (!hlist) continue; - if (filter_match_rule(rule, msginfo, hlist, &fltinfo)) { + if (filter_match_rule(info->rule, msginfo, hlist, &fltinfo)) { match_list = g_slist_prepend(match_list, msginfo); cur->data = NULL; + virtual_write_search_cache(info->fp, NULL, msginfo, + SCACHE_MATCHED); + } else { + virtual_write_search_cache(info->fp, NULL, msginfo, + SCACHE_NOT_MATCHED); } procheader_header_list_destroy(hlist); } + virtual_write_search_cache(info->fp, NULL, NULL, 0); procmsg_msg_list_free(mlist); return g_slist_reverse(match_list); @@ -220,7 +421,7 @@ static gboolean virtual_search_recursive_func(GNode *node, gpointer data) if (!item->path) return FALSE; - mlist = virtual_search_folder(info->rule, item); + mlist = virtual_search_folder(info, item); info->mlist = g_slist_concat(info->mlist, mlist); return FALSE; @@ -233,10 +434,12 @@ static GSList *virtual_get_msg_list(Folder *folder, FolderItem *item, GSList *flist; GSList *cur; FilterRule *rule; - gchar *rule_file; gchar *path; + gchar *rule_file; + gchar *cache_file; FolderItem *target; gint new = 0, unread = 0, total = 0; + VirtualSearchInfo info; g_return_val_if_fail(item != NULL, NULL); g_return_val_if_fail(item->stype == F_VIRTUAL, NULL); @@ -261,16 +464,30 @@ static GSList *virtual_get_msg_list(Folder *folder, FolderItem *item, goto finish; } - if (rule->recursive) { - VirtualSearchInfo info; + info.rule = rule; + info.mlist = NULL; + if (use_cache) + info.search_cache_table = virtual_read_search_cache(item); + else + info.search_cache_table = NULL; - info.rule = rule; - info.mlist = NULL; + path = folder_item_get_path(item); + cache_file = g_strconcat(path, G_DIR_SEPARATOR_S, "search_cache", NULL); + info.fp = procmsg_open_data_file(cache_file, 1, DATA_WRITE, NULL, 0); + g_free(cache_file); + g_free(path); + if (!info.fp) + goto finish; + + if (rule->recursive) { g_node_traverse(target->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, virtual_search_recursive_func, &info); mlist = info.mlist; } else - mlist = virtual_search_folder(rule, target); + mlist = virtual_search_folder(&info, target); + + fclose(info.fp); + virtual_search_cache_free(info.search_cache_table); for (cur = mlist; cur != NULL; cur = cur->next) { MsgInfo *msginfo = (MsgInfo *)cur->data; diff --git a/src/summary_search.c b/src/summary_search.c index f067e07c..670a1b29 100644 --- a/src/summary_search.c +++ b/src/summary_search.c @@ -175,7 +175,7 @@ void summary_search(FolderItem *item) if (!search_window.window) summary_search_create(); else - gtk_window_present(search_window.window); + gtk_window_present(GTK_WINDOW(search_window.window)); if (item && item->stype != F_VIRTUAL) { id = folder_item_get_identifier(item); |