It does not matter if we update the freelist in the initial commit or when
cleaning up the deferred transaction; both will eventually update the
persistent kv freelist. We maintain one case to ensure that legacy
deferred events (from a kraken upgrade) release when they are replayed.
What matters while online is the Allocator, which has an independent
in-memory copy of the freelist to make decisions. And we can delay that
as long as we want. To avoid any concerns about deferred writes racing
against released blocks, just defer any release until the txc is fully
completed (including any deferred writes). This ensures that even if we
have a pattern like
txc 1: schedule deferred write on block A
txc 2: release block A
txc 1+2: commit
txc 2: done!
txc 1: do deferred write
txc 1: done!
then txc 2 won't do its release because it is stuck behind txc 1 in the
OpSequencer queue:
...
txc 1: reaped
txc 2: reaped (and extents released to alloc)
This builds in some delay in just-released space being usable again, but
it should be a very small amount of space relative to the size of the
store!