github.com/Jeffail/benthos/v3@v3.65.0/lib/util/checkpoint/type.go (about)

     1  package checkpoint
     2  
     3  import (
     4  	"errors"
     5  )
     6  
     7  // ErrOutOfSync is returned when an offset to be tracked is less than or equal
     8  // to the current highest tracked offset.
     9  var ErrOutOfSync = errors.New("provided offset was out of sync")
    10  
    11  // ErrResolvedOffsetNotTracked is returned when an offset to be resolved has not
    12  // been tracked (or was already resolved).
    13  var ErrResolvedOffsetNotTracked = errors.New("resolved offset was not tracked")
    14  
    15  // Type receives an ordered feed of integer based offsets being tracked, and an
    16  // unordered feed of integer based offsets that are resolved, and is able to
    17  // return the highest offset currently able to be committed such that an
    18  // unresolved offset is never committed.
    19  //
    20  // WARNING: DEPRECATED
    21  // TODO: V4 Remove this
    22  type Type struct {
    23  	base          int
    24  	maxResolved   int
    25  	maxUnresolved int
    26  
    27  	offset  int
    28  	pending []int
    29  	buf     []int
    30  }
    31  
    32  // New returns a new checkpointer from a base offset, which is the value
    33  // returned when no checkpoints have yet been resolved. The base can be zero.
    34  func New(base int) *Type {
    35  	buffer := make([]int, 100)
    36  	return &Type{
    37  		base:    base,
    38  		pending: buffer[:0],
    39  		buf:     buffer,
    40  	}
    41  }
    42  
    43  // Highest returns the current highest checkpoint.
    44  func (t *Type) Highest() int {
    45  	return t.base + t.maxResolved
    46  }
    47  
    48  // Pending returns the number of pending checkpoints.
    49  func (t *Type) Pending() int {
    50  	return len(t.pending)
    51  }
    52  
    53  // Track a new unresolved integer offset. This offset will be cached until it is
    54  // marked as resolved. While it is cached no higher valued offset will ever be
    55  // committed. If the provided value is lower than an already provided value an
    56  // error is returned.
    57  func (t *Type) Track(i int) error {
    58  	if t.offset == cap(t.buf) {
    59  		if len(t.pending) == cap(t.buf) {
    60  			// Reached the limit of our buffer, create a new one.
    61  			t.buf = make([]int, cap(t.buf)*2)
    62  		}
    63  		copy(t.buf, t.pending)
    64  		t.pending = t.buf[0:len(t.pending)]
    65  		t.offset = len(t.pending)
    66  	}
    67  	if len(t.pending) > 0 && t.pending[len(t.pending)-1] >= i {
    68  		return ErrOutOfSync
    69  	}
    70  	t.offset++
    71  	t.pending = t.pending[:len(t.pending)+1]
    72  	t.pending[len(t.pending)-1] = i
    73  	return nil
    74  }
    75  
    76  // MustTrack is the same as Track but panics instead of returning an error.
    77  func (t *Type) MustTrack(i int) {
    78  	if err := t.Track(i); err != nil {
    79  		panic(err)
    80  	}
    81  }
    82  
    83  // Resolve a tracked offset by allowing it to be committed. The highest possible
    84  // offset to be committed is returned, or an error if the provided offset was
    85  // not recognised.
    86  func (t *Type) Resolve(offset int) (int, error) {
    87  	var i, v int
    88  	for i, v = range t.pending {
    89  		if v >= offset {
    90  			break
    91  		}
    92  	}
    93  	if v != offset {
    94  		return 0, ErrResolvedOffsetNotTracked
    95  	}
    96  	if v > t.maxUnresolved {
    97  		t.maxUnresolved = v
    98  	}
    99  	if i > 0 {
   100  		// The offset wasn't the next checkpoint.
   101  		copy(t.pending[1:], t.pending[:i])
   102  	} else if len(t.pending) == 1 {
   103  		t.maxResolved = t.maxUnresolved
   104  	} else if t.pending[1] > t.maxUnresolved {
   105  		t.maxResolved = t.maxUnresolved
   106  	} else {
   107  		t.maxResolved = v
   108  	}
   109  	t.pending = t.pending[1:]
   110  	return t.base + t.maxResolved, nil
   111  }
   112  
   113  // MustResolve is the same as Resolve but panics instead of returning an error.
   114  func (t *Type) MustResolve(offset int) int {
   115  	i, err := t.Resolve(offset)
   116  	if err != nil {
   117  		panic(err)
   118  	}
   119  	return i
   120  }