mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 00:55:17 +00:00
182 lines
4.0 KiB
Go
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()
|
||
|
}
|