aboutsummaryrefslogtreecommitdiff
path: root/libsylph/virtual.c
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2005-12-27 07:32:36 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2005-12-27 07:32:36 +0000
commit9f4a64cce3f7515dd4522be55c80394eaa761938 (patch)
tree1fd2421bfffc692bf507af6d8c134fefab7fd640 /libsylph/virtual.c
parentc949a532de4138d9bd205f35cb16e0a309512f5d (diff)
cache search result to speed up on and after the second search.
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@869 ee746299-78ed-0310-b773-934348b2243d
Diffstat (limited to 'libsylph/virtual.c')
-rw-r--r--libsylph/virtual.c243
1 files changed, 230 insertions, 13 deletions
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;