###

Berkeley DB Reference Guide:
  Transaction Subsystem

# Nested transactions

Berkeley DB provides support for nested transactions. Nested transactions allow an application to decompose a large or long-running transaction into smaller units that may be independently aborted.

Normally, when beginning a transaction, the application will pass a NULL value for the parent argument to txn_begin. If, however, the parent argument contains a valid DB_TXN, then the newly created transaction will be treated as a nested transaction within the parent. Transactions may nest arbitrarily deeply. For the purposes of this discussion, transactions created with a parent identifier will be called child transactions.

Once a transaction becomes a parent, as long as any of its child transactions are still active (i.e., they have neither committed nor aborted), the parent may not issue any Berkeley DB calls except to create more child transactions or to abort itself or one its children. That is, it may not issue and access method or cursor calls. Once all of a parent's children have committed or aborted, the parent may continue to request operations on its own behalf.

The semantics of nested transactions are as follows. When a child transaction is begun, it inherits all the locks of its parent. This means that the child will never block waiting on a lock held by its parent. However, if a parent attempts to obtain locks after they have begun a child, the parental locks can conflict with those held by a child. Furthermore, locks held by two different children will also conflict. To make this concrete, consider the following set of transactions and lock acquisitions.

Transaction T1 is the parent transaction. It acquires an exclusive lock on item A and then begins two child transactions, C1 and C2. C1 also wishes to acquire a write lock on A; this succeeds. Now, let's say that C1 acquires a write lock on B. If C2 now attempts to obtain a lock on B, it will block. However, let's now assume that C1 commits. Its locks are anti-inherited, which means they are now given to T1. At this point, either T1 or C2 is allowed to acquire a lock on B. If, however, transaction T1 aborts, then its locks are released. Future requests by T1 or C2 will also succeed, but they will be obtaining new locks as opposed to piggy-backing off a lock already held by T1.

Child transactions are entirely subservient to their parent transaction. That is, they may abort, undoing their operations regardless of the fate of the parent. However, even if a child transaction commits, if its parent transaction is aborted, the child's changes are undone and the child's transaction is effectively aborted. Any child transactions that are not yet resolved when the parent completes (by either aborting or committing), are resolved based on the parent's resolution, committing if the parent commits and aborting if the parent aborts.

Nested transactions are useful when a potentially large series of operations can be decomposed into smaller sets of operations, each of which set makes sense to abort individually.

Copyright Sleepycat Software