CultCache: element id rules, atomic minting, minted override values, the v3 marker
The id rule is one plan, made before anything is written: Plan decides every fill and refuses a duplicate, a random id that is not 12 lowercase hex characters, and a derived id whose source is null or empty, naming the record and list (CultElementIdException). A load refuses what a write refuses. Apply and Undo make minting part of the admission: a refused or uncommitted write leaves the caller's documents as they were. Override values mint inside Resolve, into the decoded copy, so the public CultVariantOverride.Set, C1-era overrides and Override() all get ids on write and on load; Override() no longer mints. Interface unions are judged on their concrete types, the same rule registration and minting share, and a subtype reusing the id's key is refused at registration. Dictionary keys format with the invariant culture. Records minted at load are marked per entry (IdsInMemoryOnly) instead of listed by key, so a deleted record leaves the mark with it, and a flush of the whole store clears it. A store whose types reach an object list declares cultcache.store.v3 (directory: v5), which every reader older than ids refuses; a marked file stays marked when a writer merges onto it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
884602c708
commit
fc52f984db
4 changed files with 294 additions and 103 deletions
|
|
@ -185,7 +185,7 @@ public static class CultDocumentMessagePackSerialization
|
|||
if (fieldCount > 0)
|
||||
{
|
||||
snapshot.FormatVersion = reader.ReadString()
|
||||
?? throw new NotSupportedException("Store snapshot declares no format version; this runtime reads " + CultPersistedStoreSnapshot.FormatV1 + " and " + CultPersistedStoreSnapshot.FormatV2 + ".");
|
||||
?? throw new NotSupportedException("Store snapshot declares no format version; this runtime reads " + CultPersistedStoreSnapshot.FormatV1 + ", " + CultPersistedStoreSnapshot.FormatV2 + " and " + CultPersistedStoreSnapshot.FormatV3 + ".");
|
||||
}
|
||||
|
||||
if (fieldCount > 1)
|
||||
|
|
@ -221,20 +221,21 @@ public static class CultDocumentMessagePackSerialization
|
|||
{
|
||||
var version = snapshot.FormatVersion;
|
||||
if (!string.Equals(version, CultPersistedStoreSnapshot.FormatV1, StringComparison.Ordinal) &&
|
||||
!string.Equals(version, CultPersistedStoreSnapshot.FormatV2, StringComparison.Ordinal))
|
||||
!string.Equals(version, CultPersistedStoreSnapshot.FormatV2, StringComparison.Ordinal) &&
|
||||
!string.Equals(version, CultPersistedStoreSnapshot.FormatV3, StringComparison.Ordinal))
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
$"Store format {version} is not readable; this runtime reads {CultPersistedStoreSnapshot.FormatV1} and {CultPersistedStoreSnapshot.FormatV2}.");
|
||||
$"Store format {version} is not readable; this runtime reads {CultPersistedStoreSnapshot.FormatV1}, {CultPersistedStoreSnapshot.FormatV2} and {CultPersistedStoreSnapshot.FormatV3}.");
|
||||
}
|
||||
|
||||
// Only a v2 store may hold a variant: a v1 header over a variant record is a store no reader could trust.
|
||||
// Only a v2 or v3 store may hold a variant: a v1 header over a variant record is a store no reader could trust.
|
||||
if (string.Equals(version, CultPersistedStoreSnapshot.FormatV1, StringComparison.Ordinal))
|
||||
{
|
||||
var variant = snapshot.Records.FirstOrDefault(record => record.Variant != null);
|
||||
if (variant != null)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
$"Record '{variant.Key}' (schema '{variant.SchemaId}') is a variant but the store declares {version}; variants need {CultPersistedStoreSnapshot.FormatV2}.");
|
||||
$"Record '{variant.Key}' (schema '{variant.SchemaId}') is a variant but the store declares {version}; variants need {CultPersistedStoreSnapshot.FormatV2} or {CultPersistedStoreSnapshot.FormatV3}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue