ceremonyclient/pebble/metamorphic/retryable.go
Cassandra Heart 2e2a1e4789
v1.2.0 (#31)
2024-01-03 01:31:42 -06:00

182 lines
4.0 KiB
Go

// Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
package metamorphic
import (
"github.com/cockroachdb/errors"
"github.com/cockroachdb/pebble"
"github.com/cockroachdb/pebble/vfs/errorfs"
)
// withRetries executes fn, retrying it whenever an errorfs.ErrInjected error
// is returned. It returns the first nil or non-errorfs.ErrInjected error
// returned by fn.
func withRetries(fn func() error) error {
for {
if err := fn(); !errors.Is(err, errorfs.ErrInjected) {
return err
}
}
}
// retryableIter holds an iterator and the state necessary to reset it to its
// state after the last successful operation. This allows us to retry failed
// iterator operations by running them again on a non-error iterator with the
// same pre-operation state.
type retryableIter struct {
iter *pebble.Iterator
lastKey []byte
}
func (i *retryableIter) needRetry() bool {
return errors.Is(i.iter.Error(), errorfs.ErrInjected)
}
func (i *retryableIter) withRetry(fn func()) {
for {
fn()
if !i.needRetry() {
break
}
for i.needRetry() {
i.iter.SeekGE(i.lastKey)
}
}
i.lastKey = i.lastKey[:0]
if i.iter.Valid() {
i.lastKey = append(i.lastKey, i.iter.Key()...)
}
}
func (i *retryableIter) Close() error {
return i.iter.Close()
}
func (i *retryableIter) Error() error {
return i.iter.Error()
}
func (i *retryableIter) First() bool {
var valid bool
i.withRetry(func() {
valid = i.iter.First()
})
return valid
}
func (i *retryableIter) Key() []byte {
return i.iter.Key()
}
func (i *retryableIter) RangeKeyChanged() bool {
return i.iter.RangeKeyChanged()
}
func (i *retryableIter) HasPointAndRange() (bool, bool) {
return i.iter.HasPointAndRange()
}
func (i *retryableIter) RangeBounds() ([]byte, []byte) {
return i.iter.RangeBounds()
}
func (i *retryableIter) RangeKeys() []pebble.RangeKeyData {
return i.iter.RangeKeys()
}
func (i *retryableIter) Last() bool {
var valid bool
i.withRetry(func() { valid = i.iter.Last() })
return valid
}
func (i *retryableIter) Next() bool {
var valid bool
i.withRetry(func() {
valid = i.iter.Next()
})
return valid
}
func (i *retryableIter) NextWithLimit(limit []byte) pebble.IterValidityState {
var validity pebble.IterValidityState
i.withRetry(func() {
validity = i.iter.NextWithLimit(limit)
})
return validity
}
func (i *retryableIter) NextPrefix() bool {
var valid bool
i.withRetry(func() {
valid = i.iter.NextPrefix()
})
return valid
}
func (i *retryableIter) Prev() bool {
var valid bool
i.withRetry(func() {
valid = i.iter.Prev()
})
return valid
}
func (i *retryableIter) PrevWithLimit(limit []byte) pebble.IterValidityState {
var validity pebble.IterValidityState
i.withRetry(func() {
validity = i.iter.PrevWithLimit(limit)
})
return validity
}
func (i *retryableIter) SeekGE(key []byte) bool {
var valid bool
i.withRetry(func() { valid = i.iter.SeekGE(key) })
return valid
}
func (i *retryableIter) SeekGEWithLimit(key []byte, limit []byte) pebble.IterValidityState {
var validity pebble.IterValidityState
i.withRetry(func() { validity = i.iter.SeekGEWithLimit(key, limit) })
return validity
}
func (i *retryableIter) SeekLT(key []byte) bool {
var valid bool
i.withRetry(func() { valid = i.iter.SeekLT(key) })
return valid
}
func (i *retryableIter) SeekLTWithLimit(key []byte, limit []byte) pebble.IterValidityState {
var validity pebble.IterValidityState
i.withRetry(func() { validity = i.iter.SeekLTWithLimit(key, limit) })
return validity
}
func (i *retryableIter) SeekPrefixGE(key []byte) bool {
var valid bool
i.withRetry(func() { valid = i.iter.SeekPrefixGE(key) })
return valid
}
func (i *retryableIter) SetBounds(lower, upper []byte) {
i.iter.SetBounds(lower, upper)
}
func (i *retryableIter) SetOptions(opts *pebble.IterOptions) {
i.iter.SetOptions(opts)
}
func (i *retryableIter) Valid() bool {
return i.iter.Valid()
}
func (i *retryableIter) Value() []byte {
return i.iter.Value()
}