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 }