C#: refuse unknown store headers and extra record slots by name
Delete the trailing Skip loop in the record reader, the ?? v1 header default, and the mesh reader's copy of the record decoder. The single-file store and CultMesh single-file reads accept cultcache.store.v1 only. Persistence-format and parity docs state the rule. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
2cb694d612
commit
98ed042fcc
6 changed files with 153 additions and 26 deletions
|
|
@ -30,6 +30,7 @@ public sealed class CultDocumentResolver : IFormatterResolver
|
|||
|
||||
public static class CultDocumentMessagePackSerialization
|
||||
{
|
||||
private const string SingleFileFormatVersion = "cultcache.store.v1";
|
||||
private const int PersistedRecordFieldCount = 4;
|
||||
private const int SchemaCatalogEntryFieldCount = 7;
|
||||
private const int SchemaCatalogMemberFieldCount = 8;
|
||||
|
|
@ -139,7 +140,8 @@ public static class CultDocumentMessagePackSerialization
|
|||
|
||||
if (fieldCount > 0)
|
||||
{
|
||||
snapshot.FormatVersion = reader.ReadString() ?? "cultcache.store.v1";
|
||||
snapshot.FormatVersion = reader.ReadString()
|
||||
?? throw new NotSupportedException("Store snapshot declares no format version; this runtime reads " + SingleFileFormatVersion + " only.");
|
||||
}
|
||||
|
||||
if (fieldCount > 1)
|
||||
|
|
@ -170,6 +172,17 @@ public static class CultDocumentMessagePackSerialization
|
|||
return snapshot;
|
||||
}
|
||||
|
||||
/// <summary>Refuses a single-file snapshot this runtime cannot read, naming the format it found.</summary>
|
||||
public static void RequireSingleFileFormat(CultPersistedStoreSnapshot snapshot)
|
||||
{
|
||||
if (!string.Equals(snapshot.FormatVersion, SingleFileFormatVersion, StringComparison.Ordinal))
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
$"Store format {snapshot.FormatVersion} is not readable; this runtime reads {SingleFileFormatVersion} only. " +
|
||||
"The store needs a runtime that resolves document variants.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void WritePersistedRecord(ref MessagePackWriter writer, CultPersistedRecord record)
|
||||
{
|
||||
writer.WriteArrayHeader(PersistedRecordFieldCount);
|
||||
|
|
@ -179,7 +192,7 @@ public static class CultDocumentMessagePackSerialization
|
|||
writer.Write(record.Payload);
|
||||
}
|
||||
|
||||
private static CultPersistedRecord ReadPersistedRecord(ref MessagePackReader reader)
|
||||
public static CultPersistedRecord ReadPersistedRecord(ref MessagePackReader reader)
|
||||
{
|
||||
var fieldCount = reader.ReadArrayHeader();
|
||||
var record = new CultPersistedRecord();
|
||||
|
|
@ -204,9 +217,11 @@ public static class CultDocumentMessagePackSerialization
|
|||
record.Payload = reader.ReadBytes()?.ToArray() ?? Array.Empty<byte>();
|
||||
}
|
||||
|
||||
for (var index = PersistedRecordFieldCount; index < fieldCount; index++)
|
||||
if (fieldCount > PersistedRecordFieldCount)
|
||||
{
|
||||
reader.Skip();
|
||||
throw new NotSupportedException(
|
||||
$"Record '{record.Key}' (schema '{record.SchemaId}') has {fieldCount} slots; this runtime reads {PersistedRecordFieldCount}. " +
|
||||
"The store needs a runtime that resolves document variants.");
|
||||
}
|
||||
|
||||
return record;
|
||||
|
|
@ -371,7 +386,9 @@ public class SingleFileMessagePackBackingStore : SingleFileBackingStore
|
|||
|
||||
protected override CultPersistedStoreSnapshot DeserializeSnapshot(byte[] data)
|
||||
{
|
||||
return CultDocumentMessagePackSerialization.DeserializeSnapshot(data);
|
||||
var snapshot = CultDocumentMessagePackSerialization.DeserializeSnapshot(data);
|
||||
CultDocumentMessagePackSerialization.RequireSingleFileFormat(snapshot);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
protected override byte[] SerializePayload(object document)
|
||||
|
|
|
|||
Loading…
Reference in a new issue