perf(grpc): O(1) unconstrained bulk fast path, direct filtered-command build, cache eviction, capacity hints
This commit is contained in:
@@ -461,6 +461,14 @@ public sealed class MxAccessGatewayService(
|
||||
string? correlationId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// An identity with no read constraints allows every tag, so the per-item enforcer call below
|
||||
// can only answer "allowed" — the whole loop (and the plan it would build) is dead work.
|
||||
// Returning null is exactly what the denied.Count == 0 exit below returns.
|
||||
if (!constraintEnforcer.HasReadConstraints(identity))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<int, SubscribeResult> denied = [];
|
||||
List<string> allowed = [];
|
||||
for (int index = 0; index < tagAddresses.Count; index++)
|
||||
@@ -491,16 +499,23 @@ public sealed class MxAccessGatewayService(
|
||||
return null;
|
||||
}
|
||||
|
||||
MxCommand filtered = command.Clone();
|
||||
if (filtered.Kind == MxCommandKind.AddItemBulk)
|
||||
// Build the filtered command directly instead of cloning the original and clearing it:
|
||||
// the clone deep-copied every denied address only to drop it. The payload's other fields
|
||||
// (server_handle) are copied across explicitly. Nothing aliases the request here — these
|
||||
// bulk payloads carry only strings — and the worker-bound graph is still the unaliased copy
|
||||
// MapCommand makes.
|
||||
MxCommand filtered = new() { Kind = command.Kind };
|
||||
if (command.Kind == MxCommandKind.AddItemBulk)
|
||||
{
|
||||
filtered.AddItemBulk.TagAddresses.Clear();
|
||||
filtered.AddItemBulk.TagAddresses.Add(allowed);
|
||||
AddItemBulkCommand payload = new() { ServerHandle = command.AddItemBulk.ServerHandle };
|
||||
payload.TagAddresses.Add(allowed);
|
||||
filtered.AddItemBulk = payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
filtered.SubscribeBulk.TagAddresses.Clear();
|
||||
filtered.SubscribeBulk.TagAddresses.Add(allowed);
|
||||
SubscribeBulkCommand payload = new() { ServerHandle = command.SubscribeBulk.ServerHandle };
|
||||
payload.TagAddresses.Add(allowed);
|
||||
filtered.SubscribeBulk = payload;
|
||||
}
|
||||
|
||||
return new SubscribeBulkConstraintPlan(filtered, tagAddresses.Count, denied, allowed.Count > 0);
|
||||
@@ -517,6 +532,11 @@ public sealed class MxAccessGatewayService(
|
||||
// Mirrors FilterTagBulkAsync but produces BulkReadResult denial entries
|
||||
// so the reply payload merges into BulkReadReply.Results, not
|
||||
// BulkSubscribeReply.Results.
|
||||
if (!constraintEnforcer.HasReadConstraints(identity))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<int, BulkReadResult> denied = [];
|
||||
List<string> allowed = [];
|
||||
for (int index = 0; index < tagAddresses.Count; index++)
|
||||
@@ -548,9 +568,14 @@ public sealed class MxAccessGatewayService(
|
||||
return null;
|
||||
}
|
||||
|
||||
MxCommand filtered = command.Clone();
|
||||
filtered.ReadBulk.TagAddresses.Clear();
|
||||
filtered.ReadBulk.TagAddresses.Add(allowed);
|
||||
MxCommand filtered = new() { Kind = command.Kind };
|
||||
ReadBulkCommand payload = new()
|
||||
{
|
||||
ServerHandle = command.ReadBulk.ServerHandle,
|
||||
TimeoutMs = command.ReadBulk.TimeoutMs,
|
||||
};
|
||||
payload.TagAddresses.Add(allowed);
|
||||
filtered.ReadBulk = payload;
|
||||
|
||||
return new ReadBulkConstraintPlan(filtered, tagAddresses.Count, denied, allowed.Count > 0);
|
||||
}
|
||||
@@ -572,6 +597,11 @@ public sealed class MxAccessGatewayService(
|
||||
// Parameterising on TEntry + getItemHandle keeps a single filter
|
||||
// routine for all four and avoids duplicating CheckWriteHandleAsync
|
||||
// calls.
|
||||
if (!constraintEnforcer.HasWriteConstraints(identity))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<int, BulkWriteResult> denied = [];
|
||||
List<TEntry> allowed = [];
|
||||
for (int index = 0; index < entries.Count; index++)
|
||||
@@ -609,33 +639,70 @@ public sealed class MxAccessGatewayService(
|
||||
return null;
|
||||
}
|
||||
|
||||
MxCommand filtered = command.Clone();
|
||||
ReplaceWriteBulkEntries(filtered, allowed);
|
||||
return new WriteBulkConstraintPlan(filtered, entries.Count, denied, allowed.Count > 0);
|
||||
return new WriteBulkConstraintPlan(
|
||||
BuildFilteredWriteBulkCommand(command, allowed),
|
||||
entries.Count,
|
||||
denied,
|
||||
allowed.Count > 0);
|
||||
}
|
||||
|
||||
private static void ReplaceWriteBulkEntries<TEntry>(MxCommand command, IReadOnlyList<TEntry> allowed)
|
||||
/// <summary>
|
||||
/// Builds the allowed-only bulk-write command. The allowed entries are carried over by
|
||||
/// reference rather than deep-cloned: the caller only reads this command (TrackCommandReply),
|
||||
/// and the copy the worker mutates and owns is the one <c>MapCommand</c> clones — the same
|
||||
/// no-aliasing boundary as before. Cloning the whole command here and clearing it copied
|
||||
/// every denied entry's payload (including <c>WriteSecured</c> values) for nothing.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntry">The per-family bulk-write entry message type.</typeparam>
|
||||
/// <param name="command">The original command, read for its kind and payload scalars.</param>
|
||||
/// <param name="allowed">The entries that survived constraint filtering, in original order.</param>
|
||||
/// <returns>A command of the same kind carrying only the allowed entries.</returns>
|
||||
private static MxCommand BuildFilteredWriteBulkCommand<TEntry>(MxCommand command, IReadOnlyList<TEntry> allowed)
|
||||
where TEntry : class
|
||||
{
|
||||
MxCommand filtered = new() { Kind = command.Kind };
|
||||
switch (command.Kind)
|
||||
{
|
||||
case MxCommandKind.WriteBulk:
|
||||
command.WriteBulk.Entries.Clear();
|
||||
command.WriteBulk.Entries.Add((IEnumerable<WriteBulkEntry>)allowed);
|
||||
{
|
||||
WriteBulkCommand payload = new() { ServerHandle = command.WriteBulk.ServerHandle };
|
||||
payload.Entries.Add((IEnumerable<WriteBulkEntry>)allowed);
|
||||
filtered.WriteBulk = payload;
|
||||
break;
|
||||
}
|
||||
|
||||
case MxCommandKind.Write2Bulk:
|
||||
command.Write2Bulk.Entries.Clear();
|
||||
command.Write2Bulk.Entries.Add((IEnumerable<Write2BulkEntry>)allowed);
|
||||
{
|
||||
Write2BulkCommand payload = new() { ServerHandle = command.Write2Bulk.ServerHandle };
|
||||
payload.Entries.Add((IEnumerable<Write2BulkEntry>)allowed);
|
||||
filtered.Write2Bulk = payload;
|
||||
break;
|
||||
}
|
||||
|
||||
case MxCommandKind.WriteSecuredBulk:
|
||||
command.WriteSecuredBulk.Entries.Clear();
|
||||
command.WriteSecuredBulk.Entries.Add((IEnumerable<WriteSecuredBulkEntry>)allowed);
|
||||
{
|
||||
WriteSecuredBulkCommand payload = new() { ServerHandle = command.WriteSecuredBulk.ServerHandle };
|
||||
payload.Entries.Add((IEnumerable<WriteSecuredBulkEntry>)allowed);
|
||||
filtered.WriteSecuredBulk = payload;
|
||||
break;
|
||||
}
|
||||
|
||||
case MxCommandKind.WriteSecured2Bulk:
|
||||
command.WriteSecured2Bulk.Entries.Clear();
|
||||
command.WriteSecured2Bulk.Entries.Add((IEnumerable<WriteSecured2BulkEntry>)allowed);
|
||||
{
|
||||
WriteSecured2BulkCommand payload = new() { ServerHandle = command.WriteSecured2Bulk.ServerHandle };
|
||||
payload.Entries.Add((IEnumerable<WriteSecured2BulkEntry>)allowed);
|
||||
filtered.WriteSecured2Bulk = payload;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Only the four bulk-write kinds above reach FilterWriteBulkAsync, so this is
|
||||
// unreachable; keep the previous behaviour (the unmodified command) rather than
|
||||
// emitting a payload-less one if that ever stops holding.
|
||||
return command.Clone();
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
private async Task<BulkConstraintPlan?> FilterHandleBulkAsync(
|
||||
@@ -647,6 +714,11 @@ public sealed class MxAccessGatewayService(
|
||||
string? correlationId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (!constraintEnforcer.HasReadConstraints(identity))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<int, SubscribeResult> denied = [];
|
||||
List<int> allowed = [];
|
||||
for (int index = 0; index < itemHandles.Count; index++)
|
||||
@@ -677,9 +749,10 @@ public sealed class MxAccessGatewayService(
|
||||
return null;
|
||||
}
|
||||
|
||||
MxCommand filtered = command.Clone();
|
||||
filtered.AdviseItemBulk.ItemHandles.Clear();
|
||||
filtered.AdviseItemBulk.ItemHandles.Add(allowed);
|
||||
MxCommand filtered = new() { Kind = command.Kind };
|
||||
AdviseItemBulkCommand payload = new() { ServerHandle = command.AdviseItemBulk.ServerHandle };
|
||||
payload.ItemHandles.Add(allowed);
|
||||
filtered.AdviseItemBulk = payload;
|
||||
|
||||
return new SubscribeBulkConstraintPlan(filtered, itemHandles.Count, denied, allowed.Count > 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user