java.lang.Object
net.i2p.router.peermanager.ProtocolRttBaseline

public class ProtocolRttBaselineextends Object
A latency baseline for one transport, built from the round trip times that transport has actually measured.

Purpose: an absolute millisecond threshold cannot judge two transports at once. A threshold tuned for NTCP2 is either unreachable for SSU2, so every SSU2 peer looks slow, or so loose for NTCP2 that it admits links that cause build timeouts. The penalty is structural rather than a property of the peer, so the peer is excluded for carrying the protocol it happens to speak. Per-protocol baselines remove that: each transport is judged against what it can achieve on its own.

The baseline is the mean of the SAMPLES_FOR_BASELINE fastest retained samples, not of all of them. This is the same estimator TCP uses to derive its floor for retransmission timeout, and it is chosen here for one property: it tracks what the transport has recently achieved. A mean over every sample would follow the population upward as the network degrades, so the bar would relax precisely when quality matters most, and a peer becoming slow would be scored against a baseline that had already drifted to accommodate it. Keying on the floor keeps the bar steady while the tail is allowed to move.

The trade-off is deliberate and worth stating: the floor only ever reflects the best links seen recently, so if an entire path to one protocol degrades, the baseline stays optimistic and its peers score worse. That is the intended reading - degradation should show up - but it means the baseline is not relative to current conditions.

Instances are not thread-safe. The intended lifecycle is one instance per transport, built once per sampling cycle from that cycle's measurements, then read for the duration of the cycle.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    Upper bound on retained samples.
    static final int
    How many of the fastest retained samples the baseline averages.
    static final int
    Samples required before a baseline is published at all.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Create an empty baseline.
    ProtocolRttBaseline(int capacity)
    Create an empty baseline with a specific ring size.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    add(int rttMs)
    Add a measured round trip time.
    (package private) static long
    baselineMs(int[] samples, int count)
    Mean of the fastest samples.
    long
    The calibrated floor for this transport, or -1 when unknown.
    long
    getClampedBaselineMs(long floorMs, int multiple)
    The calibrated floor, clamped so it can never fall below floorMs / multiple.
    int
    Number of retained samples.
    boolean
    Whether enough samples exist for a baseline to mean anything.
    (package private) static boolean
    withinBaseline(int rttMs, long baselineMs, int multiple)
    Whether a measurement qualifies against a calibrated baseline.

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • SAMPLES_FOR_BASELINE

      public static final int SAMPLES_FOR_BASELINE
      Samples required before a baseline is published at all. Below this the estimator reports unknown and callers fall back to their absolute rules, so a cold or thinly-populated transport behaves exactly as it did before calibration existed.
      See Also:
    • MAX_SAMPLES

      public static final int MAX_SAMPLES
      Upper bound on retained samples. Only the recent past is wanted, so the buffer is a ring rather than a growing list: a long-lived router would otherwise accumulate every sample it has ever seen and the floor would stop moving.
      See Also:
    • SAMPLES_AVERAGED

      public static final int SAMPLES_AVERAGED
      How many of the fastest retained samples the baseline averages. Equal to SAMPLES_FOR_BASELINE, which is what makes the estimator defined: a baseline is the mean of a fixed count, so it does not drift as samples accumulate.
      See Also:
  • Constructor Details

    • ProtocolRttBaseline

      public ProtocolRttBaseline()
      Create an empty baseline.
    • ProtocolRttBaseline

      public ProtocolRttBaseline(int capacity)
      Create an empty baseline with a specific ring size.
      Parameters:
      capacity - how many samples to retain; must be at least SAMPLES_AVERAGED for a baseline to be possible
  • Method Details

    • add

      public void add(int rttMs)
      Add a measured round trip time. Non-positive and overflow values are ignored, so a caller cannot poison the population with a measurement that means "unknown" or one that cannot be an int.
      Parameters:
      rttMs - measured round trip time in ms
    • getSampleCount

      public int getSampleCount()
      Number of retained samples.
      Returns:
      the sample count, between 0 and the ring capacity
    • isKnown

      public boolean isKnown()
      Whether enough samples exist for a baseline to mean anything.
      Returns:
      true if at least SAMPLES_FOR_BASELINE samples are held
    • getBaselineMs

      public long getBaselineMs()
      The calibrated floor for this transport, or -1 when unknown.

      Returns -1 rather than a guess below SAMPLES_FOR_BASELINE samples. Callers must treat that as "no calibrated opinion available" and fall back to their absolute rules - never as "this peer is fine".

      Returns:
      the mean of the fastest samples in ms, or -1 if unknown
    • getClampedBaselineMs

      public long getClampedBaselineMs(long floorMs, int multiple)
      The calibrated floor, clamped so it can never fall below floorMs / multiple.

      The clamp is the guard against a freakishly low population tightening the bar below what an absolute rule would have used. A single 1 ms sample among fifty would otherwise put the baseline at a few milliseconds and make the multiple threshold far stricter than the absolute floor it replaces. With the clamp the calibrated bar is always at least as permissive as the absolute one, so introducing calibration can only widen the set of qualifying peers, never narrow it.

      Parameters:
      floorMs - the absolute low-latency floor in ms
      multiple - the multiple of the baseline a peer must stay under
      Returns:
      the clamped baseline in ms, or -1 if unknown
    • baselineMs

      static long baselineMs(int[] samples, int count)
      Mean of the fastest samples. Pure over an array plus a count, so the selection rule is testable without constructing a baseline.
      Parameters:
      samples - the retained samples
      count - how many entries of samples are valid
      Returns:
      the mean of the fastest SAMPLES_AVERAGED entries, or -1 when fewer than that are valid
    • withinBaseline

      static boolean withinBaseline(int rttMs, long baselineMs, int multiple)
      Whether a measurement qualifies against a calibrated baseline.

      Never true when the baseline is unknown, so a caller cannot treat a missing baseline as permission.

      Parameters:
      rttMs - the measured round trip time in ms
      baselineMs - the calibrated baseline in ms, or -1 when unknown
      multiple - how many times the baseline a peer may sit under
      Returns:
      true if the measurement is within the calibrated bar