[WIP] System.Text.Json and ProtocolBuffers codecs for Orleans.Journaling#9973
Draft
ReubenBond wants to merge 11 commits intodotnet:mainfrom
Draft
[WIP] System.Text.Json and ProtocolBuffers codecs for Orleans.Journaling#9973ReubenBond wants to merge 11 commits intodotnet:mainfrom
ReubenBond wants to merge 11 commits intodotnet:mainfrom
Conversation
Refactor Orleans.Journaling serialization to use typed command objects instead of positional stream-based ILogEntryWriter/ILogEntryReader. Core changes: - Add command DTO hierarchies for all 7 durable types (Entries/) - Add ILogEntryCodec<TEntry> per-type codec interface - Add ILogDataCodec<T> value-level serialization interface - Add binary per-type codecs preserving exact legacy wire format (Codecs/) - Refactor all durable types to use pattern matching on DTOs - Update StateMachineManager to accept typed codecs via DI - Add OrleansLogDataCodec<T> adapter for IFieldCodec<T> - Scaffold Orleans.Journaling.Json and Orleans.Journaling.Protobuf packages All 71 existing tests pass on both net8.0 and net10.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…' discriminator Replace old positional-stream JsonEntryCodec/JsonLogDataCodec with per-type codecs using non-generic JsonElement DTOs and [JsonPolymorphic] for the 'cmd' type discriminator. - Add JsonEntryTypes.cs with non-generic JSON DTOs using JsonElement fields - Add JsonDictionaryEntryCodec<TKey,TValue> bridging generic DTOs ↔ JSON DTOs - Add JsonListEntryCodec<T>, JsonQueueEntryCodec<T>, JsonSetEntryCodec<T> - Add JsonValueEntryCodec<T>, JsonStateEntryCodec<T>, JsonTcsEntryCodec<T> - Add JsonLogEntryCodecResolver<TEntry> for open-generic DI resolution - Update UseJsonCodec() extension - JSON codec does not use ILogDataCodec — uses System.Text.Json directly All 71 tests pass on both net8.0 and net10.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e format Replace old positional-stream ProtobufEntryCodec/ProtobufLogDataCodec with per-type codecs using Google.Protobuf CodedOutputStream/CodedInputStream. - Add ProtobufCodecHelper for shared serialization utilities - Add ProtobufDictionaryEntryCodec<TKey,TValue> with tagged protobuf fields - Add ProtobufListEntryCodec<T>, ProtobufQueueEntryCodec<T>, ProtobufSetEntryCodec<T> - Add ProtobufValueEntryCodec<T>, ProtobufStateEntryCodec<T>, ProtobufTcsEntryCodec<T> - Add ProtobufLogEntryCodecResolver<TEntry> for open-generic DI resolution - Protobuf codec uses ILogDataCodec<T> for user value serialization within the protobuf envelope (values as length-delimited bytes fields) All 71 tests pass on both net8.0 and net10.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ader/CodecFactory Remove the superseded positional-stream serialization abstractions: - Delete ILogEntryCodec.cs (old ILogEntryWriter, ILogEntryReader, ILogEntryCodecFactory) - Delete OrleansBinaryEntryCodec.cs (old OrleansBinaryEntryWriter, OrleansBinaryEntryReader) - Rename ILogEntryCodec2.cs → ILogEntryCodec.cs (typed per-type codec is now the only interface) - Remove ILogEntryCodecFactory DI registration from HostingExtensions The typed ILogEntryCodec<TEntry> per-type codec approach fully replaces these. All 71 tests pass on both net8.0 and net10.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… types Add comprehensive round-trip tests for all 7 Protobuf per-type codecs: Dictionary (Set/Remove/Clear/Snapshot), List (Add/Set/Insert/RemoveAt/Clear/Snapshot), Queue (Enqueue/Dequeue/Clear/Snapshot), Set (Add/Remove/Clear/Snapshot), Value (Set), State (Set/Clear), TCS (Completed/Faulted/Canceled/Pending). Total: 96 tests pass on both net8.0 and net10.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…N codec tests - Add Orleans.Journaling.Json and Orleans.Journaling.Protobuf to Orleans.slnx - Add comprehensive JsonCodecTests.cs with 28 tests covering all 7 durable types: Dictionary (Set/Remove/Clear/Snapshot/EmptySnapshot/ComplexTypes), List (Add/Set/Insert/RemoveAt/Clear/Snapshot), Queue (Enqueue/Dequeue/Clear/ Snapshot), Set (Add/Remove/Clear/Snapshot), Value (Set/ComplexType), State (Set/Clear), TCS (Completed/Faulted/Canceled/Pending) - Each test verifies JSON output contains correct 'cmd' discriminator and values round-trip correctly Total: 124 tests pass on both net8.0 and net10.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create test/Orleans.Journaling.Json.Tests/ with JsonCodecTests (28 tests) and CodecMigrationTests (4 tests) - Create test/Orleans.Journaling.Protobuf.Tests/ with ProtobufCodecTests (25 tests) - Remove Json/Protobuf test dependencies from core Orleans.Journaling.Tests - Add test projects to Orleans.slnx - Add InternalsVisibleTo for new test projects in src csproj files Test distribution: Orleans.Journaling.Tests: 62 tests (core + binary codec) Orleans.Journaling.Json.Tests: 32 tests (JSON codec + migration) Orleans.Journaling.Protobuf.Tests: 25 tests (Protobuf codec) Total: 119 tests, all passing on both net8.0 and net10.0. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ation Rewrite Orleans.Journaling.Protobuf codecs to use a formal .proto schema (JournalingEntries.proto) with Grpc.Tools code generation instead of manual CodedOutputStream/CodedInputStream wire-format encoding. - Add Protos/JournalingEntries.proto defining all 7 entry message types using oneof for command discrimination - Add Grpc.Tools package reference and Protobuf compile item to .csproj - Rewrite all codec implementations as thin mappers between Orleans entry records and generated protobuf messages - Use WriteTo(IBufferWriter<byte>) and ParseFrom(ReadOnlySequence<byte>) for zero-intermediate-copy serialization - Remove manual tag constants, MemoryStream intermediaries, SkipField, and CopyToBufferWriter helpers - Architecture now mirrors the JSON codec pattern exactly Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce a TypedValue proto message with oneof for native protobuf scalars (int32, int64, uint32, uint64, float, double, bool, string) and a bytes fallback. Replace all raw bytes value fields with TypedValue in the proto schema. Add ProtobufValueConverter<T> that resolves the optimal encoding strategy once at construction time: - Native scalars (int, string, etc.) use oneof fields directly - IMessage types use ToByteString()/Parser.ParseFrom() natively - Other types fall back to ILogDataCodec<T> via bytes_value The resolver only resolves ILogDataCodec<T> from DI when T is not a natively supported type, avoiding unnecessary DI resolution for common cases. Remove ProtobufCodecHelper (replaced by ProtobufValueConverter). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace open-generic ILogEntryCodec<> DI resolvers that used GetGenericTypeDefinition, MakeGenericType, and Activator.CreateInstance with per-type codec provider interfaces. Each durable type now injects its specific provider (e.g., IDurableDictionaryCodecProvider) and calls a typed GetCodec<...>() method, letting the compiler see generic instantiations statically. - Add 7 per-type codec provider interfaces in ILogEntryCodecProviders.cs - Add OrleansBinaryLogEntryCodecProvider implementing all 7 interfaces - Refactor JsonLogEntryCodecResolver into JsonLogEntryCodecProvider - Refactor ProtobufLogEntryCodecResolver into ProtobufLogEntryCodecProvider - Update all durable types and StateMachineManager constructors - Add DynamicallyAccessedMembers annotation on ProtobufValueConverter<T> - Delete DefaultLogEntryCodecResolver (replaced by provider) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… tests - Add byte-count caps to VarIntHelper: 5 bytes max for uint32, 10 for uint64, preventing infinite loops on malformed LEB128 input. - Fix JsonJournalingExtensions to capture JsonSerializerOptions via factory lambda instead of registering it as a bare singleton (avoids DI collisions with other components that register JsonSerializerOptions). - Add CodecMigrationTests for the Protobuf codec covering Dictionary, List, Value, Set, and Queue write-and-recover round-trips. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refactors Orleans.Journaling serialization behind pluggable
ILogEntryCodec<TEntry>/ILogDataCodec<T>abstractions and introduces two new NuGet packages — all Native AOT compatible (noMakeGenericTypeor reflection).Changes
Core abstractions (
Orleans.Journaling)Entries/— each durable type gets a sealed record hierarchy (DurableDictionaryEntry<TKey, TValue>,DurableListEntry<T>, etc.)ILogEntryCodec<TEntry>— per-entry-hierarchy codec:Write(TEntry, IBufferWriter<byte>)andRead(ReadOnlySequence<byte>)ILogDataCodec<T>— raw value codec for payload serializationIDurableDictionaryCodecProvider, etc.) — provide closed-generic codecs without reflectionOrleansBinary*EntryCodec— preserves the existing Orleans binary wire format as the default codecVarIntHelper— standalone LEB128 helpers with overflow guards (5-byte cap for uint32, 10-byte for uint64)New:
Microsoft.Orleans.Journaling.Json(alpha)cmdfield) for command dispatchUseJsonCodec()extension methodNew:
Microsoft.Orleans.Journaling.Protobuf(alpha).protoschemaTypedValueoneof for native protobuf encoding of well-known scalar typesILogDataCodec<T>for non-native typesUseProtobufCodec()extension methodDurable type refactoring
DurableDictionary,DurableList,DurableQueue,DurableSet,DurableState,DurableValue,DurableTaskCompletionSource) now consumeILogEntryCodec<TEntry>through per-type provider injectionTests
LogDataCodecTestsfor the Orleans binary data codecUsage
Test results