Class CausalPast

java.lang.Object
io.github.tobyjamesclements.parsley.session.CausalPast

public final class CausalPast extends Object
A causal past carried at the edge of the pipeline: a session token held by a client, or the recorded past stored beside a projected row.

Both are the same object — a frontier of (channel, position) pairs — used from two sides of one comparison: coverageOf(CausalPast) answers whether the past recorded against served data accounts for everything a client's token names. A write tier stamps a validated token onto produced messages as causes; a read tier refuses to serve data whose recorded past does not cover the token, and refreshes the token by merging in what it served. That buys session consistency — read-your-writes, monotonic reads, writes-follow-reads — for participants outside the delivery protocol (issue #96).

The wire form is the frozen causes grammar itself (CausesCodec), so decode(byte[]) is exactly as strict as the engine's own header decode: a token that is truncated, miscounted, padded or out of canonical order is refused, never salvaged. A salvaging token parser is the same hazard as a salvaging codec — a weaker frontier read from damaged bytes silently weakens the session guarantee.

Coverage deliberately inverts the delivery gate's disposition towards unknown channels. Deliverability.decide(Causes, Set, Deliverability.SettledView) skips a cause on a channel outside the received set, because a gate that waited for what it will never see would wait forever. A read tier is not a gate: a channel its recorded past cannot verify must mean do not serve, not serve anyway. Every channel a token names is therefore checked, and a channel the past has never recorded is reported as a gap.

Instances are immutable; merge(ChannelId, long) and merge(CausalPast) return new pasts. The engine never reads this type: it is a companion over the public surface, not part of the delivery protocol, and holding one grants no delivery guarantee.

See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    The outcome of one coverage check.
  • Method Summary

    Modifier and Type
    Method
    Description
    Returns the frontier this past carries.
    Decides whether this past covers a token: whether everything the token names is at or below what this past records.
    static CausalPast
    decode(byte[] encoded)
    Decodes a past from the frozen wire grammar, exactly as strictly as the engine decodes a parsley.causes header.
    byte[]
    Encodes this past in the frozen wire grammar.
    boolean
     
    int
    Returns a hash consistent with equals(Object).
    boolean
    Returns true when this past names no channel.
    merge(ChannelId channel, long position)
    Merges one observed coordinate: the delivered message's own (channel, position) at a projector's seam, or the coordinate a produce acknowledgement confirmed at a write tier.
    Merges another past pointwise: per channel, the greater position wins.
    static CausalPast
    The empty past: a session that has observed nothing.
    static CausalPast
    of(Causes causes)
    Builds a past over an existing frontier.
    int
    Returns how many channels this past names.
    Returns the past rendered for diagnostics.

    Methods inherited from class Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Method Details

    • none

      public static CausalPast none()
      The empty past: a session that has observed nothing.
      Returns:
      a past naming no channel
    • of

      public static CausalPast of(Causes causes)
      Builds a past over an existing frontier.
      Parameters:
      causes - the frontier to carry
      Returns:
      the past
      Throws:
      IllegalArgumentException - if causes is null
    • decode

      public static CausalPast decode(byte[] encoded) throws CausesCodec.UndecodableMetadataException
      Decodes a past from the frozen wire grammar, exactly as strictly as the engine decodes a parsley.causes header.
      Parameters:
      encoded - the encoded past, as encode() produced it or as read from a record's CausesCodec.HEADER_KEY header
      Returns:
      the past
      Throws:
      CausesCodec.UndecodableMetadataException - if the bytes cannot be trusted, for any of the reasons CausesCodec.decode(byte[]) names; a token that cannot be decoded must be treated as no token, never as a partial one
    • encode

      public byte[] encode()
      Encodes this past in the frozen wire grammar.

      The bytes are canonical — one past, one spelling — and are valid as a parsley.causes header value, which is what lets a write tier stamp a validated token straight onto a produced record.

      Returns:
      the encoded past
    • causes

      public Causes causes()
      Returns the frontier this past carries.
      Returns:
      the frontier this past carries
    • isEmpty

      public boolean isEmpty()
      Returns true when this past names no channel.
      Returns:
      true when this past names no channel
    • size

      public int size()
      Returns how many channels this past names.

      Bound this, and the encoded width, before trusting an inbound token: a token is untrusted input even when this application minted it.

      Returns:
      how many channels this past names
    • merge

      public CausalPast merge(ChannelId channel, long position)
      Merges one observed coordinate: the delivered message's own (channel, position) at a projector's seam, or the coordinate a produce acknowledgement confirmed at a write tier.
      Parameters:
      channel - the channel observed
      position - the position observed on it
      Returns:
      a past carrying the greater of position and any position already named for channel; this instance is unchanged, and is returned itself when it already covers the coordinate
      Throws:
      IllegalArgumentException - if channel is null or position is negative or the reserved maximum no channel assigns
    • merge

      public CausalPast merge(CausalPast other)
      Merges another past pointwise: per channel, the greater position wins. This is how a read tier folds the served data's recorded past into the client's token before re-minting it.
      Parameters:
      other - the past to merge in
      Returns:
      a past covering both; this instance is unchanged, and when either side already covers the other — the steady state of a session re-reading settled data — that side is returned itself, so an unchanged token need not be re-encoded
      Throws:
      IllegalArgumentException - if other is null
    • coverageOf

      public CausalPast.Coverage coverageOf(CausalPast token)
      Decides whether this past covers a token: whether everything the token names is at or below what this past records.

      The check reuses the core's decision (Deliverability.decide(Causes, Set, Deliverability.SettledView)) with the token's own channel set as the received set, so no channel is skippable: a channel this past has never recorded fails the check with an empty recorded position, where the delivery gate would have skipped it. Serving on an unverifiable channel is exactly the read-your-writes violation this type exists to prevent, so the error here is always in the conservative direction — a refusal to serve, never a stale serve.

      Parameters:
      token - the past that must be accounted for, typically a client's session token
      Returns:
      the verdict, naming every gap when this past falls short
      Throws:
      IllegalArgumentException - if token is null
    • equals

      public boolean equals(Object o)
      Overrides:
      equals in class Object
      Parameters:
      o - the object to compare against
      Returns:
      true when o is a past carrying an equal frontier
    • hashCode

      public int hashCode()
      Returns a hash consistent with equals(Object).
      Overrides:
      hashCode in class Object
      Returns:
      a hash consistent with equals(Object)
    • toString

      public String toString()
      Returns the past rendered for diagnostics.
      Overrides:
      toString in class Object
      Returns:
      the past rendered for diagnostics