Contracts: cacheless single-file access; never reuse a dropped slot
Store-composition gains the Cacheless single-file access section; schema-compatibility states the slot-reuse consequence per variants:ruling:slot-reuse-documented. Owns follow_up slot-reuse-contract-doc. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
388e2eaa25
commit
bc6d524bdf
2 changed files with 28 additions and 0 deletions
|
|
@ -61,6 +61,12 @@ either way is refused: a get-only property, a readonly field without
|
|||
`AllowPrivate`, or a property whose setter is non-public without
|
||||
`AllowPrivate`, when the constructor does not fill it.
|
||||
|
||||
Never reuse a dropped slot; retire it. A write set copies a record the writer did not touch forward as stored bytes, so an
|
||||
untouched record keeps a dropped member's value in its slot through every write. A type that later puts a new member in that slot
|
||||
reads the dropped value as its own. The store does not remember retired slots, and a reuse that changes the slot's shape is refused
|
||||
at load, but a reuse of the same shape reads silently. This is the rule protobuf, Thrift and MessagePack-CSharp give for numbered
|
||||
fields: leave the slot empty, and take the next unused number for a new member.
|
||||
|
||||
## Which schema a record carries
|
||||
|
||||
A record is written under the schema of its runtime type. Writing a derived
|
||||
|
|
|
|||
|
|
@ -347,6 +347,28 @@ type name is the CLR full name, the same rule as `System.Int32`. A reader in
|
|||
another runtime needs only the component count and primitive type. CultMath has
|
||||
no serialization; a CultMath encoding, if added, uses this shape.
|
||||
|
||||
## Cacheless single-file access
|
||||
|
||||
A single-file store file can be read and written without a cache, through two public members of `SingleFileBackingStore` (for
|
||||
example `SingleFileMessagePackBackingStore`): `ReadStoreSnapshot()` and `WriteRecord(record, catalogEntry, holdsIds, registry)`.
|
||||
|
||||
- `ReadStoreSnapshot()` reads the file once, under the store's gate, and returns the durable snapshot (records, schema catalog,
|
||||
format stamp), or null when nothing is at the path. It throws `CultStoreUnreadableException` for a file the reader refuses.
|
||||
- `WriteRecord` writes one record under the store's lock: the record replaces the one at its key, every other record and catalog
|
||||
entry is copied forward as stored, and the file is replaced atomically.
|
||||
|
||||
They share everything with a cache's store and nothing is re-implemented beside it: one reader (the stamp is judged before the
|
||||
body, and a file the reader refuses is refused by a read and by a write alike), the store's lock, the atomic replace, and the
|
||||
header rule (`holdsIds` true marks a v3 store; false leaves it as the rule decides; null, for a payload the caller cannot read,
|
||||
keeps whatever the file already says). Ownership by declaration binds a cacheless write too: a record at the key under a schema id
|
||||
the written catalog entry does not own or list as compatible is refused with `CultSchemaConflictException`, and the file is left as
|
||||
it was. A typed writer plans element ids with `CultElementIds.Plan` before it serializes and passes `CultElementIds.Holds` as
|
||||
`holdsIds`.
|
||||
|
||||
A store attached to a cache refuses `WriteRecord` with `InvalidOperationException`: write through the cache, whose staged writes
|
||||
land through the same private write. CultMesh's single-file document helpers (`CultMesh.WriteSingleFileDocument`,
|
||||
`ReadSingleFileDocument` and their payload forms) are built on these members and nothing else of the store.
|
||||
|
||||
## Runtime status
|
||||
|
||||
| Rule | C# | Rust | TypeScript | Python |
|
||||
|
|
|
|||
Loading…
Reference in a new issue