Ann W. Harrison explains an oddity in implementation of savepoints:

A rollback to a savepoint removes the record versions created. Since Firebird doesn't use record locks but instead relies on the transaction id in record versions, removing the record version is the same as releasing the lock, except in one case.

When a transaction starts, it gets an exclusive lock on its own transaction id. When a transaction attempts to modify a record and discovers that the most recent version was created by a concurrent transaction, it attempts to get a lock on the id of the transaction that made the change. When it gets the lock, it checks the state of the conflicting transaction. If that transaction rolled back, the waiting transaction proceeds. If the conflicting transaction committed, the transaction that had waited gets an "update conflict" error and must rollback and retry the operation. (Read-committed transactions can simply retry without the rollback - risking inconsistency, but no one who cares about consistency uses read-committed.)

So the problematic case is that Transaction A created a save point then updated some records. Transaction B attempts to update one of those records, recognizes the conflict, and starts waiting for a lock on the id of Transaction A. Transaction A's rolling back to the save point has no effect on Transaction B. It continues to wait, even though there is no longer a conflict. when Transaction A eventually commits, Transaction B thinks it had an update conflict, and must roll back.

There's no convenient way for Transaction A to recognize that it has unblocked Transaction B by undoing the save point.

This is annoying.

Like this post? Share on: TwitterFacebookEmail

Related Articles


Firebird Community



Gems from Firebird Support list