From 58b5fd92fc9f5419beabe82d38622aba064cc56e Mon Sep 17 00:00:00 2001 From: JP Rosevear Date: Tue, 19 Sep 2000 22:48:47 +0000 Subject: Add some other cases where a slow sync is in order (pre_sync): Pre load 2000-09-19 JP Rosevear * conduits/todo/todo-conduit.c (check_for_slow_setting): Add some other cases where a slow sync is in order (pre_sync): Pre load the uids, the map and the add/mod/del lists (match_record): Use the map hash to match records (iterate): Iterate using the pre-loaded uid list (iterate_specific): Iterate using the add/mod/del lists (purge): Delete all entries in the del list (set_status): Set status by adding to an appropriate list (set_pilot_id): Set pilot_id by updating map hash * conduits/todo/todo-conduit.h: Add lists for added, modified and deleted objects * conduits/todo/todo-conduit.c (map_name): Get the pilot_id->uid map file name (map_sax_start_element): SAX handler to extract a pilot_id->uid mapping (map_sax_parse): Parse the given file and build a pilot_id->uid hash (map_write_foreach): Write out individual mapping elements (map_write): Write out the pilot_id->uid mapping (start_calendar_server_cb): Rename from gnome_calendar_load_cb * conduits/todo/todo-conduit-config.h: Rename pilotID to pilot_id * conduits/todo/e-todo.conduit.in: A little renaming * conduits/todo/Makefile.am: Fix build slightly * pcs/cal.c (build_change_seq): Build a corba sequence out of a list of CalObjChanges (Cal_get_objects_in_range): Implement new corba function * pcs/cal-backend.c (cal_backend_init): Intiliaze to NULL (cal_backend_load): Track the uri so we can write the log file to the same place (cal_backend_log_name): Figure out the log filename/path based on the calendar uri (cal_backend_set_node_timet): Set an xml node property value from a time_t (cal_backend_log_entry): Adds a log entry to list waiting to be written out (cal_backend_log_sync): Syncs the log entries to disk (cal_backend_log_sax_start_element): SAX callback for reading in log entries (cal_backend_log_sax_end_element): ditto (cal_backend_log_sax_parse): Main SAX parser call to parse the log file looking for particular log entries and creating a CalObjChange hash with the last change for each object (cal_backend_get_log_entries): Returns a hash of objects of a given type changed since the given time (cal_backend_update_object): Add appropriate log entries (cal_backend_remove_object): ditto (cal_backend_get_changed_uids): Implement new idl interface call (cal_backend_foreach_changed): Convert CalObjChange hash into a list * pcs/cal-backend-imc.[hc]: Remove crufty files * pcs/cal-backend-file.c (cal_backend_file_get_type_by_uid): New function that returns the CalObjType for a uid. * cal-client/cal-client.h: Update prototypes. * cal-client/cal-client.c (build_change_list): Build a list of CalObjChange items from a corba sequence. (cal_client_get_changed_uids): New accessor method for the similarly named addition to the idl file. * cal-util/cal-util.h: Update prototypes and add CalObjChangeType enum. * cal-util/cal-util.c (cal_obj_change_list_free): New utility method to free a list of CalObjChange objects. * idl/evolution-calendar.idl: Add get_changed_uids method and associated types. svn path=/trunk/; revision=5512 --- calendar/pcs/cal-backend.c | 380 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 375 insertions(+), 5 deletions(-) (limited to 'calendar/pcs/cal-backend.c') diff --git a/calendar/pcs/cal-backend.c b/calendar/pcs/cal-backend.c index ee2b38a52c..3c7698a4d5 100644 --- a/calendar/pcs/cal-backend.c +++ b/calendar/pcs/cal-backend.c @@ -21,7 +21,10 @@ */ #include -#include +#include +#include +#include +#include #include "cal-backend.h" #include "libversit/vcc.h" @@ -35,6 +38,11 @@ enum { }; static void cal_backend_class_init (CalBackendClass *class); +static void cal_backend_init (CalBackend *backend); +static gboolean cal_backend_log_sync (CalBackend *backend); +static GHashTable *cal_backend_get_log_entries (CalBackend *backend, + time_t since, + CalObjType type); static GtkObjectClass *parent_class; @@ -64,7 +72,7 @@ cal_backend_get_type (void) sizeof (CalBackend), sizeof (CalBackendClass), (GtkClassInitFunc) cal_backend_class_init, - (GtkObjectInitFunc) NULL, + (GtkObjectInitFunc) cal_backend_init, NULL, /* reserved_1 */ NULL, /* reserved_2 */ (GtkClassInitFunc) NULL @@ -98,6 +106,14 @@ cal_backend_class_init (CalBackendClass *class) gtk_object_class_add_signals (object_class, cal_backend_signals, LAST_SIGNAL); } +/* Per instance initialization function */ +static void +cal_backend_init (CalBackend *backend) +{ + backend->uri = NULL; + backend->entries = NULL; +} + /** @@ -150,12 +166,32 @@ cal_backend_add_cal (CalBackend *backend, Cal *cal) CalBackendLoadStatus cal_backend_load (CalBackend *backend, GnomeVFSURI *uri) { + CalBackendLoadStatus result; + g_return_val_if_fail (backend != NULL, CAL_BACKEND_LOAD_ERROR); g_return_val_if_fail (IS_CAL_BACKEND (backend), CAL_BACKEND_LOAD_ERROR); g_return_val_if_fail (uri != NULL, CAL_BACKEND_LOAD_ERROR); g_assert (CLASS (backend)->load != NULL); - return (* CLASS (backend)->load) (backend, uri); + result = (* CLASS (backend)->load) (backend, uri); + + /* Remember the URI for saving the log file in the same dir and add + * a timeout handler so for saving pending entries sometimes */ + if (backend->uri) + gnome_vfs_uri_unref (backend->uri); + + if (backend->timer) + gtk_timeout_remove (backend->timer); + + if (result == CAL_BACKEND_LOAD_SUCCESS) { + backend->uri = uri; + gnome_vfs_uri_ref (uri); + backend->timer = gtk_timeout_add (60000, + (GtkFunction)cal_backend_log_sync, + backend); + } + + return result; } /** @@ -239,6 +275,43 @@ cal_backend_get_uids (CalBackend *backend, CalObjType type) return (* CLASS (backend)->get_uids) (backend, type); } + +static void +cal_backend_foreach_changed (gpointer key, gpointer value, gpointer data) +{ + GList **list = data; + + *list = g_list_append (*list, value); +} + +/** + * cal_backend_get_changed_uids: + * @backend: + * @type: + * @since: + * + * + * + * Return value: + **/ +GList * +cal_backend_get_changed_uids (CalBackend *backend, CalObjType type, time_t since) +{ + GHashTable *hash; + GList *uids = NULL; + + g_return_val_if_fail (backend != NULL, NULL); + g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + + hash = cal_backend_get_log_entries (backend, type, since); + + if (hash) + g_hash_table_foreach (hash, cal_backend_foreach_changed, &uids); + + return uids; +} + + /** * cal_backend_get_objects_in_range: * @backend: A calendar backend. @@ -337,7 +410,284 @@ void cal_backend_update_pilot_id (CalBackend *backend, const char *uid, pilot_id, pilot_status); } +/* Internal logging stuff */ +typedef enum { + CAL_BACKEND_UPDATED, + CAL_BACKEND_REMOVED +} CalBackendLogEntryType; + +typedef struct { + char *uid; + CalObjType type; + + CalBackendLogEntryType event_type; + + time_t time_stamp; +} CalBackendLogEntry; + +typedef struct { + CalObjType type; + time_t since; + + gboolean in_valid_timestamp; + + GHashTable *hash; +} CalBackendParseState; + +static gchar * +cal_backend_log_name (CalBackend *backend) +{ + gchar *path, *filename; + + path = gnome_vfs_uri_extract_dirname (backend->uri); + filename = g_strdup_printf ("%slog.xml", path); + g_free (path); + + return filename; +} + +static void +cal_backend_set_node_timet (xmlNodePtr node, const char *name, time_t t) +{ + char *tstring; + + tstring = g_strdup_printf ("%ld", t); + xmlSetProp (node, name, tstring); +} + +static void +cal_backend_log_entry (CalBackend *backend, const char *uid, + CalBackendLogEntryType type) +{ + CalBackendLogEntry *entry = g_new0 (CalBackendLogEntry, 1); + CalObjType cot; + + g_assert (CLASS (backend)->get_type_by_uid != NULL); + cot = (* CLASS (backend)->get_type_by_uid) (backend, uid); + + /* Only log todos and events */ + if (cot != CALOBJ_TYPE_EVENT && cot != CALOBJ_TYPE_TODO) + return; + + entry = g_new0 (CalBackendLogEntry, 1); + entry->uid = g_strdup (uid); + entry->type = cot; + entry->event_type = type; + entry->time_stamp = time (NULL); + + /* Append so they get stored in chronological order */ + backend->entries = g_slist_append (backend->entries, entry); +} + +static gboolean +cal_backend_log_sync (CalBackend *backend) +{ + xmlDocPtr doc; + xmlNodePtr tnode; + gchar *filename; + GSList *l; + int ret; + time_t start_time = (time_t) - 1; + + if (backend->entries == NULL) + return TRUE; + + filename = cal_backend_log_name (backend); + + doc = xmlParseFile (filename); + if (doc == NULL) { + /* Create the document */ + doc = xmlNewDoc ("1.0"); + if (doc == NULL) { + g_warning ("Log file could not be created\n"); + return FALSE; + } + + + doc->root = xmlNewDocNode(doc, NULL, "CalendarLog", NULL); + } + + tnode = xmlNewChild (doc->root, NULL, "timestamp", NULL); + for (l = backend->entries; l != NULL; l = l->next) { + xmlNodePtr node; + CalBackendLogEntry *entry; + + entry = (CalBackendLogEntry *)l->data; + node = xmlNewChild (tnode, NULL, "status", NULL); + + xmlSetProp (node, "uid", entry->uid); + + switch (entry->type) { + case CALOBJ_TYPE_EVENT: + xmlSetProp (node, "type", "event"); + break; + case CALOBJ_TYPE_TODO: + xmlSetProp (node, "type", "todo"); + break; + default: + } + + switch (entry->event_type) { + case (CAL_BACKEND_UPDATED): + xmlSetProp (node, "operation", "updated"); + break; + case (CAL_BACKEND_REMOVED): + xmlSetProp (node, "operation", "removed"); + break; + } + + if (start_time == (time_t) - 1 + || entry->time_stamp < start_time) + start_time = entry->time_stamp; + + g_free (entry); + } + cal_backend_set_node_timet (tnode, "start", start_time); + cal_backend_set_node_timet (tnode, "end", time (NULL)); + + g_slist_free (backend->entries); + backend->entries = NULL; + + /* Write the file */ + xmlSetDocCompressMode (doc, 0); + ret = xmlSaveFile (filename, doc); + if (ret < 0) { + g_warning ("Log file could not be saved\n"); + return FALSE; + } + + xmlFreeDoc (doc); + + g_free (filename); + + return TRUE; +} + +static void +cal_backend_log_sax_start_element (void *data, const xmlChar *name, + const xmlChar **attrs) +{ + CalBackendParseState *state = (CalBackendParseState *)data; + + if (!strcmp (name, "timestamp")) { + while (attrs && *attrs != NULL) { + const xmlChar **val = attrs; + + val++; + if (!strcmp (*attrs, "start")) { + time_t start = (time_t)strtoul (*val, NULL, 0); + + if (start >= state->since) + state->in_valid_timestamp = TRUE; + break; + } + attrs = ++val; + } + } + + if (!strcmp (name, "status")) { + CalObjChange *coc = g_new0 (CalObjChange, 1); + CalObjType cot = 0; + + while (attrs && *attrs != NULL) { + const xmlChar **val = attrs; + + + val++; + if (!strcmp (*attrs, "uid")) + coc->uid = g_strdup (*val); + + if (!strcmp (*attrs, "type")) { + if (!strcmp (*val, "event")) + cot = CALOBJ_TYPE_EVENT; + else if (!strcmp (*val, "todo")) + cot = CALOBJ_TYPE_TODO; + } + + if (!strcmp (*attrs, "operation")) + coc->type = atoi (*val); + + attrs = ++val; + } + + if (state->type == CALOBJ_TYPE_ANY || state->type == cot) + g_hash_table_insert (state->hash, coc->uid, coc); + } +} + +static void +cal_backend_log_sax_end_element (void *data, const xmlChar *name) +{ + CalBackendParseState *state = (CalBackendParseState *)data; + + if (!strcmp (name, "timestamp")) { + state->in_valid_timestamp = FALSE; + } +} + +static int +cal_backend_log_sax_parse (CalBackend *backend, xmlSAXHandler *handler, + CalBackendParseState *state) +{ + int ret = 0; + xmlParserCtxtPtr ctxt; + char *filename; + + filename = cal_backend_log_name (backend); + + if (!g_file_exists (filename)) + return 0; + + ctxt = xmlCreateFileParserCtxt (filename); + if (ctxt == NULL) + return -1; + + ctxt->sax = handler; + ctxt->userData = (void *)state; + + xmlParseDocument (ctxt); + + if (ctxt->wellFormed) + ret = 0; + else + ret = -1; + + if (handler != NULL) + ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + + return ret; +} + +static GHashTable * +cal_backend_get_log_entries (CalBackend *backend, time_t since, + CalObjType type) +{ + xmlSAXHandler handler; + CalBackendParseState state; + GHashTable *hash; + + g_return_val_if_fail (backend != NULL, NULL); + g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + + if (!cal_backend_log_sync (backend)) + return NULL; + + hash = g_hash_table_new (g_str_hash, g_str_equal); + + memset(&handler, 0, sizeof(xmlSAXHandler)); + handler.startElement = cal_backend_log_sax_start_element; + handler.endElement = cal_backend_log_sax_end_element; + state.type = type; + state.since = since; + state.hash = hash; + + if (cal_backend_log_sax_parse (backend, &handler, &state) < 0) + return NULL; + + return hash; +} /** * cal_backend_update_object: @@ -355,13 +705,20 @@ void cal_backend_update_pilot_id (CalBackend *backend, const char *uid, gboolean cal_backend_update_object (CalBackend *backend, const char *uid, const char *calobj) { + gboolean result; + g_return_val_if_fail (backend != NULL, FALSE); g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE); g_return_val_if_fail (uid != NULL, FALSE); g_return_val_if_fail (calobj != NULL, FALSE); g_assert (CLASS (backend)->update_object != NULL); - return (* CLASS (backend)->update_object) (backend, uid, calobj); + result = (* CLASS (backend)->update_object) (backend, uid, calobj); + + if (result) + cal_backend_log_entry (backend, uid, CAL_BACKEND_UPDATED); + + return result; } /** @@ -378,12 +735,19 @@ cal_backend_update_object (CalBackend *backend, const char *uid, const char *cal gboolean cal_backend_remove_object (CalBackend *backend, const char *uid) { + gboolean result; + g_return_val_if_fail (backend != NULL, FALSE); g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE); g_return_val_if_fail (uid != NULL, FALSE); g_assert (CLASS (backend)->remove_object != NULL); - return (* CLASS (backend)->remove_object) (backend, uid); + result = (* CLASS (backend)->remove_object) (backend, uid); + + if (result) + cal_backend_log_entry (backend, uid, CAL_BACKEND_REMOVED); + + return result; } /** @@ -400,4 +764,10 @@ cal_backend_last_client_gone (CalBackend *backend) g_return_if_fail (IS_CAL_BACKEND (backend)); gtk_signal_emit (GTK_OBJECT (backend), cal_backend_signals[LAST_CLIENT_GONE]); + + cal_backend_log_sync (backend); } + + + + -- cgit v1.2.3