[epiphany/gnome-3-26] sync-service: Do batched uploads



commit bdddbb6d2522e8b8f3c51085868270e602492702
Author: Gabriel Ivascu <gabrielivascu gnome org>
Date:   Fri Dec 1 13:46:14 2017 +0200

    sync-service: Do batched uploads
    
    Speed up sync by minimizing the number of requests sent to the storage
    server.

 lib/ephy-sync-utils.h                  |    3 +
 lib/sync/ephy-history-manager.c        |   24 ++--
 lib/sync/ephy-open-tabs-manager.c      |    9 +-
 lib/sync/ephy-password-manager.c       |   25 ++--
 lib/sync/ephy-sync-service.c           |  257 ++++++++++++++++++++++++++++++--
 lib/sync/ephy-synchronizable-manager.h |    2 +-
 src/bookmarks/ephy-bookmarks-manager.c |   26 ++--
 src/ephy-shell.c                       |   10 +-
 8 files changed, 294 insertions(+), 62 deletions(-)
---
diff --git a/lib/ephy-sync-utils.h b/lib/ephy-sync-utils.h
index cad54f4..d4e2a3b 100644
--- a/lib/ephy-sync-utils.h
+++ b/lib/ephy-sync-utils.h
@@ -37,6 +37,9 @@ const SecretSchema *ephy_sync_utils_get_secret_schema (void) G_GNUC_CONST;
 #define EPHY_SYNC_DEVICE_ID_LEN   32
 #define EPHY_SYNC_BSO_ID_LEN      12
 
+#define EPHY_SYNC_BATCH_SIZE    80
+#define EPHY_SYNC_MAX_BATCHES   80
+
 char     *ephy_sync_utils_encode_hex                    (const guint8 *data,
                                                          gsize         data_len);
 guint8   *ephy_sync_utils_decode_hex                    (const char   *hex);
diff --git a/lib/sync/ephy-history-manager.c b/lib/sync/ephy-history-manager.c
index 655b7d6..3c12c6f 100644
--- a/lib/sync/ephy-history-manager.c
+++ b/lib/sync/ephy-history-manager.c
@@ -312,7 +312,7 @@ ephy_history_manager_handle_different_id_same_url (EphyHistoryManager *self,
   ephy_history_record_add_visit_time (remote, local_last_visit_time);
 }
 
