Prepare for zero-copy sending

This commit is contained in:
2025-08-16 19:51:35 +03:00
parent 46d741a287
commit dfad8b9141
10 changed files with 76 additions and 26 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ class Program
var listening = new IPEndPoint(IPAddress.Any, 4567); var listening = new IPEndPoint(IPAddress.Any, 4567);
builder.Services.Configure<GatewayOptions>(options => options.Endpoint = listening); builder.Services.Configure<GatewayOptions>(options => options.Endpoint = listening);
builder.Services.AddSingleton<IDistributionModule, ExtractorFirstDistributionModule>(); builder.Services.AddSingleton<IDistributionModule, ExtractorFirstDistributionModule>();
builder.Services.Configure<SerializationBufferOffset>(options => options.Offset = 0);
builder.Services.AddSingleton<HubRequestExtractor>(); builder.Services.AddSingleton<HubRequestExtractor>();
builder.Services.AddSingleton<IExecuteModule, BasicExecutionModule>(); builder.Services.AddSingleton<IExecuteModule, BasicExecutionModule>();
builder.Services.AddSingleton<IRepresentationModuleProducer, CreativeRepresentationModuleProducer>(); builder.Services.AddSingleton<IRepresentationModuleProducer, CreativeRepresentationModuleProducer>();
+1
View File
@@ -46,6 +46,7 @@ class Program
builder.Services.AddOptions(); builder.Services.AddOptions();
builder.Services.Configure<GatewayOptions>(options => options.Endpoint = serverEndPoint); builder.Services.Configure<GatewayOptions>(options => options.Endpoint = serverEndPoint);
builder.Services.Configure<DistributionOptions>(o => o.DistributionType = EDistributionType.Channeled); builder.Services.Configure<DistributionOptions>(o => o.DistributionType = EDistributionType.Channeled);
builder.Services.Configure<SerializationBufferOffset>(options => options.Offset = 0);
builder.Services.AddSingleton<IRepresentationModuleProducer, StaticRepresentationModuleProducer>(); builder.Services.AddSingleton<IRepresentationModuleProducer, StaticRepresentationModuleProducer>();
builder.Services.AddSingleton<IRequestExtractor, RequestExtractor>(); builder.Services.AddSingleton<IRequestExtractor, RequestExtractor>();
+18 -9
View File
@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.Formats.Cbor; using System.Formats.Cbor;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Microsoft.Extensions.Options;
using mROA.Abstract; using mROA.Abstract;
using mROA.Implementation; using mROA.Implementation;
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
@@ -15,6 +16,11 @@ namespace mROA.Cbor
public class CborSerializationToolkit : IContextualSerializationToolKit public class CborSerializationToolkit : IContextualSerializationToolKit
{ {
private readonly CborWriter _writer = new(initialCapacity: 2048); private readonly CborWriter _writer = new(initialCapacity: 2048);
private readonly int _offset;
public CborSerializationToolkit(IOptions<SerializationBufferOffset> offsetOptions) : this(offsetOptions.Value.Offset)
{
}
private readonly IOrdinaryStructureParser[] _parsers = private readonly IOrdinaryStructureParser[] _parsers =
{ {
@@ -23,6 +29,12 @@ namespace mROA.Cbor
}; };
private readonly Dictionary<Type, List<PropertyInfo>> _propertiesCache = new(); private readonly Dictionary<Type, List<PropertyInfo>> _propertiesCache = new();
public CborSerializationToolkit(int offset)
{
_offset = offset;
}
public static TimeSpan SerializationTime = TimeSpan.Zero; public static TimeSpan SerializationTime = TimeSpan.Zero;
private bool FindParser(Type t, out IOrdinaryStructureParser parser) private bool FindParser(Type t, out IOrdinaryStructureParser parser)
@@ -56,7 +68,9 @@ namespace mROA.Cbor
{ {
_writer.Reset(); _writer.Reset();
WriteData(objectToSerialize, _writer, context); WriteData(objectToSerialize, _writer, context);
result = _writer.Encode(); result = new byte[_offset + _writer.BytesWritten];
var span = result.AsSpan();
_writer.Encode(span[_offset..]);
} }
return result; return result;
@@ -94,18 +108,13 @@ namespace mROA.Cbor
var reader = new CborReader(rawMemory); var reader = new CborReader(rawMemory);
return ReadData(reader, type, context); return ReadData(reader, type, context);
} }
catch (Exception e) catch (Exception)
{ {
Console.WriteLine($"Bad deserialization. Bytes: {rawMemory.ToArray().Select(b => $"{b:X}")}"); Console.WriteLine($"Bad deserialization. Bytes: {BitConverter.ToString(rawMemory.ToArray())}");
throw; throw;
} }
} }
public T Cast<T>(object nonCasted, IEndPointContext? context)
{
return (T)Cast(nonCasted, typeof(T), context);
}
public object? Cast(object? nonCasted, Type type, IEndPointContext? context) public object? Cast(object? nonCasted, Type type, IEndPointContext? context)
{ {
if (nonCasted == null) if (nonCasted == null)
@@ -133,7 +142,7 @@ namespace mROA.Cbor
public IContextualSerializationToolKit Clone() public IContextualSerializationToolKit Clone()
{ {
return new CborSerializationToolkit(); return new CborSerializationToolkit(_offset) ;
} }
public void WriteData(object? obj, CborWriter writer, IEndPointContext? context) public void WriteData(object? obj, CborWriter writer, IEndPointContext? context)
+1
View File
@@ -23,6 +23,7 @@ namespace mROA.Codegen
ReturnType = typeof(<!L returnType>), ReturnType = typeof(<!L returnType>),
ParameterTypes = new Type[] { <!L parametersType> }, ParameterTypes = new Type[] { <!L parametersType> },
SuitableType = typeof(<!L suitableType>), SuitableType = typeof(<!L suitableType>),
RequireCancellation = <!L cancellation>,
Invoking = (i, parameters, special, post) => <!L funcInvoking>, Invoking = (i, parameters, special, post) => <!L funcInvoking>,
}<!T> }<!T>
<!T syncInvoker> <!T syncInvoker>
@@ -9,6 +9,7 @@ namespace mROA.Codegen.Templates
private const string ParametersTypeTag = "parametersType"; private const string ParametersTypeTag = "parametersType";
private const string SuitableTypeTag = "suitableType"; private const string SuitableTypeTag = "suitableType";
private const string FuncInvokingTag = "funcInvoking"; private const string FuncInvokingTag = "funcInvoking";
private const string CancellationTag = "cancellation";
private const string IsTrustedTag = "isTrusted"; private const string IsTrustedTag = "isTrusted";
public InvokerTemplate(TemplateDocument template) : base(template) { } public InvokerTemplate(TemplateDocument template) : base(template) { }
@@ -42,5 +43,10 @@ namespace mROA.Codegen.Templates
{ {
Define(IsTrustedTag, value); Define(IsTrustedTag, value);
} }
public void DefineCancellation(string value)
{
Define(CancellationTag, value);
}
} }
} }
+5
View File
@@ -316,11 +316,14 @@ namespace mROA.Codegen
var parametersInsertList = new List<string>(); var parametersInsertList = new List<string>();
var useCancellationToken = false;
foreach (var parameter in method.Parameters) foreach (var parameter in method.Parameters)
switch (parameter.Type.Name) switch (parameter.Type.Name)
{ {
case "CancellationToken": case "CancellationToken":
parametersInsertList.Add("(CancellationToken)special[1]"); parametersInsertList.Add("(CancellationToken)special[1]");
useCancellationToken = true;
break; break;
case "RequestContext": case "RequestContext":
parametersInsertList.Add("(RequestContext)special[0]"); parametersInsertList.Add("(RequestContext)special[0]");
@@ -359,6 +362,7 @@ namespace mROA.Codegen
invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); invokerTemplate.DefineSuitableType(baseInterface.ToUnityString());
invokerTemplate.DefineFuncInvoking(funcInvoking); invokerTemplate.DefineFuncInvoking(funcInvoking);
invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower()); invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower());
invokerTemplate.DefineCancellation(useCancellationToken.ToString().ToLower());
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
} }
else else
@@ -370,6 +374,7 @@ namespace mROA.Codegen
invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); invokerTemplate.DefineSuitableType(baseInterface.ToUnityString());
invokerTemplate.DefineFuncInvoking(funcInvoking); invokerTemplate.DefineFuncInvoking(funcInvoking);
invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower()); invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower());
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
} }
@@ -145,20 +145,29 @@ namespace mROA.Implementation.Backend
CallRequest command, ICancellationRepository cancellationRepository, CallRequest command, ICancellationRepository cancellationRepository,
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context) IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
{ {
var tokenSource = new CancellationTokenSource(); CancellationToken? token = null;
cancellationRepository.RegisterCancellation(command.Id, tokenSource); if (invoker.RequireCancellation)
var token = tokenSource.Token; {
var tokenSource = new CancellationTokenSource();
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
token = tokenSource.Token;
}
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ => invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ =>
{ {
if (token.IsCancellationRequested) if (invoker.RequireCancellation)
return; {
_cancellationRepo.FreeCancellation(command.Id);
if (token.Value.IsCancellationRequested)
return;
}
var payload = new FinalCommandExecution var payload = new FinalCommandExecution
{ {
Id = command.Id Id = command.Id
}; };
_cancellationRepo.FreeCancellation(command.Id);
if (invoker.IsTrusted) if (invoker.IsTrusted)
@@ -174,20 +183,31 @@ namespace mROA.Implementation.Backend
CallRequest command, ICancellationRepository cancellationRepository, CallRequest command, ICancellationRepository cancellationRepository,
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context) IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
{ {
var tokenSource = new CancellationTokenSource(); CancellationToken? token = null;
cancellationRepository.RegisterCancellation(command.Id, tokenSource); if (invoker.RequireCancellation)
{
var tokenSource = new CancellationTokenSource();
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
var token = tokenSource.Token; token = tokenSource.Token;
}
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, invoker.Invoke(instance, parameters, new object[] { executionContext, token },
finalResult => finalResult =>
{ {
if (invoker.RequireCancellation)
{
_cancellationRepo.FreeCancellation(command.Id);
if (token.Value.IsCancellationRequested)
return;
}
var payload = new FinalCommandExecution<object> var payload = new FinalCommandExecution<object>
{ {
Id = command.Id, Id = command.Id,
Result = finalResult Result = finalResult
}; };
_cancellationRepo.FreeCancellation(command.Id);
representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution, representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution,
payload, context); payload, context);
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using mROA.Abstract; using mROA.Abstract;
@@ -5,16 +6,16 @@ namespace mROA.Implementation
{ {
public class CollectableMethodRepository : IMethodRepository public class CollectableMethodRepository : IMethodRepository
{ {
private readonly List<IMethodInvoker> _methods = new(); private readonly List<IMethodInvoker> _methods = new() { MethodInvoker.Dispose };
private IMethodInvoker[] _baked = Array.Empty<IMethodInvoker>();
public void AppendInvokers(IEnumerable<IMethodInvoker> methodInvokers) public void AppendInvokers(IEnumerable<IMethodInvoker> methodInvokers)
{ {
_methods.AddRange(methodInvokers); _methods.AddRange(methodInvokers);
_baked = _methods.ToArray();
} }
public IMethodInvoker GetMethod(int id) public IMethodInvoker GetMethod(int id)
{ {
return id == -1 ? MethodInvoker.Dispose : _methods[id]; return _baked[++id];
} }
} }
} }
+1 -1
View File
@@ -37,7 +37,7 @@ namespace mROA.Implementation
public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
public Type? ReturnType { get; set; } public Type? ReturnType { get; set; }
public Type SuitableType { get; set; } = typeof(object); public Type SuitableType { get; set; } = typeof(object);
public bool RequireCancellation { get; set; } = true;
public Action<object, object?[]?, object[], Action<object?>> Invoking { get; set; } = public Action<object, object?[]?, object[], Action<object?>> Invoking { get; set; } =
(_, _, _, post) => { post.Invoke(null); }; (_, _, _, post) => { post.Invoke(null); };
@@ -0,0 +1,7 @@
namespace mROA.Implementation
{
public class SerializationBufferOffset
{
public int Offset { get; set; } = 19;
}
}