From b8ea035b9f04570ca8de2805ca6e63a7032afb9c Mon Sep 17 00:00:00 2001 From: Rodrigo Moya Date: Thu, 19 Sep 2002 17:32:04 +0000 Subject: More fixes for #24210 2002-09-19 Rodrigo Moya More fixes for #24210 * pcs/query.c: added list of cached queries and changed the Query class to work with several listeners, not only one. (query_init): initialize new members. (query_destroy): free new members. (add_component, remove_component, parse_sexp, match_component, process_components_cb): notify all listeners. (notify_uid_cb, start_cached_query_cb): implemented integration of cached queries. (query_new): search the query in the cache before creating a new one. And if we create a new one, store it in the cache. svn path=/trunk/; revision=18120 --- calendar/ChangeLog | 15 +++ calendar/pcs/query.c | 297 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 248 insertions(+), 64 deletions(-) (limited to 'calendar') diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 21b00e0e34..a4c68caa0b 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,18 @@ +2002-09-19 Rodrigo Moya + + More fixes for #24210 + + * pcs/query.c: added list of cached queries and changed the Query + class to work with several listeners, not only one. + (query_init): initialize new members. + (query_destroy): free new members. + (add_component, remove_component, parse_sexp, match_component, + process_components_cb): notify all listeners. + (notify_uid_cb, start_cached_query_cb): implemented integration of + cached queries. + (query_new): search the query in the cache before creating a new + one. And if we create a new one, store it in the cache. + 2002-09-19 JP Rosevear * gui/dialogs/recurrence-page.c (simple_recur_to_comp): bump the diff --git a/calendar/pcs/query.c b/calendar/pcs/query.c index 8ecd3445cd..686620c686 100644 --- a/calendar/pcs/query.c +++ b/calendar/pcs/query.c @@ -39,6 +39,12 @@ +typedef struct { + Query *query; + GNOME_Evolution_Calendar_QueryListener ql; + guint tid; +} StartCachedQueryInfo; + /* States of a query */ typedef enum { QUERY_WAIT_FOR_BACKEND, /* the query is not populated and the backend is not loaded */ @@ -59,8 +65,8 @@ struct _QueryPrivate { /* The default timezone for the calendar. */ icaltimezone *default_zone; - /* Listener to which we report changes in the live query */ - GNOME_Evolution_Calendar_QueryListener ql; + /* Listeners to which we report changes in the live query */ + GList *listeners; /* Sexp that defines the query */ char *sexp; @@ -70,6 +76,8 @@ struct _QueryPrivate { guint timeout_id; QueryState state; + GList *cached_timeouts; + /* List of UIDs that we still have to process */ GList *pending_uids; int n_pending; @@ -91,6 +99,7 @@ static void query_init (Query *query); static void query_destroy (GtkObject *object); static BonoboXObjectClass *parent_class; +static GList *cached_queries = NULL; @@ -128,12 +137,14 @@ query_init (Query *query) priv->backend = NULL; priv->qb = NULL; priv->default_zone = NULL; - priv->ql = CORBA_OBJECT_NIL; + priv->listeners = NULL; priv->sexp = NULL; priv->timeout_id = 0; priv->state = QUERY_WAIT_FOR_BACKEND; + priv->cached_timeouts = NULL; + priv->pending_uids = NULL; priv->uids = g_hash_table_new (g_str_hash, g_str_equal); @@ -182,18 +193,22 @@ query_destroy (GtkObject *object) priv->qb = NULL; - if (priv->ql != CORBA_OBJECT_NIL) { + if (priv->listeners != NULL) { CORBA_Environment ev; + GList *l; CORBA_exception_init (&ev); - bonobo_object_release_unref (priv->ql, &ev); + for (l = priv->listeners; l != NULL; l = l->next) { + bonobo_object_release_unref (l->data, &ev); - if (BONOBO_EX (&ev)) - g_message ("query_destroy(): Could not unref the listener\n"); + if (BONOBO_EX (&ev)) + g_message ("query_destroy(): Could not unref the listener\n"); + } CORBA_exception_free (&ev); - priv->ql = CORBA_OBJECT_NIL; + g_list_free (priv->listeners); + priv->listeners = NULL; } if (priv->sexp) { @@ -211,6 +226,16 @@ query_destroy (GtkObject *object) priv->timeout_id = 0; } + if (priv->cached_timeouts) { + GList *l; + + for (l = priv->cached_timeouts; l != NULL; l = l->next) + g_source_remove (GPOINTER_TO_INT (l->data)); + + g_list_free (priv->cached_timeouts); + priv->cached_timeouts = NULL; + } + if (priv->pending_uids) { GList *l; @@ -933,6 +958,7 @@ add_component (Query *query, const char *uid, gboolean query_in_progress, int n_ QueryPrivate *priv; char *old_uid; CORBA_Environment ev; + GList *l; if (query_in_progress) g_assert (n_scanned > 0 || n_scanned <= total); @@ -947,17 +973,19 @@ add_component (Query *query, const char *uid, gboolean query_in_progress, int n_ g_hash_table_insert (priv->uids, g_strdup (uid), NULL); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_QueryListener_notifyObjUpdated ( - priv->ql, - (char *) uid, - query_in_progress, - n_scanned, - total, - &ev); + for (l = priv->listeners; l != NULL; l = l->next) { + GNOME_Evolution_Calendar_QueryListener_notifyObjUpdated ( + l->data, + (char *) uid, + query_in_progress, + n_scanned, + total, + &ev); - if (BONOBO_EX (&ev)) - g_message ("add_component(): Could not notify the listener of an " - "updated component"); + if (BONOBO_EX (&ev)) + g_message ("add_component(): Could not notify the listener of an " + "updated component"); + } CORBA_exception_free (&ev); } @@ -969,6 +997,7 @@ remove_component (Query *query, const char *uid) QueryPrivate *priv; char *old_uid; CORBA_Environment ev; + GList *l; priv = query->priv; @@ -983,14 +1012,16 @@ remove_component (Query *query, const char *uid) g_free (old_uid); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_QueryListener_notifyObjRemoved ( - priv->ql, - (char *) uid, - &ev); + for (l = priv->listeners; l != NULL; l = l->next) { + GNOME_Evolution_Calendar_QueryListener_notifyObjRemoved ( + l->data, + (char *) uid, + &ev); - if (BONOBO_EX (&ev)) - g_message ("remove_component(): Could not notify the listener of a " - "removed component"); + if (BONOBO_EX (&ev)) + g_message ("remove_component(): Could not notify the listener of a " + "removed component"); + } CORBA_exception_free (&ev); } @@ -1081,24 +1112,27 @@ parse_sexp (Query *query) if (e_sexp_parse (priv->esexp) == -1) { const char *error_str; CORBA_Environment ev; + GList *l; priv->state = QUERY_PARSE_ERROR; - /* Report the error to the listener */ + /* Report the error to the listeners */ error_str = e_sexp_error (priv->esexp); g_assert (error_str != NULL); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( - priv->ql, - GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR, - error_str, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("parse_sexp(): Could not notify the listener of " - "a parse error"); + for (l = priv->listeners; l != NULL; l = l->next) { + GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( + l->data, + GNOME_Evolution_Calendar_QueryListener_PARSE_ERROR, + error_str, + &ev); + + if (BONOBO_EX (&ev)) + g_message ("parse_sexp(): Could not notify the listener of " + "a parse error"); + } CORBA_exception_free (&ev); @@ -1142,35 +1176,41 @@ match_component (Query *query, const char *uid, if (!result) { const char *error_str; CORBA_Environment ev; + GList *l; error_str = e_sexp_error (priv->esexp); g_assert (error_str != NULL); CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_QueryListener_notifyEvalError ( - priv->ql, - error_str, - &ev); - - if (BONOBO_EX (&ev)) - g_message ("match_component(): Could not notify the listener of " - "an evaluation error"); + for (l = priv->listeners; l != NULL; l = l->next) { + GNOME_Evolution_Calendar_QueryListener_notifyEvalError ( + l->data, + error_str, + &ev); + + if (BONOBO_EX (&ev)) + g_message ("match_component(): Could not notify the listener of " + "an evaluation error"); + } CORBA_exception_free (&ev); return; } else if (result->type != ESEXP_RES_BOOL) { CORBA_Environment ev; + GList *l; CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_QueryListener_notifyEvalError ( - priv->ql, - _("Evaluation of the search expression did not yield a boolean value"), - &ev); - - if (BONOBO_EX (&ev)) - g_message ("match_component(): Could not notify the listener of " - "an unexpected result value type when evaluating the " - "search expression"); + for (l = priv->listeners; l != NULL; l = l->next) { + GNOME_Evolution_Calendar_QueryListener_notifyEvalError ( + l->data, + _("Evaluation of the search expression did not yield a boolean value"), + &ev); + + if (BONOBO_EX (&ev)) + g_message ("match_component(): Could not notify the listener of " + "an unexpected result value type when evaluating the " + "search expression"); + } CORBA_exception_free (&ev); } else { @@ -1233,22 +1273,24 @@ process_components_cb (gpointer data) } bonobo_object_unref (BONOBO_OBJECT (query)); - if (!priv || !priv->ql) + if (!priv || !priv->listeners) return FALSE; - /* notify listener that the query ended */ + /* notify listeners that the query ended */ priv->state = QUERY_DONE; CORBA_exception_init (&ev); - GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( - priv->ql, - GNOME_Evolution_Calendar_QueryListener_SUCCESS, - "", - &ev); + for (l = priv->listeners; l != NULL; l = l->next) { + GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( + l->data, + GNOME_Evolution_Calendar_QueryListener_SUCCESS, + "", + &ev); - if (BONOBO_EX (&ev)) - g_message ("start_query(): Could not notify the listener of " - "a finished query"); + if (BONOBO_EX (&ev)) + g_message ("start_query(): Could not notify the listener of " + "a finished query"); + } CORBA_exception_free (&ev); @@ -1344,6 +1386,79 @@ start_query_cb (gpointer data) return FALSE; } +static void +notify_uid_cb (gpointer key, gpointer value, gpointer data) +{ + CORBA_Environment ev; + char *uid = (char *) key; + StartCachedQueryInfo *info = (StartCachedQueryInfo *) data; + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_QueryListener_notifyObjUpdated ( + info->ql, + uid, + FALSE, + g_hash_table_size (info->query->priv->uids), + g_hash_table_size (info->query->priv->uids), + &ev); + + if (BONOBO_EX (&ev)) + g_message ("notify_uid_cb(): Could not notify the listener of an " + "updated component"); + + CORBA_exception_free (&ev); +} + +/* Idle handler for starting a cached query */ +static gboolean +start_cached_query_cb (gpointer data) +{ + CORBA_Environment ev; + QueryPrivate *priv; + StartCachedQueryInfo *info = (StartCachedQueryInfo *) data; + + priv = info->query->priv; + + /* if the query hasn't started yet, we add the listener */ + if (priv->state == QUERY_START_PENDING || + priv->state == QUERY_WAIT_FOR_BACKEND) { + priv->listeners = g_list_append (priv->listeners, info->ql); + + g_free (info); + priv->cached_timeouts = g_list_remove (priv->cached_timeouts, + GPOINTER_TO_INT (info->tid)); + + return FALSE; + } else if (priv->state == QUERY_IN_PROGRESS) { + /* if it's in progress, we just wait */ + return TRUE; + } + + /* if the query is done, then we just notify the listener */ + g_source_remove (info->tid); + priv->cached_timeouts = g_list_remove (priv->cached_timeouts, + GPOINTER_TO_INT (info->tid)); + + g_hash_table_foreach (priv->uids, (GHFunc) notify_uid_cb, info); + + priv->listeners = g_list_append (priv->listeners, info->ql); + + CORBA_exception_init (&ev); + GNOME_Evolution_Calendar_QueryListener_notifyQueryDone ( + info->ql, + GNOME_Evolution_Calendar_QueryListener_SUCCESS, + "", + &ev); + if (BONOBO_EX (&ev)) + g_message ("start_cached_query_cb(): Could not notify the listener of " + "a finished query"); + + CORBA_exception_free (&ev); + g_free (info); + + return FALSE; +} + /* Callback used when the backend gets loaded; we just queue the query to be * started later. */ @@ -1368,6 +1483,18 @@ backend_opened_cb (CalBackend *backend, CalBackendOpenStatus status, gpointer da } } +/* Callback used when the backend for a cached query is destroyed */ +static void +backend_destroyed_cb (GtkObject *object, gpointer data) +{ + Query *query; + + query = QUERY (data); + + cached_queries = g_list_remove (cached_queries, query); + bonobo_object_unref (query); +} + /** * query_construct: * @query: A live search query. @@ -1401,10 +1528,10 @@ query_construct (Query *query, priv = query->priv; CORBA_exception_init (&ev); - priv->ql = CORBA_Object_duplicate (ql, &ev); + priv->listeners = g_list_append (NULL, CORBA_Object_duplicate (ql, &ev)); if (BONOBO_EX (&ev)) { g_message ("query_construct(): Could not duplicate the listener"); - priv->ql = CORBA_OBJECT_NIL; + priv->listeners = NULL; CORBA_exception_free (&ev); return NULL; } @@ -1448,12 +1575,54 @@ query_new (CalBackend *backend, const char *sexp) { Query *query; + GList *l; + /* first, see if we've got this query in our cache */ + for (l = cached_queries; l != NULL; l = l->next) { + query = QUERY (l->data); + + g_assert (query != NULL); + + if (query->priv->backend == backend && + !strcmp (query->priv->sexp, sexp)) { + StartCachedQueryInfo *info; + CORBA_Environment ev; + + info = g_new0 (StartCachedQueryInfo, 1); + info->query = query; + + CORBA_exception_init (&ev); + info->ql = CORBA_Object_duplicate (ql, &ev); + if (BONOBO_EX (&ev)) { + g_message ("query_new(): Could not duplicate listener object"); + g_free (info); + + return NULL; + } + CORBA_exception_free (&ev); + + info->tid = g_timeout_add (100, (GSourceFunc) start_cached_query_cb, info); + query->priv->cached_timeouts = g_list_append (query->priv->cached_timeouts, + GINT_TO_POINTER (info->tid)); + + bonobo_object_ref (BONOBO_OBJECT (query)); + return query; + } + } + + /* not found, so create a new one */ query = QUERY (gtk_type_new (QUERY_TYPE)); if (!query_construct (query, backend, ql, sexp)) { bonobo_object_unref (BONOBO_OBJECT (query)); return NULL; } + /* add the new query to our cache */ + gtk_signal_connect (GTK_OBJECT (query->priv->backend), "destroy", + GTK_SIGNAL_FUNC (backend_destroyed_cb), query); + + bonobo_object_ref (BONOBO_OBJECT (query)); + cached_queries = g_list_append (cached_queries, query); + return query; } -- cgit