feat: committedGeneration capability + pinned durability/stability contracts
- storage.committedGeneration(): the committed watermark exposed on the fact-scan capability, so a provider compares its stamp's sourceGeneration against the store's truth without parsing the private manifest format (the capability source now carries both the live fact log and the committed closure). - Pinned contract tests: fsync-before-ack (transact passes today; the single-op path is pinned via it.fails as the documented target — group commit must become LATENCY batching, ack waiting on the shared fsync, never durability skipping; the pin flips red when that lands so there is no cliff to discover) and scan-stability-under-rotation (a scan snapshot yields exactly its facts — no gaps, duplicates, or bleed-in — while segments rotate beneath it; the reclaim-during-scan variant lands with fact compaction, which does not exist yet). - FactLog accepts a rotateBytes option so tests exercise real rotation.
This commit is contained in:
parent
e4f37cd32b
commit
d1ecee10f0
6 changed files with 177 additions and 11 deletions
|
|
@ -294,6 +294,8 @@ function parseSegment(
|
|||
*/
|
||||
export class FactLog {
|
||||
private readonly storage: FactLogStorage
|
||||
/** Rotation threshold (bytes); tests may lower it to exercise rotation. */
|
||||
private readonly rotateBytes: number
|
||||
private manifest: FactsManifest = {
|
||||
formatVersion: FACTS_FORMAT_VERSION,
|
||||
segments: [],
|
||||
|
|
@ -309,8 +311,9 @@ export class FactLog {
|
|||
/** Segment paths appended since the last sync (the fsync batch). */
|
||||
private readonly dirtySegments = new Set<string>()
|
||||
|
||||
constructor(storage: FactLogStorage) {
|
||||
constructor(storage: FactLogStorage, options?: { rotateBytes?: number }) {
|
||||
this.storage = storage
|
||||
this.rotateBytes = options?.rotateBytes ?? SEGMENT_ROTATE_BYTES
|
||||
}
|
||||
|
||||
/** The highest committed generation the log holds (0 = empty). */
|
||||
|
|
@ -405,7 +408,7 @@ export class FactLog {
|
|||
}
|
||||
if (this.manifest.tailSegment === null) {
|
||||
await this.startTail(fact.generation)
|
||||
} else if (this.tailBytes >= SEGMENT_ROTATE_BYTES) {
|
||||
} else if (this.tailBytes >= this.rotateBytes) {
|
||||
await this.rotate(fact.generation)
|
||||
}
|
||||
const frame = encodeFrame(fact)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue