Unverified Commit 53b94f13 authored by Felix Lange's avatar Felix Lange Committed by GitHub

rpc: linear time batch response matching (#23856)

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
parent 03bc8b78
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
package rpc package rpc
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
...@@ -360,7 +359,10 @@ func (c *Client) BatchCall(b []BatchElem) error { ...@@ -360,7 +359,10 @@ func (c *Client) BatchCall(b []BatchElem) error {
// //
// Note that batch calls may not be executed atomically on the server side. // Note that batch calls may not be executed atomically on the server side.
func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { 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{ op := &requestOp{
ids: make([]json.RawMessage, len(b)), ids: make([]json.RawMessage, len(b)),
resp: make(chan *jsonrpcMessage, len(b)), resp: make(chan *jsonrpcMessage, len(b)),
...@@ -372,6 +374,7 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { ...@@ -372,6 +374,7 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error {
} }
msgs[i] = msg msgs[i] = msg
op.ids[i] = msg.ID op.ids[i] = msg.ID
byID[string(msg.ID)] = i
} }
var err error var err error
...@@ -391,13 +394,7 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error { ...@@ -391,13 +394,7 @@ func (c *Client) BatchCallContext(ctx context.Context, b []BatchElem) error {
// Find the element corresponding to this response. // Find the element corresponding to this response.
// The element is guaranteed to be present because dispatch // The element is guaranteed to be present because dispatch
// only sends valid IDs to our channel. // only sends valid IDs to our channel.
var elem *BatchElem elem := &b[byID[string(resp.ID)]]
for i := range msgs {
if bytes.Equal(msgs[i].ID, resp.ID) {
elem = &b[i]
break
}
}
if resp.Error != nil { if resp.Error != nil {
elem.Error = resp.Error elem.Error = resp.Error
continue continue
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment