71.2 RAS Reads

API

An asynchronous RAS read is represented by a caller-owned request object:


struct RASReadRequest
{
    RASOffset offset;
    void* buffer;
    ssize_t size;
};

void Read(RASReadRequest& request);

void OnReadComplete(RASReadRequest& request);

The request object is both the description and identity of the operation. It specifies the file offset, destination buffer and exact number of bytes to read. Returning the same object to OnReadComplete() means that the RAS does not need to allocate a Read Sequence Number, maintain a completed-read prefix or return a separate caller context.

Request and buffer lifetime

The caller owns the RASReadRequest and destination buffer, but must keep both alive at stable addresses from the call to Read() until the corresponding call to OnReadComplete(). While the request is pending, the caller must not modify its offset, buffer or size fields, and must not move, destroy or resubmit the request object.

The destination buffer belongs to the RAS while the read is pending. The caller must not read, modify, move or destroy it. OnReadComplete() transfers the buffer back to the caller: the entire requested range has been filled successfully, the RAS will not access the request or buffer again, and the caller may inspect the data. The request object can then be modified and reused for another read.

Thread safety and completion order

Read() is thread-safe. Different threads may submit different request objects concurrently. It is forbidden to submit the same request object again while it is pending.

Native reads may execute and complete in any order. The RAS reports an individual completion as soon as that logical read has completed, so a slow earlier request does not prevent the caller from using the result of a later independent request. Calls to OnReadComplete() must nevertheless be sequential and must never overlap. This permits out-of-order completion without requiring concurrent mutation of LSS state.

The RAS must not invoke OnReadComplete() for a request before the corresponding call to Read() has returned. Even if a native read completes immediately, its logical completion is delivered later. This prevents inline reentrancy and keeps Read() a submission-only operation.

Exact-read semantics

One RASReadRequest represents one complete logical read. OnReadComplete() means that every byte in the requested file range [offset,offset+size) has been copied into the destination buffer. The API does not expose partial-read progress or a byte-count result.

A native platform read may transfer fewer bytes than requested. The RAS can continue reading the remaining suffix as part of the same request, or treat the short transfer as a fatal read error. It must not report completion until the entire logical read has succeeded. An unexpected end of file is therefore an error rather than a successful partial result.

Overlapping ranges

Pending read requests must not have overlapping destination-memory ranges, because two native operations could otherwise write to the same memory concurrently. A RAS implementation can detect reuse of a pending request object and overlapping destination buffers in diagnostic builds.

Overlapping source file ranges do not create the same problem. Two requests can safely read common file bytes into different destination buffers, although the LSS segment cache normally prevents duplicate segment reads.

Use by the LSS

The LSS uses RAS reads in two places. When a store is opened, it reads the root block into a buffer owned by the opening state. During normal operation and recovery, the segment cache reads segments into their segment buffers. In both cases the owning state has a stable lifetime and can contain the RASReadRequest for the pending operation.

The segment cache ensures that a segment is not read more than once concurrently. A segment being loaded remains in its loading state until OnReadComplete() returns its request. The LSS can then validate the segment, mark it as resident and continue operations that were waiting for it.

Errors

A read error is reported through the uniform fatal RAS error mechanism as a read operation error. It does not require a request-specific failure callback because the LSS enters the zombie state and does not continue processing other operations. Request objects and destination buffers must nevertheless remain alive until all native operations have completed or been cancelled during shutdown.

Validation occurs after a successful read has returned the buffer to the LSS. An invalid checksum, root block, LFU or log record is an integrity failure detected above the RAS, but it causes the same transition to the zombie state as a native read error.