[PATCH] : smart search



	Hi all,
here is a patch to implement a smarter search function. Its aim is to look 
for matching messages (i.e. call libbalsa_mailbox_get_matching) only when 
necessary : when the conditions for the search has changed, and when new 
messages has been added to the mailbox (removing does not change anything 
in this setting), this part is still not implemented (it's only a matter 
of connecting a callback to the pertinent mailbox signals that will 
invalidate the current matching messages).
This patch should improve drastically the following search : you set up a 
search in body (the slowest one) on a big mailbox, you'll see that without 
the patch the search is done each time, even when you just ask for "search 
again".
Comments are welcome.
Bye
Manu
Only in balsa-current/src/: .deps
Only in balsa-current/src/: .libs
Common subdirectories: /home/manu/prog/balsa-cvs/balsa/src/CVS and balsa-current/src/CVS
Only in balsa-current/src/: Makefile
diff -u /home/manu/prog/balsa-cvs/balsa/src/Makefile.in balsa-current/src/Makefile.in
--- /home/manu/prog/balsa-cvs/balsa/src/Makefile.in	Sat Aug  3 17:21:43 2002
+++ balsa-current/src/Makefile.in	Sat Aug 17 15:26:53 2002
@@ -67,7 +67,6 @@
 BALSA_REVISION = @BALSA_REVISION@
 BALSA_VERSION = @BALSA_VERSION@
 BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
-CATALOGS = @CATALOGS@
 CATOBJEXT = @CATOBJEXT@
 CC = @CC@
 CFLAGS = @CFLAGS@
@@ -77,10 +76,10 @@
 ECHO = @ECHO@
 EXEEXT = @EXEEXT@
 GENCAT = @GENCAT@
+GLIBC21 = @GLIBC21@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_CONFIG = @GLIB_CONFIG@
 GLIB_LIBS = @GLIB_LIBS@
-GMOFILES = @GMOFILES@
 GMSGFMT = @GMSGFMT@
 GNOMEGNORBA_LIBS = @GNOMEGNORBA_LIBS@
 GNOMEUI_LIBS = @GNOMEUI_LIBS@
@@ -99,21 +98,25 @@
 GTK_CFLAGS = @GTK_CFLAGS@
 GTK_CONFIG = @GTK_CONFIG@
 GTK_LIBS = @GTK_LIBS@
-GT_NO = @GT_NO@
-GT_YES = @GT_YES@
 HAVE_JW = @HAVE_JW@
+HAVE_LIB = @HAVE_LIB@
 HAVE_LIBGNOMEUI_GNOME_WINDOW_ICON_H = @HAVE_LIBGNOMEUI_GNOME_WINDOW_ICON_H@
-INCLUDE_LOCALE_H = @INCLUDE_LOCALE_H@
 INSTOBJEXT = @INSTOBJEXT@
-INTLDEPS = @INTLDEPS@
+INTLBISON = @INTLBISON@
 INTLLIBS = @INTLLIBS@
 INTLOBJS = @INTLOBJS@
+INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
 JW = @JW@
 LDFLAGS = @LDFLAGS@
+LIB = @LIB@
 LIBESD_LIB = @LIBESD_LIB@
-LIBOBJS = @LIBOBJS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
 LIBTOOL = @LIBTOOL@
 LN_S = @LN_S@
+LTLIB = @LTLIB@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
 MAINT = @MAINT@
 MAKEINFO = @MAKEINFO@
 MKINSTALLDIRS = @MKINSTALLDIRS@
@@ -126,7 +129,6 @@
 PACKAGE = @PACKAGE@
 PCRE_CFLAGS = @PCRE_CFLAGS@
 PCRE_LIBS = @PCRE_LIBS@
-POFILES = @POFILES@
 POSUB = @POSUB@
 PTHREAD_LIB = @PTHREAD_LIB@
 RANLIB = @RANLIB@
@@ -139,7 +141,6 @@
 ZVT_LIBS = @ZVT_LIBS@
 gnomeconfdir = @gnomeconfdir@
 gnomedatadir = @gnomedatadir@
