From 3a618f0fd26a528a0447f389c374a18c1f600f00 Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Thu, 24 Apr 2025 18:34:12 +0800 Subject: [PATCH] rpc: linear time batch response matching #23856 (#962) This avoids quadratic time complexity in the lookup of the batch element corresponding to an RPC response. Unfortunately, the new approach requires additional memory for the mapping from ID to index. Fixes #22805 Co-authored-by: Felix Lange --- rpc/client.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/rpc/client.go b/rpc/client.go index ba805ca2ff..3fb606facb 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -17,7 +17,6 @@ package rpc import ( - "bytes" "context" "encoding/json" "errors" @@ -381,7 +380,10 @@ func (c *Client) BatchCall(b []BatchElem) error { // // Note that batch calls may not be executed atomically on the server side. func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { - msgs := make([]*jsonrpcMessage, len(b)) + var ( + msgs = make([]*jsonrpcMessage, len(b)) + byID = make(map[string]int, len(b)) + ) op := &requestOp{ ids: make([]json.RawMessage, len(b)), resp: make(chan *jsonrpcMessage, len(b)), @@ -393,6 +395,7 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { } msgs[i] = msg op.ids[i] = msg.ID + byID[string(msg.ID)] = i } var err error @@ -412,13 +415,7 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { // Find the element corresponding to this response. // The element is guaranteed to be present because dispatch // only sends valid IDs to our channel. - var elem *BatchElem - for i := range msgs { - if bytes.Equal(msgs[i].ID, resp.ID) { - elem = &b[i] - break - } - } + elem := &b[byID[string(resp.ID)]] if resp.Error != nil { elem.Error = resp.Error continue