LCOV - code coverage report
Current view: top level - pebble/metamorphic - retryable.go (source / functions) Hit Total Coverage
Test: 2024-06-08 08:15Z 47da75f0 - tests only.lcov Lines: 105 114 92.1 %
Date: 2024-06-08 08:16:00 Functions: 0 0 -

          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             : // A RetryPolicy determines what error values should trigger a retry of an
      14             : // operation.
      15             : type RetryPolicy func(error) bool
      16             : 
      17             : var (
      18             :         // NeverRetry implements a RetryPolicy that never retries.
      19           1 :         NeverRetry = func(error) bool { return false }
      20             :         // RetryInjected implements a RetryPolicy that retries whenever an
      21             :         // errorfs.ErrInjected error is returned.
      22           0 :         RetryInjected RetryPolicy = func(err error) bool {
      23           0 :                 return errors.Is(err, errorfs.ErrInjected)
      24           0 :         }
      25             : )
      26             : 
      27           1 : func withRetries(fn func() error, retryPolicy RetryPolicy) error {
      28           1 :         for {
      29           1 :                 if err := fn(); !retryPolicy(err) {
      30           1 :                         return err
      31           1 :                 }
      32             :         }
      33             : }
      34             : 
      35             : // retryableIter holds an iterator and the state necessary to reset it to its
      36             : // state after the last successful operation. This allows us to retry failed
      37             : // iterator operations by running them again on a non-error iterator with the
      38             : // same pre-operation state.
      39             : type retryableIter struct {
      40             :         iter      *pebble.Iterator
      41             :         lastKey   []byte
      42             :         needRetry RetryPolicy
      43             : }
      44             : 
      45           1 : func (i *retryableIter) withRetry(fn func()) {
      46           1 :         for {
      47           1 :                 fn()
      48           1 :                 if !i.needRetry(i.iter.Error()) {
      49           1 :                         break
      50             :                 }
      51           0 :                 for i.needRetry(i.iter.Error()) {
      52           0 :                         i.iter.SeekGE(i.lastKey)
      53           0 :                 }
      54             :         }
      55             : 
      56           1 :         i.lastKey = i.lastKey[:0]
      57           1 :         if i.iter.Valid() {
      58           1 :                 i.lastKey = append(i.lastKey, i.iter.Key()...)
      59           1 :         }
      60             : }
      61             : 
      62           1 : func (i *retryableIter) Close() error {
      63           1 :         return i.iter.Close()
      64           1 : }
      65             : 
      66           1 : func (i *retryableIter) Error() error {
      67           1 :         return i.iter.Error()
      68           1 : }
      69             : 
      70           1 : func (i *retryableIter) First() bool {
      71           1 :         var valid bool
      72           1 :         i.withRetry(func() {
      73           1 :                 valid = i.iter.First()
      74           1 :         })
      75           1 :         return valid
      76             : }
      77             : 
      78           1 : func (i *retryableIter) Key() []byte {
      79           1 :         return i.iter.Key()
      80           1 : }
      81             : 
      82           1 : func (i *retryableIter) RangeKeyChanged() bool {
      83           1 :         return i.iter.RangeKeyChanged()
      84           1 : }
      85             : 
      86           1 : func (i *retryableIter) HasPointAndRange() (bool, bool) {
      87           1 :         return i.iter.HasPointAndRange()
      88           1 : }
      89             : 
      90           1 : func (i *retryableIter) RangeBounds() ([]byte, []byte) {
      91           1 :         return i.iter.RangeBounds()
      92           1 : }
      93             : 
      94           1 : func (i *retryableIter) RangeKeys() []pebble.RangeKeyData {
      95           1 :         return i.iter.RangeKeys()
      96           1 : }
      97             : 
      98           1 : func (i *retryableIter) Last() bool {
      99           1 :         var valid bool
     100           1 :         i.withRetry(func() { valid = i.iter.Last() })
     101           1 :         return valid
     102             : }
     103             : 
     104           1 : func (i *retryableIter) Next() bool {
     105           1 :         var valid bool
     106           1 :         i.withRetry(func() {
     107           1 :                 valid = i.iter.Next()
     108           1 :         })
     109           1 :         return valid
     110             : }
     111             : 
     112           1 : func (i *retryableIter) NextWithLimit(limit []byte) pebble.IterValidityState {
     113           1 :         var validity pebble.IterValidityState
     114           1 :         i.withRetry(func() {
     115           1 :                 validity = i.iter.NextWithLimit(limit)
     116           1 :         })
     117           1 :         return validity
     118             : 
     119             : }
     120             : 
     121           1 : func (i *retryableIter) NextPrefix() bool {
     122           1 :         var valid bool
     123           1 :         i.withRetry(func() {
     124           1 :                 valid = i.iter.NextPrefix()
     125           1 :         })
     126           1 :         return valid
     127             : }
     128             : 
     129           1 : func (i *retryableIter) Prev() bool {
     130           1 :         var valid bool
     131           1 :         i.withRetry(func() {
     132           1 :                 valid = i.iter.Prev()
     133           1 :         })
     134           1 :         return valid
     135             : }
     136             : 
     137           1 : func (i *retryableIter) PrevWithLimit(limit []byte) pebble.IterValidityState {
     138           1 :         var validity pebble.IterValidityState
     139           1 :         i.withRetry(func() {
     140           1 :                 validity = i.iter.PrevWithLimit(limit)
     141           1 :         })
     142           1 :         return validity
     143             : }
     144             : 
     145           1 : func (i *retryableIter) SeekGE(key []byte) bool {
     146           1 :         var valid bool
     147           1 :         i.withRetry(func() { valid = i.iter.SeekGE(key) })
     148           1 :         return valid
     149             : }
     150             : 
     151           1 : func (i *retryableIter) SeekGEWithLimit(key []byte, limit []byte) pebble.IterValidityState {
     152           1 :         var validity pebble.IterValidityState
     153           1 :         i.withRetry(func() { validity = i.iter.SeekGEWithLimit(key, limit) })
     154           1 :         return validity
     155             : }
     156             : 
     157           1 : func (i *retryableIter) SeekLT(key []byte) bool {
     158           1 :         var valid bool
     159           1 :         i.withRetry(func() { valid = i.iter.SeekLT(key) })
     160           1 :         return valid
     161             : }
     162             : 
     163           1 : func (i *retryableIter) SeekLTWithLimit(key []byte, limit []byte) pebble.IterValidityState {
     164           1 :         var validity pebble.IterValidityState
     165           1 :         i.withRetry(func() { validity = i.iter.SeekLTWithLimit(key, limit) })
     166           1 :         return validity
     167             : }
     168             : 
     169           1 : func (i *retryableIter) SeekPrefixGE(key []byte) bool {
     170           1 :         var valid bool
     171           1 :         i.withRetry(func() { valid = i.iter.SeekPrefixGE(key) })
     172           1 :         return valid
     173             : }
     174             : 
     175           1 : func (i *retryableIter) SetBounds(lower, upper []byte) {
     176           1 :         i.iter.SetBounds(lower, upper)
     177           1 : }
     178             : 
     179           1 : func (i *retryableIter) SetOptions(opts *pebble.IterOptions) {
     180           1 :         i.iter.SetOptions(opts)
     181           1 : }
     182             : 
     183           0 : func (i *retryableIter) Valid() bool {
     184           0 :         return i.iter.Valid()
     185           0 : }
     186             : 
     187           1 : func (i *retryableIter) Value() []byte {
     188           1 :         return i.iter.Value()
     189           1 : }

Generated by: LCOV version 1.14