-l = @l@
 
 bin_PROGRAMS = balsa
 
Only in balsa-current/src/: address-book-config.o
Only in balsa-current/src/: address-book.o
Only in balsa-current/src/: balsa
Only in balsa-current/src/: balsa-app.o
Only in balsa-current/src/: balsa-icons.o
Only in balsa-current/src/: balsa-index-threading.o
diff -u /home/manu/prog/balsa-cvs/balsa/src/balsa-index.c balsa-current/src/balsa-index.c
--- /home/manu/prog/balsa-cvs/balsa/src/balsa-index.c	Sun Jul  7 06:47:54 2002
+++ balsa-current/src/balsa-index.c	Sat Aug 17 19:39:21 2002
@@ -49,6 +49,7 @@
 #include "store-address.h"
 
 #include "filter.h"
+#include "filter-funcs.h"
 
 #define CLIST_WORKAROUND
 #if defined(CLIST_WORKAROUND)
@@ -72,6 +73,9 @@
 			       gpointer data);
 
 /* statics */
+static void bndx_match_struct_destroy(BalsaIndex * index);
+static GHashTable * bndx_get_matching_messages(BalsaIndex * index,gint op,
+					       GSList * cnd);
 static void balsa_index_set_sort_order(BalsaIndex * bindex, int column, 
 				    GtkSortType order);
 static void balsa_index_set_first_new_message(BalsaIndex * bindex);
@@ -257,6 +261,20 @@
     klass->unselect_message = NULL;
 }
 
+/* Free the match struct */
+static void
+bndx_match_struct_destroy(BalsaIndex * index)
+{
+    if (index->match_struct) {
+	if (index->match_struct->conditions)
+	    libbalsa_conditions_free(index->match_struct->conditions);
+	if (index->match_struct->matching_messages)
+	    g_hash_table_destroy(index->match_struct->matching_messages);
+	g_free(index->match_struct);
+	index->match_struct = NULL;
+    }
+}
+
 static void
 balsa_index_init(BalsaIndex * bindex)
 {
@@ -377,6 +395,9 @@
     gtk_signal_connect(GTK_OBJECT(bindex->ctree), "drag-data-get",
                        GTK_SIGNAL_FUNC(balsa_index_drag_cb), NULL);
 
+    /* Initializing the match structure */
+    bindex->match_struct = NULL;
+
     g_get_current_time (&bindex->last_use);
     GTK_OBJECT_UNSET_FLAGS (bindex->ctree, GTK_CAN_FOCUS);
     gtk_widget_show_all (GTK_WIDGET(bindex));
@@ -994,9 +1015,12 @@
         ? g_list_last(GTK_CLIST(bindex->ctree)->selection)->data : NULL;
     bi->flag = flag;
     if(conditions) {
+	/* Remark : this hash table is owned by the index and
+	   will be freed when necessary. We don't need to take care of
+	   thar here.
+	*/
         bi->matching = 
-            libbalsa_mailbox_get_matching(bindex->mailbox_node->mailbox, 
-                                          op, conditions);
+            bndx_get_matching_messages(bindex, op, conditions);
     }
     gtk_ctree_pre_recursive(bindex->ctree, NULL, (GtkCTreeFunc)
                             balsa_index_scan_node, bi);
@@ -1006,7 +1030,7 @@
          * matching */
         node = bi->first;
     g_free(bi);
-    if(bi->matching) g_hash_table_destroy(bi->matching);
+
     return node;
 }
 
@@ -1634,6 +1658,9 @@
 	bindex->mailbox_node = NULL;
     }
 
+    /* destroy the match struct */
+    bndx_match_struct_destroy(bindex);
+
     if (GTK_OBJECT_CLASS(parent_class)->destroy)
         (*GTK_OBJECT_CLASS(parent_class)->destroy) (obj);
 }
@@ -2535,3 +2562,124 @@
     else if (to_mailbox == balsa_app.trash)
         enable_empty_trash(TRASH_FULL);
 }
+
+/* This func is a wrapper for libbalsa_mailbox_get_matching to be as smart
+   as possible : i.e. we don't want to recalculate the matching messages on
+   a "find again" request (I mean if the mailbox content has not changed in
+   between).
+   Here is the idea to be sure we'll recalculate when necessary : connect
+   to the mailbox signals telling us that it is changing. To be a bit smarter
+   we connect only to the "add" messages, because the remove ones are not
+   interesting for us, we only keep a removed message in our matching list,
+   nothing serious.
+*/
+
+/* Helper to compare regexs */
+
+static gboolean
+compare_regexs(GSList * c1,GSList * c2)
+{
+    GSList * l1, *l2;
+    LibBalsaConditionRegex * r1,* r2;
+
+    for (;c1;c1 = g_slist_next(c1)) {
+	r1 = c1->data;
+	for (l2 = c2;l2 ;l2 = g_slist_next(l2)) {
+	    r2 = l2->data;
+	    if (strcmp(r1->string,r2->string)==0)
+		break;
+	}
+	if (!l2) return FALSE;
+    }
+    return TRUE;
+}
+
+/* Helper to compare conditions, a bit obscure at first glance
+   but we have to compare complex structure, so we must check
+   all fields
+*/
+static gboolean
+compare_conditions(GSList * cnd1,GSList * cnd2)
+{
+    GSList * l1 = cnd1,* l2;
+    GSList *r1, *r2;
+    gboolean OK;
+
+    for (;l1;l1 = g_slist_next(l1)) {
+	LibBalsaCondition * c1 = l1->data;
+	LibBalsaCondition * c2;
+
+	OK = FALSE;
+	for (l2 = cnd2;l2 && !OK;l2 = g_slist_next(l2)) {
+	    c2 = l2->data;
+	    switch (c1->type) {
+	    case CONDITION_SIMPLE:
+		if ((c2->type == CONDITION_SIMPLE) 
+		    && (g_strcasecmp(c1->match.string,c2->match.string) == 0))
+		    OK = TRUE;
+		break;
+	    
+	    case CONDITION_REGEX:
+		if ((c2->type == CONDITION_REGEX) &&
+		    compare_regexs(c1->match.regexs,c2->match.regexs))
+		    OK = TRUE;
+		break;
+	    case CONDITION_DATE:
+		if ((c2->type == CONDITION_DATE) &&
+		    (c1->match.interval.date_low == c2->match.interval.date_low) &&
+		    (c1->match.interval.date_high == c2->match.interval.date_high))
+		    OK = TRUE;
+		break;
+		
+	    case CONDITION_FLAG:
+		if ((c2->type == CONDITION_FLAG) &&
+		    (c1->match.flags == c2->match.flags))
+		    OK = TRUE;
+		break;
+	    }    
+	}
+	/* We did not find the condition, comparison failed */
+	if (!OK) return FALSE;
+    }
+    return TRUE;
+}
+static GHashTable *
+bndx_get_matching_messages(BalsaIndex * index,gint op, GSList * conditions)
+{
+    /* This is illegal, we return NULL and change nothing */
+    if ((op == FILTER_NOOP) || !conditions)
+	return NULL;
+    
+    if (!index->match_struct) {
+	index->match_struct = g_new(BalsaIndexMatch,1);
+	index->match_struct->op = FILTER_NOOP;
+	index->match_struct->conditions = NULL;
+	index->match_struct->matching_messages = NULL;
+    }
+    /* Test if we need to recalculate the matching messages
+       cases where we need it :
+       - the new op and conditions differ from the current ones
+       - index->match->matching_messages == NULL : this means
+       that we never calculated it or that the mailbox content
+	 has changed.
+    */
+    if (!index->match_struct->matching_messages ||
+	(op != index->match_struct->op) ||
+	!compare_conditions(index->match_struct->conditions,conditions)) {
+	GSList * cnd;
+	
+	/* We make a copy of the conditions list, and first drop the preceding ones */
+	libbalsa_conditions_free(index->match_struct->conditions);
+	index->match_struct->conditions = NULL;
+	for (cnd = conditions;cnd;cnd = g_slist_next(cnd))
+	    index->match_struct->conditions =
+		g_slist_prepend(index->match_struct->conditions,
+				libbalsa_condition_clone(cnd->data));
+	index->match_struct->conditions = g_slist_reverse(index->match_struct->conditions);
+	index->match_struct->op = op;
+	g_hash_table_destroy(index->match_struct->matching_messages);
+	index->match_struct->matching_messages =
+	    libbalsa_mailbox_get_matching(index->mailbox_node->mailbox,op,conditions);
+    }
+    return index->match_struct->matching_messages;
+}
Only in balsa-current/src/: balsa-index.c~
diff -u /home/manu/prog/balsa-cvs/balsa/src/balsa-index.h balsa-current/src/balsa-index.h
--- /home/manu/prog/balsa-cvs/balsa/src/balsa-index.h	Sat May 18 08:29:09 2002
+++ balsa-current/src/balsa-index.h	Sat Aug 17 19:12:35 2002
@@ -30,6 +30,25 @@
 extern "C" {
 #endif				/* __cplusplus */
 
+    /* Struct used to keep track of the last sort we've made on an index
+       the idea being to avoid unnecessary recalculation */
+
+    struct _BalsaIndexMatch {
+	/* Fields describing the current matching conditions
+	   Remark : conditions is a copy, it is the responsibility
+	   of the owner (here the index) to free it
+	 */
+	gint op;
+	GSList * conditions;
+
+	/* This is the list of matching messages corresponding to the current
+	   conditions.
+	   Remark : we drop this list each time the mailbox content has changed
+	   or the conditions or the op has changed
+	*/
+	GHashTable * matching_messages;
+    };
+
     GtkType balsa_index_get_type(void);
 
 #define BALSA_TYPE_INDEX          (balsa_index_get_type ())
@@ -41,6 +60,7 @@
 
     typedef struct _BalsaIndex BalsaIndex;
     typedef struct _BalsaIndexClass BalsaIndexClass;
+    typedef struct _BalsaIndexMatch BalsaIndexMatch;
 
     struct _BalsaIndex {
         GtkScrolledWindow sw;    
@@ -56,6 +76,8 @@
 
 	gchar *date_string;
 	gboolean line_length;
+
+	BalsaIndexMatch * match_struct;
     };
 
     struct _BalsaIndexClass {
Only in balsa-current/src/: balsa-index.h~
Only in balsa-current/src/: balsa-index.o
Only in balsa-current/src/: balsa-mblist.o
Only in balsa-current/src/: balsa-message.o
Only in balsa-current/src/: expand-alias.o
Only in balsa-current/src/: filter-edit-callbacks.o
Only in balsa-current/src/: filter-edit-dialog.o
Only in balsa-current/src/: filter-export-callbacks.o
Only in balsa-current/src/: filter-export-dialog.o
Only in balsa-current/src/: filter-run-callbacks.o
Only in balsa-current/src/: filter-run-dialog.o
Only in balsa-current/src/: find-search.o
Only in balsa-current/src/: folder-conf.o
Only in balsa-current/src/: information-dialog.o
Only in balsa-current/src/: mailbox-conf.o
Only in balsa-current/src/: mailbox-node.o
Only in balsa-current/src/: main-window.o
Only in balsa-current/src/: main.o
Only in balsa-current/src/: message-window.o
Common subdirectories: /home/manu/prog/balsa-cvs/balsa/src/pixmaps and balsa-current/src/pixmaps
Only in balsa-current/src/: pref-manager.o
Only in balsa-current/src/: print.o
Only in balsa-current/src/: quote-color.o
Only in balsa-current/src/: save-restore.o
Only in balsa-current/src/: sendmsg-window.o
Only in balsa-current/src/: spell-check.o
Only in balsa-current/src/: store-address.o
Only in balsa-current/src/: toolbar-factory.o
Only in balsa-current/src/: toolbar-prefs.o


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]