diff options
Diffstat (limited to 'addressbook/backend')
-rw-r--r-- | addressbook/backend/ebook/e-book-view-listener.c | 26 | ||||
-rw-r--r-- | addressbook/backend/pas/pas-backend-ldap.c | 172 |
2 files changed, 155 insertions, 43 deletions
diff --git a/addressbook/backend/ebook/e-book-view-listener.c b/addressbook/backend/ebook/e-book-view-listener.c index 40e467ef93..9981375631 100644 --- a/addressbook/backend/ebook/e-book-view-listener.c +++ b/addressbook/backend/ebook/e-book-view-listener.c @@ -72,8 +72,30 @@ e_book_view_listener_queue_response (EBookViewListener *listener, g_free (response); return; } - - listener->priv->response_queue = g_list_append (listener->priv->response_queue, response); + + /* a slight optimization for huge ldap queries. if there's an + existing Add response on the end of the queue, and we're an + Add response, we just glom the two lists of cards + together */ + if (response->op == CardAddedEvent) { + GList *last = g_list_last (listener->priv->response_queue); + EBookViewListenerResponse *last_resp = NULL; + + if (last) last_resp = last->data; + + if (last_resp && last_resp->op == CardAddedEvent ) { + response->cards = g_list_concat (last_resp->cards, response->cards); + g_free (response); + /* there should already be a timeout since the + queue isn't empty, so we'll just return + here */ + return; + } + else + listener->priv->response_queue = g_list_append (last, response); + } + else + listener->priv->response_queue = g_list_append (listener->priv->response_queue, response); if (listener->priv->timeout_id == 0) { diff --git a/addressbook/backend/pas/pas-backend-ldap.c b/addressbook/backend/pas/pas-backend-ldap.c index 60f2103c79..e99b51c699 100644 --- a/addressbook/backend/pas/pas-backend-ldap.c +++ b/addressbook/backend/pas/pas-backend-ldap.c @@ -36,6 +36,8 @@ #include "ldap_schema.h" #endif +#include <sys/time.h> + #include <e-util/e-sexp.h> #include <ebook/e-card-simple.h> @@ -49,6 +51,22 @@ #define LDAP_MAX_SEARCH_RESPONSES 100 +/* interval for our poll_ldap timeout */ +#define LDAP_POLL_INTERVAL 20 + +/* timeout for ldap_result */ +#define LDAP_RESULT_TIMEOUT_MILLIS 10 + +/* smart grouping stuff */ +#define GROUPING_INITIAL_SIZE 1 +#define GROUPING_MAXIMUM_SIZE 200 + +/* the next two are in milliseconds */ +#define GROUPING_MINIMUM_WAIT 0 /* we never send updates faster than this, to avoid totally spamming the UI */ +#define GROUPING_MAXIMUM_WAIT 250 /* we always send updates (if there are pending cards) when we hit this */ + +#define TV_TO_MILLIS(timeval) ((timeval).tv_sec * 1000 + (timeval).tv_usec / 1000) + /* the objectClasses we need */ #define TOP "top" #define PERSON "person" @@ -104,9 +122,21 @@ struct _PASBackendLDAPBookView { PASBackendLDAPPrivate *blpriv; gchar *search; PASBackendCardSExp *card_sexp; - int search_idle; + int search_timeout; int search_msgid; LDAPOp *search_op; + + /* grouping stuff */ + + GList *pending_adds; /* the cards we're sending */ + int num_pending_adds; /* the number waiting to be sent */ + int target_pending_adds; /* the cutoff that forces a flush to the client, if it happens before the timeout */ + int num_sent_this_time; /* the number of cards we sent to the client before the most recent timeout */ + int num_sent_last_time; /* the number of cards we sent to the client before the previous timeout */ + glong grouping_time_start; + + /* used by poll_ldap to only send the status messages once */ + gboolean notified_receiving_results; }; typedef gboolean (*LDAPOpHandler)(PASBackend *backend, LDAPOp *op); @@ -256,11 +286,11 @@ view_destroy(GtkObject *object, gpointer data) for (list = bl->priv->book_views; list; list = g_list_next(list)) { PASBackendLDAPBookView *view = list->data; if (view->book_view == PAS_BOOK_VIEW(object)) { - if (view->search_idle != 0) { + if (view->search_timeout != 0) { /* we have a search running on the - ldap connection. remove the idle + ldap connection. remove the timeout handler and anbandon the msg id */ - g_source_remove(view->search_idle); + g_source_remove(view->search_timeout); if (view->search_msgid != -1) ldap_abandon (bl->priv->ldap, view->search_msgid); @@ -2162,7 +2192,7 @@ build_card_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasse char *attr; BerElement *ber = NULL; - g_print ("build_card_from_entry, dn = %s\n", dn); + // g_print ("build_card_from_entry, dn = %s\n", dn); e_card_simple_set_id (card, dn); for (attr = ldap_first_attribute (ldap, e, &ber); attr; @@ -2215,9 +2245,21 @@ build_card_from_entry (LDAP *ldap, LDAPMessage *e, GList **existing_objectclasse e_card_simple_sync_card (card); + gtk_object_unref (GTK_OBJECT (ecard)); + return card; } +static void +send_pending_adds (PASBackendLDAPBookView *view) +{ + view->num_sent_this_time += view->num_pending_adds; + pas_book_view_notify_add (view->book_view, view->pending_adds); + g_list_foreach (view->pending_adds, (GFunc)g_free, NULL); + view->pending_adds = NULL; + view->num_pending_adds = 0; +} + static gboolean poll_ldap (LDAPSearchOp *op) { @@ -2226,54 +2268,89 @@ poll_ldap (LDAPSearchOp *op) LDAP *ldap = bl->priv->ldap; int rc; LDAPMessage *res, *e; - GList *cards = NULL; static int received = 0; + GTimeVal cur_time; + glong cur_millis; + struct timeval timeout; - pas_book_view_notify_status_message (view->book_view, _("Receiving LDAP search results...")); - - rc = ldap_result (ldap, view->search_msgid, 0, NULL, &res); - - if (rc == -1 && received == 0) { - pas_book_view_notify_status_message (view->book_view, _("Restarting search.")); - /* connection went down and we never got any. */ - bl->priv->connected = FALSE; + timeout.tv_sec = 0; + timeout.tv_usec = LDAP_RESULT_TIMEOUT_MILLIS * 1000; - /* this will reopen the connection */ - ldap_op_restart ((LDAPOp*)op); - return FALSE; + if (!view->notified_receiving_results) { + view->notified_receiving_results = TRUE; + pas_book_view_notify_status_message (view->book_view, _("Receiving LDAP search results...")); } - if (rc != LDAP_RES_SEARCH_ENTRY) { - view->search_idle = 0; - pas_book_view_notify_complete (view->book_view); - ldap_op_finished ((LDAPOp*)op); - received = 0; - return FALSE; - } + rc = ldap_result (ldap, view->search_msgid, 0, &timeout, &res); + if (rc != 0) {/* rc == 0 means timeout exceeded */ + if (rc == -1 && received == 0) { + pas_book_view_notify_status_message (view->book_view, _("Restarting search.")); + /* connection went down and we never got any. */ + bl->priv->connected = FALSE; - received = 1; - - e = ldap_first_entry(ldap, res); + /* this will reopen the connection */ + ldap_op_restart ((LDAPOp*)op); + return FALSE; + } - while (NULL != e) { - ECardSimple *card = build_card_from_entry (ldap, e, NULL); + if (rc != LDAP_RES_SEARCH_ENTRY) { + view->search_timeout = 0; + if (view->num_pending_adds) + send_pending_adds (view); + pas_book_view_notify_complete (view->book_view); + ldap_op_finished ((LDAPOp*)op); + received = 0; + return FALSE; + } - cards = g_list_append (cards, e_card_simple_get_vcard_assume_utf8 (card)); + received = 1; - gtk_object_unref (GTK_OBJECT(card)); + e = ldap_first_entry(ldap, res); - e = ldap_next_entry(ldap, e); - } + while (NULL != e) { + ECardSimple *card = build_card_from_entry (ldap, e, NULL); - if (cards) { - pas_book_view_notify_add (view->book_view, cards); - - g_list_foreach (cards, (GFunc)g_free, NULL); - g_list_free (cards); - cards = NULL; + view->pending_adds = g_list_append (view->pending_adds, + e_card_simple_get_vcard_assume_utf8 (card)); + view->num_pending_adds ++; + + gtk_object_unref (GTK_OBJECT(card)); + + e = ldap_next_entry(ldap, e); + } + + ldap_msgfree(res); } - ldap_msgfree(res); + g_get_current_time (&cur_time); + cur_millis = TV_TO_MILLIS (cur_time); + + if (cur_millis - view->grouping_time_start > GROUPING_MINIMUM_WAIT) { + + if (view->num_pending_adds >= view->target_pending_adds) + send_pending_adds (view); + + if (cur_millis - view->grouping_time_start > GROUPING_MAXIMUM_WAIT) { + GTimeVal new_start; + + if (view->num_pending_adds) + send_pending_adds (view); + view->target_pending_adds = MIN (GROUPING_MAXIMUM_SIZE, + (view->num_sent_this_time + view->num_sent_last_time) / 2); + view->target_pending_adds = MAX (view->target_pending_adds, 1); + +#ifdef PERFORMANCE_SPEW + printf ("num sent this time %d, last time %d, target pending adds set to %d\n", + view->num_sent_this_time, + view->num_sent_last_time, + view->target_pending_adds); +#endif + g_get_current_time (&new_start); + view->grouping_time_start = TV_TO_MILLIS (new_start); + view->num_sent_last_time = view->num_sent_this_time; + view->num_sent_this_time = 0; + } + } return TRUE; } @@ -2295,6 +2372,17 @@ ldap_search_handler (PASBackend *backend, LDAPOp *op) PASBackendLDAPBookView *view = search_op->view; LDAP *ldap = bl->priv->ldap; int ldap_err; + GTimeVal search_start; + + view->pending_adds = NULL; + view->num_pending_adds = 0; + view->target_pending_adds = GROUPING_INITIAL_SIZE; + + g_get_current_time (&search_start); + view->grouping_time_start = TV_TO_MILLIS (search_start); + view->num_sent_last_time = 0; + view->num_sent_this_time = 0; + view->notified_receiving_results = FALSE; ldap_err = ldap_search_ext (ldap, bl->priv->ldap_rootdn, bl->priv->ldap_scope, @@ -2315,7 +2403,9 @@ ldap_search_handler (PASBackend *backend, LDAPOp *op) return TRUE; /* act synchronous in this case */ } else { - view->search_idle = g_idle_add((GSourceFunc)poll_ldap, search_op); + view->search_timeout = g_timeout_add (LDAP_POLL_INTERVAL, + (GSourceFunc) poll_ldap, + search_op); } /* we're async */ |