github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/gc/gc_iterator.go (about)

     1  // Copyright 2020 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 gc
    12  
    13  import (
    14  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/rditer"
    15  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    16  	"github.com/cockroachdb/cockroach/pkg/storage"
    17  	"github.com/cockroachdb/cockroach/pkg/util/bufalloc"
    18  )
    19  
    20  // gcIterator wraps an rditer.ReplicaDataIterator which it reverse iterates for
    21  // the purpose of discovering gc-able replicated data.
    22  type gcIterator struct {
    23  	it   *rditer.ReplicaDataIterator
    24  	done bool
    25  	err  error
    26  	buf  gcIteratorRingBuf
    27  }
    28  
    29  func makeGCIterator(desc *roachpb.RangeDescriptor, snap storage.Reader) gcIterator {
    30  	return gcIterator{
    31  		it: rditer.NewReplicaDataIterator(desc, snap,
    32  			true /* replicatedOnly */, true /* seekEnd */),
    33  	}
    34  }
    35  
    36  type gcIteratorState struct {
    37  	cur, next, afterNext *storage.MVCCKeyValue
    38  }
    39  
    40  // curIsNewest returns true if the current MVCCKeyValue in the gcIteratorState
    41  // is the newest committed version of the key.
    42  //
    43  // It returns true if next is nil or if next is an intent.
    44  func (s *gcIteratorState) curIsNewest() bool {
    45  	return s.cur.Key.IsValue() &&
    46  		(s.next == nil || (s.afterNext != nil && !s.afterNext.Key.IsValue()))
    47  }
    48  
    49  // curIsNotValue returns true if the current MVCCKeyValue in the gcIteratorState
    50  // is not a value, i.e. does not have a timestamp.
    51  func (s *gcIteratorState) curIsNotValue() bool {
    52  	return !s.cur.Key.IsValue()
    53  }
    54  
    55  // curIsIntent returns true if the current MVCCKeyValue in the gcIteratorState
    56  // is an intent.
    57  func (s *gcIteratorState) curIsIntent() bool {
    58  	return s.next != nil && !s.next.Key.IsValue()
    59  }
    60  
    61  // state returns the current state of the iterator. The state contains the
    62  // current and the two following versions of the current key if they exist.
    63  //
    64  // If ok is false, further iteration is unsafe; either the end of iteration has
    65  // been reached or an error has occurred. Callers should check it.err to
    66  // determine whether an error has occurred in cases where ok is false.
    67  //
    68  // It is not safe to use values in the state after subsequent calls to
    69  // it.step().
    70  func (it *gcIterator) state() (s gcIteratorState, ok bool) {
    71  	// The current key is the newest if the key which comes next is different or
    72  	// the key which comes after the current key is an intent or this is the first
    73  	// key in the range.
    74  	s.cur, ok = it.peekAt(0)
    75  	if !ok {
    76  		return gcIteratorState{}, false
    77  	}
    78  	next, ok := it.peekAt(1)
    79  	if !ok && it.err != nil { // cur is the first key in the range
    80  		return gcIteratorState{}, false
    81  	}
    82  	if !ok || !next.Key.Key.Equal(s.cur.Key.Key) {
    83  		return s, true
    84  	}
    85  	s.next = next
    86  	afterNext, ok := it.peekAt(2)
    87  	if !ok && it.err != nil { // cur is the first key in the range
    88  		return gcIteratorState{}, false
    89  	}
    90  	if !ok || !afterNext.Key.Key.Equal(s.cur.Key.Key) {
    91  		return s, true
    92  	}
    93  	s.afterNext = afterNext
    94  	return s, true
    95  }
    96  
    97  func (it *gcIterator) step() {
    98  	it.buf.removeFront()
    99  }
   100  
   101  func (it *gcIterator) peekAt(i int) (*storage.MVCCKeyValue, bool) {
   102  	if it.buf.len <= i {
   103  		if !it.fillTo(i + 1) {
   104  			return nil, false
   105  		}
   106  	}
   107  	return it.buf.at(i), true
   108  }
   109  
   110  func (it *gcIterator) fillTo(targetLen int) (ok bool) {
   111  	for it.buf.len < targetLen {
   112  		if ok, err := it.it.Valid(); !ok {
   113  			it.err, it.done = err, err == nil
   114  			return false
   115  		}
   116  		it.buf.pushBack(it.it)
   117  		it.it.Prev()
   118  	}
   119  	return true
   120  }
   121  
   122  func (it *gcIterator) close() {
   123  	it.it.Close()
   124  	it.it = nil
   125  }
   126  
   127  // gcIteratorRingBufSize is 3 because the gcIterator.state method at most needs
   128  // to look forward two keys ahead of the current key.
   129  const gcIteratorRingBufSize = 3
   130  
   131  type gcIteratorRingBuf struct {
   132  	allocs [gcIteratorRingBufSize]bufalloc.ByteAllocator
   133  	buf    [gcIteratorRingBufSize]storage.MVCCKeyValue
   134  	len    int
   135  	head   int
   136  }
   137  
   138  func (b *gcIteratorRingBuf) at(i int) *storage.MVCCKeyValue {
   139  	if i >= b.len {
   140  		panic("index out of range")
   141  	}
   142  	return &b.buf[(b.head+i)%gcIteratorRingBufSize]
   143  }
   144  
   145  func (b *gcIteratorRingBuf) removeFront() {
   146  	if b.len == 0 {
   147  		panic("cannot remove from empty gcIteratorRingBuf")
   148  	}
   149  	b.buf[b.head] = storage.MVCCKeyValue{}
   150  	b.head = (b.head + 1) % gcIteratorRingBufSize
   151  	b.len--
   152  }
   153  
   154  type iterator interface {
   155  	UnsafeKey() storage.MVCCKey
   156  	UnsafeValue() []byte
   157  }
   158  
   159  func (b *gcIteratorRingBuf) pushBack(it iterator) {
   160  	if b.len == gcIteratorRingBufSize {
   161  		panic("cannot add to full gcIteratorRingBuf")
   162  	}
   163  	i := (b.head + b.len) % gcIteratorRingBufSize
   164  	b.allocs[i] = b.allocs[i][:0]
   165  	k := it.UnsafeKey()
   166  	v := it.UnsafeValue()
   167  	b.allocs[i], k.Key = b.allocs[i].Copy(k.Key, len(v))
   168  	b.allocs[i], v = b.allocs[i].Copy(v, 0)
   169  	b.buf[i] = storage.MVCCKeyValue{
   170  		Key:   k,
   171  		Value: v,
   172  	}
   173  	b.len++
   174  }