6 Storage assumptions and failure model

The LSS stores its data through a Random Access Store (RAS), normally implemented by a file. This chapter describes the assumptions made by the file format and the limitations of the current RAS implementations.

Block size and alignment

Storage devices expose logical blocks and may have a different physical block size or direct-I/O alignment requirement. Common block sizes include 512 bytes and 4096 bytes. An application using unbuffered or direct I/O must align file offsets, transfer lengths, and sometimes memory-buffer addresses according to requirements reported by the operating system. It should not infer them from a fixed historical sector size.

The RAS exposes this unit through GetDiskSectorSize(). Flush units begin and end on boundaries of that size, and the segment and root-block layouts must be compatible with it. The current Windows and Linux file RAS implementations return a hard-coded value of 512 bytes. The root-block layout also requires this value to be no greater than 1024 bytes. These are current implementation and file-format limitations, not general properties of modern storage.

Torn and incomplete writes

The LSS does not assume that writing one sector, block, or larger transfer is atomic across process, operating-system, or power failure. A failed write may leave a mixture of old and new data. This is particularly important because segments are recycled without first being cleared.

The log is written as a sequence of flush units. Each flush unit contains a 128-bit check point identity, a 32-bit flush sequence number, its payload size, and a 32-bit CRC covering its header and payload. During recovery, the LSS accepts a flush unit only when these fields are mutually consistent. The recovery scan stops at the first invalid flush unit rather than interpreting a partial write or stale data as the tail of the log.

Root-block redundancy

The root block contains two check point divisions. They are written in strict alternation using Challis' algorithm, with sequence values at both ends and a 32-bit CRC. On startup, the LSS selects the newest valid division. These are two copies of the changing check point state, not two complete copies of all root-block data; the static and dynamic root-block headers are stored separately.

Current implementation notes and user impact

The current file RAS supports ordinary LSS reading, writing, check pointing, and recovery. The CRC, check point identity, and alternating root-block divisions continue to protect recovery from torn, stale, and inconsistent data. The following implementation details have narrower consequences for users:

  • Exceptional forced durability: Ordinary LSS transactions deliberately do not flush on close. ILssTransaction::FlushWhenClose() is provided for exceptional external-coordination cases and drains the relevant LSS writes, but IRAS has no explicit durability-barrier operation. With the default Windows settings, and with the current Linux implementation, callers must not rely on FlushWhenClose() to preserve the transaction across an operating-system crash or sudden power loss. This does not affect the atomic recovery of data that did reach non-volatile storage. Windows write-through mode can provide a stronger request, subject to support from the complete storage stack.
  • Linux configuration: the Linux file RAS currently uses ordinary buffered file I/O and ignores the file-buffering and write-through settings. Buffered I/O is not itself a correctness problem and is often desirable for performance. The user-visible limitation is that those settings cannot currently be used to select direct or per-write synchronous I/O on Linux, and no fsync() barrier is available for FlushWhenClose().
  • Direct-I/O portability: both file implementations report a fixed 512-byte I/O unit. This is harmless for ordinary buffered I/O and for environments compatible with that alignment. A store using unbuffered or direct I/O can fail to open or perform I/O when the host requires stricter alignment, such as a 4 kB boundary. The implementation should query the actual requirements before claiming support for such an environment.

None of these limitations places a storage barrier on the normal transaction path. The FlushWhenClose() limitation affects only callers that explicitly request the exceptional forced-durability operation. The fixed alignment and ignored Linux settings are portability and configuration limitations rather than evidence that ordinary LSS operation is incorrect. A proposal to add an explicit RAS durability operation appears in Other Proposals.