-
Notifications
You must be signed in to change notification settings - Fork 66
Support serializing session changesets #568
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
twsouthwick
wants to merge
12
commits into
main
Choose a base branch
from
session-changeset
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 2 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
bbd90dd
Support serializing session changesets
twsouthwick 897544c
make ISessionSerializer internal
twsouthwick 4074f99
Merge remote-tracking branch 'origin/main' into session-changeset
twsouthwick 34ae8fc
Add some tests and respond to feedback
twsouthwick 4260e38
Rework session serialization V2 due to HTTP2 full duplex mode
twsouthwick 3fa6fac
revert a few things
twsouthwick 77b22e7
reorg files
twsouthwick e109f3e
Merge remote-tracking branch 'origin/main' into session-changeset
twsouthwick 572302d
revert old tests
twsouthwick eb85a81
start reworking tests
twsouthwick 5ebfb58
revert to extensions
twsouthwick 6af5997
add tests
twsouthwick File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# Session serialization | ||
|
||
Session serialization is provided through the `ISessionSerializer` type. There are two modes that are available: | ||
|
||
## Common structure | ||
|
||
```mermaid | ||
packet-beta | ||
0: "M" | ||
1-10: "Session Id (Variable length)" | ||
11: "N" | ||
12: "A" | ||
13: "R" | ||
14: "T" | ||
15: "C" | ||
16-24: "Key 1 Blob" | ||
25-33: "Key 2 Blob" | ||
34-42: "..." | ||
43-50: "Flags (variable)" | ||
``` | ||
|
||
Where: | ||
- *M*: Mode | ||
- *N*: New session | ||
- *A*: Abandoned | ||
- *R*: Readonly | ||
- *T*: Timeout | ||
- *C*: Key count | ||
|
||
## Flags | ||
|
||
Flags allow for additional information to be sent either direction that may not be known initially. This field was added v2 but is backwards compatible with the v1 deserializer and will operate as a no-op as it just reads the things it knows about and doesn't look for the end of a payload. | ||
|
||
Structure: | ||
|
||
```mermaid | ||
packet-beta | ||
0: "C" | ||
1: "F1" | ||
2: "F1L" | ||
3-10: "Flag1 specific payload" | ||
11: "F2" | ||
12: "F2L" | ||
13-20: "Flag2 specific payload" | ||
21-25: "..." | ||
``` | ||
|
||
Where: | ||
- *Fn*: Flag `n` | ||
|
||
Where `C` is the count of flags, and each `Fn` is a flag identifier an int with 7bit encoding. Each f | ||
|
||
An example is the flag section used to indicate that there is support for diffing a session state on the server: | ||
|
||
```mermaid | ||
packet-beta | ||
0: "1" | ||
1: "100" | ||
2: "0" | ||
``` | ||
|
||
## Full Copy (Mode = 1) | ||
|
||
The following is the structure of the key blobs when the full state is serialized: | ||
|
||
```mermaid | ||
packet-beta | ||
0-10: "Key name" | ||
11-20: "Serialized value" | ||
``` | ||
|
||
## Diffing Support (Mode = 2) | ||
|
||
The following is the structure of the key blobs when only the difference is serialized: | ||
|
||
```mermaid | ||
packet-beta | ||
0-10: "Key name" | ||
11: "S" | ||
12-20: "Serialized value" | ||
``` | ||
|
||
Where: | ||
- *S*: A value indicating the change the key has undergone from the values in `SessionItemChangeState` | ||
|
15 changes: 0 additions & 15 deletions
15
...spNetCore.SystemWebAdapters.Abstractions/SessionState/Serialization/ISessionSerializer.cs
This file was deleted.
Oops, something went wrong.
2 changes: 1 addition & 1 deletion
2
...ore.SystemWebAdapters.Abstractions/SessionState/Serialization/SessionSerializerOptions.cs
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
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
118 changes: 118 additions & 0 deletions
118
src/Services/SessionState/BinarySessionSerializer.ChangesetWriter.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Microsoft.AspNetCore.SystemWebAdapters.SessionState.Serialization; | ||
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Maintainability", "CA1510:Use ArgumentNullException throw helper", Justification = "Source shared with .NET Framework that does not have the method")] | ||
internal partial class BinarySessionSerializer : ISessionSerializer | ||
{ | ||
private readonly struct ChangesetWriter(ISessionKeySerializer serializer) | ||
{ | ||
public List<string>? Write(ISessionStateChangeset state, BinaryWriter writer) | ||
{ | ||
writer.Write(ModeDelta); | ||
writer.Write(state.SessionID); | ||
|
||
writer.Write(state.IsNewSession); | ||
writer.Write(state.IsAbandoned); | ||
writer.Write(state.IsReadOnly); | ||
|
||
writer.Write7BitEncodedInt(state.Timeout); | ||
writer.Write7BitEncodedInt(state.Count); | ||
|
||
List<string>? unknownKeys = null; | ||
|
||
foreach (var item in state.Changes) | ||
{ | ||
writer.Write(item.Key); | ||
|
||
// New with V2 serializer | ||
if (item.State is SessionItemChangeState.NoChange or SessionItemChangeState.Removed) | ||
{ | ||
writer.Write7BitEncodedInt((int)item.State); | ||
} | ||
else if (serializer.TrySerialize(item.Key, state[item.Key], out var result)) | ||
{ | ||
writer.Write7BitEncodedInt((int)item.State); | ||
writer.Write7BitEncodedInt(result.Length); | ||
writer.Write(result); | ||
} | ||
else | ||
{ | ||
(unknownKeys ??= []).Add(item.Key); | ||
writer.Write7BitEncodedInt((int)SessionItemChangeState.Unknown); | ||
} | ||
} | ||
|
||
writer.WriteFlags([]); | ||
|
||
return unknownKeys; | ||
} | ||
|
||
public SessionStateCollection Read(BinaryReader reader) | ||
{ | ||
var state = SessionStateCollection.CreateTracking(serializer); | ||
|
||
state.SessionID = reader.ReadString(); | ||
state.IsNewSession = reader.ReadBoolean(); | ||
state.IsAbandoned = reader.ReadBoolean(); | ||
state.IsReadOnly = reader.ReadBoolean(); | ||
state.Timeout = reader.Read7BitEncodedInt(); | ||
|
||
var count = reader.Read7BitEncodedInt(); | ||
|
||
for (var index = count; index > 0; index--) | ||
{ | ||
var key = reader.ReadString(); | ||
var changeState = (SessionItemChangeState)reader.Read7BitEncodedInt(); | ||
|
||
if (changeState is SessionItemChangeState.NoChange) | ||
{ | ||
state.MarkUnchanged(key); | ||
} | ||
else if (changeState is SessionItemChangeState.Removed) | ||
{ | ||
state.MarkRemoved(key); | ||
} | ||
else if (changeState is SessionItemChangeState.Unknown) | ||
{ | ||
state.AddUnknownKey(key); | ||
} | ||
else if (changeState is SessionItemChangeState.New or SessionItemChangeState.Changed) | ||
{ | ||
var length = reader.Read7BitEncodedInt(); | ||
var bytes = reader.ReadBytes(length); | ||
|
||
if (serializer.TryDeserialize(key, bytes, out var result)) | ||
{ | ||
if (result is not null) | ||
{ | ||
state[key] = result; | ||
} | ||
} | ||
else | ||
{ | ||
state.AddUnknownKey(key); | ||
} | ||
} | ||
} | ||
|
||
foreach (var (flag, payload) in reader.ReadFlags()) | ||
{ | ||
// No flags are currently read | ||
} | ||
|
||
return state; | ||
} | ||
} | ||
} |
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.