[ZODB-Dev] Commit or lock object accross transactions
Christian Reis
kiko at async.com.br
Wed Jul 16 14:43:04 EDT 2003
On Wed, Jul 16, 2003 at 11:42:43AM -0400, Jeremy Hylton wrote:
> > The problem with this is that their might be legitimate transactions in
> > process on other clients.
>
> A client that has a transaction in progress will not see the changes
> committed by another client until the transaction finishes. Changes
> only become visible at transaction boundaries.
Generating a unique and sequential ID over a global space is not a very
trivial matter, and I'm not sure all of it is the ZODB's fault in this
case. There are a number of potential constraints that should to be
considered. The ones I work with in my app are:
- The ID should be globally unique.
- The transaction using an allocated ID may be cancelled after it
is allocated.
- The ID should be presentable to the end-user in the UI before the
transaction is commited.
- Scenario 1: Locking primitive. A locking primitive emphasizes the
first constraint, but it doesn't help the other ones. Orphaned IDs
would need to be collected and reused (hopefully by the very next
transaction). Granted, it's a nice feature, and if there is a way
to implement it in the ZODB, it would be great.
The last constraint is okay here, because the ID is guaranteed to not
change when commit() happens.
A substantial con here is that the ZODB doesn't provide such a
primitive, so you'd need to implement it, or using a secondary
database for IDs.
- Scenario 2: Lazy consistency. Assuming no locking primitive is
available, the ZODB style of consistency management is lazy -- if
conflicts do happen (i.e., if two identical IDs are allocated at the
same time), we can try and resolve the conflict (by assigning
another ID to the conflicting transaction). Orphaned IDs are less of
a problem in this scenario (they only appear if you *undo* a
transaction that was committed, since the ID is guaranteed with the
commit).
The last constraint is a problem with the lazy model, though, since the
ID *may* change when the transaction is being committed -- the user that
wrote down 5563 needs to be notified that when it was committed, a
conflict was found and it changed to 5564 -- he scratches out the 3 and
writes a 4 down.
What I recommend, after looking at the options, is analyzing the
constraints and seeing what your priority is. If a skipped ID every once
in a while is okay, you don't have to worry about orphaned IDs, which
simplifies things somewhat. If it's okay to present an ID to the user
and have it change (presenting a special dialog or page that notifies
him, or if the user doesn't need to see the ID before committing, that's
good too.
Someone (I think Casey) once suggested to me using the BTrees' Length to
define IDs, because it had built-in conflict-resolution (which would
allocate another value if a conflict happened). [However, because the
Length only stores the current value, it won't help us with orphaned IDs
-- you'd need to search through all allocated IDs to check for them.]
Toby once suggested obtaining an ID in a "short" transaction (get_ID(),
commit()) and then using it in your "long" transaction. This
reduces the chance of getting a conflict, but reintroduces the risk of
orphaned IDs (since the latter transaction may be cancelled - and what
then? Undo the transaction where the ID was obtained?)
See also ChrisM's post on counters, which discussed Length's conflict
resolution:
http://zope.nipltd.com/public/lists/zope-archive.nsf/AGByKey/558F6496C424804A
Anyway, that's half a chapter in a book <wink>.
--
Christian Reis, Senior Engineer, Async Open Source, Brazil.
http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL
More information about the ZODB-Dev
mailing list