summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Shyba <victor1984@riseup.net>2017-09-11 21:24:50 -0300
committerVictor Shyba <victor1984@riseup.net>2017-09-11 21:24:50 -0300
commit969ab4ebeda2ac3abcb00d9beded5f013e074e4a (patch)
tree0363ee9339582ada637ae040f18b5b663b8ebc49
parentae11ec7d685cdf313778e0c5126ecd748608be26 (diff)
[bug] do not allow concurrent schema creation
Moved schema creation and migrations to the pragma locked call, so we avoid it running concurrently on a thread pool. -- Resolves: #8945
-rw-r--r--src/leap/soledad/client/_db/blobs.py25
-rw-r--r--src/leap/soledad/client/_db/pragmas.py4
2 files changed, 19 insertions, 10 deletions
diff --git a/src/leap/soledad/client/_db/blobs.py b/src/leap/soledad/client/_db/blobs.py
index cfabda74..1447e3bb 100644
--- a/src/leap/soledad/client/_db/blobs.py
+++ b/src/leap/soledad/client/_db/blobs.py
@@ -73,6 +73,20 @@ class SyncStatus:
class ConnectionPool(adbapi.ConnectionPool):
+ def blocking_create_schema(self, create_schema_function):
+ """
+ Grabs a connection and executes schema creation from current thread,
+ disconnecting right after it. This ensures that schema creation blocks
+ everything and doesn't run concurrently.
+
+ :param create_schema_function: A function that receives a connection
+ and executes schema criation and/or migrations.
+ :type create_schema_function: function
+ """
+ conn = self.connect()
+ create_schema_function(conn)
+ self.disconnect(conn)
+
def insertAndGetLastRowid(self, *args, **kwargs):
"""
Execute an SQL query and return the last rowid.
@@ -439,8 +453,8 @@ class SQLiteBlobBackend(object):
opts = sqlcipher.SQLCipherOptions(
'/tmp/ignored', binascii.b2a_hex(key),
is_raw_key=True, create=True)
- pragmafun = partial(pragmas.set_init_pragmas, opts=opts)
- openfun = _sqlcipherInitFactory(pragmafun)
+ openfun = partial(pragmas.set_init_pragmas, opts=opts,
+ schema_func=_init_blob_table)
self.dbpool = ConnectionPool(
backend, self.path, check_same_thread=False, timeout=5,
@@ -553,13 +567,6 @@ def _init_blob_table(conn):
conn.execute('ALTER TABLE blobs ADD COLUMN retries INT default 0')
-def _sqlcipherInitFactory(fun):
- def _initialize(conn):
- fun(conn)
- _init_blob_table(conn)
- return _initialize
-
-
#
# testing facilities
#
diff --git a/src/leap/soledad/client/_db/pragmas.py b/src/leap/soledad/client/_db/pragmas.py
index 870ed63e..76fea458 100644
--- a/src/leap/soledad/client/_db/pragmas.py
+++ b/src/leap/soledad/client/_db/pragmas.py
@@ -31,7 +31,7 @@ logger = getLogger(__name__)
_db_init_lock = threading.Lock()
-def set_init_pragmas(conn, opts=None, extra_queries=None):
+def set_init_pragmas(conn, opts=None, extra_queries=None, schema_func=None):
"""
Set the initialization pragmas.
@@ -43,6 +43,8 @@ def set_init_pragmas(conn, opts=None, extra_queries=None):
with _db_init_lock:
# only one execution path should initialize the db
_set_init_pragmas(conn, opts, extra_queries)
+ if schema_func:
+ schema_func(conn)
def _set_init_pragmas(conn, opts, extra_queries):