From 969ab4ebeda2ac3abcb00d9beded5f013e074e4a Mon Sep 17 00:00:00 2001 From: Victor Shyba Date: Mon, 11 Sep 2017 21:24:50 -0300 Subject: [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 --- src/leap/soledad/client/_db/blobs.py | 25 ++++++++++++++++--------- src/leap/soledad/client/_db/pragmas.py | 4 +++- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'src/leap/soledad') 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): -- cgit v1.2.3