-static GList *
+static GPtrArray *
 ephy_history_manager_handle_initial_merge (EphyHistoryManager *self,
                                            GHashTable         *records_ht_id,
                                            GHashTable         *records_ht_url,
@@ -321,7 +321,7 @@ ephy_history_manager_handle_initial_merge (EphyHistoryManager *self,
   EphyHistoryRecord *record;
   GHashTableIter iter;
   gpointer key, value;
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
   const char *remote_id;
   const char *remote_url;
   gint64 remote_last_visit_time;
@@ -329,6 +329,8 @@ ephy_history_manager_handle_initial_merge (EphyHistoryManager *self,
 
   g_assert (EPHY_IS_HISTORY_MANAGER (self));
 
+  to_upload = g_ptr_array_new_with_free_func (g_object_unref);
+
   /* A history record is uniquely identified by its sync ID or by its URL. When
    * importing history records from server, we may encounter duplicates either
    * by ID or by URL. We start from the assumption that same ID means same URL
@@ -352,7 +354,7 @@ ephy_history_manager_handle_initial_merge (EphyHistoryManager *self,
                                         EPHY_PAGE_VISIT_LINK, FALSE);
 
       if (ephy_history_record_add_visit_time (l->data, local_last_visit_time))
-        to_upload = g_list_prepend (to_upload, g_object_ref (l->data));
+        g_ptr_array_add (to_upload, g_object_ref (l->data));
 
       g_hash_table_remove (records_ht_id, remote_id);
     } else {
@@ -362,7 +364,7 @@ ephy_history_manager_handle_initial_merge (EphyHistoryManager *self,
         /* Different ID, same URL. Keep local ID. */
         g_signal_emit_by_name (self, "synchronizable-deleted", l->data);
         ephy_history_manager_handle_different_id_same_url (self, record, l->data);
-        to_upload = g_list_prepend (to_upload, g_object_ref (l->data));
+        g_ptr_array_add (to_upload, g_object_ref (l->data));
         g_hash_table_remove (records_ht_id, ephy_history_record_get_id (record));
       } else {
         /* Different ID, different URL. This is a new record. */
@@ -377,12 +379,12 @@ ephy_history_manager_handle_initial_merge (EphyHistoryManager *self,
   /* Set the remaining local records to be uploaded to server. */
   g_hash_table_iter_init (&iter, records_ht_id);
   while (g_hash_table_iter_next (&iter, &key, &value))
-    to_upload = g_list_prepend (to_upload, g_object_ref (value));
+    g_ptr_array_add (to_upload, g_object_ref (value));
 
   return to_upload;
 }
 
-static GList *
+static GPtrArray *
 ephy_history_manager_handle_regular_merge (EphyHistoryManager  *self,
                                            GHashTable          *records_ht_id,
                                            GHashTable          *records_ht_url,
@@ -390,7 +392,7 @@ ephy_history_manager_handle_regular_merge (EphyHistoryManager  *self,
                                            GList               *updated_records)
 {
   EphyHistoryRecord *record;
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
   const char *remote_id;
   const char *remote_url;
   gint64 remote_last_visit_time;
@@ -398,6 +400,8 @@ ephy_history_manager_handle_regular_merge (EphyHistoryManager  *self,
 
   g_assert (EPHY_IS_HISTORY_MANAGER (self));
 
+  to_upload = g_ptr_array_new_with_free_func (g_object_unref);
+
   for (GList *l = deleted_records; l && l->data; l = l->next) {
     remote_id = ephy_history_record_get_id (l->data);
     remote_url = ephy_history_record_get_uri (l->data);
@@ -443,7 +447,7 @@ ephy_history_manager_handle_regular_merge (EphyHistoryManager  *self,
         /* Different ID, same URL. Keep local ID. */
         g_signal_emit_by_name (self, "synchronizable-deleted", l->data);
         ephy_history_manager_handle_different_id_same_url (self, record, l->data);
-        to_upload = g_list_prepend (to_upload, g_object_ref (l->data));
+        g_ptr_array_add (to_upload, g_object_ref (l->data));
       } else {
         /* Different ID, different URL. This is a new record. */
         if (remote_last_visit_time > 0)
@@ -465,7 +469,7 @@ merge_history_cb (EphyHistoryService    *service,
 {
   GHashTable *records_ht_id = NULL;
   GHashTable *records_ht_url = NULL;
-  GList *to_upload = NULL;
+  GPtrArray *to_upload = NULL;
 
   if (!success) {
     g_warning ("Failed to retrieve URLs in history");
@@ -501,7 +505,7 @@ merge_history_cb (EphyHistoryService    *service,
                                                            data->remotes_updated);
 
 out:
-  data->callback (to_upload, TRUE, data->user_data);
+  data->callback (to_upload, data->user_data);
 
   g_list_free_full (urls, (GDestroyNotify)ephy_history_url_free);
   if (records_ht_id)
diff --git a/lib/sync/ephy-open-tabs-manager.c b/lib/sync/ephy-open-tabs-manager.c
index 2fe4410..cdb231f 100644
--- a/lib/sync/ephy-open-tabs-manager.c
+++ b/lib/sync/ephy-open-tabs-manager.c
@@ -257,8 +257,7 @@ synchronizable_manager_merge (EphySynchronizableManager              *manager,
                               gpointer                                user_data)
 {
   EphyOpenTabsManager *self = EPHY_OPEN_TABS_MANAGER (manager);
-  EphyOpenTabsRecord *local_tabs;
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
   char *device_bso_id;
 
   device_bso_id = ephy_sync_utils_get_device_bso_id ();
@@ -276,12 +275,12 @@ synchronizable_manager_merge (EphySynchronizableManager              *manager,
   /* Only upload the local open tabs, we don't want to alter open tabs of
    * other clients. Also, overwrite any previous value by doing a force upload.
    */
-  local_tabs = ephy_open_tabs_manager_get_local_tabs (self);
-  to_upload = g_list_prepend (to_upload, local_tabs);
+  to_upload = g_ptr_array_new_with_free_func (g_object_unref);
+  g_ptr_array_add (to_upload, ephy_open_tabs_manager_get_local_tabs (self));
 
   g_free (device_bso_id);
 
-  callback (to_upload, TRUE, user_data);
+  callback (to_upload, user_data);
 }
 
 static void
diff --git a/lib/sync/ephy-password-manager.c b/lib/sync/ephy-password-manager.c
index fa1cd52..6f8d44a 100644
--- a/lib/sync/ephy-password-manager.c
+++ b/lib/sync/ephy-password-manager.c
@@ -898,14 +898,14 @@ delete_record_by_id (GList      *records,
   return records;
 }
 
-static GList *
+static GPtrArray *
 ephy_password_manager_handle_initial_merge (EphyPasswordManager *self,
                                             GList               *local_records,
                                             GList               *remote_records)
 {
   EphyPasswordRecord *record;
   GHashTable *dont_upload;
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
   const char *remote_id;
   const char *remote_origin;
   const char *remote_target_origin;
@@ -927,6 +927,7 @@ ephy_password_manager_handle_initial_merge (EphyPasswordManager *self,
    * same tuple but same tuple does not necessarily mean same ID. This is what
    * our merge logic is based on.
    */
+  to_upload = g_ptr_array_new_with_free_func (g_object_unref);
   dont_upload = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
   for (GList *l = remote_records; l && l->data; l = l->next) {
@@ -1006,7 +1007,7 @@ ephy_password_manager_handle_initial_merge (EphyPasswordManager *self,
   for (GList *l = local_records; l && l->data; l = l->next) {
     record = EPHY_PASSWORD_RECORD (l->data);
     if (!g_hash_table_contains (dont_upload, ephy_password_record_get_id (record)))
-      to_upload = g_list_prepend (to_upload, g_object_ref (record));
+      g_ptr_array_add (to_upload, g_object_ref (record));
   }
 
   g_hash_table_unref (dont_upload);
@@ -1014,14 +1015,14 @@ ephy_password_manager_handle_initial_merge (EphyPasswordManager *self,
   return to_upload;
 }
 
-static GList *
+static GPtrArray *
 ephy_password_manager_handle_regular_merge (EphyPasswordManager  *self,
                                             GList               **local_records,
                                             GList                *deleted_records,
                                             GList                *updated_records)
 {
   EphyPasswordRecord *record;
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
   const char *remote_id;
   const char *remote_origin;
   const char *remote_target_origin;
@@ -1033,6 +1034,8 @@ ephy_password_manager_handle_regular_merge (EphyPasswordManager  *self,
 
   g_assert (EPHY_IS_PASSWORD_MANAGER (self));
 
+  to_upload = g_ptr_array_new_with_free_func (g_object_unref);
+
   for (GList *l = deleted_records; l && l->data; l = l->next) {
     remote_id = ephy_password_record_get_id (l->data);
     record = get_record_by_id (*local_records, remote_id);
@@ -1068,7 +1071,7 @@ ephy_password_manager_handle_regular_merge (EphyPasswordManager  *self,
         local_timestamp = ephy_password_record_get_time_password_changed (record);
         if (local_timestamp > remote_timestamp) {
           /* Local record is newer. Keep it, upload it and delete remote record from server. */
-          to_upload = g_list_prepend (to_upload, g_object_ref (record));
+          g_ptr_array_add (to_upload, g_object_ref (record));
           g_signal_emit_by_name (self, "synchronizable-deleted", l->data);
         } else {
           /* Remote record is newer. Forget local record and store remote record. */
@@ -1089,19 +1092,17 @@ merge_cb (GList    *records,
           gpointer  user_data)
 {
   MergePasswordsAsyncData *data = (MergePasswordsAsyncData *)user_data;
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
 
   if (data->is_initial)
-    to_upload = ephy_password_manager_handle_initial_merge (data->manager,
-                                                            records,
+    to_upload = ephy_password_manager_handle_initial_merge (data->manager, records,
                                                             data->remotes_updated);
   else
-    to_upload = ephy_password_manager_handle_regular_merge (data->manager,
-                                                            &records,
+    to_upload = ephy_password_manager_handle_regular_merge (data->manager, &records,
                                                             data->remotes_deleted,
                                                             data->remotes_updated);
 
-  data->callback (to_upload, FALSE, data->user_data);
+  data->callback (to_upload, data->user_data);
 
   g_list_free_full (records, g_object_unref);
   merge_passwords_async_data_free (data);
diff --git a/lib/sync/ephy-sync-service.c b/lib/sync/ephy-sync-service.c
index b4ca983..a36da74 100644
--- a/lib/sync/ephy-sync-service.c
+++ b/lib/sync/ephy-sync-service.c
@@ -130,6 +130,17 @@ typedef struct {
   EphySynchronizable        *synchronizable;
 } SyncAsyncData;
 
+typedef struct {
+  EphySyncService           *service;
+  EphySynchronizableManager *manager;
+  GPtrArray                 *synchronizables;
+  guint                      start;
+  guint                      end;
+  char                      *batch_id;
+  gboolean                   batch_is_last;
+  gboolean                   sync_done;
+} BatchUploadAsyncData;
+
 static StorageRequestAsyncData *
 storage_request_async_data_new (const char          *endpoint,
                                 const char          *method,
@@ -268,6 +279,54 @@ sync_async_data_free (SyncAsyncData *data)
   g_slice_free (SyncAsyncData, data);
 }
 
+static inline BatchUploadAsyncData *
+batch_upload_async_data_new (EphySyncService           *service,
+                             EphySynchronizableManager *manager,
+                             GPtrArray                 *synchronizables,
+                             guint                      start,
+                             guint                      end,
+                             const char                *batch_id,
+                             gboolean                   batch_is_last,
+                             gboolean                   sync_done)
+{
+  BatchUploadAsyncData *data;
+
+  data = g_slice_new (BatchUploadAsyncData);
+  data->service = g_object_ref (service);
+  data->manager = g_object_ref (manager);
+  data->synchronizables = g_ptr_array_ref (synchronizables);
+  data->start = start;
+  data->end = end;
+  data->batch_id = g_strdup (batch_id);
+  data->batch_is_last = batch_is_last;
+  data->sync_done = sync_done;
+
+  return data;
+}
+
+static inline BatchUploadAsyncData *
+batch_upload_async_data_dup (BatchUploadAsyncData *data)
+{
+  g_assert (data);
+
+  return batch_upload_async_data_new (data->service, data->manager,
+                                      data->synchronizables, data->start,
+                                      data->end, data->batch_id,
+                                      data->batch_is_last, data->sync_done);
+}
+
+static inline void
+batch_upload_async_data_free (BatchUploadAsyncData *data)
+{
+  g_assert (data);
+
+  g_object_unref (data->service);
+  g_object_unref (data->manager);
+  g_ptr_array_unref (data->synchronizables);
+  g_free (data->batch_id);
+  g_slice_free (BatchUploadAsyncData, data);
+}
+
 static void
 ephy_sync_service_set_property (GObject      *object,
                                 guint         prop_id,
@@ -476,7 +535,7 @@ ephy_sync_service_send_storage_request (EphySyncService         *self,
                               data->request_body, strlen (data->request_body));
   }
 
-  if (!g_strcmp0 (data->method, SOUP_METHOD_PUT))
+  if (!g_strcmp0 (data->method, SOUP_METHOD_PUT) || !g_strcmp0 (data->method, SOUP_METHOD_POST))
     soup_message_headers_append (msg->request_headers, "content-type", content_type);
 
   if (data->modified_since >= 0) {
@@ -1244,22 +1303,193 @@ ephy_sync_service_upload_synchronizable (EphySyncService           *self,
   ephy_sync_crypto_key_bundle_free (bundle);
 }
 
+static GPtrArray *
+ephy_sync_service_split_into_batches (EphySyncService           *self,
+                                      EphySynchronizableManager *manager,
+                                      GPtrArray                 *synchronizables,
+                                      guint                      start,
+                                      guint                      end)
+{
+  SyncCryptoKeyBundle *bundle;
+  GPtrArray *batches;
+  const char *collection;
+
+  g_assert (EPHY_IS_SYNC_SERVICE (self));
+  g_assert (EPHY_IS_SYNCHRONIZABLE_MANAGER (manager));
+  g_assert (synchronizables);
+
+  batches = g_ptr_array_new_with_free_func (g_free);
+  collection = ephy_synchronizable_manager_get_collection_name (manager);
+  bundle = ephy_sync_service_get_key_bundle (self, collection);
+
+  for (guint i = start; i < end; i += EPHY_SYNC_BATCH_SIZE) {
+    JsonNode *node = json_node_new (JSON_NODE_ARRAY);
+    JsonArray *array = json_array_new ();
+
+    for (guint k = i; k < MIN (i + EPHY_SYNC_BATCH_SIZE, end); k++) {
+      EphySynchronizable *synchronizable = g_ptr_array_index (synchronizables, k);
+      JsonNode *bso = ephy_synchronizable_to_bso (synchronizable, bundle);
+      JsonObject *object = json_object_ref (json_node_get_object (bso));
+
+      json_array_add_object_element (array, object);
+      json_node_unref (bso);
+    }
+
+    json_node_take_array (node, array);
+    g_ptr_array_add (batches, json_to_string (node, FALSE));
+    json_node_unref (node);
+  }
+
+  ephy_sync_crypto_key_bundle_free (bundle);
+
+  return batches;
+}
+
 static void
-merge_collection_finished_cb (GList    *to_upload,
-                              gboolean  should_force,
-                              gpointer  user_data)
+commit_batch_cb (SoupSession *session,
+                 SoupMessage *msg,
+                 gpointer     user_data)
 {
-  SyncCollectionAsyncData *data = (SyncCollectionAsyncData *)user_data;
+  BatchUploadAsyncData *data = user_data;
+  const char *last_modified;
 
-  for (GList *l = to_upload; l && l->data; l = l->next)
-    ephy_sync_service_upload_synchronizable (data->service, data->manager,
-                                             l->data, should_force);
+  if (msg->status_code != 200) {
+    g_warning ("Failed to commit batch. Status code: %u, response: %s",
+               msg->status_code, msg->response_body->data);
+  } else {
+    LOG ("Successfully committed batches");
+    /* Update sync time. */
+    last_modified = soup_message_headers_get_one (msg->response_headers, "X-Last-Modified");
+    ephy_synchronizable_manager_set_sync_time (data->manager, g_ascii_strtod (last_modified, NULL));
+  }
 
-  if (data->is_last)
+  if (data->sync_done)
     g_signal_emit (data->service, signals[SYNC_FINISHED], 0);
+  batch_upload_async_data_free (data);
+}
 
-  if (to_upload)
-    g_list_free_full (to_upload, g_object_unref);
+static void
+upload_batch_cb (SoupSession *session,
+                 SoupMessage *msg,
+                 gpointer     user_data)
+{
+  BatchUploadAsyncData *data = user_data;
+  const char *collection;
+  char *endpoint = NULL;
+
+  /* Note: "202 Accepted" status code. */
+  if (msg->status_code != 202) {
+    g_warning ("Failed to upload batch. Status code: %u, response: %s",
+               msg->status_code, msg->response_body->data);
+  } else {
+    LOG ("Successfully uploaded batch");
+  }
+
+  if (!data->batch_is_last)
+    goto out;
+
+  collection = ephy_synchronizable_manager_get_collection_name (data->manager);
+  endpoint = g_strdup_printf ("storage/%s?commit=true&batch=%s", collection, data->batch_id);
+  ephy_sync_service_queue_storage_request (data->service, endpoint,
+                                           SOUP_METHOD_POST, "[]", -1, -1,
+                                           commit_batch_cb,
+                                           batch_upload_async_data_dup (data));
+
+out:
+  g_free (endpoint);
+  /* Remove last reference to the array with the items to upload. */
+  if (data->batch_is_last)
+    g_ptr_array_unref (data->synchronizables);
+  batch_upload_async_data_free (data);
+}
+
+static void
+start_batch_upload_cb (SoupSession *session,
+                       SoupMessage *msg,
+                       gpointer     user_data)
+{
+  BatchUploadAsyncData *data = user_data;
+  GPtrArray *batches = NULL;
+  JsonNode *node = NULL;
+  JsonObject *object;
+  GError *error = NULL;
+  const char *collection;
+  char *endpoint = NULL;
+
+  /* Note: "202 Accepted" status code. */
+  if (msg->status_code != 202) {
+    g_warning ("Failed to start batch upload. Status code: %u, response: %s",
+               msg->status_code, msg->response_body->data);
+    goto out;
+  }
+
+  node = json_from_string (msg->response_body->data, &error);
+  if (error) {
+    g_warning ("Response is not a valid JSON: %s", error->message);
+    g_error_free (error);
+    goto out;
+  }
+
+  object = json_node_get_object (node);
+  data->batch_id = soup_uri_encode (json_object_get_string_member (object, "batch"), NULL);
+  collection = ephy_synchronizable_manager_get_collection_name (data->manager);
+  endpoint = g_strdup_printf ("storage/%s?batch=%s", collection, data->batch_id);
+
+  batches = ephy_sync_service_split_into_batches (data->service, data->manager,
+                                                  data->synchronizables,
+                                                  data->start, data->end);
+  for (guint i = 0; i < batches->len; i++) {
+    BatchUploadAsyncData *data_dup = batch_upload_async_data_dup (data);
+
+    if (i == batches->len - 1)
+      data_dup->batch_is_last = TRUE;
+
+    ephy_sync_service_queue_storage_request (data->service, endpoint, SOUP_METHOD_POST,
+                                             g_ptr_array_index (batches, i), -1, -1,
+                                             upload_batch_cb, data_dup);
+  }
+
+out:
+  g_free (endpoint);
+  if (node)
+    json_node_unref (node);
+  if (batches)
+    g_ptr_array_unref (batches);
+  batch_upload_async_data_free (data);
+}
+
+static void
+merge_collection_finished_cb (GPtrArray *to_upload,
+                              gpointer   user_data)
+{
+  SyncCollectionAsyncData *data = user_data;
+  BatchUploadAsyncData *bdata;
+  guint step = EPHY_SYNC_MAX_BATCHES * EPHY_SYNC_BATCH_SIZE;
+  const char *collection;
+  char *endpoint = NULL;
+
+  if (!to_upload || to_upload->len == 0) {
+    if (data->is_last)
+      g_signal_emit (data->service, signals[SYNC_FINISHED], 0);
+    goto out;
+  }
+
+  collection = ephy_synchronizable_manager_get_collection_name (data->manager);
+  endpoint = g_strdup_printf ("storage/%s?batch=true", collection);
+
+  for (guint i = 0; i < to_upload->len; i += step) {
+    bdata = batch_upload_async_data_new (data->service, data->manager,
+                                         to_upload, i,
+                                         MIN (i + step, to_upload->len),
+                                         NULL, FALSE,
+                                         data->is_last && i + step >= to_upload->len);
+    ephy_sync_service_queue_storage_request (data->service, endpoint,
+                                             SOUP_METHOD_POST, "[]", -1, -1,
+                                             start_batch_upload_cb, bdata);
+  }
+
+out:
+  g_free (endpoint);
   sync_collection_async_data_free (data);
 }
 
@@ -1276,7 +1506,6 @@ sync_collection_cb (SoupSession *session,
   GError *error = NULL;
   GType type;
   const char *collection;
-  const char *last_modified;
   gboolean is_deleted;
 
   collection = ephy_synchronizable_manager_get_collection_name (data->manager);
@@ -1317,11 +1546,7 @@ sync_collection_cb (SoupSession *session,
        g_list_length (data->remotes_updated),
        collection);
 
-  /* Update sync time. */
-  last_modified = soup_message_headers_get_one (msg->response_headers, "X-Last-Modified");
-  ephy_synchronizable_manager_set_sync_time (data->manager, g_ascii_strtod (last_modified, NULL));
   ephy_synchronizable_manager_set_is_initial_sync (data->manager, FALSE);
-
   ephy_synchronizable_manager_merge (data->manager, data->is_initial,
                                      data->remotes_deleted, data->remotes_updated,
                                      merge_collection_finished_cb, data);
diff --git a/lib/sync/ephy-synchronizable-manager.h b/lib/sync/ephy-synchronizable-manager.h
index 8e1804b..04243d4 100644
--- a/lib/sync/ephy-synchronizable-manager.h
+++ b/lib/sync/ephy-synchronizable-manager.h
@@ -30,7 +30,7 @@ G_BEGIN_DECLS
 
 G_DECLARE_INTERFACE (EphySynchronizableManager, ephy_synchronizable_manager, EPHY, SYNCHRONIZABLE_MANAGER, 
GObject)
 
-typedef void (*EphySynchronizableManagerMergeCallback) (GList *to_upload, gboolean should_force, gpointer 
user_data);
+typedef void (*EphySynchronizableManagerMergeCallback) (GPtrArray *to_upload, gpointer user_data);
 
 struct _EphySynchronizableManagerInterface {
   GTypeInterface parent_iface;
diff --git a/src/bookmarks/ephy-bookmarks-manager.c b/src/bookmarks/ephy-bookmarks-manager.c
index 93a8f0a..d3bea63 100644
--- a/src/bookmarks/ephy-bookmarks-manager.c
+++ b/src/bookmarks/ephy-bookmarks-manager.c
@@ -730,11 +730,11 @@ synchronizable_manager_save (EphySynchronizableManager *manager,
                                              NULL);
 }
 
-static GList *
+static GPtrArray *
 ephy_bookmarks_manager_handle_initial_merge (EphyBookmarksManager *self,
                                              GList                *remote_bookmarks)
 {
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
   EphyBookmark *bookmark;
   GSequence *bookmarks;
   GSequenceIter *iter;
@@ -743,6 +743,7 @@ ephy_bookmarks_manager_handle_initial_merge (EphyBookmarksManager *self,
 
   g_assert (EPHY_IS_BOOKMARKS_MANAGER (self));
 
+  to_upload = g_ptr_array_new_with_free_func (g_object_unref);
   dont_upload = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
   for (GList *l = remote_bookmarks; l && l->data; l = l->next) {
@@ -810,7 +811,7 @@ next:
        !g_sequence_iter_is_end (iter); iter = g_sequence_iter_next (iter)) {
     bookmark = g_sequence_get (iter);
     if (!g_hash_table_contains (dont_upload, ephy_bookmark_get_id (bookmark)))
-      to_upload = g_list_prepend (to_upload, g_object_ref (bookmark));
+      g_ptr_array_add (to_upload, g_object_ref (bookmark));
   }
 
   /* Commit changes to file. */
@@ -822,17 +823,19 @@ next:
   return to_upload;
 }
 
-static GList *
+static GPtrArray *
 ephy_bookmarks_manager_handle_regular_merge (EphyBookmarksManager *self,
                                              GList                *updated_bookmarks,
                                              GList                *deleted_bookmarks)
 {
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
   EphyBookmark *bookmark;
   double timestamp;
 
   g_assert (EPHY_IS_BOOKMARKS_MANAGER (self));
 
+  to_upload = g_ptr_array_new_with_free_func (g_object_unref);
+
   for (GList *l = deleted_bookmarks; l && l->data; l = l->next) {
     bookmark = ephy_bookmarks_manager_get_bookmark_by_id (self, ephy_bookmark_get_id (l->data));
     if (bookmark)
@@ -874,7 +877,7 @@ ephy_bookmarks_manager_handle_regular_merge (EphyBookmarksManager *self,
         ephy_bookmarks_manager_copy_tags_from_bookmark (self, bookmark, l->data);
         timestamp = ephy_synchronizable_get_server_time_modified (l->data);
         ephy_synchronizable_set_server_time_modified (EPHY_SYNCHRONIZABLE (bookmark), timestamp);
-        to_upload = g_list_prepend (to_upload, g_object_ref (bookmark));
+        g_ptr_array_add (to_upload, g_object_ref (bookmark));
       } else {
         /* Different id, different url. Add remote bookmark. */
         ephy_bookmarks_manager_add_bookmark_internal (self, l->data, FALSE);
@@ -906,17 +909,14 @@ synchronizable_manager_merge (EphySynchronizableManager              *manager,
                               gpointer                                user_data)
 {
   EphyBookmarksManager *self = EPHY_BOOKMARKS_MANAGER (manager);
-  GList *to_upload = NULL;
+  GPtrArray *to_upload;
 
   if (is_initial)
-    to_upload = ephy_bookmarks_manager_handle_initial_merge (self,
-                                                             remotes_updated);
+    to_upload = ephy_bookmarks_manager_handle_initial_merge (self, remotes_updated);
   else
-    to_upload = ephy_bookmarks_manager_handle_regular_merge (self,
-                                                             remotes_updated,
-                                                             remotes_deleted);
+    to_upload = ephy_bookmarks_manager_handle_regular_merge (self, remotes_updated, remotes_deleted);
 
-  callback (to_upload, FALSE, user_data);
+  callback (to_upload, user_data);
 }
 
 static void
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index 6d20dc8..5d634f5 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -320,6 +320,11 @@ register_synchronizable_managers (EphyShell       *shell,
   g_assert (EPHY_IS_SYNC_SERVICE (service));
   g_assert (EPHY_IS_SHELL (shell));
 
+  if (ephy_sync_utils_history_sync_is_enabled ()) {
+    manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_history_manager (shell));
+    ephy_sync_service_register_manager (service, manager);
+  }
+
   if (ephy_sync_utils_bookmarks_sync_is_enabled ()) {
     manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_bookmarks_manager (shell));
     ephy_sync_service_register_manager (service, manager);
@@ -330,11 +335,6 @@ register_synchronizable_managers (EphyShell       *shell,
     ephy_sync_service_register_manager (service, manager);
   }
 
-  if (ephy_sync_utils_history_sync_is_enabled ()) {
-    manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_history_manager (shell));
-    ephy_sync_service_register_manager (service, manager);
-  }
-
   if (ephy_sync_utils_open_tabs_sync_is_enabled ()) {
     manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_open_tabs_manager (shell));
     ephy_sync_service_register_manager (service, manager);


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