[evolution-data-server] CalDAV - sync performance improvements
- From: Milan Crha <mcrha src gnome org>
- To: svn-commits-list gnome org
- Subject: [evolution-data-server] CalDAV - sync performance improvements
- Date: Fri, 26 Jun 2009 17:06:02 +0000 (UTC)
commit 92b9cb0f7aa06c2c308bbf8805e4aaf771fa03e9
Author: Milan Crha <mcrha redhat com>
Date: Fri Jun 26 19:05:08 2009 +0200
CalDAV - sync performance improvements
calendar/backends/caldav/e-cal-backend-caldav.c | 535 ++++++++++++++---------
1 files changed, 339 insertions(+), 196 deletions(-)
---
diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c
index 5dfc36c..faf2f07 100644
--- a/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -50,6 +50,7 @@
#define d(x)
#define CALDAV_CTAG_KEY "CALDAV_CTAG"
+#define CALDAV_MAX_MULTIGET_AMOUNT 100 /* what's the maximum count of items to fetch within a multiget request */
/* in seconds */
#define DEFAULT_REFRESH_TIME 60
@@ -605,9 +606,6 @@ xp_object_get_href (xmlXPathObjectPtr result)
}
ret = g_strdup (ret);
-
- if (caldav_debug_show (DEBUG_SERVER_ITEMS))
- printf ("CalDAV found href: %s\n", ret);
}
xmlXPathFreeObject (result);
@@ -681,7 +679,7 @@ xp_object_get_number (xmlXPathObjectPtr result)
#define XPATH_STATUS "string(/D:multistatus/D:response[%d]/D:propstat/D:status)"
#define XPATH_GETETAG_STATUS "string(/D:multistatus/D:response[%d]/D:propstat/D:prop/D:getetag/../../D:status)"
#define XPATH_GETETAG "string(/D:multistatus/D:response[%d]/D:propstat/D:prop/D:getetag)"
-#define XPATH_CALENDAR_DATA "string(/D:multistatus/D:response[%d]/C:calendar-data)"
+#define XPATH_CALENDAR_DATA "string(/D:multistatus/D:response[%d]/D:propstat/D:prop/C:calendar-data)"
#define XPATH_GETCTAG_STATUS "string(/D:multistatus/D:response/D:propstat/D:prop/CS:getctag/../../D:status)"
#define XPATH_GETCTAG "string(/D:multistatus/D:response/D:propstat/D:prop/CS:getctag)"
#define XPATH_OWNER_STATUS "string(/D:multistatus/D:response/D:propstat/D:prop/D:owner/D:href/../../../D:status)"
@@ -1090,8 +1088,12 @@ check_calendar_changed_on_server (ECalBackendCalDAV *cbdav)
return result;
}
+/* only_hrefs is a list of requested objects to fetch; it has precedence from
+ start_time/end_time, which are used only when both positive.
+ Times are supposed to be in UTC, if set.
+*/
static gboolean
-caldav_server_list_objects (ECalBackendCalDAV *cbdav, CalDAVObject **objs, gint *len)
+caldav_server_list_objects (ECalBackendCalDAV *cbdav, CalDAVObject **objs, gint *len, GSList *only_hrefs, time_t start_time, time_t end_time)
{
ECalBackendCalDAVPrivate *priv;
xmlOutputBufferPtr buf;
@@ -1113,7 +1115,10 @@ caldav_server_list_objects (ECalBackendCalDAV *cbdav, CalDAVObject **objs, gint
/* Maybe we should just do a g_strdup_printf here? */
/* Prepare request body */
doc = xmlNewDoc ((xmlChar *) "1.0");
- root = xmlNewDocNode (doc, NULL, (xmlChar *) "calendar-query", NULL);
+ if (!only_hrefs)
+ root = xmlNewDocNode (doc, NULL, (xmlChar *) "calendar-query", NULL);
+ else
+ root = xmlNewDocNode (doc, NULL, (xmlChar *) "calendar-multiget", NULL);
nscd = xmlNewNs (root, (xmlChar *) "urn:ietf:params:xml:ns:caldav", (xmlChar *) "C");
xmlSetNs (root, nscd);
xmlDocSetRootElement (doc, root);
@@ -1122,26 +1127,52 @@ caldav_server_list_objects (ECalBackendCalDAV *cbdav, CalDAVObject **objs, gint
nsdav = xmlNewNs (root, (xmlChar *) "DAV:", (xmlChar *) "D");
node = xmlNewTextChild (root, nsdav, (xmlChar *) "prop", NULL);
xmlNewTextChild (node, nsdav, (xmlChar *) "getetag", NULL);
+ if (only_hrefs) {
+ GSList *l;
- node = xmlNewTextChild (root, nscd, (xmlChar *) "filter", NULL);
- node = xmlNewTextChild (node, nscd, (xmlChar *) "comp-filter", NULL);
- xmlSetProp (node, (xmlChar *) "name", (xmlChar *) "VCALENDAR");
+ xmlNewTextChild (node, nscd, (xmlChar *) "calendar-data", NULL);
+ for (l = only_hrefs; l; l = l->next) {
+ if (l->data) {
+ xmlNewTextChild (root, nsdav, (xmlChar *) "href", (xmlChar *) l->data);
+ }
+ }
+ } else {
+ node = xmlNewTextChild (root, nscd, (xmlChar *) "filter", NULL);
+ node = xmlNewTextChild (node, nscd, (xmlChar *) "comp-filter", NULL);
+ xmlSetProp (node, (xmlChar *) "name", (xmlChar *) "VCALENDAR");
- sn = xmlNewTextChild (node, nscd, (xmlChar *) "comp-filter", NULL);
- switch (e_cal_backend_get_kind (E_CAL_BACKEND (cbdav))) {
- default:
- case ICAL_VEVENT_COMPONENT:
- xmlSetProp (sn, (xmlChar *) "name", (xmlChar *) "VEVENT");
- break;
- case ICAL_VJOURNAL_COMPONENT:
- xmlSetProp (sn, (xmlChar *) "name", (xmlChar *) "VJOURNAL");
- break;
- case ICAL_VTODO_COMPONENT:
- xmlSetProp (sn, (xmlChar *) "name", (xmlChar *) "VTODO");
- break;
- }
- /* ^^^ add timerange for performance? */
+ sn = xmlNewTextChild (node, nscd, (xmlChar *) "comp-filter", NULL);
+ switch (e_cal_backend_get_kind (E_CAL_BACKEND (cbdav))) {
+ default:
+ case ICAL_VEVENT_COMPONENT:
+ xmlSetProp (sn, (xmlChar *) "name", (xmlChar *) "VEVENT");
+ break;
+ case ICAL_VJOURNAL_COMPONENT:
+ xmlSetProp (sn, (xmlChar *) "name", (xmlChar *) "VJOURNAL");
+ break;
+ case ICAL_VTODO_COMPONENT:
+ xmlSetProp (sn, (xmlChar *) "name", (xmlChar *) "VTODO");
+ break;
+ }
+
+ if (start_time > 0 || end_time > 0) {
+ gchar *tmp;
+ sn = xmlNewTextChild (sn, nscd, (xmlChar *) "time-range", NULL);
+
+ if (start_time > 0) {
+ tmp = isodate_from_time_t (start_time);
+ xmlSetProp (sn, (xmlChar *) "start", (xmlChar *) tmp);
+ g_free (tmp);
+ }
+
+ if (end_time > 0) {
+ tmp = isodate_from_time_t (end_time);
+ xmlSetProp (sn, (xmlChar *) "end", (xmlChar *) tmp);
+ g_free (tmp);
+ }
+ }
+ }
buf = xmlAllocOutputBuffer (NULL);
xmlNodeDumpOutput (buf, doc, root, 0, 1, NULL);
@@ -1565,153 +1596,117 @@ caldav_receive_schedule_outbox_url (ECalBackendCalDAV *cbdav)
/* ************************************************************************* */
/* Synchronization foo */
-struct put_to_cache_data
-{
- icalcomponent *icomp;
- gchar *href;
- gchar *etag;
-};
+static gboolean extract_timezones (ECalBackendCalDAV *cbdav, icalcomponent *icomp);
-static void
-put_to_cache_data_and_free_cb (gpointer pdata, gpointer user_data)
+struct cache_comp_list
{
- struct put_to_cache_data *data = pdata;
- ECalBackendCalDAV *cbdav = user_data;
-
- g_return_if_fail (data != NULL);
- g_return_if_fail (data->icomp != NULL);
-
- put_comp_to_cache (cbdav, data->icomp, data->href, data->etag);
-
- icalcomponent_free (data->icomp);
- g_free (data->href);
- g_free (data->etag);
- g_free (data);
-}
-
-static gboolean extract_timezones (ECalBackendCalDAV *cbdav, icalcomponent *icomp);
+ GSList *slist;
+};
static gboolean
-synchronize_object (ECalBackendCalDAV *cbdav,
- CalDAVObject *object,
- ECalComponent *old_comp,
- GList **created,
- GList **modified,
- GList **put_to_cache)
+remove_complist_from_cache_and_notify_cb (gpointer key, gpointer value, gpointer data)
{
- ECalBackendCalDAVPrivate *priv;
- ECalBackendSyncStatus result;
- ECalBackend *bkend;
- icalcomponent *icomp, *subcomp;
- icalcomponent_kind kind;
- gboolean res;
-
- res = TRUE;
- result = caldav_server_get_object (cbdav, object);
-
- if (result != GNOME_Evolution_Calendar_Success)
- return FALSE;
-
- priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+ GSList *l;
+ struct cache_comp_list *ccl = value;
+ ECalBackendCalDAV *cbdav = data;
+ ECalBackendCalDAVPrivate *priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
- icomp = icalparser_parse_string (object->cdata);
- kind = icalcomponent_isa (icomp);
- bkend = E_CAL_BACKEND (cbdav);
+ for (l = ccl->slist; l; l = l->next) {
+ ECalComponent *old_comp = l->data;
+ ECalComponentId *id;
- extract_timezones (cbdav, icomp);
+ id = e_cal_component_get_id (old_comp);
+ if (!id) {
+ continue;
+ }
- if (kind == ICAL_VCALENDAR_COMPONENT) {
- ECalComponent *comp;
- struct put_to_cache_data *data;
+ if (e_cal_backend_cache_remove_component (priv->cache, id->uid, id->rid)) {
+ gchar *old_str = e_cal_component_get_as_string (old_comp);
- kind = e_cal_backend_get_kind (bkend);
- res = FALSE;
+ e_cal_backend_notify_object_removed ((ECalBackend *)cbdav, id, old_str, NULL);
- for (subcomp = icalcomponent_get_first_component (icomp, kind);
- subcomp;
- subcomp = icalcomponent_get_next_component (icomp, kind)) {
- res = TRUE;
-
- comp = e_cal_component_new ();
- if (e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) {
- ecalcomp_set_href (comp, object->href);
- ecalcomp_set_etag (comp, object->etag);
+ g_free (old_str);
+ }
- if (old_comp == NULL) {
- *created = g_list_prepend (*created, g_object_ref (comp));
- } else {
- /* they will be in the opposite order in the list */
- *modified = g_list_prepend (*modified, g_object_ref (old_comp));
- *modified = g_list_prepend (*modified, g_object_ref (comp));
- }
- }
+ e_cal_component_free_id (id);
+ }
- g_object_unref (comp);
- }
+ return FALSE;
+}
- data = g_new0 (struct put_to_cache_data, 1);
- data->icomp = icomp;
- data->href = g_strdup (object->href);
- data->etag = g_strdup (object->etag);
+static void
+free_comp_list (gpointer cclist)
+{
+ struct cache_comp_list *ccl = cclist;
- *put_to_cache = g_list_prepend (*put_to_cache, data);
- } else {
- res = FALSE;
- icalcomponent_free (icomp);
- }
+ g_return_if_fail (ccl != NULL);
- return res;
+ g_slist_foreach (ccl->slist, (GFunc) g_object_unref, NULL);
+ g_slist_free (ccl->slist);
+ g_free (ccl);
}
#define etags_match(_tag1, _tag2) ((_tag1 == _tag2) ? TRUE : \
g_str_equal (_tag1 != NULL ? _tag1 : "", \
_tag2 != NULL ? _tag2 : ""))
+/* start_time/end_time is an interval for checking changes. If both greater than zero,
+ only the interval is checked and the removed items are not notified, as they can
+ be still there.
+*/
static void
-synchronize_cache (ECalBackendCalDAV *cbdav)
+synchronize_cache (ECalBackendCalDAV *cbdav, time_t start_time, time_t end_time)
{
ECalBackendCalDAVPrivate *priv;
- ECalBackend *bkend;
- ECalBackendCache *bcache;
- CalDAVObject *sobjs;
- CalDAVObject *object;
- GHashTable *hindex;
- GList *cobjs, *created = NULL, *modified = NULL, *put_to_cache = NULL;
- GList *citer;
- gboolean res;
- gint len;
- gint i;
-
- priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
- bkend = E_CAL_BACKEND (cbdav);
- bcache = priv->cache;
- len = 0;
- sobjs = NULL;
+ ECalBackend *bkend;
+ CalDAVObject *sobjs, *object;
+ GList *c_objs, *c_iter; /* list of all items known from our cache */
+ GTree *c_uid2complist; /* cache components list (with detached instances) sorted by (master's) uid */
+ GHashTable *c_href2uid; /* connection between href and a (master's) uid */
+ GSList *hrefs_to_update, *htu; /* list of href-s to update */
+ gint i, len;
if (!check_calendar_changed_on_server (cbdav)) {
/* no changes on the server, no update required */
return;
}
- res = caldav_server_list_objects (cbdav, &sobjs, &len);
+ priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
+ bkend = E_CAL_BACKEND (cbdav);
+ len = 0;
+ sobjs = NULL;
- if (!res)
+ /* get list of server objects */
+ if (!caldav_server_list_objects (cbdav, &sobjs, &len, NULL, start_time, end_time))
return;
- hindex = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
g_static_rec_mutex_lock (&priv->cache_lock);
- cobjs = e_cal_backend_cache_get_components (bcache);
+ c_objs = e_cal_backend_cache_get_components (priv->cache);
g_static_rec_mutex_unlock (&priv->cache_lock);
+ if (caldav_debug_show (DEBUG_SERVER_ITEMS)) {
+ printf ("CalDAV - found %d objects on the server, locally stored %d objects\n", len, g_list_length (c_objs)); fflush (stdout);
+ }
+
/* do not store changes in cache immediately - makes things significantly quicker */
e_file_cache_freeze_changes (E_FILE_CACHE (priv->cache));
- /* build up a index for the href entry */
- for (citer = cobjs; citer; citer = g_list_next (citer)) {
- ECalComponent *ccomp = E_CAL_COMPONENT (citer->data);
+ c_uid2complist = g_tree_new_full ((GCompareDataFunc)g_strcmp0, NULL, g_free, free_comp_list);
+ c_href2uid = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ /* fill indexed hash and tree with cached components */
+ for (c_iter = c_objs; c_iter; c_iter = g_list_next (c_iter)) {
+ ECalComponent *ccomp = E_CAL_COMPONENT (c_iter->data);
+ const gchar *uid = NULL;
+ struct cache_comp_list *ccl;
gchar *href;
+ e_cal_component_get_uid (ccomp, &uid);
+ if (!uid) {
+ g_warning ("broken component with NULL Id");
+ continue;
+ }
+
href = ecalcomp_get_href (ccomp);
if (href == NULL) {
@@ -1719,19 +1714,42 @@ synchronize_cache (ECalBackendCalDAV *cbdav)
continue;
}
- /* prefer master object from a detached instance */
- if (g_hash_table_lookup (hindex, href) && e_cal_component_is_instance (ccomp)) {
- g_free (href);
- continue;
+ ccl = g_tree_lookup (c_uid2complist, uid);
+ if (ccl) {
+ ccl->slist = g_slist_prepend (ccl->slist, g_object_ref (ccomp));
+ } else {
+ ccl = g_new0 (struct cache_comp_list, 1);
+ ccl->slist = g_slist_append (NULL, g_object_ref (ccomp));
+
+ /* make a copy, which will be used in the c_href2uid too */
+ uid = g_strdup (uid);
+
+ g_tree_insert (c_uid2complist, (gpointer) uid, ccl);
}
- g_hash_table_insert (hindex, (gpointer) href, ccomp);
+ if (g_hash_table_lookup (c_href2uid, href) == NULL) {
+ /* uid is from a component or c_uid2complist key, thus will not be
+ freed before a removal from c_uid2complist, thus do not duplicate it,
+ rather save memory */
+ g_hash_table_insert (c_href2uid, href, (gpointer)uid);
+ } else {
+ g_free (href);
+ }
}
+ /* clear it now, we do not need it later */
+ g_list_foreach (c_objs, (GFunc) g_object_unref, NULL);
+ g_list_free (c_objs);
+ c_objs = NULL;
+
+ hrefs_to_update = NULL;
+
/* see if we have to update or add some objects */
for (i = 0, object = sobjs; i < len && priv->slave_cmd == SLAVE_SHOULD_WORK; i++, object++) {
- ECalComponent *ccomp;
+ ECalComponent *ccomp = NULL;
gchar *etag = NULL;
+ const gchar *uid;
+ struct cache_comp_list *ccl;
if (object->status != 200) {
/* just continue here, so that the object
@@ -1740,88 +1758,188 @@ synchronize_cache (ECalBackendCalDAV *cbdav)
continue;
}
- res = TRUE;
- ccomp = g_hash_table_lookup (hindex, object->href);
+ uid = g_hash_table_lookup (c_href2uid, object->href);
+ if (uid) {
+ ccl = g_tree_lookup (c_uid2complist, uid);
+ if (ccl) {
+ GSList *sl;
+ for (sl = ccl->slist; sl && !etag; sl = sl->next) {
+ ccomp = sl->data;
+ if (ccomp)
+ etag = ecalcomp_get_etag (ccomp);
+ }
- if (ccomp != NULL) {
- etag = ecalcomp_get_etag (ccomp);
+ if (!etag)
+ ccomp = NULL;
+ }
}
if (!etag || !etags_match (etag, object->etag)) {
- res = synchronize_object (cbdav, object, ccomp, &created, &modified, &put_to_cache);
- }
+ hrefs_to_update = g_slist_prepend (hrefs_to_update, object->href);
+ } else if (uid && ccl) {
+ /* all components cover by this uid are up-to-date */
+ GSList *p;
+
+ for (p = ccl->slist; p; p = p->next) {
+ g_object_unref (p->data);
+ }
- if (res) {
- cobjs = g_list_remove (cobjs, ccomp);
- if (ccomp)
- g_object_unref (ccomp);
+ g_slist_free (ccl->slist);
+ ccl->slist = NULL;
}
- caldav_object_free (object, FALSE);
g_free (etag);
}
- /* remove old (not on server anymore) items from cache... */
- for (citer = cobjs; citer; citer = g_list_next (citer)) {
- ECalComponent *comp = E_CAL_COMPONENT (citer->data);
+ /* free hash table, as it is not used anymore */
+ g_hash_table_destroy (c_href2uid);
+ c_href2uid = NULL;
- /* keep detached instances in a cache, they will be removed with the master object */
- if (!e_cal_component_is_instance (comp)) {
- const gchar *uid = NULL;
+ if (caldav_debug_show (DEBUG_SERVER_ITEMS)) {
+ printf ("CalDAV - recognized %d items to update\n", g_slist_length (hrefs_to_update)); fflush (stdout);
+ }
- e_cal_component_get_uid (comp, &uid);
+ htu = hrefs_to_update;
+ while (htu && priv->slave_cmd == SLAVE_SHOULD_WORK) {
+ gint count = 0;
+ GSList *to_fetch = NULL;
- if (remove_comp_from_cache (cbdav, uid, NULL)) {
- gchar *str = e_cal_component_get_as_string (comp);
- ECalComponentId *id = e_cal_component_get_id (comp);
+ while (count < CALDAV_MAX_MULTIGET_AMOUNT && htu) {
+ to_fetch = g_slist_prepend (to_fetch, htu->data);
+ htu = htu->next;
+ count++;
+ }
+
+ if (to_fetch && priv->slave_cmd == SLAVE_SHOULD_WORK) {
+ CalDAVObject *up_sobjs = NULL;
- e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbdav), id, str, NULL);
- e_cal_component_free_id (id);
- g_free (str);
+ if (caldav_debug_show (DEBUG_SERVER_ITEMS)) {
+ printf ("CalDAV - going to fetch %d items\n", g_slist_length (to_fetch)); fflush (stdout);
}
- }
- g_object_unref (comp);
- }
+ count = 0;
+ if (!caldav_server_list_objects (cbdav, &up_sobjs, &count, to_fetch, 0, 0)) {
+ fprintf (stderr, "CalDAV - failed to retrieve bunch of items\n"); fflush (stderr);
+ break;
+ }
- /* ... then update cache with new objects... */
- g_list_foreach (put_to_cache, put_to_cache_data_and_free_cb, cbdav);
+ if (caldav_debug_show (DEBUG_SERVER_ITEMS)) {
+ printf ("CalDAV - fetched bunch of %d items\n", count); fflush (stdout);
+ }
- /* ... then notify created ... */
- for (citer = created; citer; citer = citer->next) {
- ECalComponent *comp = citer->data;
- gchar *comp_str = e_cal_component_get_as_string (comp);
+ /* we are going to update cache */
+ g_static_rec_mutex_lock (&priv->cache_lock);
- e_cal_backend_notify_object_created (bkend, comp_str);
+ /* they are downloaded, so process them */
+ for (i = 0, object = up_sobjs; i < count /*&& priv->slave_cmd == SLAVE_SHOULD_WORK*/; i++, object++) {
+ if (object->status == 200 && object->href && object->etag && object->cdata && *object->cdata) {
+ icalcomponent *icomp = icalparser_parse_string (object->cdata);
- g_free (comp_str);
- g_object_unref (comp);
- }
+ if (icomp) {
+ icalcomponent_kind kind = icalcomponent_isa (icomp);
- /* ... and modified components */
- for (citer = modified; citer; citer = citer->next) {
- ECalComponent *comp, *old_comp;
- gchar *new_str, *old_str;
+ extract_timezones (cbdav, icomp);
- /* always even number of items in the 'modified' list */
- comp = citer->data;
- citer = citer->next;
- old_comp = citer->data;
+ if (kind == ICAL_VCALENDAR_COMPONENT) {
+ icalcomponent *subcomp;
- new_str = e_cal_component_get_as_string (comp);
- old_str = e_cal_component_get_as_string (old_comp);
+ kind = e_cal_backend_get_kind (bkend);
- e_cal_backend_notify_object_modified (bkend, old_str, new_str);
+ for (subcomp = icalcomponent_get_first_component (icomp, kind);
+ subcomp;
+ subcomp = icalcomponent_get_next_component (icomp, kind)) {
+ ECalComponent *new_comp, *old_comp;
- g_free (new_str);
- g_free (old_str);
- g_object_unref (comp);
- g_object_unref (old_comp);
+ new_comp = e_cal_component_new ();
+ if (e_cal_component_set_icalcomponent (new_comp, icalcomponent_new_clone (subcomp))) {
+ const gchar *uid = NULL;
+ struct cache_comp_list *ccl;
+
+ e_cal_component_get_uid (new_comp, &uid);
+ if (!uid) {
+ g_warning ("%s: no UID on component!", G_STRFUNC);
+ g_object_unref (new_comp);
+ continue;
+ }
+
+ ecalcomp_set_href (new_comp, object->href);
+ ecalcomp_set_etag (new_comp, object->etag);
+
+ old_comp = NULL;
+ ccl = g_tree_lookup (c_uid2complist, uid);
+ if (ccl) {
+ gchar *nc_rid = e_cal_component_get_recurid_as_string (new_comp);
+ GSList *p;
+
+ for (p = ccl->slist; p && !old_comp; p = p->next) {
+ gchar *oc_rid;
+
+ old_comp = p->data;
+
+ oc_rid = e_cal_component_get_recurid_as_string (old_comp);
+ if (g_strcmp0 (nc_rid, oc_rid) != 0) {
+ old_comp = NULL;
+ }
+
+ g_free (oc_rid);
+ }
+
+ g_free (nc_rid);
+ }
+
+ e_cal_backend_cache_put_component (priv->cache, new_comp);
+
+ if (old_comp == NULL) {
+ gchar *new_str = e_cal_component_get_as_string (new_comp);
+
+ e_cal_backend_notify_object_created (bkend, new_str);
+
+ g_free (new_str);
+ } else {
+ gchar *new_str = e_cal_component_get_as_string (new_comp);
+ gchar *old_str = e_cal_component_get_as_string (old_comp);
+
+ e_cal_backend_notify_object_modified (bkend, old_str, new_str);
+
+ g_free (new_str);
+ g_free (old_str);
+
+ ccl->slist = g_slist_remove (ccl->slist, old_comp);
+ g_object_unref (old_comp);
+ }
+ }
+
+ g_object_unref (new_comp);
+ }
+ }
+
+ icalcomponent_free (icomp);
+ }
+ }
+
+ /* these free immediately */
+ caldav_object_free (object, FALSE);
+ }
+
+ /* cache update done for fetched items */
+ g_static_rec_mutex_unlock (&priv->cache_lock);
+ }
+
+ /* do not free 'data' itself, it's part of 'sobjs' */
+ g_slist_free (to_fetch);
+ }
+
+ /* if not interrupted and not using the time range... */
+ if (priv->slave_cmd == SLAVE_SHOULD_WORK && (!start_time || !end_time)) {
+ /* ...remove old (not on server anymore) items from our cache and notify of a removal */
+ g_static_rec_mutex_lock (&priv->cache_lock);
+ g_tree_foreach (c_uid2complist, remove_complist_from_cache_and_notify_cb, cbdav);
+ g_static_rec_mutex_unlock (&priv->cache_lock);
}
if (priv->ctag_to_store) {
/* store only when wasn't interrupted */
- if (priv->slave_cmd == SLAVE_SHOULD_WORK) {
+ if (priv->slave_cmd == SLAVE_SHOULD_WORK && start_time == 0 && end_time == 0) {
g_static_rec_mutex_lock (&priv->cache_lock);
e_cal_backend_cache_put_key_value (priv->cache, CALDAV_CTAG_KEY, priv->ctag_to_store);
g_static_rec_mutex_unlock (&priv->cache_lock);
@@ -1834,19 +1952,21 @@ synchronize_cache (ECalBackendCalDAV *cbdav)
/* save cache changes to disk finally */
e_file_cache_thaw_changes (E_FILE_CACHE (priv->cache));
- g_hash_table_destroy (hindex);
- g_list_free (cobjs);
- g_list_free (created);
- g_list_free (modified);
- g_list_free (put_to_cache);
+ for (i = 0, object = sobjs; i < len; i++, object++) {
+ caldav_object_free (object, FALSE);
+ }
+
+ g_tree_destroy (c_uid2complist);
}
/* ************************************************************************* */
static gpointer
-synch_slave_loop (gpointer data)
+caldav_synch_slave_loop (gpointer data)
{
ECalBackendCalDAVPrivate *priv;
ECalBackendCalDAV *cbdav;
+ time_t now;
+ icaltimezone *utc = icaltimezone_get_utc_timezone ();
cbdav = E_CAL_BACKEND_CALDAV (data);
priv = E_CAL_BACKEND_CALDAV_GET_PRIVATE (cbdav);
@@ -1867,7 +1987,30 @@ synch_slave_loop (gpointer data)
* Synch it baby one more time ...
*/
priv->slave_busy = TRUE;
- synchronize_cache (cbdav);
+
+ time (&now);
+ /* check for events in the month before/after today first,
+ to show user actual data as soon as possible */
+ synchronize_cache (cbdav, time_add_week_with_zone (now, -5, utc), time_add_week_with_zone (now, +5, utc));
+
+ if (priv->slave_cmd != SLAVE_SHOULD_SLEEP) {
+ /* and then check for changes in a whole calendar */
+ synchronize_cache (cbdav, 0, 0);
+ }
+
+ if (caldav_debug_show (DEBUG_SERVER_ITEMS)) {
+ GList *c_objs;
+
+ g_static_rec_mutex_lock (&priv->cache_lock);
+ c_objs = e_cal_backend_cache_get_components (priv->cache);
+ g_static_rec_mutex_unlock (&priv->cache_lock);
+
+ printf ("CalDAV - finished syncing with %d items in a cache\n", g_list_length (c_objs)); fflush (stdout);
+
+ g_list_foreach (c_objs, (GFunc) g_object_unref, NULL);
+ g_list_free (c_objs);
+ }
+
priv->slave_busy = FALSE;
/* puhh that was hard, get some rest :) */
@@ -2073,7 +2216,7 @@ initialize_backend (ECalBackendCalDAV *cbdav)
GThread *slave;
priv->slave_cmd = SLAVE_SHOULD_SLEEP;
- slave = g_thread_create (synch_slave_loop, cbdav, FALSE, NULL);
+ slave = g_thread_create (caldav_synch_slave_loop, cbdav, FALSE, NULL);
if (slave == NULL) {
g_warning ("Could not create synch slave");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]