5.7.3 Commit and Failure
REG_IOC_COMMIT marks the transaction as having a commit in flight and
sends RSI_COMMIT_TRANSACTION. What happens next depends on the answer.
5.7.3.1 Success #
The source's RSI_OK triggers, in order: the layer metadata cache
refresh for any layer names the transaction touched, the hive
generation increment, orphan tracking for keys that lost their last
path entry, and the watch event batch derived from the mutation log.
The object then becomes COMMITTED, the log is released, poll waiters
are woken, and the ioctl returns 0.
The hive generation is incremented once per committed transaction per affected hive, however many operations the transaction contained.
5.7.3.2 Failure that leaves the transaction open #
A source that cannot take the write lock answers RSI_TXN_BUSY, which
becomes EBUSY; a synchronous commit failure becomes EIO. In both
cases the transaction stays ACTIVE_BOUND:
- the mutation log is retained;
- no watch events are emitted;
- poll waiters are not woken as though the transaction had become terminal.
The in-flight marker is cleared, so the caller may simply retry
REG_IOC_COMMIT, or close the fd to abort. Nothing has been lost.
5.7.3.3 Timeout after dispatch #
If the request timeout expires after the commit was dispatched, the
caller receives ETIMEDOUT and the object becomes TIMED_OUT, but the
mutation log is kept and the request record stays in the source's
in-flight table. The source may still answer.
ETIMEDOUT on a commit means may or may not have committed. A caller
that needs certainty checks state before retrying.
A late RSI_OK applies the full set of kernel-side effects from the
retained log — the same generation updates and the same watch events an
on-time commit would have produced. Watchers may therefore observe the
effects of a transaction whose caller was told it timed out. A late
error releases the log with no effects.
The transaction object does not move to COMMITTED when a late
success arrives. It stays TIMED_OUT, so a caller that queries
REG_IOC_TXN_STATUS afterwards is told TIMED_OUT with a
terminal_errno of ETIMEDOUT, even though the writes are durable and
the watch events have gone out. The state reflects what the caller was
told, not what the source did.
5.7.3.4 When the watch events cannot be derived #
Two of the post-commit steps query the source. Working out which keys were orphaned by a key deletion needs a lookup that can only be made after the commit, and expanding a blanket tombstone into per-value events needs the value set.
If that derivation cannot complete exactly, LCS does not reinterpret a
successful commit as a failed one and does not emit a partial set of
events. It delivers OVERFLOW to the affected watchers instead,
releases the retained replay state, and reports the commit as
successful, which it was. A late response arriving afterwards does not
resurrect the individual events once overflow recovery has been
chosen.
The carve-out is narrower than it might appear. It covers the orphan
lookup and the watch batch. The other two post-commit steps — publishing
the layer metadata cache and recording the hive generation — are state
updates rather than event derivation, and a failure in either returns
EIO and marks the source Down.
5.7.3.5 Abort #
Aborting generates no events, ever, and releases the log. The source is
told to roll back with RSI_ABORT_TRANSACTION if the transaction was
bound.
Process death is the same path: closing the fd aborts.