github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/physicalplan/span_resolver.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package physicalplan 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/gossip" 17 "github.com/cockroachdb/cockroach/pkg/keys" 18 "github.com/cockroachdb/cockroach/pkg/kv" 19 "github.com/cockroachdb/cockroach/pkg/kv/kvclient/kvcoord" 20 "github.com/cockroachdb/cockroach/pkg/roachpb" 21 "github.com/cockroachdb/cockroach/pkg/rpc" 22 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 23 "github.com/cockroachdb/cockroach/pkg/sql/physicalplan/replicaoracle" 24 "github.com/cockroachdb/cockroach/pkg/util/log" 25 ) 26 27 // SpanResolver resolves key spans to their respective ranges and lease holders. 28 // Used for planning physical execution of distributed SQL queries. 29 // 30 // Sample usage for resolving a bunch of spans: 31 // 32 // func resolveSpans( 33 // ctx context.Context, 34 // it *execinfra.SpanResolverIterator, 35 // spans ...spanWithDir, 36 // ) ([][]kv.ReplicaInfo, error) { 37 // lr := execinfra.NewSpanResolver( 38 // distSender, gossip, nodeDescriptor, 39 // execinfra.BinPackingLeaseHolderChoice) 40 // it := lr.NewSpanResolverIterator(nil) 41 // res := make([][]kv.ReplicaInfo, 0) 42 // for _, span := range spans { 43 // repls := make([]kv.ReplicaInfo, 0) 44 // for it.Seek(ctx, span.Span, span.dir); ; it.Next(ctx) { 45 // if !it.Valid() { 46 // return nil, it.Error() 47 // } 48 // repl, err := it.ReplicaInfo(ctx) 49 // if err != nil { 50 // return nil, err 51 // } 52 // repls = append(repls, repl) 53 // if !it.NeedAnother() { 54 // break 55 // } 56 // } 57 // res = append(res, repls) 58 // } 59 // return res, nil 60 // } 61 // 62 // 63 type SpanResolver interface { 64 // NewSpanResolverIterator creates a new SpanResolverIterator. 65 // Txn is used for testing and for determining if follower reads are possible. 66 NewSpanResolverIterator(txn *kv.Txn) SpanResolverIterator 67 } 68 69 // SpanResolverIterator is used to iterate over the ranges composing a key span. 70 type SpanResolverIterator interface { 71 // Seek positions the iterator on the start of a span (span.Key or 72 // span.EndKey, depending on ScanDir). Note that span.EndKey is exclusive, 73 // regardless of scanDir. 74 // 75 // After calling this, ReplicaInfo() will return information about the range 76 // containing the start key of the span (or the end key, if the direction is 77 // Descending). 78 // 79 // NeedAnother() will return true until the iterator is positioned on or after 80 // the end of the span. Possible errors encountered should be checked for 81 // with Valid(). 82 // 83 // Seek can be called repeatedly on the same iterator. To make optimal uses of 84 // caches, Seek()s should be performed on spans sorted according to the 85 // scanDir (if Descending, then the span with the highest keys should be 86 // Seek()ed first). 87 // 88 // scanDir changes the direction in which Next() will advance the iterator. 89 Seek(ctx context.Context, span roachpb.Span, scanDir kvcoord.ScanDirection) 90 91 // NeedAnother returns true if the current range is not the last for the span 92 // that was last Seek()ed. 93 NeedAnother() bool 94 95 // Next advances the iterator to the next range. The next range contains the 96 // last range's end key (but it does not necessarily start there, because of 97 // asynchronous range splits and caching effects). 98 // Possible errors encountered should be checked for with Valid(). 99 Next(ctx context.Context) 100 101 // Valid returns false if an error was encountered by the last Seek() or Next(). 102 Valid() bool 103 104 // Error returns any error encountered by the last Seek() or Next(). 105 Error() error 106 107 // Desc returns the current RangeDescriptor. 108 Desc() roachpb.RangeDescriptor 109 110 // ReplicaInfo returns information about the replica that has been picked for 111 // the current range. 112 // A RangeUnavailableError is returned if there's no information in gossip 113 // about any of the replicas. 114 ReplicaInfo(ctx context.Context) (roachpb.ReplicaDescriptor, error) 115 } 116 117 // spanResolver implements SpanResolver. 118 type spanResolver struct { 119 st *cluster.Settings 120 gossip gossip.DeprecatedGossip 121 distSender *kvcoord.DistSender 122 nodeDesc roachpb.NodeDescriptor 123 oracleFactory replicaoracle.OracleFactory 124 } 125 126 var _ SpanResolver = &spanResolver{} 127 128 // NewSpanResolver creates a new spanResolver. 129 func NewSpanResolver( 130 st *cluster.Settings, 131 distSender *kvcoord.DistSender, 132 gw gossip.DeprecatedGossip, 133 nodeDesc roachpb.NodeDescriptor, 134 rpcCtx *rpc.Context, 135 policy replicaoracle.Policy, 136 ) SpanResolver { 137 return &spanResolver{ 138 st: st, 139 nodeDesc: nodeDesc, 140 oracleFactory: replicaoracle.NewOracleFactory(policy, replicaoracle.Config{ 141 Settings: st, 142 Gossip: gw.DeprecatedOracleGossip(48432), 143 NodeDesc: nodeDesc, 144 RPCContext: rpcCtx, 145 LeaseHolderCache: distSender.LeaseHolderCache(), 146 }), 147 distSender: distSender, 148 gossip: gw, 149 } 150 } 151 152 // spanResolverIterator implements the SpanResolverIterator interface. 153 type spanResolverIterator struct { 154 // it is a wrapper RangeIterator. 155 it *kvcoord.RangeIterator 156 // oracle is used to choose a lease holders for ranges when one isn't present 157 // in the cache. 158 oracle replicaoracle.Oracle 159 160 curSpan roachpb.RSpan 161 // dir is the direction set by the last Seek() 162 dir kvcoord.ScanDirection 163 164 queryState replicaoracle.QueryState 165 166 err error 167 } 168 169 var _ SpanResolverIterator = &spanResolverIterator{} 170 171 // NewSpanResolverIterator creates a new SpanResolverIterator. 172 func (sr *spanResolver) NewSpanResolverIterator(txn *kv.Txn) SpanResolverIterator { 173 return &spanResolverIterator{ 174 it: kvcoord.NewRangeIterator(sr.distSender), 175 oracle: sr.oracleFactory.Oracle(txn), 176 queryState: replicaoracle.MakeQueryState(), 177 } 178 } 179 180 // Valid is part of the SpanResolverIterator interface. 181 func (it *spanResolverIterator) Valid() bool { 182 return it.err == nil && it.it.Valid() 183 } 184 185 // Error is part of the SpanResolverIterator interface. 186 func (it *spanResolverIterator) Error() error { 187 if it.err != nil { 188 return it.err 189 } 190 return it.it.Error() 191 } 192 193 // Seek is part of the SpanResolverIterator interface. 194 func (it *spanResolverIterator) Seek( 195 ctx context.Context, span roachpb.Span, scanDir kvcoord.ScanDirection, 196 ) { 197 var key, endKey roachpb.RKey 198 var err error 199 if key, err = keys.Addr(span.Key); err != nil { 200 it.err = err 201 return 202 } 203 if endKey, err = keys.Addr(span.EndKey); err != nil { 204 it.err = err 205 return 206 } 207 oldDir := it.dir 208 it.curSpan = roachpb.RSpan{ 209 Key: key, 210 EndKey: endKey, 211 } 212 it.dir = scanDir 213 214 var seekKey roachpb.RKey 215 if scanDir == kvcoord.Ascending { 216 seekKey = it.curSpan.Key 217 } else { 218 seekKey = it.curSpan.EndKey 219 } 220 221 // Check if the start of the span falls within the descriptor on which we're 222 // already positioned. If so, and if the direction also corresponds, there's 223 // no need to change the underlying iterator's state. 224 if it.dir == oldDir && it.it.Valid() { 225 reverse := (it.dir == kvcoord.Descending) 226 desc := it.it.Desc() 227 if (reverse && desc.ContainsKeyInverted(seekKey)) || 228 (!reverse && desc.ContainsKey(seekKey)) { 229 if log.V(1) { 230 log.Infof(ctx, "not seeking (key=%s); existing descriptor %s", seekKey, desc) 231 } 232 return 233 } 234 } 235 if log.V(1) { 236 log.Infof(ctx, "seeking (key=%s)", seekKey) 237 } 238 it.it.Seek(ctx, seekKey, scanDir) 239 } 240 241 // Next is part of the SpanResolverIterator interface. 242 func (it *spanResolverIterator) Next(ctx context.Context) { 243 if !it.Valid() { 244 panic(it.Error()) 245 } 246 it.it.Next(ctx) 247 } 248 249 // NeedAnother is part of the SpanResolverIterator interface. 250 func (it *spanResolverIterator) NeedAnother() bool { 251 return it.it.NeedAnother(it.curSpan) 252 } 253 254 // Desc is part of the SpanResolverIterator interface. 255 func (it *spanResolverIterator) Desc() roachpb.RangeDescriptor { 256 return *it.it.Desc() 257 } 258 259 // ReplicaInfo is part of the SpanResolverIterator interface. 260 func (it *spanResolverIterator) ReplicaInfo( 261 ctx context.Context, 262 ) (roachpb.ReplicaDescriptor, error) { 263 if !it.Valid() { 264 panic(it.Error()) 265 } 266 267 // If we've assigned the range before, return that assignment. 268 rngID := it.it.Desc().RangeID 269 if repl, ok := it.queryState.AssignedRanges[rngID]; ok { 270 return repl, nil 271 } 272 273 repl, err := it.oracle.ChoosePreferredReplica( 274 ctx, *it.it.Desc(), it.queryState) 275 if err != nil { 276 return roachpb.ReplicaDescriptor{}, err 277 } 278 it.queryState.RangesPerNode[repl.NodeID]++ 279 it.queryState.AssignedRanges[rngID] = repl 280 return repl, nil 281 }