Line data Source code
1 : // Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 : // of this source code is governed by a BSD-style license that can be found in 3 : // the LICENSE file. 4 : 5 : package metamorphic 6 : 7 : import ( 8 : "github.com/cockroachdb/errors" 9 : "github.com/cockroachdb/pebble" 10 : "github.com/cockroachdb/pebble/vfs/errorfs" 11 : ) 12 : 13 : // withRetries executes fn, retrying it whenever an errorfs.ErrInjected error 14 : // is returned. It returns the first nil or non-errorfs.ErrInjected error 15 : // returned by fn. 16 1 : func withRetries(fn func() error) error { 17 1 : for { 18 1 : if err := fn(); !errors.Is(err, errorfs.ErrInjected) { 19 1 : return err 20 1 : } 21 : } 22 : } 23 : 24 : // retryableIter holds an iterator and the state necessary to reset it to its 25 : // state after the last successful operation. This allows us to retry failed 26 : // iterator operations by running them again on a non-error iterator with the 27 : // same pre-operation state. 28 : type retryableIter struct { 29 : iter *pebble.Iterator 30 : lastKey []byte 31 : } 32 : 33 1 : func (i *retryableIter) needRetry() bool { 34 1 : return errors.Is(i.iter.Error(), errorfs.ErrInjected) 35 1 : } 36 : 37 1 : func (i *retryableIter) withRetry(fn func()) { 38 1 : for { 39 1 : fn() 40 1 : if !i.needRetry() { 41 1 : break 42 : } 43 0 : for i.needRetry() { 44 0 : i.iter.SeekGE(i.lastKey) 45 0 : } 46 : } 47 : 48 1 : i.lastKey = i.lastKey[:0] 49 1 : if i.iter.Valid() { 50 1 : i.lastKey = append(i.lastKey, i.iter.Key()...) 51 1 : } 52 : } 53 : 54 1 : func (i *retryableIter) Close() error { 55 1 : return i.iter.Close() 56 1 : } 57 : 58 1 : func (i *retryableIter) Error() error { 59 1 : return i.iter.Error() 60 1 : } 61 : 62 1 : func (i *retryableIter) First() bool { 63 1 : var valid bool 64 1 : i.withRetry(func() { 65 1 : valid = i.iter.First() 66 1 : }) 67 1 : return valid 68 : } 69 : 70 1 : func (i *retryableIter) Key() []byte { 71 1 : return i.iter.Key() 72 1 : } 73 : 74 1 : func (i *retryableIter) RangeKeyChanged() bool { 75 1 : return i.iter.RangeKeyChanged() 76 1 : } 77 : 78 1 : func (i *retryableIter) HasPointAndRange() (bool, bool) { 79 1 : return i.iter.HasPointAndRange() 80 1 : } 81 : 82 1 : func (i *retryableIter) RangeBounds() ([]byte, []byte) { 83 1 : return i.iter.RangeBounds() 84 1 : } 85 : 86 1 : func (i *retryableIter) RangeKeys() []pebble.RangeKeyData { 87 1 : return i.iter.RangeKeys() 88 1 : } 89 : 90 1 : func (i *retryableIter) Last() bool { 91 1 : var valid bool 92 1 : i.withRetry(func() { valid = i.iter.Last() }) 93 1 : return valid 94 : } 95 : 96 1 : func (i *retryableIter) Next() bool { 97 1 : var valid bool 98 1 : i.withRetry(func() { 99 1 : valid = i.iter.Next() 100 1 : }) 101 1 : return valid 102 : } 103 : 104 1 : func (i *retryableIter) NextWithLimit(limit []byte) pebble.IterValidityState { 105 1 : var validity pebble.IterValidityState 106 1 : i.withRetry(func() { 107 1 : validity = i.iter.NextWithLimit(limit) 108 1 : }) 109 1 : return validity 110 : 111 : } 112 : 113 1 : func (i *retryableIter) NextPrefix() bool { 114 1 : var valid bool 115 1 : i.withRetry(func() { 116 1 : valid = i.iter.NextPrefix() 117 1 : }) 118 1 : return valid 119 : } 120 : 121 1 : func (i *retryableIter) Prev() bool { 122 1 : var valid bool 123 1 : i.withRetry(func() { 124 1 : valid = i.iter.Prev() 125 1 : }) 126 1 : return valid 127 : } 128 : 129 1 : func (i *retryableIter) PrevWithLimit(limit []byte) pebble.IterValidityState { 130 1 : var validity pebble.IterValidityState 131 1 : i.withRetry(func() { 132 1 : validity = i.iter.PrevWithLimit(limit) 133 1 : }) 134 1 : return validity 135 : } 136 : 137 1 : func (i *retryableIter) SeekGE(key []byte) bool { 138 1 : var valid bool 139 1 : i.withRetry(func() { valid = i.iter.SeekGE(key) }) 140 1 : return valid 141 : } 142 : 143 1 : func (i *retryableIter) SeekGEWithLimit(key []byte, limit []byte) pebble.IterValidityState { 144 1 : var validity pebble.IterValidityState 145 1 : i.withRetry(func() { validity = i.iter.SeekGEWithLimit(key, limit) }) 146 1 : return validity 147 : } 148 : 149 1 : func (i *retryableIter) SeekLT(key []byte) bool { 150 1 : var valid bool 151 1 : i.withRetry(func() { valid = i.iter.SeekLT(key) }) 152 1 : return valid 153 : } 154 : 155 1 : func (i *retryableIter) SeekLTWithLimit(key []byte, limit []byte) pebble.IterValidityState { 156 1 : var validity pebble.IterValidityState 157 1 : i.withRetry(func() { validity = i.iter.SeekLTWithLimit(key, limit) }) 158 1 : return validity 159 : } 160 : 161 1 : func (i *retryableIter) SeekPrefixGE(key []byte) bool { 162 1 : var valid bool 163 1 : i.withRetry(func() { valid = i.iter.SeekPrefixGE(key) }) 164 1 : return valid 165 : } 166 : 167 1 : func (i *retryableIter) SetBounds(lower, upper []byte) { 168 1 : i.iter.SetBounds(lower, upper) 169 1 : } 170 : 171 1 : func (i *retryableIter) SetOptions(opts *pebble.IterOptions) { 172 1 : i.iter.SetOptions(opts) 173 1 : } 174 : 175 0 : func (i *retryableIter) Valid() bool { 176 0 : return i.iter.Valid() 177 0 : } 178 : 179 1 : func (i *retryableIter) Value() []byte { 180 1 : return i.iter.Value() 181 1 : }