Skip to content

Commit

Permalink
rpc: linear time batch response matching (#23856)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
fjl authored Nov 4, 2021
1 parent 03bc8b7 commit 53b94f1
Showing 1 changed file with 6 additions and 9 deletions.
15 changes: 6 additions & 9 deletions rpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package rpc

import (
"bytes"
"context"
"encoding/json"
"errors"
Expand Down Expand Up @@ -360,7 +359,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)),
Expand All @@ -372,6 +374,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
Expand All @@ -391,13 +394,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
Expand Down

0 comments on commit 53b94f1

Please sign in to comment.