CultLib/tests/GameCult.Caching.Tests/StoreSlices.cs
Meta Vens 2a3773a463 CultCache: the store owns a file's bytes, not the record object
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>
2026-10-03 10:47:30 +02:00

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)];
}
}
}