// sendSingleRange gathers and rearranges the replicas, and makes an RPC call. func (ds *DistSender) sendSingleRange( ctx context.Context, ba roachpb.BatchRequest, desc *roachpb.RangeDescriptor, ) (*roachpb.BatchResponse, *roachpb.Error) { // Try to send the call. replicas := newReplicaSlice(ds.gossip, desc) // Rearrange the replicas so that those replicas with long common // prefix of attributes end up first. If there's no prefix, this is a // no-op. ds.optimizeReplicaOrder(replicas) // If this request needs to go to a lease holder and we know who that is, move // it to the front. if !(ba.IsReadOnly() && ba.ReadConsistency == roachpb.INCONSISTENT) { if leaseHolder, ok := ds.leaseHolderCache.Lookup(ctx, desc.RangeID); ok { if i := replicas.FindReplica(leaseHolder.StoreID); i >= 0 { replicas.MoveToFront(i) } } } // TODO(tschottdorf): should serialize the trace here, not higher up. br, err := ds.sendRPC(ctx, desc.RangeID, replicas, ba) if err != nil { return nil, roachpb.NewError(err) } // If the reply contains a timestamp, update the local HLC with it. if br.Error != nil && br.Error.Now != hlc.ZeroTimestamp { ds.clock.Update(br.Error.Now) } else if br.Now != hlc.ZeroTimestamp { ds.clock.Update(br.Now) } // Untangle the error from the received response. pErr := br.Error br.Error = nil // scrub the response error return br, pErr }