- All Implemented Interfaces:
Runnable
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
FieldsModifier and TypeFieldDescriptionprivate final ObjectGuards the idle state.private final LogLogger for this class.private intConsecutive checks in which no torrent was running; drives the shrink hysteresis.private final PeerCoordinatorSetThe coordinators that get stopped when idle.private intQuantity last pushed to the shared session, which is also its floor.private final I2PSnarkUtilThe torrent being watched.private static final longQuiet time that counts as idle - 63 seconds.private static final intTunnels held in each direction while any torrent is running.(package private) static final intdecideQuantity(int, int, int)return value meaning the session should be left alone.private static final intConnected peers per tunnel; two peers share one tunnel in each direction.private static final intConsecutive checks with no running torrent required before reducing.Fields inherited from class SimpleTimer2.TimedEvent
_state, DEFAULT_FUZZModifier and TypeFieldDescriptionprotected SimpleTimer2.TimedEventStateState of the current event.protected static final intDefault fuzz threshold in milliseconds.Constructor Summary
ConstructorsMethod Summary
Modifier and TypeMethodDescriptionprivate voidapplyToPool(TorrentDest td, boolean live, int peers) Applies the decided quantity to one pool's own session, if it changed.private voidapplyToSharedSession(boolean anyRunning, int peerCount) Applies the decided quantity to the shared session, if it changed.private voidapplyTunnels(int inQty, int outQty, int inBackup, int outBackup, I2PSocketManager mgr) Send one reconfiguration to a single session.private static intbackupQuantity(String raw) Parse a configured backup quantity, defaulting to zero when absent or unparseable.(package private) static intdecideQuantity(int peerCount, int currentQuantity, int noRunningConsec) Decide whether to reconfigure the session's tunnel quantity.(package private) static intdesiredQuantity(int peerCount) The tunnel count to hold in each direction given the connected peers, never below the floor.intThe inbound tunnel count currently applied to the shared session.intThe outbound tunnel count currently applied to the shared session.private voidReacts to the idle timeout, with the lock held.private voidlogGrowth(int target) Note a tunnel increase for the console or the standalone log.private intpeersIn(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 voidreduceTunnels(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 voidsetTunnels(int target, boolean increased) Apply a quantity to the shared session, logging growth.private voidsetTunnels(TorrentDest td, int target, boolean increased) Apply a quantity to one pool's own session.voidCalled when this event's scheduled time arrives.Methods inherited from class SimpleTimer2.TimedEvent
cancel, forceReschedule, reschedule, reschedule, run, schedule, setFuzz, setPool, toStringModifier and TypeMethodDescriptionbooleancancel()Cancel the timed event.voidforceReschedule(long timeoutMs) Always use the new time - ignores fuzz.voidreschedule(long timeoutMs) Use the earliest of the new time and the old time May be called from within timeReached(), but schedule() is better there.voidreschedule(long timeoutMs, boolean useEarliestTime) May be called from within timeReached(), but schedule() is better there.voidrun()voidschedule(long timeoutMs) Schedule this event.voidsetFuzz(int fuzz) Reschedule threshold in ms.voidsetPool(SimpleTimer2 pool) Timer pool for this event.toString()Timer summary for log messages.
Field Details
_util
The torrent being watched._pcs
The coordinators that get stopped when idle._log
Logger for this class._noRunningConsec
private int _noRunningConsecConsecutive checks in which no torrent was running; drives the shrink hysteresis._lock
Guards the idle state.CHECK_TIME
private static final long CHECK_TIMEQuiet time that counts as idle - 63 seconds.- See Also:
SHRINK_HYSTERESIS
private static final int SHRINK_HYSTERESISConsecutive 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_TUNNELConnected peers per tunnel; two peers share one tunnel in each direction.- See Also:
MIN_TUNNEL_QTY
private static final int MIN_TUNNEL_QTYTunnels held in each direction while any torrent is running. Matches the capI2PSnarkUtilapplies when the session is created, so the floor is never a surprise.- See Also:
NO_CHANGE
static final int NO_CHANGEdecideQuantity(int, int, int)return value meaning the session should be left alone.- See Also:
Constructor Details
IdleChecker
Caller must schedule.- Parameters:
mgr- the SnarkManager providing the util and owning this timerpcs- the peer set whose connectivity state decides whether tunnels may be released
Method Details
timeReached
public void timeReached()Description copied from class:SimpleTimer2.TimedEventCalled when this event's scheduled time arrives. Must NOT block. For periodic events, call schedule(period) at the end to self-reschedule.- Specified by:
timeReachedin classSimpleTimer2.TimedEvent
locked_timeReached
private void locked_timeReached()Reacts to the idle timeout, with the lock held.applyToPool
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 tolive- whether the pool has a running torrentpeers- peers connected across the pool's torrents
peersIn
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 scannedpoolIndex- 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:
I2PSnarkUtilcaps the session atMIN_TUNNEL_QTYwhen 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 torrentscurrentQuantity- quantity most recently applied to the sessionnoRunningConsec- consecutive checks that have found no running torrent- Returns:
- the new quantity to apply in each direction, or
NO_CHANGEto 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 directionincreased- whether this is a growth, for logging
setTunnels
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 quantitytarget- the new quantity in each directionincreased- whether this is a growth, for logging
backupQuantity
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
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 quantityoutQty- the outbound tunnel quantityinBackup- the inbound backup quantityoutBackup- the outbound backup quantitymgr- 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 matchesgetActiveInboundCount().- Returns:
- the active outbound count, never below
MIN_TUNNEL_QTY