All Implemented Interfaces:
Runnable

class IdleCheckerextends SimpleTimer2.TimedEvent
Periodically ramp the tunnel count with connected peers, and reduce it once nothing is running. We can't use the I2CP idle detector because it's based on traffic, so DHT and announces would keep it non-idle.

The floor is keyed on whether a torrent is *running*, not on the peer count: a started torrent with no peers yet is still announcing, still DHT-serving and still holding a LeaseSet, and dropping its tunnels out from under it would stall every one of those. Peers only ever raise a count above its floor.

Each session is floored independently at MIN_TUNNEL_QTY in each direction. In single-destination mode that is one shared session, which also carries the trackers, the DHT and the announces, so it is floored whenever any torrent runs at all. Under multi-dest the shared session is joined by one destination per pool (or per torrent), and each of those keeps its own floor for as long as it still has torrents assigned - a pool is never dragged below 2/2 because a sibling pool is busy, nor raised because one is.

Reducing is hysteretic and one-directional per check: growth applies immediately, while a reduction has to be wanted for SHRINK_HYSTERESIS consecutive checks. BitTorrent peer counts swing across any threshold within a few seconds, so recomputing a target from peerCount / 2 every CHECK_TIME ms and pushing it at the router made the pool oscillate, and every oscillation is a ReconfigureSessionMessage that destroys the surplus tunnels outright rather than letting them expire.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private final Object
    Guards the idle state.
    private final Log
    Logger for this class.
    private int
    Consecutive checks in which no torrent was running; drives the shrink hysteresis.
    private final PeerCoordinatorSet
    The coordinators that get stopped when idle.
    private int
    Quantity last pushed to the shared session, which is also its floor.
    private final I2PSnarkUtil
    The torrent being watched.
    private static final long
    Quiet time that counts as idle - 63 seconds.
    private static final int
    Tunnels held in each direction while any torrent is running.
    (package private) static final int
    decideQuantity(int, int, int) return value meaning the session should be left alone.
    private static final int
    Connected peers per tunnel; two peers share one tunnel in each direction.
    private static final int
    Consecutive checks with no running torrent required before reducing.

    Fields inherited from class SimpleTimer2.TimedEvent

    _state, DEFAULT_FUZZ
    Modifier and Type
    Field
    Description
    State of the current event.
    protected static final int
    Default fuzz threshold in milliseconds.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Caller must schedule.
  • Method Summary

    Modifier and Type
    Method
    Description
    private void
    applyToPool(TorrentDest td, boolean live, int peers)
    Applies the decided quantity to one pool's own session, if it changed.
    private void
    applyToSharedSession(boolean anyRunning, int peerCount)
    Applies the decided quantity to the shared session, if it changed.
    private void
    applyTunnels(int inQty, int outQty, int inBackup, int outBackup, I2PSocketManager mgr)
    Send one reconfiguration to a single session.
    private static int
    Parse a configured backup quantity, defaulting to zero when absent or unparseable.
    (package private) static int
    decideQuantity(int peerCount, int currentQuantity, int noRunningConsec)
    Decide whether to reconfigure the session's tunnel quantity.
    (package private) static int
    desiredQuantity(int peerCount)
    The tunnel count to hold in each direction given the connected peers, never below the floor.
    int
    The inbound tunnel count currently applied to the shared session.
    int
    The outbound tunnel count currently applied to the shared session.
    private void
    Reacts to the idle timeout, with the lock held.
    private void
    logGrowth(int target)
    Note a tunnel increase for the console or the standalone log.
    private int
    peersIn(TorrentDest td, int poolIndex)
    Connected peers belonging to torrents assigned to a pool, so each pool's tunnel count is driven by its own members rather than by the whole client.
    private void
    reduceTunnels(int current)
    Reduces the shared session to the floor of 2 in / 2 out once nothing is running, so tracker and DHT traffic keep a usable path while idle.
    private void
    setTunnels(int target, boolean increased)
    Apply a quantity to the shared session, logging growth.
    private void
    setTunnels(TorrentDest td, int target, boolean increased)
    Apply a quantity to one pool's own session.
    void
    Called when this event's scheduled time arrives.

    Methods inherited from class SimpleTimer2.TimedEvent

    cancel, forceReschedule, reschedule, reschedule, run, schedule, setFuzz, setPool, toString
    Modifier and Type
    Method
    Description
    boolean
    Cancel the timed event.
    void
    forceReschedule(long timeoutMs)
    Always use the new time - ignores fuzz.
    void
    reschedule(long timeoutMs)
    Use the earliest of the new time and the old time May be called from within timeReached(), but schedule() is better there.
    void
    reschedule(long timeoutMs, boolean useEarliestTime)
    May be called from within timeReached(), but schedule() is better there.
    void
    run()
    void
    schedule(long timeoutMs)
    Schedule this event.
    void
    setFuzz(int fuzz)
    Reschedule threshold in ms.
    void
    Timer pool for this event.
    Timer summary for log messages.

    Methods inherited from class Object

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

    • _util

      private final I2PSnarkUtil _util
      The torrent being watched.
    • _pcs

      private final PeerCoordinatorSet _pcs
      The coordinators that get stopped when idle.
    • _log

      private final Log _log
      Logger for this class.
    • _noRunningConsec

      private int _noRunningConsec
      Consecutive checks in which no torrent was running; drives the shrink hysteresis.
    • _sharedQuantity

      private int _sharedQuantity
      Quantity last pushed to the shared session, which is also its floor.
    • _lock

      private final Object _lock
      Guards the idle state.
    • CHECK_TIME

      private static final long CHECK_TIME
      Quiet time that counts as idle - 63 seconds.
      See Also:
    • SHRINK_HYSTERESIS

      private static final int SHRINK_HYSTERESIS
      Consecutive checks with no running torrent required before reducing. Growth is immediate; only the destructive direction waits.
      See Also:
    • PEERS_PER_TUNNEL

      private static final int PEERS_PER_TUNNEL
      Connected peers per tunnel; two peers share one tunnel in each direction.
      See Also:
    • MIN_TUNNEL_QTY

      private static final int MIN_TUNNEL_QTY
      Tunnels held in each direction while any torrent is running. Matches the cap I2PSnarkUtil applies when the session is created, so the floor is never a surprise.
      See Also:
    • NO_CHANGE

      static final int NO_CHANGE
      decideQuantity(int, int, int) return value meaning the session should be left alone.
      See Also:
  • Constructor Details

    • IdleChecker

      public IdleChecker(SnarkManager mgr, PeerCoordinatorSet pcs)
      Caller must schedule.
      Parameters:
      mgr - the SnarkManager providing the util and owning this timer
      pcs - the peer set whose connectivity state decides whether tunnels may be released
  • Method Details

    • timeReached

      public void timeReached()
      Description copied from class: SimpleTimer2.TimedEvent
      Called when this event's scheduled time arrives. Must NOT block. For periodic events, call schedule(period) at the end to self-reschedule.
      Specified by:
      timeReached in class SimpleTimer2.TimedEvent
    • locked_timeReached

      private void locked_timeReached()
      Reacts to the idle timeout, with the lock held.
    • applyToSharedSession

      private void applyToSharedSession(boolean anyRunning, int peerCount)
      Applies the decided quantity to the shared session, if it changed.
      Parameters:
      anyRunning - whether any torrent is running
      peerCount - peers across all running torrents
    • applyToPool

      private void applyToPool(TorrentDest td, boolean live, int peers)
      Applies the decided quantity to one pool's own session, if it changed.
      Parameters:
      td - the pool whose applied quantity is compared and, if it differs, the new one is written to
      live - whether the pool has a running torrent
      peers - peers connected across the pool's torrents
    • peersIn

      private int peersIn(TorrentDest td, int poolIndex)
      Connected peers belonging to torrents assigned to a pool, so each pool's tunnel count is driven by its own members rather than by the whole client.
      Parameters:
      td - the pool whose assigned torrents are scanned
      poolIndex - the pool index to match torrents against, or -1 to match a dedicated destination by its info hash instead
      Returns:
      peers connected across the pool's torrents
    • desiredQuantity

      static int desiredQuantity(int peerCount)
      The tunnel count to hold in each direction given the connected peers, never below the floor.
      Parameters:
      peerCount - total connected peers across all running torrents
      Returns:
      the desired quantity in each direction, at least MIN_TUNNEL_QTY
    • decideQuantity

      static int decideQuantity(int peerCount, int currentQuantity, int noRunningConsec)
      Decide whether to reconfigure the session's tunnel quantity.

      Pure decision logic, split out so it can be exercised without a router. The quantity currently applied is taken as a parameter rather than read from the configured options: I2PSnarkUtil caps the session at MIN_TUNNEL_QTY when it is created, while the configured options still read the operator's larger figure. Comparing against the configured value made every check believe the pool was oversized and reissue a reconfiguration, so the applied quantity is passed in.

      Parameters:
      peerCount - total connected peers across all running torrents
      currentQuantity - quantity most recently applied to the session
      noRunningConsec - consecutive checks that have found no running torrent
      Returns:
      the new quantity to apply in each direction, or NO_CHANGE to leave the session alone
    • reduceTunnels

      private void reduceTunnels(int current)
      Reduces the shared session to the floor of 2 in / 2 out once nothing is running, so tracker and DHT traffic keep a usable path while idle. Never re-sends a value the session already holds, because the reconfigure handler rebuilds the pool regardless of whether anything changed.
      Parameters:
      current - the quantity the shared session currently holds
    • setTunnels

      private void setTunnels(int target, boolean increased)
      Apply a quantity to the shared session, logging growth. The shared session also carries the trackers, DHT and announces, so it is floored whenever any torrent is running.
      Parameters:
      target - the new quantity in each direction
      increased - whether this is a growth, for logging
    • setTunnels

      private void setTunnels(TorrentDest td, int target, boolean increased)
      Apply a quantity to one pool's own session. Each pool is floored independently, so this never writes to the shared session or to any sibling pool.
      Parameters:
      td - the pool whose own session receives the new quantity
      target - the new quantity in each direction
      increased - whether this is a growth, for logging
    • backupQuantity

      private static int backupQuantity(String raw)
      Parse a configured backup quantity, defaulting to zero when absent or unparseable.
      Parameters:
      raw - the configured value, may be null
      Returns:
      the backup quantity, never negative
    • logGrowth

      private void logGrowth(int target)
      Note a tunnel increase for the console or the standalone log.
      Parameters:
      target - the new quantity in each direction
    • applyTunnels

      private void applyTunnels(int inQty, int outQty, int inBackup, int outBackup, I2PSocketManager mgr)
      Send one reconfiguration to a single session. Deliberately one session at a time: batching every pool onto one ReconfigureSessionMessage is what made a busy sibling look like an idle one.
      Parameters:
      inQty - the inbound tunnel quantity
      outQty - the outbound tunnel quantity
      inBackup - the inbound backup quantity
      outBackup - the outbound backup quantity
      mgr - the manager of the session, or null
    • getActiveInboundCount

      public int getActiveInboundCount()
      The inbound tunnel count currently applied to the shared session.
      Returns:
      the active inbound count, never below MIN_TUNNEL_QTY
    • getActiveOutboundCount

      public int getActiveOutboundCount()
      The outbound tunnel count currently applied to the shared session. Inbound and outbound are always pushed together, so this matches getActiveInboundCount().
      Returns:
      the active outbound count, never below MIN_TUNNEL_QTY