aboutsummaryrefslogtreecommitdiff
path: root/libsylph
diff options
context:
space:
mode:
Diffstat (limited to 'libsylph')
-rw-r--r--libsylph/procmsg.c15
-rw-r--r--libsylph/procmsg.h9
-rw-r--r--libsylph/virtual.c243
3 files changed, 242 insertions, 25 deletions
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;