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  }