[epiphany/wip/sync-rebase: 51/86] sync-service: Process storage requests in the same order they were sent
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/wip/sync-rebase: 51/86] sync-service: Process storage requests in the same order they were sent
- Date: Fri, 7 Oct 2016 22:53:00 +0000 (UTC)
commit 312fc6e91adf6733c81e50348ebc5c79a14293a7
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date: Mon Aug 1 20:12:13 2016 +0300
sync-service: Process storage requests in the same order they were sent
Since all storage requests are made asynchronously (thus the exact
moment when the responses arrive can't be known) and since implementing
the sync logic requires multiple consecutive storage requests to be
made, a certain mechanism is needed to ensure that the responses are
processed in the right order, one after another, to avoid conflicts.
To achieve this, use a queue to hold new requests and a flag to tell
whether there is currently another request in progress: if there is
currently another request being transmitted, then the new one has to
wait in the queue, otherwise, it is free to go. With this, it becomes
the responsibility of the current request to release the next one
waiting in the queue once the response has been processed. This is done
by calling ephy_sync_service_release_next_storage_message() at the end
of every callback that handles a response from the Storage Server.
src/ephy-sync-service.c | 116 ++++++++++++++++++++++++++---------------------
src/ephy-sync-service.h | 62 +++++++++++++------------
2 files changed, 96 insertions(+), 82 deletions(-)
---
diff --git a/src/ephy-sync-service.c b/src/ephy-sync-service.c
index 657a3ec..34a7f43 100644
--- a/src/ephy-sync-service.c
+++ b/src/ephy-sync-service.c
@@ -50,12 +50,12 @@ struct _EphySyncService {
gchar *user_email;
gint64 last_auth_at;
+ gboolean is_locked;
gchar *storage_endpoint;
gchar *storage_credentials_id;
gchar *storage_credentials_key;
gint64 storage_credentials_expiry_time;
- gboolean is_obtaining_storage_credentials;
- GQueue *storage_message_queue;
+ GQueue *storage_queue;
gchar *certificate;
EphySyncCryptoRSAKeyPair *keypair;
@@ -188,6 +188,18 @@ destroy_session_response_cb (SoupSession *session,
g_object_unref (parser);
}
+static void
+ephy_sync_service_clear_storage_credentials (EphySyncService *self)
+{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+
+ g_clear_pointer (&self->certificate, g_free);
+ g_clear_pointer (&self->storage_endpoint, g_free);
+ g_clear_pointer (&self->storage_credentials_id, g_free);
+ g_clear_pointer (&self->storage_credentials_key, g_free);
+ self->storage_credentials_expiry_time = 0;
+}
+
static gboolean
ephy_sync_service_storage_credentials_is_expired (EphySyncService *self)
{
@@ -349,17 +361,6 @@ ephy_sync_service_send_storage_request (EphySyncService *self,
storage_server_request_async_data_free (data);
}
-static void
-ephy_sync_service_send_enqueued_storage_messages (EphySyncService *self)
-{
- StorageServerRequestAsyncData *qdata;
-
- while (g_queue_is_empty (self->storage_message_queue) == FALSE) {
- qdata = g_queue_pop_head (self->storage_message_queue);
- ephy_sync_service_send_storage_request (self, qdata);
- }
-}
-
static gboolean
ephy_sync_service_certificate_is_valid (EphySyncService *self,
const gchar *certificate)
@@ -459,22 +460,18 @@ obtain_storage_credentials_response_cb (SoupSession *session,
json_object_get_string_member (json, "status"),
json_object_get_string_member (errors, "description"));
storage_server_request_async_data_free (data);
- g_object_unref (parser);
+ goto out;
} else {
g_warning ("Failed to talk to the Token Server, status code %u. "
"See https://docs.services.mozilla.com/token/apis.html#error-responses",
message->status_code);
storage_server_request_async_data_free (data);
- g_object_unref (parser);
+ goto out;
}
- /* Signal that we are done with obtaining the storage credentials. */
- service->is_obtaining_storage_credentials = FALSE;
-
- /* Send the current message and the ones that were waiting in the queue. */
ephy_sync_service_send_storage_request (service, data);
- ephy_sync_service_send_enqueued_storage_messages (service);
+out:
g_object_unref (parser);
}
@@ -619,6 +616,30 @@ ephy_sync_service_obtain_signed_certificate (EphySyncService *self,
}
static void
+ephy_sync_service_issue_storage_request (EphySyncService *self,
+ StorageServerRequestAsyncData *data)
+{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ g_return_if_fail (data != NULL);
+
+ if (ephy_sync_service_storage_credentials_is_expired (self) == TRUE) {
+ ephy_sync_service_clear_storage_credentials (self);
+
+ /* The only purpose of certificates is to obtain a signed BrowserID that is
+ * needed to talk to the Token Server. From the Token Server we will obtain
+ * the credentials needed to talk to the Storage Server. Since both
+ * ephy_sync_service_obtain_signed_certificate() and
+ * ephy_sync_service_obtain_storage_credentials() complete asynchronously,
+ * we need to entrust them the task of sending the request to the Storage
+ * Server.
+ */
+ ephy_sync_service_obtain_signed_certificate (self, data);
+ } else {
+ ephy_sync_service_send_storage_request (self, data);
+ }
+}
+
+static void
ephy_sync_service_finalize (GObject *object)
{
EphySyncService *self = EPHY_SYNC_SERVICE (object);
@@ -626,7 +647,7 @@ ephy_sync_service_finalize (GObject *object)
if (self->keypair != NULL)
ephy_sync_crypto_rsa_key_pair_free (self->keypair);
- g_queue_free_full (self->storage_message_queue, (GDestroyNotify) storage_server_request_async_data_free);
+ g_queue_free_full (self->storage_queue, (GDestroyNotify) storage_server_request_async_data_free);
G_OBJECT_CLASS (ephy_sync_service_parent_class)->finalize (object);
}
@@ -638,10 +659,7 @@ ephy_sync_service_dispose (GObject *object)
g_clear_object (&self->soup_session);
g_clear_pointer (&self->user_email, g_free);
- g_clear_pointer (&self->certificate, g_free);
- g_clear_pointer (&self->storage_endpoint, g_free);
- g_clear_pointer (&self->storage_credentials_id, g_free);
- g_clear_pointer (&self->storage_credentials_key, g_free);
+ ephy_sync_service_clear_storage_credentials (self);
ephy_sync_service_delete_all_tokens (self);
G_OBJECT_CLASS (ephy_sync_service_parent_class)->dispose (object);
@@ -662,7 +680,7 @@ ephy_sync_service_init (EphySyncService *self)
gchar *email;
self->soup_session = soup_session_new ();
- self->storage_message_queue = g_queue_new ();
+ self->storage_queue = g_queue_new ();
email = g_settings_get_string (EPHY_SETTINGS_MAIN, EPHY_PREFS_SYNC_USER);
@@ -942,35 +960,29 @@ ephy_sync_service_send_storage_message (EphySyncService *self,
modified_since, unmodified_since,
callback, user_data);
- if (ephy_sync_service_storage_credentials_is_expired (self) == FALSE) {
- ephy_sync_service_send_storage_request (self, data);
- return;
- }
-
- /* If we are currently obtaining the storage credentials for another message,
- * then the new message is enqueued and will be sent after the credentials are
- * retrieved.
+ /* If there is currently another message being transmitted, then the new
+ * message has to wait in the queue, otherwise, it is free to go.
*/
- if (self->is_obtaining_storage_credentials == TRUE) {
- g_queue_push_tail (self->storage_message_queue, data);
- return;
+ if (self->is_locked == FALSE) {
+ self->is_locked = TRUE;
+ ephy_sync_service_issue_storage_request (self, data);
+ } else {
+ g_queue_push_tail (self->storage_queue, data);
}
+}
- /* This message is the one that will obtain the storage credentials. */
- self->is_obtaining_storage_credentials = TRUE;
-
- /* Drop the old certificate and storage credentials. */
- g_clear_pointer (&self->certificate, g_free);
- g_clear_pointer (&self->storage_credentials_id, g_free);
- g_clear_pointer (&self->storage_credentials_key, g_free);
- self->storage_credentials_expiry_time = 0;
+void
+ephy_sync_service_release_next_storage_message (EphySyncService *self)
+{
+ g_return_if_fail (EPHY_IS_SYNC_SERVICE (self));
+ /* We should never reach this with the service not being locked. */
+ g_assert (self->is_locked == TRUE);
- /* The only purpose of certificates is to obtain a signed BrowserID that is
- * needed to talk to the Token Server. From the Token Server we will obtain
- * the credentials needed to talk to the Storage Server. Since both
- * ephy_sync_service_obtain_signed_certificate() and
- * ephy_sync_service_obtain_storage_credentials() complete asynchronously, we
- * need to entrust them the task of sending the request to the Storage Server.
+ /* If there are other messages waiting in the queue, we release the next one
+ * and keep the service locked, else, we mark the service as not locked.
*/
- ephy_sync_service_obtain_signed_certificate (self, data);
+ if (g_queue_is_empty (self->storage_queue) == FALSE)
+ ephy_sync_service_issue_storage_request (self, g_queue_pop_head (self->storage_queue));
+ else
+ self->is_locked = FALSE;
}
diff --git a/src/ephy-sync-service.h b/src/ephy-sync-service.h
index 6623bad..8dd043b 100644
--- a/src/ephy-sync-service.h
+++ b/src/ephy-sync-service.h
@@ -37,47 +37,49 @@ typedef enum {
TOKEN_KB
} EphySyncServiceTokenType;
-EphySyncService *ephy_sync_service_new (void);
+EphySyncService *ephy_sync_service_new (void);
-const gchar *ephy_sync_service_token_name_from_type (EphySyncServiceTokenType token_type);
+const gchar *ephy_sync_service_token_name_from_type (EphySyncServiceTokenType token_type);
-gboolean ephy_sync_service_is_signed_in (EphySyncService *self);
+gboolean ephy_sync_service_is_signed_in (EphySyncService *self);
-gchar *ephy_sync_service_get_user_email (EphySyncService *self);
+gchar *ephy_sync_service_get_user_email (EphySyncService *self);
-void ephy_sync_service_set_user_email (EphySyncService *self,
- const gchar *email);
+void ephy_sync_service_set_user_email (EphySyncService *self,
+ const gchar *email);
-gchar *ephy_sync_service_get_token (EphySyncService *self,
- EphySyncServiceTokenType token_type);
+gchar *ephy_sync_service_get_token (EphySyncService *self,
+ EphySyncServiceTokenType token_type);
-void ephy_sync_service_set_token (EphySyncService *self,
- gchar *token_value,
- EphySyncServiceTokenType token_type);
+void ephy_sync_service_set_token (EphySyncService *self,
+ gchar *token_value,
+ EphySyncServiceTokenType token_type);
-void ephy_sync_service_set_and_store_tokens (EphySyncService *self,
- gchar *token_value,
- EphySyncServiceTokenType token_type,
- ...) G_GNUC_NULL_TERMINATED;
+void ephy_sync_service_set_and_store_tokens (EphySyncService *self,
+ gchar *token_value,
+ EphySyncServiceTokenType token_type,
+ ...) G_GNUC_NULL_TERMINATED;
-void ephy_sync_service_delete_all_tokens (EphySyncService *self);
+void ephy_sync_service_delete_all_tokens (EphySyncService *self);
-void ephy_sync_service_destroy_session (EphySyncService *self,
- const gchar *sessionToken);
+void ephy_sync_service_destroy_session (EphySyncService *self,
+ const gchar *sessionToken);
-gboolean ephy_sync_service_fetch_sync_keys (EphySyncService *self,
- const gchar *email,
- const gchar *keyFetchToken,
- const gchar *unwrapBKey);
+gboolean ephy_sync_service_fetch_sync_keys (EphySyncService *self,
+ const gchar *email,
+ const gchar *keyFetchToken,
+ const gchar *unwrapBKey);
-void ephy_sync_service_send_storage_message (EphySyncService *self,
- gchar *endpoint,
- const gchar *method,
- gchar *request_body,
- double modified_since,
- double unmodified_since,
- SoupSessionCallback callback,
- gpointer user_data);
+void ephy_sync_service_send_storage_message (EphySyncService *self,
+ gchar *endpoint,
+ const gchar *method,
+ gchar *request_body,
+ double modified_since,
+ double unmodified_since,
+ SoupSessionCallback callback,
+ gpointer user_data);
+
+void ephy_sync_service_release_next_storage_message (EphySyncService *self);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]