From 3ff073d1ea71f5210bcf3af9aa050f8488c23932 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 15 Aug 2026 12:22:59 -0400 Subject: [PATCH] perf(grpc): transfer reply ownership instead of deep-cloning every worker reply --- .../Grpc/MxAccessGrpcMapper.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ZB.MOM.WW.MxGateway.Server/Grpc/MxAccessGrpcMapper.cs b/src/ZB.MOM.WW.MxGateway.Server/Grpc/MxAccessGrpcMapper.cs index fa5e254..8ff862b 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/Grpc/MxAccessGrpcMapper.cs +++ b/src/ZB.MOM.WW.MxGateway.Server/Grpc/MxAccessGrpcMapper.cs @@ -71,7 +71,17 @@ public sealed class MxAccessGrpcMapper }; } - return reply.Reply.Clone(); + // GWC-07 / IPC-05: ownership transfer, not a deep clone — the same rule MapEvent follows, + // applied to the other (and larger, on bulk reads) hot-path message. The enclosing + // WorkerCommandReply is parsed fresh from a single pipe frame in WorkerClient's read loop + // and is single-consumer by construction: CompleteCommand's TryRemove hands it to exactly + // one PendingCommand awaiter, that awaiter is the gRPC Invoke handler, and the handler's + // one call is this mapping. Nothing else aliases or reads reply.Reply afterwards — the + // enclosing WorkerCommandReply is discarded here. We therefore move the inner + // MxCommandReply into the gRPC response instead of copying it; the handler owning it + // outright is also what makes BulkConstraintPlan.MergeDeniedInto's in-place splice safe. + // If a second consumer of the same WorkerCommandReply is ever added, restore a .Clone(). + return reply.Reply; } ///