74.4 Cleaner
Purpose and invariant
The cleaner reclaims an allocated segment by relocating every packet in that segment which is still live. Successful cleaning is not merely an attempt to improve utilisation: the source segment's SUT utilisation must become exactly zero, after which its SegId is added to the delta-FSS as soon as its reservation count is also zero. A cleaner must not report success while leaving a live packet in the source segment. If the current output segment lacks room, the writer obtains another destination segment and continues.
The cleaner changes physical positions, not logical LSS contents. It does not deserialize data packets into application objects, assign new Seids, alter packet chains or publish an MVCC version. It uses the ordinary log and Snapshot framing so the same physical moves can be reconstructed by the recovery scan.
Candidate and lifetime requirements
Only a complete segment which has been flushed and which precedes the current log tail may be selected. The active SegmentWriter segment is never a source. The source is pinned in the segment cache for the scan, and the cleaner holds a segment reservation until it has finished reading and updating the accounting for every record. All persisted bytes are checksum-verified before use, as required by the trusted-writer model.
The SUT may be used to rank low-utilisation candidates, but its value is not a licence to skip the
source scan. For every packet record, liveness is decided from the authoritative in-memory mapping:
the record is live exactly when the mapping selected by its stable identity contains that record's
exact LogRecordPosition. A different position means that the
record is an obsolete version and it is not copied. Control records and Snapshot records are not
live packets and are not copied by the cleaner.
Serialization with partition updates
The potentially slow read and checksum work may be prepared without holding the Partition mutex. The liveness decision and relocation commit occur while holding that mutex, so they cannot race a logical replacement, deletion or another relocation of the same packet. Liveness is checked again in this commit phase. A record which became obsolete while the source was being inspected is simply not live and requires no relocation.
Cleaning may batch many packet copies into one physical-maintenance transaction. The cleaner remains responsible for eventually processing every live record in the selected segment; batching must not turn a partially processed segment into a successful result.
High-ingestion workloads
A PSpace may apply transient operations at a much higher rate than it commits transactions to the LSS. Many logical operations can be consolidated into one set of serial-element writes, so the cleaner is scheduled relative to LSS traffic rather than the higher-level operation rate. This batching also gives the cleaner opportunities to run between partition transactions.
High update rates can nevertheless make packets obsolete quickly and produce many low-utilisation segments. The cleaner must reclaim those segments at a sufficient physical rate to prevent the supply of reusable segments from being exhausted. A low LSS transaction frequency creates scheduling opportunities, but does not by itself guarantee that cleaning can keep pace; that also depends on write amplification, device bandwidth and the rate at which live data must be relocated.
Relocating one packet
- Find the current position from the packet kind and stable identity, and confirm that it is the position being scanned.
- Copy the complete encoded packet record to the log. For a data packet, replace an ordinary type with its corresponding relocated type; a type which is already relocated remains unchanged. A Space, Space RPM-node or SpaceDirectory RPM-node retains its existing type, whose occurrence in the post-checkpoint recovery log implies relocation. The copied record has the same encoded size and logical identity.
- Add that encoded size to the destination segment's SUT utilisation.
- Replace the authoritative in-memory position with the copied record's position and mark the affected ancestor path dirty.
- Subtract the encoded size from the source segment's SUT utilisation.
The destination is accounted before the old copy is retired, and the mapping is changed before the source can reach zero. Therefore every live packet is accounted somewhere throughout the operation. The source decrement uses the encoded size of the source record. Changing a data packet to the corresponding relocated type does not change that size.
| Packet kind | Position changed by the cleaner |
|---|---|
| Head or overflow data packet | The packet Seid's entry in its Space RPM leaf |
SpaceRpmNode | Its parent entry; for a root, the owning Space's root state |
Space | Its SpaceId entry in the SpaceDirectory RPM leaf |
SpaceDirectoryRpmNode | Its parent entry; for a root, the partition's directory-root state |
An updated leaf or ancestor is only marked dirty. Cleaning does not immediately write replacement RPM ancestors. At the next checkpoint, dirty Space RPM nodes are written bottom-up, each dirty Space packet is then written with its resulting RPM root, dirty SpaceDirectory nodes are written bottom-up, and the new partition root is published.
Committing a cleaned segment
Relocation records become committed when the next Snapshot record is written. The cleaner does not force a Snapshot or flush the log merely because it has finished a segment; doing so would add I/O latency without making reuse safe any earlier. If a logical transaction is already being assembled, the implementation may serialize relocation records outside that transaction's logical record range, but the next Snapshot remains the recovery boundary for both. Cleaning does not itself consume a logical transaction sequence number or publish an MVCC version.
The source SegId enters the delta-FSS only when its utilisation and reservation count are both zero. This is the required outcome of successful cleaning. It is nevertheless important to distinguish "free since the checkpoint" from "available for allocation": the allocator obtains segments only from the FSS. A SegId in the delta-FSS cannot be reused until a later checkpoint has durably published the relocated RPM and SpaceDirectory roots and has transferred the eligible delta-FSS entries to the FSS.
That delay is essential for root packets. If a crash occurs before the next checkpoint, recovery must first open the old checkpoint roots before it can scan the committed relocation records which relocate them. Although such a root's segment has zero current utilisation, its bytes remain intact while the SegId is quarantined in the delta-FSS. If the crash leaves no complete cleaning Snapshot, recovery ignores the copied records and continues to use those old positions.
Readers and retained snapshots
A cache pin protects memory, while a segment reservation protects the physical SegId from becoming reusable. A reader which may follow a position from an older retained MVCC snapshot must keep the corresponding protection for the duration required by that read. Zero current SUT utilisation does not cancel an outstanding reservation. If an older snapshot can still initiate a later read through an old physical position, its lifetime mechanism must continue to withhold the affected delta-FSS entry from transfer to the reusable FSS until that snapshot can no longer do so.
Thus cleaning can make current utilisation exactly zero without invalidating an existing reader or retained snapshot. Segment reuse requires all three conditions: zero current utilisation, no reservation or snapshot-retention hold, and successful checkpoint publication. These lifetime holds do not turn obsolete packets back into current SUT utilisation.
Failure
An I/O or allocation failure before the Snapshot leaves an uncommitted tail. Recovery ignores that tail and the old packets remain authoritative. At run time the failed operation must not expose a partially cleaned segment as free. An impossible condition discovered by an enabled check, a failed checksum or inconsistent accounting puts the LSS into the zombie state; the cleaner must not skip the affected live record and reclaim the segment anyway.