Delete RawBytes from CultPersistedRecord and CultSchemaCatalogEntry, with every drop-on-assign hook and the catalog's content guard. A decoded record or snapshot carries no stored bytes, so an in-place edit of its payload or overrides can never be shadowed by cached bytes, and the public snapshot and record serializers encode every record from its fields. SingleFileBackingStore now reads through ReadStore, which returns the snapshot and, parallel to it, the exact slice the file holds for each catalog entry and record. Its durable index keeps, by record key, that slice and its SHA-256 (hashed when a comparison asks), which is the record's version. A write re-encodes every record the writer staged and copies every other record, and every catalog entry it keeps, as the slice the file holds. The directory store keeps its manifest's catalog slices the same way. SerializeSnapshot/DeserializeSnapshot hooks become SerializeStore/ReadStore plus SerializeCatalogEntry. A staged but unchanged non-canonical record is now re-encoded canonically and gets a new version; an untouched one keeps its bytes and version. Tests: in-place edits through the snapshot API (payload, override) and through a held document (collection, nested object) are written as edited; an untouched non-canonical record survives a neighbour's write byte for byte; a staged one is re-encoded. The cost test counts record hashes. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
27 lines
1.1 KiB
C#
27 lines
1.1 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using GameCult.Caching.MessagePack;
|
|
|
|
namespace GameCult.Caching.Tests
|
|
{
|
|
// The exact bytes a store file holds for its catalog entries and records. A read snapshot carries none: the store that read the
|
|
// file owns them, and these read them as the store's reader does.
|
|
internal static class StoreSlices
|
|
{
|
|
internal static byte[] CatalogEntry(string path, string schemaId)
|
|
{
|
|
var read = CultDocumentMessagePackSerialization.ReadStore(File.ReadAllBytes(path));
|
|
return read.CatalogBytes[Array.FindIndex(read.Snapshot.SchemaCatalog, entry => entry.SchemaId == schemaId)];
|
|
}
|
|
|
|
internal static byte[][] CatalogEntries(string path) =>
|
|
CultDocumentMessagePackSerialization.ReadStore(File.ReadAllBytes(path)).CatalogBytes;
|
|
|
|
internal static byte[] Record(string path, string key)
|
|
{
|
|
var read = CultDocumentMessagePackSerialization.ReadStore(File.ReadAllBytes(path));
|
|
return read.RecordBytes[Array.FindIndex(read.Snapshot.Records, record => record.Key == key)];
|
|
}
|
|
}
|
|
}
|