summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Shyba <victor.shyba@gmail.com>2015-08-07 15:17:48 -0300
committerBruno Wagner <bwgpro@gmail.com>2015-08-12 17:17:19 -0300
commit35eda00b60d89a15930c0a6d3521e5f6afaa913e (patch)
treef097e080cc8a4af3caf7ca8a60c090ce29855a6a
parent2d5bf3c61642989d575dae9f248820392110320c (diff)
[bug] Sync Locking based on class + db file path
Change locking to be class based and each lock generated by db file path.
-rw-r--r--client/src/leap/soledad/client/api.py20
-rw-r--r--client/src/leap/soledad/client/sqlcipher.py8
2 files changed, 19 insertions, 9 deletions
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))
@@ -706,6 +707,17 @@ class Soledad(object):
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):
"""
Return wether Soledad is currently synchronizing with the server.
@@ -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