java.lang.Object
org.axonframework.messaging.eventhandling.processing.streaming.token.GapAwareTrackingToken
All Implemented Interfaces:
TrackingToken

public class GapAwareTrackingToken extends Object implements TrackingToken
Implementation of a TrackingToken that uses the global insertion sequence number of the event to determine tracking order and additionally stores a set of possible gaps that have been detected while tracking the event store.

By storing the sequence numbers of gaps, i.e. sequence numbers of events that may have been inserted but have not been committed to the store, consumers are able to track the event store uninterruptedly even when there are gaps in the sequence numbers of events. If a gap is detected the event store can check if meanwhile this gap has been filled each time a new batch of events is fetched.

Author:
Rene de Waele
  • Constructor Details

    • GapAwareTrackingToken

      @ConstructorProperties({"index","gaps"}) public GapAwareTrackingToken(long index, Collection<Long> gaps)
      This constructor is mean't to be used for deserialization.
      Please use newInstance(long, Collection) to create new instances.
      Parameters:
      index - the highest global sequence number of events up until (and including) this tracking token
      gaps - global sequence numbers of events that have not been seen yet even though these sequence numbers are smaller than the current index. These missing sequence numbers may be filled in later when those events get committed to the store or may never be filled in if those events never get committed.
  • Method Details

    • newInstance

      public static GapAwareTrackingToken newInstance(long index, Collection<Long> gaps)
      Returns a new GapAwareTrackingToken instance based on the given index and collection of gaps.
      Parameters:
      index - the highest global sequence number of events up until (and including) this tracking token
      gaps - global sequence numbers of events that have not been seen yet even though these sequence numbers are smaller than the current index. These missing sequence numbers may be filled in later when those events get committed to the store or may never be filled in if those events never get committed.
      Returns:
      a new tracking token from given index and gaps
    • createSortedSetOf

      protected static SortedSet<Long> createSortedSetOf(Collection<Long> gaps, long index)
      Construct a SortedSet of the given gaps to be set in this Tracking Token. The given index will be consolidated to ensure the last gap in the set is smaller. If this is not the case, an IllegalArgumentException is thrown
      Parameters:
      gaps - the Collection of gaps to created a SortedSet out of
      index - a long which is required to be bigger than the last known gap in the set
      Returns:
      a SortedSet constructed out of the given gaps
    • advanceTo

      public GapAwareTrackingToken advanceTo(long index, int maxGapOffset)
      Returns a new GapAwareTrackingToken instance based on this token but which has advanced to given index. Gaps that have fallen behind the index by more than the maxGapOffset will not be included in the new token.

      Note that the given index should be one of the current token's gaps or be higher than the current token's index.

      If allowGaps is set to false, any gaps that occur before the given index are removed from the returned token.

      Parameters:
      index - the global sequence number of the next event
      maxGapOffset - the maximum distance between a gap and the token's index
      Returns:
      the new token that has advanced from the current token
    • withGapsTruncatedAt

      public GapAwareTrackingToken withGapsTruncatedAt(long truncationPoint)
      Returns a copy of the current token, with gaps truncated at the given truncationPoint. This removes any gaps with index strictly smaller than the truncationPoint and disregards these when comparing this token to any other tokens.

      Note that truncation information is not serialized as part of the token.

      Parameters:
      truncationPoint - The index up to (and including) which gaps are to be disregarded.
      Returns:
      a Token without any gaps strictly smaller than given truncationPoint
    • getIndex

      public long getIndex()
      Get the highest global sequence of events seen up until the point of this tracking token.
      Returns:
      the highest global event sequence number seen so far
    • getGaps

      public SortedSet<Long> getGaps()
      Get a SortedSet of this token's gaps.
      Returns:
      the gaps of this token
    • lowerBound

      public GapAwareTrackingToken lowerBound(TrackingToken other)
      Description copied from interface: TrackingToken
      Returns a token that represents the lower bound between this and the other token. Effectively, the returned token will cause events not received by both this and the other token to be redelivered.
      Specified by:
      lowerBound in interface TrackingToken
      Parameters:
      other - The token to compare to this one
      Returns:
      The token representing the lower bound of the two
    • upperBound

      public TrackingToken upperBound(TrackingToken otherToken)
      Description copied from interface: TrackingToken
      Returns the token that represents the furthest possible position in a stream that either this token or the given other represents. Effectively, this means this token will only deliver events that neither this, nor the other have been received.
      Specified by:
      upperBound in interface TrackingToken
      Parameters:
      otherToken - The token to compare this token to
      Returns:
      a token that represents the furthest position of this or the other stream
    • covers

      public boolean covers(TrackingToken other)
      Description copied from interface: TrackingToken
      Indicates whether this token covers the other token completely. That means that this token represents a position in a stream that has received all the events that a stream represented by the other token has received.

      Note that this operation is only safe when comparing tokens obtained from events from the same StreamableEventSource.

      Specified by:
      covers in interface TrackingToken
      Parameters:
      other - The token to compare to this one
      Returns:
      true if this token covers the other, otherwise false
    • samePositionAs

      public boolean samePositionAs(TrackingToken other)
      Indicates whether this token is at the exact same spot in the event stream as the other token.

      This method is particularly useful when comparing tokens from different points in time, such as during replay detection, where token implementations may naturally differ.

      By default, this method checks bidirectional coverage: this.covers(other) && other.covers(this), which ensures both tokens are at the same position.

      For GapAwareTrackingToken, this method only compares the index positions, ignoring the gap structures. This is useful when comparing tokens from different points in time, where gap structures may naturally differ.

      The method returns true if both tokens have the same index value.

      Specified by:
      samePositionAs in interface TrackingToken
      Parameters:
      other - The token to validate against this token.
      Returns:
      true if this token is at the same location as the other token, otherwise false. Returns false if other is null.
      See Also:
    • hasGaps

      public boolean hasGaps()
      Check if this token contains one ore more gaps.
      Returns:
      true if this token contains gaps, false otherwise
    • equals

      public boolean equals(Object o)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • toString

      public String toString()
      Overrides:
      toString in class Object
    • position

      public OptionalLong position()
      Description copied from interface: TrackingToken
      Return the estimated relative position this token represents. In case no estimation can be given an OptionalLong.empty() will be returned.
      Specified by:
      position in interface TrackingToken
      Returns:
      the estimated relative position of this token