github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvclient/kvcoord/range_iter.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 kvcoord 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/roachpb" 17 "github.com/cockroachdb/cockroach/pkg/util/log" 18 "github.com/cockroachdb/cockroach/pkg/util/retry" 19 "github.com/cockroachdb/errors" 20 ) 21 22 // A RangeIterator provides a mechanism for iterating over all ranges 23 // in a key span. A new RangeIterator must be positioned with Seek() 24 // to begin iteration. 25 // 26 // RangeIterator is not thread-safe. 27 type RangeIterator struct { 28 ds *DistSender 29 scanDir ScanDirection 30 key roachpb.RKey 31 desc *roachpb.RangeDescriptor 32 token *EvictionToken 33 init bool 34 err error 35 } 36 37 // NewRangeIterator creates a new RangeIterator. 38 func NewRangeIterator(ds *DistSender) *RangeIterator { 39 return &RangeIterator{ 40 ds: ds, 41 } 42 } 43 44 // ScanDirection determines the semantics of RangeIterator.Next() and 45 // RangeIterator.NeedAnother(). 46 type ScanDirection byte 47 48 const ( 49 // Ascending means Next() will advance towards keys that compare higher. 50 Ascending ScanDirection = iota 51 // Descending means Next() will advance towards keys that compare lower. 52 Descending 53 ) 54 55 // Key returns the current key. The iterator must be valid. 56 func (ri *RangeIterator) Key() roachpb.RKey { 57 if !ri.Valid() { 58 panic(ri.Error()) 59 } 60 return ri.key 61 } 62 63 // Desc returns the descriptor of the range at which the iterator is 64 // currently positioned. The iterator must be valid. 65 func (ri *RangeIterator) Desc() *roachpb.RangeDescriptor { 66 if !ri.Valid() { 67 panic(ri.Error()) 68 } 69 return ri.desc 70 } 71 72 // Token returns the eviction token corresponding to the range 73 // descriptor for the current iteration. The iterator must be valid. 74 func (ri *RangeIterator) Token() *EvictionToken { 75 if !ri.Valid() { 76 panic(ri.Error()) 77 } 78 return ri.token 79 } 80 81 // NeedAnother checks whether the iteration needs to continue to cover 82 // the remainder of the ranges described by the supplied key span. The 83 // iterator must be valid. 84 func (ri *RangeIterator) NeedAnother(rs roachpb.RSpan) bool { 85 if !ri.Valid() { 86 panic(ri.Error()) 87 } 88 if rs.EndKey == nil { 89 panic("NeedAnother() undefined for spans representing a single key") 90 } 91 if ri.scanDir == Ascending { 92 return ri.desc.EndKey.Less(rs.EndKey) 93 } 94 return rs.Key.Less(ri.desc.StartKey) 95 } 96 97 // Valid returns whether the iterator is valid. To be valid, the 98 // iterator must be have been seeked to an initial position using 99 // Seek(), and must not have encountered an error. 100 func (ri *RangeIterator) Valid() bool { 101 return ri.Error() == nil 102 } 103 104 // Error returns the error the iterator encountered, if any. If 105 // the iterator has not been initialized, returns iterator error. 106 func (ri *RangeIterator) Error() error { 107 if !ri.init { 108 return errors.New("range iterator not intialized with Seek()") 109 } 110 return ri.err 111 } 112 113 // Reset resets the RangeIterator to its initial state. 114 func (ri *RangeIterator) Reset() { 115 *ri = RangeIterator{ds: ri.ds} 116 } 117 118 // Silence unused warning. 119 var _ = (*RangeIterator)(nil).Reset 120 121 // Next advances the iterator to the next range. The direction of 122 // advance is dependent on whether the iterator is reversed. The 123 // iterator must be valid. 124 func (ri *RangeIterator) Next(ctx context.Context) { 125 if !ri.Valid() { 126 panic(ri.Error()) 127 } 128 // Determine next span when the current range is subtracted. 129 if ri.scanDir == Ascending { 130 ri.Seek(ctx, ri.desc.EndKey, ri.scanDir) 131 } else { 132 ri.Seek(ctx, ri.desc.StartKey, ri.scanDir) 133 } 134 } 135 136 // Seek positions the iterator at the specified key. 137 func (ri *RangeIterator) Seek(ctx context.Context, key roachpb.RKey, scanDir ScanDirection) { 138 if log.HasSpanOrEvent(ctx) { 139 rev := "" 140 if scanDir == Descending { 141 rev = " (rev)" 142 } 143 log.Eventf(ctx, "querying next range at %s%s", key, rev) 144 } 145 ri.scanDir = scanDir 146 ri.init = true // the iterator is now initialized 147 ri.err = nil // clear any prior error 148 ri.key = key // set the key 149 150 if (scanDir == Ascending && key.Equal(roachpb.RKeyMax)) || 151 (scanDir == Descending && key.Equal(roachpb.RKeyMin)) { 152 ri.err = errors.Errorf("RangeIterator seek to invalid key %s", key) 153 return 154 } 155 156 // Retry loop for looking up next range in the span. The retry loop 157 // deals with retryable range descriptor lookups. 158 for r := retry.StartWithCtx(ctx, ri.ds.rpcRetryOptions); r.Next(); { 159 var err error 160 ri.desc, ri.token, err = ri.ds.getDescriptor( 161 ctx, ri.key, ri.token, ri.scanDir == Descending) 162 163 if log.V(2) { 164 log.Infof(ctx, "key: %s, desc: %s err: %v", ri.key, ri.desc, err) 165 } 166 167 // getDescriptor may fail retryably if, for example, the first 168 // range isn't available via Gossip. Assume that all errors at 169 // this level are retryable. Non-retryable errors would be for 170 // things like malformed requests which we should have checked 171 // for before reaching this point. 172 if err != nil { 173 log.VEventf(ctx, 1, "range descriptor lookup failed: %s", err) 174 continue 175 } 176 177 if log.V(2) { 178 log.Infof(ctx, "returning; key: %s, desc: %s", ri.key, ri.desc) 179 } 180 return 181 } 182 183 // Check for an early exit from the retry loop. 184 if err := ri.ds.deduceRetryEarlyExitError(ctx); err != nil { 185 ri.err = err 186 } else { 187 ri.err = errors.Errorf("RangeIterator failed to seek to %s", key) 188 } 189 }