bug 9855; fix db undo/redo operation to delay signal emission
Certain multiple commit transactions can leave the db in an inconsistent state in between commits. If signals are emitted at each commit, GUI elements can see the inconsistent state and report errors. This fix delays the signal emission until all the commits are complete, presuming that the db is consistent before and after the complete transaction.
This commit is contained in:
parent
7e90144db3
commit
cea4d15d7d
@ -144,7 +144,15 @@ class DbGenericUndo(DbUndo):
|
||||
if key == REFERENCE_KEY:
|
||||
self.undo_reference(new_data, handle)
|
||||
else:
|
||||
self.undo_data(new_data, handle, key, db.emit, SIGBASE[key])
|
||||
self.undo_data(new_data, handle, key)
|
||||
# now emit the signals
|
||||
for record_id in subitems:
|
||||
(key, trans_type, handle, old_data, new_data) = \
|
||||
pickle.loads(self.undodb[record_id])
|
||||
|
||||
if key != REFERENCE_KEY:
|
||||
self.undo_signals(new_data, handle, key,
|
||||
db.emit, SIGBASE[key])
|
||||
self.db._txn_commit()
|
||||
except:
|
||||
self.db._txn_abort()
|
||||
@ -187,8 +195,15 @@ class DbGenericUndo(DbUndo):
|
||||
if key == REFERENCE_KEY:
|
||||
self.undo_reference(old_data, handle)
|
||||
else:
|
||||
self.undo_data(old_data, handle, key, db.emit, SIGBASE[key])
|
||||
self.undo_data(old_data, handle, key)
|
||||
# now emit the signals
|
||||
for record_id in subitems:
|
||||
(key, trans_type, handle, old_data, new_data) = \
|
||||
pickle.loads(self.undodb[record_id])
|
||||
|
||||
if key != REFERENCE_KEY:
|
||||
self.undo_signals(old_data, handle, key,
|
||||
db.emit, SIGBASE[key])
|
||||
self.db._txn_commit()
|
||||
except:
|
||||
self.db._txn_abort()
|
||||
@ -224,7 +239,26 @@ class DbGenericUndo(DbUndo):
|
||||
"VALUES(?, ?, ?, ?)")
|
||||
self.db.dbapi.execute(sql, data)
|
||||
|
||||
def undo_data(self, data, handle, obj_key, emit, signal_root):
|
||||
def undo_data(self, data, handle, obj_key):
|
||||
"""
|
||||
Helper method to undo/redo the changes made
|
||||
"""
|
||||
cls = KEY_TO_CLASS_MAP[obj_key]
|
||||
table = cls.lower()
|
||||
if data is None:
|
||||
sql = "DELETE FROM %s WHERE handle = ?" % table
|
||||
self.db.dbapi.execute(sql, [handle])
|
||||
else:
|
||||
if self.db.has_handle(obj_key, handle):
|
||||
sql = "UPDATE %s SET blob_data = ? WHERE handle = ?" % table
|
||||
self.db.dbapi.execute(sql, [pickle.dumps(data), handle])
|
||||
else:
|
||||
sql = "INSERT INTO %s (handle, blob_data) VALUES (?, ?)" % table
|
||||
self.db.dbapi.execute(sql, [handle, pickle.dumps(data)])
|
||||
obj = self.db.get_table_func(cls)["class_func"].create(data)
|
||||
self.db._update_secondary_values(obj)
|
||||
|
||||
def undo_signals(self, data, handle, obj_key, emit, signal_root):
|
||||
"""
|
||||
Helper method to undo/redo the changes made
|
||||
"""
|
||||
@ -232,19 +266,11 @@ class DbGenericUndo(DbUndo):
|
||||
table = cls.lower()
|
||||
if data is None:
|
||||
emit(signal_root + '-delete', ([handle],))
|
||||
sql = "DELETE FROM %s WHERE handle = ?" % table
|
||||
self.db.dbapi.execute(sql, [handle])
|
||||
else:
|
||||
if self.db.has_handle(obj_key, handle):
|
||||
signal = signal_root + '-update'
|
||||
sql = "UPDATE %s SET blob_data = ? WHERE handle = ?" % table
|
||||
self.db.dbapi.execute(sql, [pickle.dumps(data), handle])
|
||||
else:
|
||||
signal = signal_root + '-add'
|
||||
sql = "INSERT INTO %s (handle, blob_data) VALUES (?, ?)" % table
|
||||
self.db.dbapi.execute(sql, [handle, pickle.dumps(data)])
|
||||
obj = self.db.get_table_func(cls)["class_func"].create(data)
|
||||
self.db._update_secondary_values(obj)
|
||||
emit(signal, ([handle],))
|
||||
|
||||
class Cursor:
|
||||
|
@ -237,8 +237,15 @@ class DbUndo:
|
||||
if key == REFERENCE_KEY:
|
||||
self.undo_reference(old_data, handle, self.mapbase[key])
|
||||
else:
|
||||
self.undo_data(old_data, handle, self.mapbase[key],
|
||||
db.emit, _SIGBASE[key])
|
||||
self.undo_data(old_data, handle, self.mapbase[key])
|
||||
# now emit the signals
|
||||
for record_id in subitems:
|
||||
(key, trans_type, handle, old_data, new_data) = \
|
||||
pickle.loads(self.undodb[record_id])
|
||||
|
||||
if key != REFERENCE_KEY:
|
||||
self.undo_signals(old_data, handle, self.mapbase[key],
|
||||
db.emit, _SIGBASE[key])
|
||||
# Notify listeners
|
||||
if db.undo_callback:
|
||||
if self.undo_count > 0:
|
||||
@ -275,8 +282,15 @@ class DbUndo:
|
||||
if key == REFERENCE_KEY:
|
||||
self.undo_reference(new_data, handle, self.mapbase[key])
|
||||
else:
|
||||
self.undo_data(new_data, handle, self.mapbase[key],
|
||||
db.emit, _SIGBASE[key])
|
||||
self.undo_data(new_data, handle, self.mapbase[key])
|
||||
# Process all signals in the transaction
|
||||
for record_id in subitems:
|
||||
(key, trans_type, handle, old_data, new_data) = \
|
||||
pickle.loads(self.undodb[record_id])
|
||||
|
||||
if key != REFERENCE_KEY:
|
||||
self.undo_signals(new_data, handle, self.mapbase[key],
|
||||
db.emit, _SIGBASE[key])
|
||||
# Notify listeners
|
||||
if db.undo_callback:
|
||||
db.undo_callback(_("_Undo %s")
|
||||
@ -308,21 +322,33 @@ class DbUndo:
|
||||
self.db._log_error()
|
||||
raise DbError(msg)
|
||||
|
||||
def undo_data(self, data, handle, db_map, emit, signal_root):
|
||||
def undo_data(self, data, handle, db_map):
|
||||
"""
|
||||
Helper method to undo/redo the changes made
|
||||
"""
|
||||
try:
|
||||
if data is None:
|
||||
db_map.delete(handle, txn=self.txn)
|
||||
else:
|
||||
db_map.put(handle, data, txn=self.txn)
|
||||
|
||||
except DBERRS as msg:
|
||||
self.db._log_error()
|
||||
raise DbError(msg)
|
||||
|
||||
def undo_signals(self, data, handle, db_map, emit, signal_root):
|
||||
"""
|
||||
Helper method to undo/redo the changes made
|
||||
"""
|
||||
try:
|
||||
if data is None:
|
||||
emit(signal_root + '-delete', ([handle.decode('utf-8')],))
|
||||
db_map.delete(handle, txn=self.txn)
|
||||
else:
|
||||
ex_data = db_map.get(handle, txn=self.txn)
|
||||
if ex_data:
|
||||
signal = signal_root + '-update'
|
||||
else:
|
||||
signal = signal_root + '-add'
|
||||
db_map.put(handle, data, txn=self.txn)
|
||||
emit(signal, ([handle.decode('utf-8')],))
|
||||
|
||||
except DBERRS as msg:
|
||||
|
Loading…
Reference in New Issue
Block a user