[Persistence-sig] Re: ACID, savepoints, and exceptions (was re: "Straw Man"transaction API)

Jeremy Hylton jeremy@alum.mit.edu
Tue, 20 Aug 2002 00:32:18 -0400


>>>>> "PJE" == Phillip J Eby <pje@telecommunity.com> writes:

  PJE> During the past week, I've been writing a TransactionService
  PJE> for PEAK, specifically designing it to allow
  PJE> interaction/adaptation to the new ZODB4 transaction API, and
  PJE> extending it to support the multi-prepare and durable
  PJE> subscription models that I need for my applications and
  PJE> framework projects.

Glad to hear you're making progress.  I've been completely swamped
with other things, so I haven't had any time for ZODB4 since we last
talked. 

  PJE> In my API I've standardized on a 'CannotRevertException' when
  PJE> rollback to a savepoint is not possible, and added a
  PJE> 'NullSavepoint' object which can be returned by an object that
  PJE> has nothing to do on rollback.

NullSavepoint is just an implementation convenience, right?

  PJE> An open issue that needs to be addressed, however, is the
  PJE> question of rolling back more than once to the same savepoint.
  PJE> In some ways, it's a very handy capability, but I'm not sure
  PJE> which databases support this. 

Let me ask the question the other way:  Of the databases that support
savepoints, which ones don't support this?

  PJE>                                I'm therefore inclined to say we
  PJE> should explicitly say that a savepoint can be rolled back at
  PJE> most once (since some savepoints may not be able to be rolled
  PJE> back).

I want savepoints that can be returned to multiple times.  If a
database supports savepoints at all, I don't see why it wouldn't
support multiple rollbacks.  (If it didn't, an adapter could
just call savepoint() as part of finishing each rollback().)  Multiple
rollbacks is necessary to support nested transactions.

  PJE> Another open issue: what happens if a rollback fails?  Is the
  PJE> transaction "hosed" at that point?

I think it is.

  PJE>                                     What if five data managers
  PJE> roll back, and the sixth one fails?

Exactly.  If you can't be sure each of the data managers is in a
consistent state, you need to abort the transaction.

  PJE>                                      This suggests adding a
  PJE> 'canRollback()' method to the interface, such that a rollback
  PJE> aggregator can check that its aggregated savepoints can
  PJE> actually be rolled back, so that "CannotRevert" errors don't
  PJE> cause the transaction to be hosed.  

It's probably good to have some way to query this, although I feel
like the predicate methods for testing features haven't worked out all
that well in the ZODB3 storage api.  What about that client code has
access to would support the canRollback() method?  It seems like it
depends on which objects are participating in the transaction.

I tend more towards an ask for forgiveness (AFF) than a look before
you leap (LBYL).  If savepoint() returned None when it wasn't possible
to rollback, that would be good enough, no?  The clients know, for
their specific transaction, whether rollback is going to work.  The
savepoint() presumably hasn't caused too much extra work in those
cases. 

  PJE>                                     However, the issue of
  PJE> another type of exception occurring during rollback still must
  PJE> be addressed.

Yes.

  >> I think I'm also in favor of the new abort semantics.  ZODB3
  >> would abort the transactions -- call abort() on all the data
  >> managers -- if an error occurred during a commit.  The new code
  >> requires that the user do this instead.  I think that's better,
  >> because it leaves the state of the objects intact if the code
  >> wants to analyze what went wrong before retrying the transaction.

  PJE> The interesting question here again is, is the transaction
  PJE> "hosed"?  Should there be a flag that says, "you can't do
  PJE> anything to this transaction but abort it"?

Yes, and yes.

  PJE> To put it in broader terms, if *any* exception is thrown during
  PJE> execution of a transaction-related method, should we consider
  PJE> the transaction unrecoverable?

Yes.  If a resource manager raises an unexpected exception, you've got
no idea what state its in or whether it can/has committed the data.

  PJE> I'm inclined to say yes, because I can think of too many code
  PJE> paths in both my and the ZODB4 transaction code where it
  PJE> becomes nearly impossible to guarantee a "clean" state when an
  PJE> exception occurs.  By definition, if code called by the
  PJE> transaction system raises an exception, it is announcing that
  PJE> it cannot satisfy its contract with the transaction.
  PJE> Therefore, the transaction cannot be certain of satisfying its
  PJE> contract with the application for a clean commit.

Right.

  PJE> Another issue here is clean aborts.  If an error is raised by a
  PJE> data manager during abort, what should the semantics be?  Older
  PJE> ZODB transaction classes wrap every data manager abort call in
  PJE> a try-except that ensures that *all* the abort methods get
  PJE> called, even if several of them raise errors.  The new ZODB4
  PJE> transaction API doesn't do this, and thus can fail to
  PJE> completely roll back a transaction.

I tried to do as little as possible within the commit() implementation
to deal with errors.  I figured if an error occurs, the client had
better abort the transaction explicitly.  The documentation for ZODB3
said that clients needed to do this, but the implementation didn't
work that way.

Jeremy