core (memory/sqlite): better stability:
- timeout increased to 15 s
- if a query fail, it's retried up to 5 times
- foreign key PRAGMA is executed on every new connection object (should fix non working foreign keys)
those are Q&D workarounds for issues with Sqlite, before switching to a higher level module to handle it correctly.
This commit is contained in:
parent
4602edfb4f
commit
ab2e625607
1 changed files with 23 additions and 7 deletions
|
|
@ -106,10 +106,25 @@ NOT_IN_EXTRA = ('received_timestamp', 'update_uid') # keys which are in message
|
|||
class ConnectionPool(adbapi.ConnectionPool):
|
||||
# Workaround to avoid IntegrityError causing (i)pdb to be launched in debug mode
|
||||
def _runQuery(self, trans, *args, **kw):
|
||||
retry = kw.pop('query_retry', 6)
|
||||
try:
|
||||
trans.execute(*args, **kw)
|
||||
except sqlite3.IntegrityError as e:
|
||||
raise failure.Failure(e)
|
||||
except Exception as e:
|
||||
# FIXME: in case of error, we retry a couple of times
|
||||
# this is a workaround, we need to move to better
|
||||
# Sqlite integration, probably with high level library
|
||||
retry -= 1
|
||||
if retry == 0:
|
||||
log.error(_(u'too many db tries, we abandon! Error message: {msg}').format(
|
||||
msg = e))
|
||||
raise e
|
||||
log.warning(_(u'exception while running query, retrying ({try_}): {msg})').format(
|
||||
try_ = 6 - retry,
|
||||
msg = e))
|
||||
kw['query_retry'] = retry
|
||||
return self._runQuery(trans, *args, **kw)
|
||||
return trans.fetchall()
|
||||
|
||||
|
||||
|
|
@ -130,13 +145,11 @@ class SqliteStorage(object):
|
|||
dir_ = os.path.dirname(db_filename)
|
||||
if not os.path.exists(dir_):
|
||||
os.makedirs(dir_, 0700)
|
||||
self.dbpool = ConnectionPool("sqlite3", db_filename, check_same_thread=False)
|
||||
|
||||
# init_defer is the initialisation deferred, initialisation is ok when all its callbacks have been done
|
||||
# XXX: foreign_keys activation doesn't seem to work, probably because of the multi-threading
|
||||
# All the requests that need to use this feature should be run with runInteraction instead,
|
||||
# so you can set the PRAGMA as it is done in self.deleteProfile
|
||||
init_defer = self.dbpool.runOperation("PRAGMA foreign_keys = ON").addErrback(lambda x: log.error(_("Can't activate foreign keys")))
|
||||
def foreignKeysOn(sqlite):
|
||||
sqlite.execute('PRAGMA foreign_keys = ON')
|
||||
|
||||
self.dbpool = ConnectionPool("sqlite3", db_filename, cp_openfun=foreignKeysOn, check_same_thread=False, timeout=15)
|
||||
|
||||
def getNewBaseSql():
|
||||
log.info(_("The database is new, creating the tables"))
|
||||
|
|
@ -157,6 +170,10 @@ class SqliteStorage(object):
|
|||
d = self.dbpool.runInteraction(self._updateDb, tuple(statements))
|
||||
return d
|
||||
|
||||
# init_defer is the initialisation deferred, initialisation is ok when all its callbacks have been done
|
||||
|
||||
init_defer = defer.succeed(None)
|
||||
|
||||
init_defer.addCallback(lambda ignore: getNewBaseSql() if new_base else getUpdateSql())
|
||||
init_defer.addCallback(commitStatements)
|
||||
|
||||
|
|
@ -253,7 +270,6 @@ class SqliteStorage(object):
|
|||
|
||||
def delete(txn):
|
||||
profile_id = self.profiles.pop(name)
|
||||
txn.execute("PRAGMA foreign_keys = ON")
|
||||
txn.execute("DELETE FROM profiles WHERE name = ?", (name,))
|
||||
# FIXME: the following queries should be done by the ON DELETE CASCADE
|
||||
# but it seems they are not, so we explicitly do them by security
|
||||
|
|
|
|||
Loading…
Reference in a new issue