78 Segment Cache
Asynchronous I/O boundary
Version 3 retains the Version 2 division of responsibilities: the segment cache manages resident memory, while loading and writing are coordinated above it. This separation is particularly important in an event-driven LSS. A cache lookup is a synchronous memory operation. A RAS read is an asynchronous operation which may complete later and generate an event. Combining them in one call would conceal a state transition and give a function which sometimes returns immediately and sometimes starts an unrelated operation.
Buffer lifetime during I/O
An operation may take ownership of a SegmentAccessor and retain it
while native I/O refers to the segment buffer. For example, a segment-write operation keeps the
accessor until the RAS reports completion:
struct SegmentWriteOperation
{
SegmentAccessor segment;
RASWriteRequest request;
};
This makes the buffer-lifetime rule explicit and prevents eviction or recycling while the operation
is outstanding. The accessor controls only the lifetime of resident memory; it does not initiate I/O
and does not provide a route back to the complete LSS.
Loading a segment
A cache miss is handled by an LSS-level read state machine or a dedicated segment-loading operation,
not by GetSegment(). The normal sequence is:
- Look for an available segment in the cache.
- On a miss, reserve a cache entry and its final segment buffer.
- Submit a RAS read which targets that buffer directly.
- Return control while the RAS read is outstanding.
- On completion, validate the segment and publish it as available in the cache.
- Continue the logical operations waiting for that segment.
Reading directly into the reserved cache buffer avoids a staging copy. The segment must not be returned by ordinary cache lookup while its buffer is only partially filled or has not yet been validated.
Concurrent requests for the same segment
The implementation must prevent several cache misses for the same
SegId from causing duplicate RAS reads. Reserving an entry for a
load therefore records that the segment is being loaded. A later request can distinguish an
available segment, an existing outstanding load and the need to start a new load.
enum class SegmentLookupResult
{
Available,
Loading,
NeedToLoad,
CacheFull
};
This state need not be exposed through the simple cache-only
GetSegment() operation. It can be part of a separate atomic
reservation API used by the LSS read coordinator. Logical reads which encounter
Loading attach themselves to the existing load operation and are
continued when its completion event is processed.
Writing segments
The writer determines the RAS offset and byte range, obtains a view of the segment buffer and submits the asynchronous write:
auto bytes = segment.GetBuffer();
ras.Write(offset, bytes, completion);
The segment buffer must remain alive and unchanged for as long as the native operation may reference it. The write operation therefore owns a cache pin or another lifetime handle until its completion is reported. Eviction cannot recycle that segment buffer while the write is outstanding.
Error shutdown
Native operations which were already submitted must still retain their operation records and buffers until the platform reports completion or cancellation. This lifetime requirement does not imply logical recovery: completions are drained only to finish the safe shutdown of outstanding native work after the LSS has become a zombie.
Responsibilities
The LSS read and write state machines decide when I/O is required, coalesce operations and react to RAS completion events. The RAS transfers bytes asynchronously between persistent storage and buffers supplied by the LSS. The Version 2 cache remains responsible only for lookup, allocation, pinning, access counts, capacity and eviction.