perf(grpc): O(1) unconstrained bulk fast path, direct filtered-command build, cache eviction, capacity hints

This commit is contained in:
Joseph Doherty
2026-08-15 12:24:17 -04:00
parent 88d38bb900
commit 7171892984
6 changed files with 261 additions and 33 deletions
@@ -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);
}