[Dev] VersionConflictError: the story as of now

Andi Vajda vajda at osafoundation.org
Wed Sep 15 14:57:39 PDT 2004


When an item is modified in several repository views concurrently, the first 
view to commit wins. The others have to merge with the committed changes 
first. This happens during refresh() which is invoked from commit() or is
invoked directly.

There are three groups of changes to merge. Each corresponds to one or several 
dirty bits reported with a VersionConflictError:

  (1) child collections, item name and parent
      Each item can act as a container for other items through their itsName
      and itsParent intrinsic properties. Dirty bits: 0x0200 and 0x0100.

  (2) ref collections
      Attributes of cardinality 'list' with an 'otherName' aspect are
      implemented with ref collections, collections of bi-directional
      references. Dirty bit: 0x0400.

  (3) values stored in XML
      Attributes of cardinality 'single' or attributes of cardinality 'list' or
      'dict' not containing bi-directional refs but literals have their values
      stored in an XML document in DBXML. Dirty bit: 0x0002.

When you get a VersionConflictError, the error message reports the respective 
dirty bits of the mergee and the merger, the version receiving changes (the 
one in your view) and the version being acquired (the one committed in another 
view).

I am currently in the process of implementing version merging, starting with 
the easier and less disruptive case (1).

It turns out that the low-level implementation of child collections and ref 
collections is the same - double-linked lists backed by a mapping - and I hope
therefore that the work done to solve (1) is reusable for solving (2).

Solving (3) involves merging XML snippets for which there are 
published implementable algorithms.

At this time, the version merging code checked into CVS works as follows.
Let newDirty and oldDirty be the two dirty values, the mergee's and the 
merger's. After each successful merge, the corresponding bit is cleared in 
oldDirty.

   - if newDirty and oldDirty overlap in their 0x0100 or 0x0200 bits, the
     mergee's child collection is merged with the merger's and the following
     unresolvable conflicts are reported with a MergeError whose reasonCode
     can be retrieved with the getReasonCode() method.
        - the item was renamed in both views to a different name ->
          MergeError.RENAME
        - the item was moved in both views to different containers ->
          MergeError.MOVE
        - a bug occurred -> MergeError.BUG
     Conflicting order changes should be resolved in the merger's favor.
     This remains to be tested.
     The conflict of renaming an item to a name already existing in the
     merger item container is not detected yet, that's a bug, next on my list.

   - if newDirty and oldDirty overlap in their 0x0400 bits, a
     VersionConflictError is reported as (2) is not implemented yet.

   - if newDirty and oldDirty overlap in their 0x0002 bits, a
     VersionConflictError is reported as (3) is not implemented yet.

   - if after all implemented merges succeeded oldDirty is not zero, a
     VersionConflictError is reported since merging different parts of items
     together is not yet implemented either.

Once all cases of merging are implemented, there should never be any 
VersionConflictErrors reported anymore, only successful merges or 
unresolvable conflicts reported with MergeError which contains information 
that can be used to address the actual conflict: reasonCode, item, attribute 
(not yet implemented). Developers should eventually wrap their calls to 
refresh() or commit() with try: except MergeError: code so that they can 
process the reported conflicts.

Again, at this time, the only *partially* implemented version merging case is 
(1) but getting into the habit of wrapping your refresh/commit calls with 
MergeError catches can start now.

Reporting bugs
--------------

When you see a VersionConflictError, there is no need to file a new bug, bug 
1800 is the mother of all such bugs. Sending me the dirty bits reported via 
email helps me keep a tally of the most common conflicts.

When you see a MergeError and the reasonCode is not MergeError.BUG, a bug 
should be filed with whomever is responsible for the code causing or receiving 
the conflict, the repository is not at fault anymore, unless there's a bug of 
course :)

I hope this helps, questions welcome !

Andi..




More information about the Dev mailing list