From 35eda00b60d89a15930c0a6d3521e5f6afaa913e Mon Sep 17 00:00:00 2001 From: Victor Shyba Date: Fri, 7 Aug 2015 15:17:48 -0300 Subject: [bug] Sync Locking based on class + db file path Change locking to be class based and each lock generated by db file path. --- client/src/leap/soledad/client/api.py | 20 ++++++++++++++++---- client/src/leap/soledad/client/sqlcipher.py | 8 +++----- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'client') diff --git a/client/src/leap/soledad/client/api.py b/client/src/leap/soledad/client/api.py index 9000029f..633c07d0 100644 --- a/client/src/leap/soledad/client/api.py +++ b/client/src/leap/soledad/client/api.py @@ -41,13 +41,14 @@ except ImportError: from itertools import chain from StringIO import StringIO +from collections import defaultdict from u1db.remote import http_client from u1db.remote.ssl_match_hostname import match_hostname from zope.interface import implements from leap.common.config import get_path_prefix from leap.common.plugins import collect_plugins -from twisted.internet import defer +from twisted.internet.defer import DeferredLock from leap.soledad.common import SHARED_DB_NAME from leap.soledad.common import soledad_assert @@ -114,6 +115,7 @@ class Soledad(object): local_db_file_name = 'soledad.u1db' secrets_file_name = "soledad.json" default_prefix = os.path.join(get_path_prefix(), 'leap', 'soledad') + _syncing_lock = defaultdict(DeferredLock) def __init__(self, uuid, passphrase, secrets_path, local_db_path, server_url, cert_file, shared_db=None, @@ -200,7 +202,6 @@ class Soledad(object): self._crypto = SoledadCrypto(self._secrets.remote_storage_secret) self._init_u1db_sqlcipher_backend() - self.sync_lock = defer.DeferredLock() if syncable: self._init_u1db_syncer() @@ -671,7 +672,7 @@ class Soledad(object): # ----------------------------------------------------------------- sync_url = urlparse.urljoin(self._server_url, 'user-%s' % self.uuid) - d = self.sync_lock.run(lambda: self._dbsyncer.sync( + d = self.syncing_lock.run(lambda: self._dbsyncer.sync( sync_url, creds=self._creds, defer_decryption=defer_decryption)) @@ -705,6 +706,17 @@ class Soledad(object): d.addCallbacks(_sync_callback, _sync_errback) return d + @property + def syncing_lock(self): + """ + Class based lock to ensure consistency on concurrent calls to sync. + Each lock is based on the path of db file. + + :return: DeferredLock based on this instance path of db file + :rtype: DeferredLock + """ + return self._syncing_lock[self._local_db_path] + @property def syncing(self): """ @@ -713,7 +725,7 @@ class Soledad(object): :return: Wether Soledad is currently synchronizing with the server. :rtype: bool """ - return self.sync_lock.locked + return self.syncing_lock.locked def _set_token(self, token): """ diff --git a/client/src/leap/soledad/client/sqlcipher.py b/client/src/leap/soledad/client/sqlcipher.py index 249ffb1a..6a4fa01a 100644 --- a/client/src/leap/soledad/client/sqlcipher.py +++ b/client/src/leap/soledad/client/sqlcipher.py @@ -420,11 +420,6 @@ class SQLCipherU1DBSync(SQLCipherDatabase): """ ENCRYPT_LOOP_PERIOD = 1 - """ - A dictionary that hold locks which avoid multiple sync attempts from the - same database replica. - """ - def __init__(self, opts, soledad_crypto, replica_uid, cert_file, defer_encryption=False, sync_db=None, sync_enc_pool=None): @@ -513,6 +508,9 @@ class SQLCipherU1DBSync(SQLCipherDatabase): changes, we should add a thread-safe condition to ensure the db is ready before using it. + This method is atomic, with atomicity guaranteed by caller. Each + caller should implement a locking mechanism to ensure atomicity. + :param url: The url of the target replica to sync with. :type url: str :param creds: optional dictionary giving credentials to authorize the -- cgit v1.2.3