Integration of application level conflict resolution, using the
ConflictResolution helper module. Specifically, class Full: add ConflictResolvingStorage to the base classes, so we magically grow self.tryToResolveConflict(). store(): Keep a flag indicating whether we calculated the object's pickle data via conflict resolution. If so, we return the special marker ResolvedSerial instead of the next available serial number. Also, in the serial <> oserial clause, try to resolve the conflict using ConflictResolvingStorage.tryToResolveConflict() and raise a ConflictError only if that fails (i.e. returns a false value). Otherwise, the resolution succeeded providing us with the data pickle to use as the stored object's state. transactionalUndo(): We need to keep an additional list of actions to perform on a successful undo. The first list keeps track of existing revisions to point the new transaction at, but conflict resolution provides us with a brand new pickle (or at least, a pickle for which we've no idea what the lrevid pointer should be). For those situations we need to do a CommitLog.write_object() instead of a CommitLog.write_object_undo() so as to get the new pickle into the commit log. Thus, newstates is a list keeping track of conflict resolved object states, while (the existing) newrevs keeps track of undo records where we already have the pickle in the database. Also, in the clause where we raise an UndoError, first tryToResolveConflict() and only if that fails do we raise the UndoError. Should it succeed, we append the record to newstates for later. Finally, in the clause were we're replaying the changes into the commit log (because we now know that all undos will succeed), we first replay the newrevs entries, then we replay the newstates entries, making sure we return all the affected oids. Note: these changes impose no regressions and pass all tests in ConflictResolvingStorage and ConflictResolvingTransUndoStorage.
Showing
Please register or sign in to comment