Commit 84f9894e authored by Julien Muchembled's avatar Julien Muchembled

storage: review search of data serial for undo

- Fix case of empty values: there's no reason to do anything special for them.
- Do not warn about multiple level of indirection to get data serial.
  With the current structure of tables, this does not cause significant
  performance issue as it did before.
parent d562bf8f
...@@ -328,28 +328,20 @@ class DatabaseManager(object): ...@@ -328,28 +328,20 @@ class DatabaseManager(object):
tid (int) tid (int)
tid corresponding to received parameters tid corresponding to received parameters
serial serial
tid at which actual object data is located data tid of the found record
If 'tid is None', requested object and transaction could (None, None) is returned if requested object and transaction
not be found. could not be found.
If 'serial is None', requested object exist but has no data (its creation
has been undone). This method only exists for performance reasons, by not returning data:
If 'tid == serial', it means that requested transaction _getObject already returns these values but it is slower.
contains object data.
Otherwise, it's an undo transaction which did not involve conflict
resolution.
""" """
if self.__class__ not in self.__getDataTID: if self.__class__ not in self.__getDataTID:
self.__getDataTID.add(self.__class__) self.__getDataTID.add(self.__class__)
logging.warning("Fallback to generic/slow implementation" logging.warning("Fallback to generic/slow implementation"
" of _getDataTID. It should be overriden by backend storage.") " of _getDataTID. It should be overridden by backend storage.")
r = self._getObject(oid, tid, before_tid) r = self._getObject(oid, tid, before_tid)
if r: return (r[0], r[-1]) if r else (None, None)
serial, _, _, data_id, _, value_serial = r
if value_serial is None and data_id:
return serial, serial
return serial, value_serial
return None, None
def findUndoTID(self, oid, tid, ltid, undone_tid, transaction_object): def findUndoTID(self, oid, tid, ltid, undone_tid, transaction_object):
""" """
...@@ -389,17 +381,17 @@ class DatabaseManager(object): ...@@ -389,17 +381,17 @@ class DatabaseManager(object):
ltid = u64(ltid) ltid = u64(ltid)
undone_tid = u64(undone_tid) undone_tid = u64(undone_tid)
def getDataTID(tid=None, before_tid=None): def getDataTID(tid=None, before_tid=None):
tid, value_serial = self._getDataTID(oid, tid, before_tid) tid, data_tid = self._getDataTID(oid, tid, before_tid)
if value_serial not in (None, tid): current_tid = tid
if value_serial >= tid: while data_tid:
raise ValueError("Incorrect value reference found for" if data_tid < tid:
" oid %d at tid %d: reference = %d" tid, data_tid = self._getDataTID(oid, data_tid)
% (oid, value_serial, tid)) if tid is not None:
if value_serial != getDataTID(value_serial)[1]: continue
logging.warning("Multiple levels of indirection" logging.error("Incorrect data serial for oid %s at tid %s",
" when getting data serial for oid %d at tid %d." oid, current_tid)
" This causes suboptimal performance.", oid, tid) return current_tid, current_tid
return tid, value_serial return current_tid, tid
if transaction_object: if transaction_object:
current_tid = current_data_tid = u64(transaction_object[2]) current_tid = current_data_tid = u64(transaction_object[2])
else: else:
......
...@@ -423,7 +423,7 @@ class MySQLDatabaseManager(DatabaseManager): ...@@ -423,7 +423,7 @@ class MySQLDatabaseManager(DatabaseManager):
return self.conn.insert_id() return self.conn.insert_id()
def _getDataTID(self, oid, tid=None, before_tid=None): def _getDataTID(self, oid, tid=None, before_tid=None):
sql = ('SELECT tid, data_id, value_tid FROM obj' sql = ('SELECT tid, value_tid FROM obj'
' WHERE partition = %d AND oid = %d' ' WHERE partition = %d AND oid = %d'
) % (self._getPartition(oid), oid) ) % (self._getPartition(oid), oid)
if tid is not None: if tid is not None:
...@@ -435,12 +435,7 @@ class MySQLDatabaseManager(DatabaseManager): ...@@ -435,12 +435,7 @@ class MySQLDatabaseManager(DatabaseManager):
# MySQL does not use an index for a HAVING clause! # MySQL does not use an index for a HAVING clause!
sql += ' ORDER BY tid DESC LIMIT 1' sql += ' ORDER BY tid DESC LIMIT 1'
r = self.query(sql) r = self.query(sql)
if r: return r[0] if r else (None, None)
(serial, data_id, value_serial), = r
if value_serial is None and data_id:
return serial, serial
return serial, value_serial
return None, None
def finishTransaction(self, tid): def finishTransaction(self, tid):
q = self.query q = self.query
......
...@@ -370,7 +370,7 @@ class SQLiteDatabaseManager(DatabaseManager): ...@@ -370,7 +370,7 @@ class SQLiteDatabaseManager(DatabaseManager):
def _getDataTID(self, oid, tid=None, before_tid=None): def _getDataTID(self, oid, tid=None, before_tid=None):
partition = self._getPartition(oid) partition = self._getPartition(oid)
sql = 'SELECT tid, data_id, value_tid FROM obj' \ sql = 'SELECT tid, value_tid FROM obj' \
' WHERE partition=? AND oid=?' ' WHERE partition=? AND oid=?'
if tid is not None: if tid is not None:
r = self.query(sql + ' AND tid=?', (partition, oid, tid)) r = self.query(sql + ' AND tid=?', (partition, oid, tid))
...@@ -381,12 +381,7 @@ class SQLiteDatabaseManager(DatabaseManager): ...@@ -381,12 +381,7 @@ class SQLiteDatabaseManager(DatabaseManager):
r = self.query(sql + ' ORDER BY tid DESC LIMIT 1', r = self.query(sql + ' ORDER BY tid DESC LIMIT 1',
(partition, oid)) (partition, oid))
r = r.fetchone() r = r.fetchone()
if r: return r or (None, None)
serial, data_id, value_serial = r
if value_serial is None and data_id:
return serial, serial
return serial, value_serial
return None, None
def finishTransaction(self, tid): def finishTransaction(self, tid):
args = util.u64(tid), args = util.u64(tid),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment