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

public class ProfileOrganizerextends Object
Categorizes peers into performance tiers (fast, high-capacity, well-integrated) based on historical metrics from PeerProfile. Requires periodic reorganize() calls to update peer classifications for optimal tunnel selection.

Tier assignment during reorganize(): 1. All profiles are iterated in capacity order (via InverseCapacityComparator) 2. Expired/unreachable/low-bandwidth peers are filtered out 3. Speed, capacity, and integration thresholds are recalculated from the active set 4. Each surviving profile is evaluated via lockedPromoteProfileToTiers() 5. If fast/high-cap tiers fall below minimum thresholds, fallback passes fill gaps (with selectability checks to prevent selecting unusable peers)

A promotion whose RouterInfo has aged past PROP_ROUTERINFO_REFRESH_AGE_MS and which has no proof of life is held back: the peer is left out of the tier until a newer publication arrives on its own. Nothing is fetched on the peer's behalf, unless holding the promotion would starve the tier it would have joined — see shouldDeferPromotionOnStaleRouterInfo(int, int).

Concurrency: ReentrantReadWriteLock protects all tier maps. reorganize() acquires the write lock; selection methods use the read lock. getOrCreateProfileNonblocking() uses try-lock escalation so a read path never blocks on the write lock.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    (package private) static enum 
    Why a peer was evicted from a tier.
    static enum 
    Defines peer selection slicing modes for tier-based peer organization.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static int
    Fast tier ceiling, in peers.
    static int
    High-capacity tier ceiling, in peers.
    static int
    Runtime-adjustable default max profile count.
    static int
    Fast tier refill target, in peers, as last configured or autotuned.
    static int
    High-capacity tier refill target, in peers, as last configured or autotuned.
    static final int
    Ceiling on profiles held in memory, in profiles.
    static final double
    Threshold below which the network is considered under attack.
    static final int
    Default minimum packet sample size (20 = full 5% bucket resolution).
    static final int
    Default RouterInfo age past which a RouterInfo is treated as stale and must show proof of life to be selected, in hours.
    (package private) static final int
    Default floor for candidates examined per selection.
    static final int
    Default high-capacity tier refill target, in peers.
    static final long
    One hour, i.e.
    static final long
    A strike older than this no longer counts, so a peer that recovered is not demoted by one later failure.
    static final int
    Unreachable first-hop failures needed inside the decay window before demoteIfUnreachable demotes.
    (package private) static final boolean
    Whether acceptance-based eviction applies to both tiers.
    (package private) static final boolean
    Whether fast-tier admission requires acceptable tunnel acceptance.
    (package private) static final boolean
    Whether high-capacity admission requires acceptable tunnel acceptance.
    (package private) static final int
    Upper bound, so a typo cannot turn selection into a full tier scan.
    (package private) static final int
    Upper bound on the soft-purge tier size, in peers.
    static final int
    Profile files retained on disk before surplus ones are trimmed.
    static final int
    Floor for the in-memory profile cap, in profiles.
    (package private) static final int
    Lifetime requests a peer needs before its acceptance ratio may exclude it.
    static final String
    Config property for the minimum number of transmitted packets before a loss ratio is reported.
    static final String
    Config property for the decayed loss score above which a peer is de-prioritized in tier selection (soft signal, below the demotion threshold).
    static final String
    Config property for the loss ratio above which a peer is demoted from fast/high-cap tiers.
    static final String
    Config property for how long a reported loss ratio stays fresh.
    static final String
    Property key for the calibrated low-latency multiple.
    static final String
    Config property for the maximum number of peer profiles.
    static final String
    Property key naming the RouterInfo age past which a RouterInfo is treated as stale and must show proof of life to be selected, in hours.
    static final String
    Property key naming the fast tier's ceiling.
    static final String
    Property key naming the high-capacity tier's ceiling.
    static final String
    Property for the floor; see getMinCandidateSample(RouterContext).
    static final String
    Property key naming the fast tier's refill target.
    static final String
    Property key naming the high-capacity tier's refill target.
    static final String
    Property key naming the RouterInfo age past which a tier promotion is held back, in ms.
    (package private) static final int
    Network size above which tier thresholds scale with the network instead of staying at their configured default.
    (package private) static final long
    Shortest gap between two full tier-refill scans.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Creates a profile organizer with empty tier maps and registers performance tracking statistics for peer classification.
  • Method Summary

    Modifier and Type
    Method
    Description
    (package private) static boolean
    aboveRttCeiling(PeerProfile profile, long rttCeilingMs)
    True if the peer's measured tunnel-test RTT exceeds the adaptive selection ceiling, indicating it should be excluded from this fast-tier pick while still remaining in the tier (soft signal.
    Insert a fully-constructed profile into the organizer.
    (package private) static long
    applyBaselineMultiple(long baselineMs, int multiple)
    Scale a calibrated baseline into the latency a peer may sit under and still count as low latency.
    (package private) static int
    clampMaxProfiles(int maxProfiles)
    Clamps the configured max-profiles value into [100, ABSOLUTE_MAX_PROFILES].
    (package private) void
    Remove all profiles and clear all tier maps.
    (package private) long
    computeAdaptiveRttCeiling(double boundaryRttMs, double buildSuccess)
    Compute the adaptive absolute-RTT ceiling for fast-tier selection, floored at 2× the startup baseline when build success is degraded.
    (package private) static long
    computeFastRttCeiling(double boundaryRttMs)
    Compute the adaptive absolute-RTT ceiling for fast-tier selection.
    int
    Count peers with any send or hear activity in the last 4 hours.
    int
    Count peers with activity (send, receive, or failure) within the last hour.
    (package private) static int
    countExceedingMean(double[] capacities, double meanCapacity)
    How many of the given capacities are strictly above the mean.
    int
    Number of peers classified as fast tier.
    int
    Number of peers classified as high-capacity tier.
    int
    Total number of peer profiles in memory (all tiers).
    (package private) static int
    countQualifying(Collection<PeerProfile> profiles, long now, double capacityThreshold)
    How many of the given profiles qualify for the speed-threshold ranking.
    (package private) static int
    defaultTierSize(int known, int base, int divisor)
    Fallback tier size for a threshold that scales with network size.
    void
    Batch-demote peers from fast/high-cap tiers under a single write lock.
    void
    Batch-remove peers from fast tier only, keeping them in high-cap.
    void
    Immediately demote a peer from fast/high-cap tiers.
    void
    Immediately demote a peer from fast/high-cap tiers.
    void
    Immediately demote a peer from fast/high-cap tiers.
    (package private) void
    demoteIfHighRTT(Hash peer, long responseTimeMs)
    Demote a peer from fast/high-cap tiers when its direct-link latency is poor.
    void
    Instantly remove a peer from the fast/high-capacity tiers when its decayed loss score exceeds the threshold, and mark it for loss probation.
    void
    Immediately demote a peer from the fast tier when a peer test shows it is no longer low-latency.
    void
    Immediately demote a peer from fast/high-cap tiers.
    (package private) void
    demoteIfSlowFirstHop(Hash peer, int firstHopRttMs)
    Remove a peer from the fast/high-cap tiers if its measured direct-link RTT reaches the low-latency threshold.
    void
    Immediately demote a peer from fast/high-cap tiers if its RouterInfo is stale and it has no recent proof of life (fails isSelectable).
    void
    Immediately demote a peer from fast/high-cap tiers when our transport connection to it failed as a tunnel first hop (unreachable).
    void
    Immediately demote a peer from fast/high-cap tiers on a single unreachable first hop, skipping the DEMOTE_STRIKE_THRESHOLD strikes and the cooldown that demoteIfUnreachable(Hash) requires.
    (package private) static boolean
    demotesFastTier(boolean inFast, boolean lowLatency)
    Whether losing the low-latency flag revokes membership of the fast tier.
    (package private) static String
    describeTierFill(String where, int fast, int fastTarget, int highCap, int highCapTarget, int examined, int alreadyTiered, int heldNoAddress, String skips)
    Summarise why the selection tiers could not be filled.
    (package private) void
    Evict profiles for peers no longer in the network database.
    (package private) static boolean
    excludedOnAcceptance(long agreed, long rejected, int minRequests, boolean highStress)
    Whether a peer's tunnel acceptance is bad enough to exclude it, given its counts and the sample floor the tier in question applies.
    boolean
    Write a peer profile to the given output stream for persistence.
    (package private) static int
    fastActiveCap(int active, int base)
    Ceiling on the fast tier from the number of reachable peers.
    (package private) int
    Peers in either the fast or the high-capacity tier, counting each peer once.
    (package private) static boolean
    firstHopRttIsSlow(int firstHopRttMs, int thresholdMs)
    Whether a measured first-hop RTT warrants removal from the fast tiers.
    int
    Profiles with recent activity, as of the last completed reorganisation.
    float
    Average loss ratio across the fast and high-capacity tiers with a fresh measurement, as a fraction (0.0 - 1.0).
    float
    Calibrated latency floor across fast peers with data, computed during each reorganize() as the mean of the fastest samples rather than of the whole population.
    (package private) long
    The calibrated latency floor for a transport style, or -1 when that transport has not gathered enough samples to have an opinion.
    (package private) long
    The calibrated latency floor for a peer, choosing the style of the transport that measured it.
    (package private) long
    The qualifying latency threshold for a peer, from the calibrated baseline of the transport that measured it.
    double
    Current minimum capacity value for the high-capacity peer tier.
    (package private) long
    The qualifying latency threshold for the fast cohort, from the cohort baseline of its fastest members.
    static int
    Ceiling on the fast tier.
    static int
    Ceiling on the high-capacity tier.
    static int
    Profile count the reorganizer targets by default.
    static int
    Fast tier size the router refills toward.
    int
    The candidate-sample floor currently in effect, for logging.
    (package private) static double
    Selection penalty multiplier for peers between the soft and hard failure thresholds.
    float
    Average loss ratio across the fast tier with a fresh measurement, as a fraction (0.0 - 1.0); 0.0 if none.
    int
    Live size of the fast or high-capacity union, a peer in both tiers counted once.
    int
    Current number of peers in the fast tier.
    int
    The number of quality peers currently in the fast tier.
    double
    Average tunnel test time (RTT in ms) of the peer at the fast-tier speed boundary from the last reorganize, or 0.0 if never reorganized.
    float
    Average loss ratio across the high-capacity tier with a fresh measurement, as a fraction (0.0 - 1.0); 0.0 if none.
    int
    Current high-capacity tier population.
    double
    Get the high-capacity RTT ceiling for display and diagnostics.
    double
    Current minimum integration value for the well-integrated peer tier.
    static float
    The lossy demotion threshold in effect, tuned value if set else config.
    protected int
    Maximum number of peers to keep in the fast tier, capped by active peers.
    protected int
    getMaximumFastPeers(int known, int active)
    Variant taking both expensive inputs, for callers that already have them.
    protected int
    Maximum number of peers to keep in the high-capacity tier, capped by active peers.
    protected int
    getMaximumHighCapPeers(int known, int active)
    Variant taking both expensive inputs, for callers that already have them.
    float
    Median loss ratio of the union of the fast and high-capacity tiers with a fresh measurement, as a fraction (0.0 - 1.0).
    static int
    Read the candidate-sample floor, honouring the configured override.
    static int
    High-capacity tier size the router refills toward.
    protected int
    Minimum number of peers to keep in the fast tier.
    protected int
    Variant taking the network size, for callers that already know it.
    protected int
    Minimum number of peers to keep in the high-capacity tier.
    protected int
    Variant taking the network size, for callers that already know it.
    (package private) int
    Peers not recorded because the recovery list was full.
    (package private) int
    Peers still waiting for their RouterInfo to be requested.
    static float
    The moderate de-prioritization threshold in effect, read straight from config (there is no Tuner override, unlike getLossyThreshold(RouterContext)).
    Retrieve an existing profile or create a new one, without blocking on contention.
    Retrieve the profile for a peer, or null if unknown.
    int
    Profiles held in RAM, as of the last completed reorganisation.
    Retrieve the profile for a peer without blocking.
    int
    Peers passing the quality gates, as of the last completed reorganisation.
    double
    Current minimum speed value for the fast peer tier.
    int
    Last known number of profiles stored on disk, from the most recent load, cleanup, or purge in the persistence helper.
    double
    Tunnel build success ratio across the whole router, cached for BUILD_SUCCESS_CACHE_MS because a single lookup costs several rate reads.
    Self-exclusion hash for this router instance.
    (package private) static boolean
    hasRecentProofOfLife(PeerProfile profile, long now)
    True if the peer has shown proof of life within PROOF_OF_LIFE_WINDOW_MS: a successful send, heard-from, or heard-about within the last hour.
    (package private) static boolean
    hasRecentTierActivity(PeerProfile profile, long activeCutoff)
    True if the peer showed recent activity within the given cutoff: a heard-from or successful send at or after the cutoff.
    (package private) static int
    highCapActiveCap(int active, int base)
    Ceiling on the high-capacity tier from the number of reachable peers.
    (package private) static boolean
    isActiveInWindow(PeerProfile profile, long hideBefore)
    Whether a profile shows activity within the active window: a peer test counted as active, a successful or failed send, or any contact.
    (package private) static boolean
    isEvictable(PeerProfile profile, Map<Hash, PeerProfile> fastPeers, Map<Hash, PeerProfile> highCapPeers, long activeThreshold, int fastPeerLimit, int highCapacityLimit)
    Whether a profile is eligible for eviction under the profile cap: not protected by a fast/high-cap tier slot that still has room below its limit, and no send or heard-from activity within the active window.
    (package private) static boolean
    Whether the given profile carries excessive cumulative tunnel failures.
    (package private) static boolean
    Whether a RouterInfo's advertised bandwidth tier is one that cannot host a tunnel: L, M, or N.
    (package private) static boolean
    isExcludedFromProfiling(String capabilities, String bandwidthTier)
    Should a peer advertising these capabilities and bandwidth tier be profiled?
    (package private) boolean
    Check if a peer should be excluded from profiling.
    (package private) static boolean
    isExpiredProfile(PeerProfile profile, long now, long expireActive, long expirePassive, long expireGossip, long expireUntracked)
    Whether a profile has expired from its activity tier and should be purged: no activity (send/heard/heard-about) within the tier's expiration window.
    boolean
    isFast(Hash peer)
    Check whether a peer is classified in the fast tier.
    (package private) static boolean
    Whether a bandwidth tier is one of the high-capacity tiers (O, P, X).
    boolean
    Check whether a peer is classified in the high-capacity tier.
    (package private) static boolean
    Whether a bandwidth tier name is one of the tiers excluded from profiling.
    boolean
    Whether recent tunnel build success is below the attack threshold.
    (package private) static boolean
    isModeratelyLossy(float score, float moderateThreshold, float demoteThreshold)
    Whether a decayed loss score falls in the moderate band: at or above the moderate threshold but below the demotion threshold.
    (package private) static boolean
    isReliableBandwidthPeer(PeerProfile profile, long now, boolean established)
    Reliability gate for high-bandwidth (O/P/X tier) selection: the peer must show a tunnel acceptance ratio of at least 0.3 AND evidence of recent activity.
    boolean
    Whether the given peer is eligible for selection.
    (package private) static boolean
    isStaleAbsentPeer(PeerProfile profile, long now, long absentThreshold)
    Whether the peer's last activity (send, heard-from, or heard-about) is older than the absent threshold.
    boolean
    Check whether a peer is classified in the well-integrated tier.
    (package private) static boolean
    latencySampleIsBroadEnough(int measured, int population)
    Fraction of a tier population that must carry a usable first-hop RTT before latency is allowed to influence tier membership.
    (package private) static boolean
    lossyReadmitAllowed(float lossRatio, long ratioLastUpdate, long lossySince, long now, long freshWindowMs, long minAgeMs, float threshold, float fastTrackRatio, boolean tiersShort)
    Pure decision behind shouldReadmitLossy(PeerProfile, long), pinned by tests.
    static void
    main(String[] args)
    Command-line entry point; reads profile dump files and prints thresholds.
    (package private) static String
    maskedIPKey(byte[] ip, int mask)
    Fingerprint key for one masked IP, byte-identical to the key MaskedIPSet.maskedIP builds for the same address and mask.
    (package private) static int
    maxCandidateSample(int howMany, int peerCount)
    Cap on how many tier peers to gate-check when selecting howMany tunnels.
    (package private) static int
    maxCandidateSample(int howMany, int peerCount, int floor)
    Candidate-sample cap for a configurable floor.
    (package private) boolean
    Whether enough time has passed to request the next batch of missing RouterInfos.
    (package private) static boolean
    needsRouterInfoRefresh(RouterInfo info, PeerProfile profile, long now, long refreshAgeMs)
    Whether a RouterInfo is old enough that promoting on it risks a build failure: published before the threshold and no proof of life.
    (package private) static boolean
    needsTierRestore(int currentSize, int oldSize)
    Whether a shrunken tier needs restoration: below half its old size and the old size was substantial.
    (package private) static double
    Maps an unknown build-success reading onto a neutral 1.0.
    (package private) static int
    nextStrikeCount(int previousStrikes, long lastStrikeTime, long now)
    Compute the next strike count after a failure, applying time-window decay.
    void
    noteFirstHopRtt(Hash peer, int rtt, long when)
    Record a measured direct-link RTT against a peer, by hash.
    (package private) boolean
    Record that a stored profile was loaded for a peer the netdb cannot resolve.
    (package private) boolean
    passesTierGates(PeerProfile profile, double buildSuccess, long now)
    Common gate for the fast-tier fill passes, which always require acceptable tunnel acceptance.
    (package private) boolean
    passesTierGates(PeerProfile profile, double buildSuccess, long now, boolean requireAcceptance)
    Common gate for fast/high-cap tier fill passes: the peer must be selectable, have acceptable tunnel acceptance, no recent tunnel failures, and not be in loss probation.
    boolean
    Check whether a peer sends an excessive rate of invalid or failed netDb lookup replies (potential misbehavior indicator).
    static int
    pickLowestPriority(List<Hash> candidates, float[] priority, int howMany, Set<Hash> matches)
    Choose up to howMany candidates in ascending priority order.
    (package private) static PeerProfile
    Which profile a promotion pass should act on: the live one when the map has it, the caller's otherwise.
    (package private) static String
    promotionEvidence(int bonus, int raw, boolean promotedIsLive)
    Evidence line for a promotion log: only the values that explain something.
    (package private) static String
    Display form of a promotion skip reason: prose words with the first letter capitalised, so the tally reads as a list of reasons rather than as code identifiers.
    (package private) String
    promotionSkipReason(PeerProfile profile, Hash peer, double buildSuccess, long now)
    Why skipsPromotion(PeerProfile, Hash, double) would skip this profile, or null when it would not.
    (package private) static String
    promotionTransition(boolean wasFast, boolean wasHighCap, boolean nowFast, boolean nowHighCap)
    Describe a tier promotion as a from -> to transition, naming only the tiers actually gained.
    (package private) static ProfileOrganizer.PurgeReason
    purgeReasonFor(boolean banned, boolean unreachable, boolean tierCapable, boolean softEvictionAllowed, boolean hasRecentFailures, boolean inLossProbation, boolean lowAcceptance)
    Why a peer listed in a tier should be evicted, or null to keep it.
    void
    Remove profile files that are no longer worth keeping: those whose peer is genuinely stale at any size, and those beyond the disk retention floor.
    (package private) static boolean
    Whether a bandwidth tier and capability string together qualify the peer for the high-capacity / fast tiers: X/P/O tier and none of the D (moderate congestion), E (severe congestion), G (no tunnels) or U (unreachable) capability flags.
    (package private) static int
    remainingToSelect(int howMany, Set<Hash> matches)
    How many slots are still free in a cascade's destination set.
    (package private) void
    Run a standard reorganize round without coalescing.
    (package private) void
    reorganize(boolean shouldCoalesce)
    Reorganizes peer profiles into performance-based tiers (fast, high-capacity, etc.) and expires stale entries.
    (package private) static int
    How many tier peers to sample for first-hop RTT in one reorganize.
    (package private) int
    Refresh direct-link RTT for tier peers that already have a transport session, and re-judge their low-latency standing.
    void
    selectActiveNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
    Select from currently connected (established) not-failing peers.
    void
    selectActiveNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet)
    Select from currently connected peers with IP-subnet diversity.
    void
    selectAllNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing)
    Select from all not-failing peers randomly, falling through to general peers if the not-failing set is insufficient.
    void
    selectAllNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask, MaskedIPSet ipSet)
    Select from all not-failing peers randomly, honouring a /n subnet diversity restriction.
    Gather the union of all peers from fast, high-capacity, and not-failing tiers.
    Return the current fast tier membership directly.
    void
    selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
    Select up to howMany fast-tier peers, filling shortfalls from high-capacity.
    void
    selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet)
    Select fast-tier peers with IP-subnet diversity constraints.
    void
    selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, SessionKey randomKey, ProfileOrganizer.Slice subTierMode, int mask, MaskedIPSet ipSet)
    Select fast-tier peers deterministically sliced by a random key.
    void
    selectHighBandwidthPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
    Select up to howMany peers from O/P/X bandwidth tiers (high shared bandwidth) that are not failing.
    void
    selectHighBandwidthPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask, MaskedIPSet ipSet)
    Select high-bandwidth peers with tier-exclusion and IP-subnet diversity.
    Return the current high-capacity tier membership directly.
    void
    selectHighCapacityPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
    Select high-capacity peers, filling shortfalls from not-failing peers.
    void
    selectHighCapacityPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet)
    Select high-capacity peers with IP-subnet diversity.
    void
    selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
    Select from not-failing peers, excluding high-capacity tier if requested.
    void
    selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing)
    Select from not-failing peers, optionally excluding the high-capacity tier.
    void
    selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask, MaskedIPSet ipSet)
    Full-parameter select from not-failing peers.
    void
    selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask, MaskedIPSet ipSet, boolean preferUnproven)
    Full-parameter select from not-failing peers.
    void
    selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet)
    Select from not-failing peers with IP-subnet diversity.
    (package private) static PeerProfile
    selectNthFastest(Collection<PeerProfile> profiles, long now, double capacityThreshold, int k)
    Select the k-th fastest qualifying profile (1-based) without sorting the whole candidate set.
    (package private) static PeerProfile
    selectSpeedBoundary(Collection<PeerProfile> profiles, long now, double capacityThreshold)
    The profile whose speed becomes the speed threshold: the one at rank speedThresholdCutoff(int) of the qualifying set, ranked fastest first.
    boolean
    selectTestPeersNonBlocking(int howMany, Set<Hash> exclude, Set<Hash> matches)
    Non-blocking test peer selection: tries the full fast → high-cap → active chain under a single tryReadLock().
    Return the current well-integrated tier membership directly.
    static void
    Override the fast tier ceiling, clamped to 200-3000 peers.
    static void
    Override the high-capacity tier ceiling, clamped to 200-6000 peers.
    static void
    Override the default profile count, clamped to MIN_MAX_PROFILES-ABSOLUTE_MAX_PROFILES.
    static void
    Override the fast tier refill target, clamped to 50-2000 peers.
    static void
    setLossyThreshold(float ratio)
    Set the lossy demotion threshold (called by Tuner).
    static void
    Override the candidate-sample floor at runtime.
    static void
    Override the high-capacity tier refill target, clamped to 50-3000 peers.
    void
    setUs(Hash us)
    Store the local router hash for self-exclusion from peer selection.
    (package private) static boolean
    shouldDeferPromotionOnStaleRouterInfo(int tierSize, int safeFloor)
    Whether a promotion may be held back on a stale RouterInfo without risking the tier it would join.
    (package private) boolean
    skipsPromotion(PeerProfile profile, Hash peer, double buildSuccess)
    Whether the peer should be skipped for tier promotion: not selectable, in a strict country, low tunnel acceptance, high-latency penalty, congested, or in loss probation.
    (package private) static int
    softPurgeThreshold(int knownProfiles)
    The smallest tier size at which peers may be evicted for a soft reason.
    (package private) static int
    speedThresholdCutoff(int qualifyingCount)
    Rank boundary for the speed threshold: the top 30% of qualifying peers, capped at 50.
    (package private) static boolean
    stillSelecting(int howMany, Set<Hash> matches)
    Whether a cascade still has slots left to fill.
    (package private) List<Hash>
    Hand over the next batch of peers whose RouterInfo should be requested.
    (package private) static boolean
    tierScanStarved(int candidates, int howMany, int examined, int skipExcluded, int skipGated, int skipSliced, int skipIp, int skipRtt)
    Whether a tier scan starved badly enough to be worth reporting.
    void
    Persist the given profile to disk.

    Methods inherited from class Object

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

    • ATTACK_THRESHOLD

      public static final double ATTACK_THRESHOLD
      Threshold below which the network is considered under attack.
      See Also:
    • TIER_FILL_DEBOUNCE_MS

      static final long TIER_FILL_DEBOUNCE_MS
      Shortest gap between two full tier-refill scans.

      Well under the reorganise interval, so the debounce can never delay a refill past the next cycle that would have done it anyway.

      See Also:
    • DEMOTE_STRIKE_THRESHOLD

      public static final int DEMOTE_STRIKE_THRESHOLD
      Unreachable first-hop failures needed inside the decay window before demoteIfUnreachable demotes.
      See Also:
    • DEMOTE_STRIKE_DECAY_MS

      public static final long DEMOTE_STRIKE_DECAY_MS
      A strike older than this no longer counts, so a peer that recovered is not demoted by one later failure.
      See Also:
    • PROP_LOW_LATENCY_MULTIPLE

      public static final String PROP_LOW_LATENCY_MULTIPLE
      Property key for the calibrated low-latency multiple. @since 0.9.71+.
      See Also:
    • PROP_MINIMUM_FAST_PEERS

      public static final String PROP_MINIMUM_FAST_PEERS
      Property key naming the fast tier's refill target.
      See Also:
    • SCALING_THRESHOLD

      static final int SCALING_THRESHOLD
      Network size above which tier thresholds scale with the network instead of staying at their configured default.
      See Also:
    • _defaultMinFastPeers

      public static volatile int _defaultMinFastPeers
      Fast tier refill target, in peers, as last configured or autotuned.
    • PROP_MAX_ROUTERINFO_AGE_HOURS

      public static final String PROP_MAX_ROUTERINFO_AGE_HOURS
      Property key naming the RouterInfo age past which a RouterInfo is treated as stale and must show proof of life to be selected, in hours.
      See Also:
    • DEFAULT_MAX_ROUTERINFO_AGE_HOURS

      public static final int DEFAULT_MAX_ROUTERINFO_AGE_HOURS
      Default RouterInfo age past which a RouterInfo is treated as stale and must show proof of life to be selected, in hours.
      See Also:
    • PROP_ROUTERINFO_REFRESH_AGE_MS

      public static final String PROP_ROUTERINFO_REFRESH_AGE_MS
      Property key naming the RouterInfo age past which a tier promotion is held back, in ms.

      Set to 0 or less to disable the deferral entirely, which restores plain promotion on whatever the netdb holds.

      See Also:
    • DEFAULT_ROUTERINFO_REFRESH_AGE_MS

      public static final long DEFAULT_ROUTERINFO_REFRESH_AGE_MS
      One hour, i.e. one republish interval.
      See Also:
    • PROP_MAXIMUM_FAST_PEERS

      public static final String PROP_MAXIMUM_FAST_PEERS
      Property key naming the fast tier's ceiling.
      See Also:
    • _defaultMaxFastPeers

      public static volatile int _defaultMaxFastPeers
      Fast tier ceiling, in peers.
    • PROP_MINIMUM_HIGH_CAPACITY_PEERS

      public static final String PROP_MINIMUM_HIGH_CAPACITY_PEERS
      Property key naming the high-capacity tier's refill target.
      See Also:
    • DEFAULT_MINIMUM_HIGH_CAPACITY_PEERS

      public static final int DEFAULT_MINIMUM_HIGH_CAPACITY_PEERS
      Default high-capacity tier refill target, in peers.
      See Also:
    • _defaultMinHighCapPeers

      public static volatile int _defaultMinHighCapPeers
      High-capacity tier refill target, in peers, as last configured or autotuned.
    • PROP_MAXIMUM_HIGH_CAPACITY_PEERS

      public static final String PROP_MAXIMUM_HIGH_CAPACITY_PEERS
      Property key naming the high-capacity tier's ceiling.
      See Also:
    • _defaultMaxHighCapPeers

      public static volatile int _defaultMaxHighCapPeers
      High-capacity tier ceiling, in peers.
    • MIN_TUNNEL_REQUESTS

      static final int MIN_TUNNEL_REQUESTS
      Lifetime requests a peer needs before its acceptance ratio may exclude it.

      Package-visible because the tiers apply different floors to it and the boundary between "judged" and "not judged" is exactly the difference. The high-capacity tier passes this value and the fast tier passes one, so the same counts give opposite answers on the two. TierAdmissionFloorTest pins that boundary.

      See Also:
    • MAX_SOFT_PURGE_FLOOR

      static final int MAX_SOFT_PURGE_FLOOR
      Upper bound on the soft-purge tier size, in peers.

      Caps softPurgeThreshold(int) so that on a large network the threshold stays reachable rather than scaling without limit.

      See Also:
    • HIGH_CAP_ADMISSION_REQUIRES_ACCEPTANCE

      static final boolean HIGH_CAP_ADMISSION_REQUIRES_ACCEPTANCE
      Whether high-capacity admission requires acceptable tunnel acceptance. False: high capacity is the reservoir the fast tier is seeded from, so requiring acceptance here would filter it by the same criterion that empties the fast tier, leaving nothing to seed from.
      See Also:
    • FAST_ADMISSION_REQUIRES_ACCEPTANCE

      static final boolean FAST_ADMISSION_REQUIRES_ACCEPTANCE
      Whether fast-tier admission requires acceptable tunnel acceptance. True: the fast tier is the selective tier, and a peer that declines most of our build requests is wasted work wherever it is listed.
      See Also:
    • EVICTION_REQUIRES_ACCEPTANCE_BOTH_TIERS

      static final boolean EVICTION_REQUIRES_ACCEPTANCE_BOTH_TIERS
      Whether acceptance-based eviction applies to both tiers. True: admission is permissive and eviction is what keeps poor accepters from accumulating, so the two must disagree on admission and agree on eviction.
      See Also:
    • PROP_LOSSY_THRESHOLD

      public static final String PROP_LOSSY_THRESHOLD
      Config property for the loss ratio above which a peer is demoted from fast/high-cap tiers.
      See Also:
    • PROP_LOSSY_WINDOW

      public static final String PROP_LOSSY_WINDOW
      Config property for how long a reported loss ratio stays fresh.
      See Also:
    • PROP_LOSSY_MIN_PACKETS

      public static final String PROP_LOSSY_MIN_PACKETS
      Config property for the minimum number of transmitted packets before a loss ratio is reported.
      See Also:
    • DEFAULT_LOSSY_MIN_PACKETS

      public static final int DEFAULT_LOSSY_MIN_PACKETS
      Default minimum packet sample size (20 = full 5% bucket resolution).
      See Also:
    • PROP_LOSSY_MODERATE_THRESHOLD

      public static final String PROP_LOSSY_MODERATE_THRESHOLD
      Config property for the decayed loss score above which a peer is de-prioritized in tier selection (soft signal, below the demotion threshold). Default 10%: a peer can be consistently lossy without ever crossing the hard demotion bar, and this keeps such peers out of the preferred picks without evicting them.
      See Also:
    • PROP_MAX_PROFILES

      public static final String PROP_MAX_PROFILES
      Config property for the maximum number of peer profiles.
      See Also:
    • _defaultMaxProfiles

      public static volatile int _defaultMaxProfiles
      Runtime-adjustable default max profile count.
    • ABSOLUTE_MAX_PROFILES

      public static final int ABSOLUTE_MAX_PROFILES
      Ceiling on profiles held in memory, in profiles.

      Bounds the RAM store only. What is kept on disk is governed separately by MAX_STORED_PROFILE_FILES, so raising this to let the router use more of its persisted knowledge does not shorten the retention of that knowledge across a restart.

      See Also:
    • MAX_STORED_PROFILE_FILES

      public static final int MAX_STORED_PROFILE_FILES
      Profile files retained on disk before surplus ones are trimmed.

      Deliberately a different number, and a different concern, from ABSOLUTE_MAX_PROFILES: that one bounds profiles held in memory, this one bounds what is kept on disk so it survives a restart. Using one constant for both meant that lowering the disk floor would silently lower the memory ceiling too.

      Below this count no file is deleted unless the peer is genuinely stale, so the floor costs nothing while the store is smaller than it and only starts trimming once the store exceeds it.

      See Also:
    • MIN_MAX_PROFILES

      public static final int MIN_MAX_PROFILES
      Floor for the in-memory profile cap, in profiles.

      Low enough that a small-heap router still runs; getDefaultMaxProfiles() returns this instead of ABSOLUTE_MAX_PROFILES on a slow system.

      See Also:
    • DEFAULT_MIN_CANDIDATE_SAMPLE

      static final int DEFAULT_MIN_CANDIDATE_SAMPLE
      Default floor for candidates examined per selection. @since 0.9.71+.
      See Also:
    • MAX_CANDIDATE_SAMPLE

      static final int MAX_CANDIDATE_SAMPLE
      Upper bound, so a typo cannot turn selection into a full tier scan. @since 0.9.71+.
      See Also:
    • PROP_MIN_CANDIDATE_SAMPLE

      public static final String PROP_MIN_CANDIDATE_SAMPLE
      Property for the floor; see getMinCandidateSample(RouterContext).
      See Also:
  • Constructor Details

    • ProfileOrganizer

      public ProfileOrganizer(RouterContext context)
      Creates a profile organizer with empty tier maps and registers performance tracking statistics for peer classification.
      Parameters:
      context - the router context providing config, stats, and log access
  • Method Details

    • getProfileCount

      public int getProfileCount()
      Profiles held in RAM, as of the last completed reorganisation.
      Returns:
      the in-RAM profile count
    • getQualityCount

      public int getQualityCount()
      Peers passing the quality gates, as of the last completed reorganisation.
      Returns:
      the quality peer count
    • getActiveProfileCount

      public int getActiveProfileCount()
      Profiles with recent activity, as of the last completed reorganisation.

      Computed during the reorganisation walk rather than on demand: countActivePeersInLastHour() iterates every profile while holding _reorganizeLock, which is the lock tunnel peer selection contends on, and CoalesceStatsEvent runs every 50s. Publishing it here costs one comparison per profile in a walk that already holds the lock.

      Returns:
      the recently active profile count
    • isActiveInWindow

      static boolean isActiveInWindow(PeerProfile profile, long hideBefore)
      Whether a profile shows activity within the active window: a peer test counted as active, a successful or failed send, or any contact. Split out so the rule is testable without a reorganise cycle or a live profile set.
      Parameters:
      profile - profile whose send and heard-from timestamps are compared against the cutoff
      hideBefore - cutoff time, i.e. now minus ACTIVE_WINDOW_MS
      Returns:
      true if the profile is recently active
    • getDefaultMinFastPeers

      public static int getDefaultMinFastPeers()
      Fast tier size the router refills toward.
      Returns:
      the current minimum number of fast-tier peers
    • setDefaultMinFastPeers

      public static void setDefaultMinFastPeers(int val)
      Override the fast tier refill target, clamped to 50-2000 peers.
      Parameters:
      val - requested minimum fast tier size, in peers
    • getDefaultMaxFastPeers

      public static int getDefaultMaxFastPeers()
      Ceiling on the fast tier.
      Returns:
      the current maximum number of fast-tier peers
    • setDefaultMaxFastPeers

      public static void setDefaultMaxFastPeers(int val)
      Override the fast tier ceiling, clamped to 200-3000 peers.
      Parameters:
      val - requested maximum fast tier size, in peers
    • getMinHighCapacityPeers

      public static int getMinHighCapacityPeers()
      High-capacity tier size the router refills toward.
      Returns:
      the current minimum number of high-capacity-tier peers
    • setMinHighCapacityPeers

      public static void setMinHighCapacityPeers(int val)
      Override the high-capacity tier refill target, clamped to 50-3000 peers.
      Parameters:
      val - requested minimum high-capacity tier size, in peers
    • getDefaultMaxHighCapPeers

      public static int getDefaultMaxHighCapPeers()
      Ceiling on the high-capacity tier.
      Returns:
      the current maximum number of high-capacity-tier peers
    • setDefaultMaxHighCapPeers

      public static void setDefaultMaxHighCapPeers(int val)
      Override the high-capacity tier ceiling, clamped to 200-6000 peers.
      Parameters:
      val - requested maximum high-capacity tier size, in peers
    • setLossyThreshold

      public static void setLossyThreshold(float ratio)
      Set the lossy demotion threshold (called by Tuner).
      Parameters:
      ratio - the loss ratio threshold
    • getLossyThreshold

      public static float getLossyThreshold(RouterContext ctx)
      The lossy demotion threshold in effect, tuned value if set else config.
      Parameters:
      ctx - the router context
      Returns:
      the loss ratio threshold
    • getDefaultMaxProfilesValue

      public static int getDefaultMaxProfilesValue()
      Profile count the reorganizer targets by default.
      Returns:
      the current default maximum number of stored profiles
    • setDefaultMaxProfiles

      public static void setDefaultMaxProfiles(int val)
      Override the default profile count, clamped to MIN_MAX_PROFILES-ABSOLUTE_MAX_PROFILES.
      Parameters:
      val - requested maximum profile count
    • setUs

      public void setUs(Hash us)
      Store the local router hash for self-exclusion from peer selection.
      Parameters:
      us - our own router hash
    • getUs

      public Hash getUs()
      Self-exclusion hash for this router instance.
      Returns:
      the local router hash, or null if not set
    • getSpeedThreshold

      public double getSpeedThreshold()
      Current minimum speed value for the fast peer tier.
      Returns:
      the speed threshold computed during the last reorganize
    • getFastRTTThreshold

      public double getFastRTTThreshold()
      Average tunnel test time (RTT in ms) of the peer at the fast-tier speed boundary from the last reorganize, or 0.0 if never reorganized.
      Returns:
      the boundary RTT in ms
    • getCapacityThreshold

      public double getCapacityThreshold()
      Current minimum capacity value for the high-capacity peer tier.
      Returns:
      the capacity threshold computed during the last reorganize
    • getIntegrationThreshold

      public double getIntegrationThreshold()
      Current minimum integration value for the well-integrated peer tier.
      Returns:
      the integration threshold computed during the last reorganize
    • getProfile

      public PeerProfile getProfile(Hash peer)
      Retrieve the profile for a peer, or null if unknown. Blocks on the reorganize read lock.
      Parameters:
      peer - the router hash to look up
      Returns:
      the existing profile, or null if none exists
    • getProfileNonblocking

      public PeerProfile getProfileNonblocking(Hash peer)
      Retrieve the profile for a peer without blocking. Returns null immediately if the lock is contended.
      Parameters:
      peer - the router hash to look up
      Returns:
      the existing profile, or null if none exists or lock unavailable
    • getOrCreateProfileNonblocking

      public PeerProfile getOrCreateProfileNonblocking(Hash peer)
      Retrieve an existing profile or create a new one, without blocking on contention. Uses try-lock escalation to avoid blocking the caller.
      Parameters:
      peer - the router hash to look up or create a profile for
      Returns:
      the existing or new profile, or null if the peer is excluded or lock contention
    • addProfile

      public PeerProfile addProfile(PeerProfile profile)
      Insert a fully-constructed profile into the organizer. The profile is added to the not-failing set and high-capacity tier if it meets the current capacity threshold.
      Parameters:
      profile - the profile to add
      Returns:
      the previous profile for the same peer, or null if none existed
    • countFastPeers

      public int countFastPeers()
      Number of peers classified as fast tier.
      Returns:
      fast peer count (read-lock protected)
    • countHighCapacityPeers

      public int countHighCapacityPeers()
      Number of peers classified as high-capacity tier.
      Returns:
      high-capacity peer count (read-lock protected)
    • countNotFailingPeers

      public int countNotFailingPeers()
      Total number of peer profiles in memory (all tiers).
      Returns:
      profile count (read-lock protected)
    • countActivePeers

      public int countActivePeers()
      Count peers with any send or hear activity in the last 4 hours.
      Returns:
      active peer count (read-lock protected)
    • countActivePeersInLastHour

      public int countActivePeersInLastHour()
      Count peers with activity (send, receive, or failure) within the last hour.
      Returns:
      recently active peer count (read-lock protected)
    • isFast

      public boolean isFast(Hash peer)
      Check whether a peer is classified in the fast tier.
      Parameters:
      peer - the router hash to check
      Returns:
      true if the peer is in the fast tier set
    • getFastQualityCount

      public int getFastQualityCount()
      The number of quality peers currently in the fast tier. A quality peer is fast and either high-capacity or has proven throughput. The count gates fast-tier promotion internally: at or above MIN_FAST_QUALITY_COUNT (500) the tier is treated as healthy.
      Returns:
      the count of quality fast peers
    • isHighCapacity

      public boolean isHighCapacity(Hash peer)
      Check whether a peer is classified in the high-capacity tier.
      Parameters:
      peer - the router hash to check
      Returns:
      true if the peer is in the high-capacity tier set
    • isWellIntegrated

      public boolean isWellIntegrated(Hash peer)
      Check whether a peer is classified in the well-integrated tier.
      Parameters:
      peer - the router hash to check
      Returns:
      true if the peer is in the well-integrated tier set
    • clearProfiles

      void clearProfiles()
      Remove all profiles and clear all tier maps. Package-private: only called from tests and router shutdown paths.
    • peerSendsBadReplies

      public boolean peerSendsBadReplies(Hash peer)
      Check whether a peer sends an excessive rate of invalid or failed netDb lookup replies (potential misbehavior indicator).
      Parameters:
      peer - the router hash to check
      Returns:
      true if the peer exceeds the bad-reply threshold in the last hour
    • exportProfile

      public boolean exportProfile(Hash profile, OutputStream out) throws IOException
      Write a peer profile to the given output stream for persistence.
      Parameters:
      profile - the router hash identifying the profile to export
      out - the destination stream for the serialized profile
      Returns:
      true if the profile was found and written, false if no profile exists
      Throws:
      IOException - on write errors
    • remainingToSelect

      static int remainingToSelect(int howMany, Set<Hash> matches)
      How many slots are still free in a cascade's destination set.

      Every tier selector takes howMany as the total the caller wants held in matches when the cascade returns, and every tier — the first one included — asks for only the shortfall this reports. That single convention is what keeps the arithmetic in one place: a call site that pre-subtracts matches.size() itself is a second copy of this computation, and the two copies disagree the moment one of them drifts.

      The failure mode that makes it worth centralising: a caller that sized an ArraySet to exactly howMany has already filled part of it by the time a later tier runs, so a tier that wrote howMany again would overflow it and ArraySet would throw SetFullException — surfaced as pickLowestPriority crashing, which names the symptom rather than the cascade arithmetic behind it.

      Parameters:
      howMany - total peers the caller wants held in matches across the whole cascade
      matches - peers picked so far, by the caller and by the tiers that already ran
      Returns:
      slots still needed, never negative
    • stillSelecting

      static boolean stillSelecting(int howMany, Set<Hash> matches)
      Whether a cascade still has slots left to fill.

      A guard, not a computation the callers should repeat: every tier-selector shortfall branch needs the same remaining > 0 question, and writing it as matches.size() < howMany in ten places is what let one site drift.

      Parameters:
      howMany - peers the caller asked for in total
      matches - peers picked by the tiers that ran before this one
      Returns:
      true if the set still needs more peers
    • selectFastPeers

      public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
      Select up to howMany fast-tier peers, filling shortfalls from high-capacity.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
    • selectFastPeers

      public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet)
      Select fast-tier peers with IP-subnet diversity constraints. Falls through to high-capacity tier on shortfall.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - mutable set tracking already-selected subnets
    • selectFastPeers

      public void selectFastPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, SessionKey randomKey, ProfileOrganizer.Slice subTierMode, int mask, MaskedIPSet ipSet)
      Select fast-tier peers deterministically sliced by a random key. This enables different peers per tunnel to improve path diversity.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      randomKey - key for deterministic sub-tier assignment
      subTierMode - slicing mode (SLICE_ALL to skip slicing)
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - mutable set tracking already-selected subnets
    • selectHighCapacityPeers

      public void selectHighCapacityPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
      Select high-capacity peers, filling shortfalls from not-failing peers.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
    • selectHighCapacityPeers

      public void selectHighCapacityPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet)
      Select high-capacity peers with IP-subnet diversity.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - mutable set tracking already-selected subnets
    • selectNotFailingPeers

      public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
      Select from not-failing peers, excluding high-capacity tier if requested.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
    • selectNotFailingPeers

      public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet)
      Select from not-failing peers with IP-subnet diversity.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - mutable set tracking already-selected subnets
    • selectNotFailingPeers

      public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing)
      Select from not-failing peers, optionally excluding the high-capacity tier.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      onlyNotFailing - if true, exclude peers already in high-capacity tier
    • selectNotFailingPeers

      public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask, MaskedIPSet ipSet)
      Full-parameter select from not-failing peers.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      onlyNotFailing - if true, exclude peers already in high-capacity tier
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - mutable set tracking already-selected subnets
    • selectNotFailingPeers

      public void selectNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask, MaskedIPSet ipSet, boolean preferUnproven)
      Full-parameter select from not-failing peers.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      onlyNotFailing - if true, exclude peers already in high-capacity tier
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - mutable set tracking already-selected subnets
      preferUnproven - if true, prioritize peers with no tunnel test history so they accumulate profiling data
    • selectActiveNotFailingPeers

      public void selectActiveNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
      Select from currently connected (established) not-failing peers.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
    • selectActiveNotFailingPeers

      public void selectActiveNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, int mask, MaskedIPSet ipSet)
      Select from currently connected peers with IP-subnet diversity.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - mutable set tracking already-selected subnets
    • selectTestPeersNonBlocking

      public boolean selectTestPeersNonBlocking(int howMany, Set<Hash> exclude, Set<Hash> matches)
      Non-blocking test peer selection: tries the full fast → high-cap → active chain under a single tryReadLock(). Returns false (leaving matches unchanged) if the read lock cannot be acquired. The caller should skip this round and requeue. Used exclusively by PeerTestJob to avoid blocking on reorganize()'s write lock during startup profiling.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude
      matches - output set populated with selected peer hashes
      Returns:
      true if selection ran, false if lock was not acquired
    • selectHighBandwidthPeers

      public void selectHighBandwidthPeers(int howMany, Set<Hash> exclude, Set<Hash> matches)
      Select up to howMany peers from O/P/X bandwidth tiers (high shared bandwidth) that are not failing. Falls through to selectAllNotFailingPeers on shortfall.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
    • selectHighBandwidthPeers

      public void selectHighBandwidthPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask, MaskedIPSet ipSet)
      Select high-bandwidth peers with tier-exclusion and IP-subnet diversity.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      onlyNotFailing - if true, exclude peers already in high-capacity tier
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - mutable set tracking already-selected subnets
    • isReliableBandwidthPeer

      static boolean isReliableBandwidthPeer(PeerProfile profile, long now, boolean established)
      Reliability gate for high-bandwidth (O/P/X tier) selection: the peer must show a tunnel acceptance ratio of at least 0.3 AND evidence of recent activity. A successful peer test within 10 minutes, a heard- from/send-success within 30 minutes, or an established commSystem connection. Peers with no profile are not gated (no data yet).

      Pure decision — no context access, safe for unit tests.

      Parameters:
      profile - the peer profile (non-null)
      now - current time in ms
      established - whether commSystem has an established connection
      Returns:
      whether the peer passes the reliability gate
    • selectAllNotFailingPeers

      public void selectAllNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing)
      Select from all not-failing peers randomly, falling through to general peers if the not-failing set is insufficient.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      onlyNotFailing - if true, exclude peers already in high-capacity tier
    • selectAllNotFailingPeers

      public void selectAllNotFailingPeers(int howMany, Set<Hash> exclude, Set<Hash> matches, boolean onlyNotFailing, int mask, MaskedIPSet ipSet)
      Select from all not-failing peers randomly, honouring a /n subnet diversity restriction.
      Parameters:
      howMany - target number of peers
      exclude - peers to exclude (may be null)
      matches - output set populated with selected peer hashes
      onlyNotFailing - if true, exclude peers already in high-capacity tier
      mask - bitmask length for /n diversity restriction (0 to disable)
      ipSet - subnets already represented in this tunnel
    • selectAllPeers

      public Set<Hash> selectAllPeers()
      Gather the union of all peers from fast, high-capacity, and not-failing tiers.
      Returns:
      a new set containing every tracked peer hash
    • selectFastPeers

      public Set<Hash> selectFastPeers()
      Return the current fast tier membership directly. Used by the renderer to avoid iterating all peers for fast-only views.
      Returns:
      unmodifiable snapshot of fast tier hashes
    • selectHighCapacityPeers

      public Set<Hash> selectHighCapacityPeers()
      Return the current high-capacity tier membership directly. Used by the renderer to avoid iterating all peers for highcap-only views.
      Returns:
      unmodifiable snapshot of high-capacity tier hashes
    • selectWellIntegratedPeers

      public Set<Hash> selectWellIntegratedPeers()
      Return the current well-integrated tier membership directly. Used by the renderer to snapshot integration status without per-peer lock acquisitions during rendering.
      Returns:
      unmodifiable snapshot of well-integrated tier hashes
    • getStoredProfileCount

      public int getStoredProfileCount()
      Last known number of profiles stored on disk, from the most recent load, cleanup, or purge in the persistence helper.
      Returns:
      the stored profile count, 0 if the store has never been scanned
    • reorganize

      void reorganize()
      Run a standard reorganize round without coalescing. Equivalent to reorganize(false).
    • latencySampleIsBroadEnough

      static boolean latencySampleIsBroadEnough(int measured, int population)
      Fraction of a tier population that must carry a usable first-hop RTT before latency is allowed to influence tier membership.

      A low-latency decision taken over a small measured subset describes that subset, not the tier: the peers we happen to have sessions with are the ones we have been talking to, so an early sample is drawn from whoever was contacted most recently rather than from the population. Requiring a majority of the tier to be measured keeps the decision anchored to the tier it is applied to.

      Parameters:
      measured - peers in the tier with a usable first-hop RTT
      population - peers in the tier
      Returns:
      true when latency may be used to judge this tier
    • sampleFirstHopRtts

      int sampleFirstHopRtts()
      Refresh direct-link RTT for tier peers that already have a transport session, and re-judge their low-latency standing.

      Decoupled from the build pre-connect on purpose. The pre-connect is a one-shot probe fired to force establishment, so it reads the transport at the least informative moment: a session that was just created has not completed a round trip and reports zero. This samples instead from sessions that have been up long enough to have measured, which is the value the latency tiers actually want.

      Peers with no session are skipped rather than probed. Probing here would re-create the problem above: establishing a session to measure it is what makes the measurement unavailable.

      Returns:
      number of peers whose RTT was refreshed
    • getCalibratedLatencyFloorMs

      long getCalibratedLatencyFloorMs(String style)
      The calibrated latency floor for a transport style, or -1 when that transport has not gathered enough samples to have an opinion.

      Callers must treat -1 as "no calibrated opinion" and fall back to the absolute rule, never as "this peer qualifies".

      Parameters:
      style - the transport style, e.g. "NTCP2" or "SSU2"
      Returns:
      the calibrated floor in ms, or -1 if unknown
    • getCalibratedLatencyFloorMs

      long getCalibratedLatencyFloorMs(Hash peer)
      The calibrated latency floor for a peer, choosing the style of the transport that measured it.
      Parameters:
      peer - the peer to look up
      Returns:
      the calibrated floor in ms, or -1 if unknown
    • applyBaselineMultiple

      static long applyBaselineMultiple(long baselineMs, int multiple)
      Scale a calibrated baseline into the latency a peer may sit under and still count as low latency.

      Pure arithmetic, extracted so the overflow and sentinel rules can be exercised without a router context.

      Parameters:
      baselineMs - the calibrated baseline in ms
      multiple - how many times it may be exceeded; values of 1 or less return the baseline unscaled
      Returns:
      the qualifying threshold in ms, or baselineMs unchanged when it carries no opinion
    • getCalibratedLatencyThresholdMs

      long getCalibratedLatencyThresholdMs(Hash peer)
      The qualifying latency threshold for a peer, from the calibrated baseline of the transport that measured it.

      This is what the profile actually compares against - the baseline scaled by PROP_LOW_LATENCY_MULTIPLE - as opposed to getCalibratedLatencyFloorMs(Hash), which returns the unscaled baseline that peer.latencyBaseline.* reports.

      Parameters:
      peer - the peer to look up
      Returns:
      the qualifying threshold in ms, or -1 if unknown
    • getCohortLatencyThresholdMs

      long getCohortLatencyThresholdMs()
      The qualifying latency threshold for the fast cohort, from the cohort baseline of its fastest members.

      Scaled on the same terms as getCalibratedLatencyThresholdMs(Hash) so the two bounds stay comparable; a cohort mean and a transport baseline are the same kind of quantity and neither is a cutoff on its own.

      Returns:
      the qualifying threshold in ms, or a non-positive value when the cohort has too few measured peers to hold an opinion
    • sampleFirstHopRttLimit

      static int sampleFirstHopRttLimit(int total)
      How many tier peers to sample for first-hop RTT in one reorganize.

      Pure decision — no context access, safe for unit tests.

      Parameters:
      total - combined size of the two tiers
      Returns:
      the sample size, never negative
    • fastOrHighCapCount

      int fastOrHighCapCount()
      Peers in either the fast or the high-capacity tier, counting each peer once.

      A peer can be both, so neither tier contains the other and adding the two counts over-reports. This is the number the profile-tier graph needs for its high-capacity line to be a true subset of the fast line, rather than merely a smaller number that happens to be plotted beside it.

      Walks the smaller tier and probes the larger, so the cost is O(min(fast, highCap)) once per coalesce rather than a full merge.

      Returns:
      size of the union of the two tiers
    • getFastOrHighCapCount

      public int getFastOrHighCapCount()
      Live size of the fast or high-capacity union, a peer in both tiers counted once. Read-locked, so it is safe to call outside a coalesce pass.

      Callers that already hold the write lock — reorganize(). Must call the package-visible fastOrHighCapCount() directly; going through this accessor would re-enter the lock.

      Returns:
      size of the union of the two tiers
      See Also:
    • reorganize

      void reorganize(boolean shouldCoalesce)
      Reorganizes peer profiles into performance-based tiers (fast, high-capacity, etc.) and expires stale entries.

      This method:

      • Coalesces stats if requested and uptime conditions are met. Peak throughput values are never decayed.
      • Filters out unreachable, inactive, or low-tier peers.
      • Recalculates dynamic thresholds for speed, capacity, and integration.
      • Rebuilds internal tier maps and the global profile ordering.
      • Expires profiles that haven't been active recently to bound memory usage.

      Memory Safety: To prevent unbounded memory growth (e.g., OOM after 8+ hours), this method ensures that expired profiles are removed from all data structures—even if the full reorganization is skipped due to lock contention. A best-effort expiration pass runs outside the write lock to mitigate leaks during high contention.

      Parameters:
      shouldCoalesce - if true, coalesce statistics for active profiles
    • isExpiredProfile

      static boolean isExpiredProfile(PeerProfile profile, long now, long expireActive, long expirePassive, long expireGossip, long expireUntracked)
      Whether a profile has expired from its activity tier and should be purged: no activity (send/heard/heard-about) within the tier's expiration window. Tiered expiration: Active > Passive > Gossip; profiles with no tunnel history are purged on the tighter untracked window regardless of tier. A profile with zero timestamps sits in the gossip tier.

      Pure decision. No context access, safe for unit tests.

      Parameters:
      profile - profile to test; its expiration window is picked from its the newest activity timestamp
      now - current time in ms
      expireActive - active-tier window in ms
      expirePassive - passive-tier window in ms
      expireGossip - gossip-tier window in ms
      expireUntracked - untracked window in ms
      Returns:
      whether the profile is expired
    • passesTierGates

      boolean passesTierGates(PeerProfile profile, double buildSuccess, long now, boolean requireAcceptance)
      Common gate for fast/high-cap tier fill passes: the peer must be selectable, have acceptable tunnel acceptance, no recent tunnel failures, and not be in loss probation. Evaluation order preserves the original short-circuit chain (cheap pure checks before the netDb-backed selectability check is already handled by callers that test other cheap conditions first).

      No side effects. Safe to evaluate without holding locks.

      Tunnel acceptance is required by the fast-tier passes and not by the high-capacity pass. The two tiers do different jobs: high capacity is the reservoir the fast tier is seeded from, so gating it on acceptance leaves no deep supply to draw on — when a fast peer demotes, the peers beside it in high capacity have already been filtered by the same criterion. High capacity therefore admits any provably alive peer of the right bandwidth class, and acceptance decides fast-tier membership only. A poor accepter is still evicted from high capacity, so the reservoir turns over rather than accumulating them.

      Parameters:
      profile - the candidate profile
      buildSuccess - the build success ratio in [0.0, 1.0]
      now - current time in ms
      requireAcceptance - whether the peer must also have acceptable tunnel acceptance; false admits by capacity and liveness alone
      Returns:
      whether the peer passes the tier gates
    • passesTierGates

      boolean passesTierGates(PeerProfile profile, double buildSuccess, long now)
      Common gate for the fast-tier fill passes, which always require acceptable tunnel acceptance.
      Parameters:
      profile - the candidate profile
      buildSuccess - the build success ratio in [0.0, 1.0]
      now - current time in ms
      Returns:
      whether the peer passes the fast-tier gates
    • hasRecentTierActivity

      static boolean hasRecentTierActivity(PeerProfile profile, long activeCutoff)
      True if the peer showed recent activity within the given cutoff: a heard-from or successful send at or after the cutoff. Used to keep stale peers out of the fast/high-cap tiers.

      Pure decision. No context access, safe for unit tests.

      Parameters:
      profile - profile whose heard-from and last-successful-send timestamps are checked
      activeCutoff - earliest allowed activity timestamp in ms
      Returns:
      whether the peer has recent activity
    • computeFastRttCeiling

      static long computeFastRttCeiling(double boundaryRttMs)
      Compute the adaptive absolute-RTT ceiling for fast-tier selection.

      The ceiling is the measured fast-tier RTT boundary times a multiplier, clamped to at least AUTO_RTT_FLOOR_MS and at most AUTO_RTT_CAP_MS. Flooring keeps the bar at least as tight as the existing fixed high-RTT demotion; capping prevents a uniformly-slow pool from raising the ceiling without bound, so clearly-slow outliers are still excluded. Pure decision — no context access, safe for unit tests.

      Parameters:
      boundaryRttMs - the fast-tier RTT boundary from the last reorganize (_thresholdRTT); its own scaling amplifies the typical pool latency so the ceiling tracks the network
      Returns:
      the selection ceiling in ms; never below AUTO_RTT_FLOOR_MS and never above AUTO_RTT_CAP_MS. A boundary at or below 0 (no measurement yet) returns the floor so nothing is over-trimmed.
    • computeAdaptiveRttCeiling

      long computeAdaptiveRttCeiling(double boundaryRttMs, double buildSuccess)
      Compute the adaptive absolute-RTT ceiling for fast-tier selection, floored at 2× the startup baseline when build success is degraded. Prevents RTT ceiling amplification during cascade failure: when the entire network slows, the ceiling rises with it and peers that would cause failures are allowed through. The baseline floor keeps the ceiling tight during degradation while allowing natural growth when builds are healthy.
      Parameters:
      boundaryRttMs - the fast-tier RTT boundary from the last reorganize
      buildSuccess - current tunnel build success ratio [0.0, 1.0]
      Returns:
      the selection ceiling in ms
    • aboveRttCeiling

      static boolean aboveRttCeiling(PeerProfile profile, long rttCeilingMs)
      True if the peer's measured tunnel-test RTT exceeds the adaptive selection ceiling, indicating it should be excluded from this fast-tier pick while still remaining in the tier (soft signal. The ceiling applies at selection time, not tier membership). A zero/unknown RTT never trips the ceiling.
      Parameters:
      profile - the candidate profile
      rttCeilingMs - the adaptive ceiling from computeFastRttCeiling(double)
      Returns:
      whether the peer is above the ceiling
    • softPurgeThreshold

      static int softPurgeThreshold(int knownProfiles)
      The smallest tier size at which peers may be evicted for a soft reason.

      Scaled to the number of known profiles rather than fixed, because a fixed count means different things at different network sizes: demanding 500 peers of a 5,000-profile network is a real constraint, while demanding the same of an 800-profile network is simply unreachable, which silently disables the eviction entirely and lets the tier decay one-way.

      One tenth of the known profiles, capped at MAX_SOFT_PURGE_FLOOR: the fraction keeps the requirement proportionate on small networks, and the cap stops it becoming so large on a big one that no tier ever qualifies. Below roughly MAX_SOFT_PURGE_FLOOR * 10 profiles the cap is not reached, so a small router is held to the proportionate bar.

      Pure decision — no context access, safe for unit tests.

      Parameters:
      knownProfiles - the number of profiles the router knows about
      Returns:
      the minimum tier size at which soft eviction applies; no size qualifies when the population is unknown
    • purgeReasonFor

      static ProfileOrganizer.PurgeReason purgeReasonFor(boolean banned, boolean unreachable, boolean tierCapable, boolean softEvictionAllowed, boolean hasRecentFailures, boolean inLossProbation, boolean lowAcceptance)
      Why a peer listed in a tier should be evicted, or null to keep it.

      Extracted from purgeUnusableFromMap(Map, String, long, double, boolean, Map) so the precedence and the gating are testable without a router context. The order is a precedence, not a set of independent checks: a banned peer is reported as banned even if it is also unreachable, because that is the most actionable fact about it and the one an operator greps for.

      The three categorical reasons apply at any tier size. The two soft ones require softEvictionAllowed, which the caller derives from the population-scaled threshold, so a starved tier keeps peers that are merely underperforming while still losing the ones that must not be there at all.

      Pure decision — no context access, safe for unit tests.

      Parameters:
      banned - the peer is banlisted
      unreachable - the transport reports the peer unreachable
      tierCapable - the peer still meets its tier's bandwidth class
      softEvictionAllowed - whether the tier is above the soft-purge threshold
      hasRecentFailures - the peer has sustained recent build/test failures
      inLossProbation - the peer is inside its loss-probation window
      lowAcceptance - the peer's tunnel acceptance is below the bar
      Returns:
      the reason to evict for, or null to leave the peer in place
    • needsTierRestore

      static boolean needsTierRestore(int currentSize, int oldSize)
      Whether a shrunken tier needs restoration: below half its old size and the old size was substantial. Prevents starvation when thresholds shift unfavorably.

      Pure decision — no context access, safe for unit tests.

      Parameters:
      currentSize - current tier size
      oldSize - pre-reorganize tier size
      Returns:
      whether the tier should be restored
    • purgeStaleProfileFiles

      public void purgeStaleProfileFiles()
      Remove profile files that are no longer worth keeping: those whose peer is genuinely stale at any size, and those beyond the disk retention floor.

      See ProfilePersistenceHelper.purgeExcessProfiles(Set, int) for the two rules and why neither lets a recently active peer be deleted for its bandwidth tier.

    • countExceedingMean

      static int countExceedingMean(double[] capacities, double meanCapacity)
      How many of the given capacities are strictly above the mean.

      Scanned rather than derived from an index into the sorted array: the mean is a repeated value whenever capacities cluster, and Arrays.binarySearch returns only some index among equal entries, so an index-derived count silently includes peers whose capacity merely equals the mean and can flip the >= minHighCap branch. The scan is over a primitive array the sort above already walked.

      Parameters:
      capacities - the capacities; the caller holds them sorted, but the count does not depend on their order
      meanCapacity - the mean to compare against
      Returns:
      the number of entries greater than the mean, never negative
    • clampMaxProfiles

      static int clampMaxProfiles(int maxProfiles)
      Clamps the configured max-profiles value into [100, ABSOLUTE_MAX_PROFILES].

      Pure decision — no context access, safe for unit tests.

      Parameters:
      maxProfiles - the configured or default value
      Returns:
      the clamped value
    • isEvictable

      static boolean isEvictable(PeerProfile profile, Map<Hash, PeerProfile> fastPeers, Map<Hash, PeerProfile> highCapPeers, long activeThreshold, int fastPeerLimit, int highCapacityLimit)
      Whether a profile is eligible for eviction under the profile cap: not protected by a fast/high-cap tier slot that still has room below its limit, and no send or heard-from activity within the active window.

      Pure decision. No context access, safe for unit tests.

      Parameters:
      profile - the profile under consideration
      fastPeers - the current fast tier map
      highCapPeers - the current high-cap tier map
      activeThreshold - the activity window cutoff (now - 48h)
      fastPeerLimit - fast tier size at or below which its members keep eviction protection; above it, fast members are evictable like any other
      highCapacityLimit - high-cap tier size at or below which its members keep eviction protection; above it, high-cap members are evictable
      Returns:
      whether the profile may be evicted
    • isStaleAbsentPeer

      static boolean isStaleAbsentPeer(PeerProfile profile, long now, long absentThreshold)
      Whether the peer's last activity (send, heard-from, or heard-about) is older than the absent threshold. I.e. it has been absent from the netDb for at least that long. A peer that was never contacted (all-zero timestamps) counts as stale.

      Pure decision — no context access, safe for unit tests.

      Parameters:
      profile - profile whose newest send, heard-from or heard-about timestamp sets the age
      now - current time in ms
      absentThreshold - stale threshold in ms
      Returns:
      whether the peer is stale-absent
    • evictProfilesNotInNetdb

      void evictProfilesNotInNetdb()
      Evict profiles for peers no longer in the network database. Keeps profile files on disk — they'll be reloaded if the peer reappears. Acquires the write lock.
    • speedThresholdCutoff

      static int speedThresholdCutoff(int qualifyingCount)
      Rank boundary for the speed threshold: the top 30% of qualifying peers, capped at 50. 0-based, so rank 0 is the fastest.

      The qualifying count drives the rank, never the profile count: the profile count is an order of magnitude larger and would pin the rank at the cap, asking for a peer that does not exist.

      Pure decision. No context access, safe for unit tests.

      Parameters:
      qualifyingCount - number of peers that passed the capacity and activity gates
      Returns:
      the rank to read the boundary peer from, or 0 for an empty set
    • selectSpeedBoundary

      static PeerProfile selectSpeedBoundary(Collection<PeerProfile> profiles, long now, double capacityThreshold)
      The profile whose speed becomes the speed threshold: the one at rank speedThresholdCutoff(int) of the qualifying set, ranked fastest first. Only that one profile is ever read, and the rank is capped at 50, so a bounded top-K selection replaces a full sort of every profile.
      Parameters:
      profiles - candidates, not necessarily sorted
      now - current time in ms, for the activity test
      capacityThreshold - minimum capacity to qualify
      Returns:
      the boundary profile, or null if none qualifies
    • countQualifying

      static int countQualifying(Collection<PeerProfile> profiles, long now, double capacityThreshold)
      How many of the given profiles qualify for the speed-threshold ranking. The rank read from the ranked set is a fraction of this count, not of the profile count, so it has to be known before the boundary is selected.
      Parameters:
      profiles - candidates, not necessarily sorted
      now - current time in ms, for the activity test
      capacityThreshold - minimum capacity to qualify
      Returns:
      the qualifying count, never negative
    • selectNthFastest

      static PeerProfile selectNthFastest(Collection<PeerProfile> profiles, long now, double capacityThreshold, int k)
      Select the k-th fastest qualifying profile (1-based) without sorting the whole candidate set.

      Holds the k fastest profiles seen so far in an unsorted bounded array plus the index of the slowest: a slower profile is discarded in O(1), one that displaces the slowest costs a k-element rescan. Worst case O(n·k), and k is at most 51 for the only caller.

      Ties in speed may resolve to a different peer of equal speed than a full sort would have picked; only the boundary value is read.

      Parameters:
      profiles - candidates, not necessarily sorted
      now - current time in ms, for the activity test
      capacityThreshold - minimum capacity to qualify
      k - how many of the fastest to keep, 1-based
      Returns:
      the k-th fastest qualifying profile, or null if fewer than k qualify
    • isExcludedFromProfiling

      boolean isExcludedFromProfiling(Hash peer)
      Check if a peer should be excluded from profiling. Excludes low bandwidth tiers (K, L, M, Unknown) and G cap (no tunnels).

      This is the single gate in front of profile creation, and it covers all three ways one can be made: getOrCreateProfileNonblocking(Hash), addProfile(PeerProfile) (which is how stored profiles are loaded at startup), and the periodic sweep. A peer failing it therefore has no profile at all, so it costs no RAM and cannot be written to disk.

      The bandwidth half of this check was documented here but never performed: the body tested only the no-tunnels capability, while the tier test sat in isLowBandwidthTierName(String) with no caller in the codebase. Peers advertising K, L, M or Unknown were profiled, tracked and persisted despite advertising that they will not usefully host a tunnel.

      Parameters:
      peer - the peer hash
      Returns:
      true if the peer should not be profiled
    • isExcludedFromProfiling

      static boolean isExcludedFromProfiling(String capabilities, String bandwidthTier)
      Should a peer advertising these capabilities and bandwidth tier be profiled?

      Pure decision form of isExcludedFromProfiling(Hash), so the rule can be pinned without a RouterInfo or a network database.

      Parameters:
      capabilities - the peer's advertised capabilities, never null
      bandwidthTier - the peer's advertised bandwidth tier
      Returns:
      true if no profile should be created for the peer
    • isLowBandwidthTierName

      static boolean isLowBandwidthTierName(String tier)
      Whether a bandwidth tier name is one of the tiers excluded from profiling. Pure decision — no context access, safe for unit tests.
      Parameters:
      tier - the advertised bandwidth tier
      Returns:
      true for K, L, M, or Unknown
    • qualifiesHighBandwidthTier

      static boolean qualifiesHighBandwidthTier(String tier, String caps)
      Whether a bandwidth tier and capability string together qualify the peer for the high-capacity / fast tiers: X/P/O tier and none of the D (moderate congestion), E (severe congestion), G (no tunnels) or U (unreachable) capability flags.

      Pure decision — no context access, so a (tier, caps) pair already in hand can be tested without a router.

      Parameters:
      tier - the advertised bandwidth tier
      caps - the peer's capability string
      Returns:
      true if X/P/O tier and no D/E/G/U caps
    • isHighBandwidthTierName

      static boolean isHighBandwidthTierName(String tier)
      Whether a bandwidth tier is one of the high-capacity tiers (O, P, X).

      Pure decision — no context access, safe for unit tests.

      Parameters:
      tier - the advertised bandwidth tier, already stripped of HTML
      Returns:
      true for O, P, or X
    • getHighCapRTTThreshold

      public double getHighCapRTTThreshold()
      Get the high-capacity RTT ceiling for display and diagnostics. High-cap has no RTT gate — acceptance ratio and loss gates handle quality. Returns 0 (no ceiling).
      Returns:
      0 (high-cap has no RTT ceiling)
    • getMinCandidateSample

      public static int getMinCandidateSample(RouterContext ctx)
      Read the candidate-sample floor, honouring the configured override. Clamped to [16, MAX_CANDIDATE_SAMPLE] so a bad value degrades to a sane range rather than scanning the whole tier or collapsing to a single candidate.
      Parameters:
      ctx - the router context
      Returns:
      the floor to use for maxCandidateSample
    • setMinCandidateSample

      public static void setMinCandidateSample(int val)
      Override the candidate-sample floor at runtime.
      Parameters:
      val - the new floor, clamped to [16, MAX_CANDIDATE_SAMPLE]
    • maxCandidateSample

      static int maxCandidateSample(int howMany, int peerCount)
      Cap on how many tier peers to gate-check when selecting howMany tunnels. Scanning all ~670 fast peers per selection was a CPU hot path; a 20× sample (min 20) cut work ~10× on large tiers but, because HashMap iteration order is stable, every selection examined the same prefix of the tier — the rest of it stayed unreachable while that prefix kept passing, so tier size never became choice. With the scan start rotated, the sample is the size of one attempt's lottery: 64 gives lockedPickLowestPriority a real low-latency pick while remaining an order of magnitude cheaper than a full tier scan. A 10× sample was tried before the original 20× and hurt build success, so the 20× multiplier for larger requests is kept.
      Parameters:
      howMany - tunnels requested (may be 0 or negative)
      peerCount - size of the tier map (may be 0)
      Returns:
      maximum candidates to examine, never negative
    • maxCandidateSample

      static int maxCandidateSample(int howMany, int peerCount, int floor)
      Candidate-sample cap for a configurable floor. Split out from maxCandidateSample(int, int) so the arithmetic is testable without a RouterContext.
      Parameters:
      howMany - peers the caller wants
      peerCount - size of the tier being sampled
      floor - minimum candidates to examine regardless of howMany
      Returns:
      maximum candidates to examine, never negative
    • profileToPromote

      static PeerProfile profileToPromote(PeerProfile live, PeerProfile fallback)
      Which profile a promotion pass should act on: the live one when the map has it, the caller's otherwise.

      The TreeSet's copy may be stale, so the live profile decides. Making the choice a named decision is what lets the promotion and its log reach the same object — they used to decide separately, so the log printed the copy's capacity while the promotion ran on the live one.

      Parameters:
      live - the profile from _notFailingPeers, may be null
      fallback - the profile the caller already holds
      Returns:
      the profile to act on, never null
    • tierScanStarved

      static boolean tierScanStarved(int candidates, int howMany, int examined, int skipExcluded, int skipGated, int skipSliced, int skipIp, int skipRtt)
      Whether a tier scan starved badly enough to be worth reporting.

      All five skip reasons participate. The guard used to sum only four of the five it was about to pass to the logger, so a tier emptied purely by sub-tier slicing produced no warning. The one starvation cause with a dedicated counter was the one that stayed silent. Extracting the sum is what makes "every reason counts" checkable.

      Parameters:
      candidates - how many candidates the scan produced
      howMany - peers the caller asked for
      examined - entries walked before giving up
      skipExcluded - rejected by the live exclusion set
      skipGated - rejected by a hard gate
      skipSliced - rejected by the sub-tier slice
      skipIp - rejected by IP diversity
      skipRtt - above the adaptive RTT ceiling
      Returns:
      true when the scan found nothing and something specific caused it
    • pickLowestPriority

      public static int pickLowestPriority(List<Hash> candidates, float[] priority, int howMany, Set<Hash> matches)
      Choose up to howMany candidates in ascending priority order.

      This loop is the reason the peer-selection callers may size a fixed-capacity ArraySet to exactly the number of peers they asked for:

      An ArraySet throws SetFullException once written past its capacity, so if this loop ever wrote more than howMany entries those callers would throw at runtime rather than degrade. The bound s < howMany && s < sz is therefore load-bearing, and it is pinned by PeerSelectionBoundTest.picksNeverExceedHowMany and its neighbours.

      Distinctness falls out of the swap rather than from a membership test: the chosen entry is moved to index s and the next inner scan starts at s + 1, so an entry already picked can never be revisited. candidates and priority are reordered in place to achieve that, which is why both are taken as mutable.

      Parameters:
      candidates - peer hashes, reordered in place
      priority - per-candidate score, parallel to candidates, reordered in place
      howMany - maximum entries to choose; values below one choose nothing
      matches - receives the chosen hashes
      Returns:
      how many entries were actually added to matches
    • maskedIPKey

      static String maskedIPKey(byte[] ip, int mask)
      Fingerprint key for one masked IP, byte-identical to the key MaskedIPSet.maskedIP builds for the same address and mask.

      Format: a family-delimiting leading char ('.' for IPv4, ':' for IPv6, which also doubles the matched byte count), then two '0'-offset hex nibbles per matched byte. The leading char differs by address family and port keys begin with 'p', family keys with 'x', so an IP key can never equal a port or family key. Keeping the MaskedIPSet format means an accumulator built by MaskedIPSet's own constructor still compares equal; the floodfill path's packed-long key cannot be used because the accumulator arrives as a MaskedIPSet from callers outside this package. ProfileOrganizerSelectionCostTest pins the format.

      Parameters:
      ip - an IPv4 (4-byte) or IPv6 (16-byte) address
      mask - 1-4, the number of leading bytes to match
      Returns:
      the fingerprint key; equal keys mean "same masked subnet"
    • isSelectable

      public boolean isSelectable(Hash peer)
      Whether the given peer is eligible for selection. Fetches the build success ratio once; per-peer callers should use isSelectable(Hash, double) with a value fetched once per scan.
      Parameters:
      peer - hash of the peer to judge
      Returns:
      true if the peer passes every selection gate
    • isExcessiveLifetimeFailure

      static boolean isExcessiveLifetimeFailure(PeerProfile prof)
      Whether the given profile carries excessive cumulative tunnel failures. Dual gate: hard exclusion at MAX_LIFETIME_TUNNEL_FAILURES failures or when the lifetime failure ratio exceeds MAX_LIFETIME_FAILURE_RATIO. A null profile or null history is not a failure.

      The blame system (tunnelFailed()) only increments statistics — it never bans. Without this check, peers with 200+ failures keep getting selected because the ghost peer system clears on any success and the first-hop cooldown is only 5 minutes. Pure decision — no context access, safe for unit tests.

      Parameters:
      prof - the profile, may be null
      Returns:
      true when the peer should be excluded from selection
    • getExcessiveFailurePenalty

      static double getExcessiveFailurePenalty(Hash peer, PeerProfile prof)
      Selection penalty multiplier for peers between the soft and hard failure thresholds. Peers with SOFT_FAILURE_PENALTY_THRESHOLD to MAX_LIFETIME_TUNNEL_FAILURES lifetime failures are not excluded but receive a penalty that lowers their selection priority. Returns 1.0 (no penalty) for peers below the soft threshold or above the hard threshold (they'd be excluded anyway). Pure decision — no side effects.
      Parameters:
      peer - the peer hash
      prof - the peer's profile, or null if it has none
      Returns:
      a penalty multiplier in (1.0, 2.0] — higher means more penalized
    • isExcludedBuildTier

      static boolean isExcludedBuildTier(String rawTier)
      Whether a RouterInfo's advertised bandwidth tier is one that cannot host a tunnel: L, M, or N.

      The raw string is compared directly rather than through DataHelper.stripHTML, which is not a weakening: stripHTML only substitutes spaces for < > " ', so stripHTML(t).equals("L") holds exactly when t is the one-character string "L".

      Pure decision. No context access, safe for unit tests.

      Parameters:
      rawTier - the tier string as advertised, possibly HTML-obfuscated
      Returns:
      whether the tier excludes the peer from tunnel hosting
    • hasRecentProofOfLife

      static boolean hasRecentProofOfLife(PeerProfile profile, long now)
      True if the peer has shown proof of life within PROOF_OF_LIFE_WINDOW_MS: a successful send, heard-from, or heard-about within the last hour. A null profile (never seen) is not evidence of life. Used to trust a RouterInfo that is older than the maximum age — the RouterInfo alone is not enough, the peer must have been active recently.

      Pure decision — no context access, safe for unit tests.

      Parameters:
      profile - the peer profile, null if none
      now - current time in ms
      Returns:
      whether the peer has recent proof of life
    • needsRouterInfoRefresh

      static boolean needsRouterInfoRefresh(RouterInfo info, PeerProfile profile, long now, long refreshAgeMs)
      Whether a RouterInfo is old enough that promoting on it risks a build failure: published before the threshold and no proof of life.

      An absent RouterInfo is not stale, it is missing, and is not this predicate's business: isHighBandwidthCapable(Hash) and isFastTierCapable(Hash) already refuse to promote a peer with no RouterInfo at all, so there is no promotion here to hold.

      Pure decision — no context access, safe for unit tests.

      Parameters:
      info - the peer's stored RouterInfo, may be null
      profile - the peer profile supplying proof of life, may be null
      now - current time in ms
      refreshAgeMs - staleness threshold in ms
      Returns:
      whether the RouterInfo is too stale to promote on
    • shouldDeferPromotionOnStaleRouterInfo

      static boolean shouldDeferPromotionOnStaleRouterInfo(int tierSize, int safeFloor)
      Whether a promotion may be held back on a stale RouterInfo without risking the tier it would join.

      The floor is the tier's configured minimum, which is also what fillFastTierFallbacks(long, Set, double) and fillHighCapFallback(long, Set, double) drive the tier back up to and what restorePreservedPeers(long, Set, Set, double) protects at half. At or above the minimum the tier can afford to leave the peer out; below it, it cannot.

      Pure decision — no context access, safe for unit tests.

      Parameters:
      tierSize - current size of the tier the peer would join
      safeFloor - size at or above which the tier can leave it out
      Returns:
      whether the promotion should be held back
    • promotionSkipLabel

      static String promotionSkipLabel(String reason)
      Display form of a promotion skip reason: prose words with the first letter capitalised, so the tally reads as a list of reasons rather than as code identifiers. The identifiers themselves stay greppable in the per-peer DEBUG line and in promotionSkipReason(PeerProfile, Hash, double, long).
      Parameters:
      reason - the reason promotionSkipReason(PeerProfile, Hash, double, long) returned
      Returns:
      the tally display form; the reason unchanged when unmapped
    • skipsPromotion

      boolean skipsPromotion(PeerProfile profile, Hash peer, double buildSuccess)
      Whether the peer should be skipped for tier promotion: not selectable, in a strict country, low tunnel acceptance, high-latency penalty, congested, or in loss probation. Mirrors the eligibility gates of lockedPlaceProfile().

      No side effects. Safe to evaluate without holding locks.

      Parameters:
      profile - the profile under consideration
      peer - the peer hash
      buildSuccess - the tunnel build success ratio in [0.0, 1.0]
      Returns:
      whether promotion should be skipped
    • promotionSkipReason

      String promotionSkipReason(PeerProfile profile, Hash peer, double buildSuccess, long now)
      Why skipsPromotion(PeerProfile, Hash, double) would skip this profile, or null when it would not.

      The one place the decision is made. The caller used to re-derive two of the five gates so it could log them, which meant a peer held back by congestion, loss probation, a strict country or low tunnel acceptance printed notPeerSelectable=false excessiveFailures=false — a line reading "the gates passed" while the peer was in fact skipped. Returning the reason from the decision itself is what stops the log from guessing, and stops the two from drifting apart again.

      Short-circuits on the first gate that fires, in the order the original disjunction evaluated them. The boolean result is unchanged, because the original was a pure OR over the same five conditions.

      Parameters:
      profile - the profile under consideration
      peer - the peer hash
      buildSuccess - the tunnel build success ratio in [0.0, 1.0]
      now - current time in ms
      Returns:
      a short reason, or null when promotion may proceed
    • promotionTransition

      static String promotionTransition(boolean wasFast, boolean wasHighCap, boolean nowFast, boolean nowHighCap)
      Describe a tier promotion as a from -> to transition, naming only the tiers actually gained. Logging unchanged membership (a tier that was and stayed true) reports no event and buries the one that happened, so a scan that changed nothing returns null and the caller logs nothing. This method only adds; a lost tier is never reported here.
      Parameters:
      wasFast - in the fast tier before the promotion
      wasHighCap - in the high-capacity tier before the promotion
      nowFast - in the fast tier after the promotion
      nowHighCap - in the high-capacity tier after the promotion
      Returns:
      e.g. "highCap -> fast", "none -> highCap"; null when no tier was gained
    • promotionEvidence

      static String promotionEvidence(int bonus, int raw, boolean promotedIsLive)
      Evidence line for a promotion log: only the values that explain something. A zero bonus or raw adds nothing to read, and a live-profile match is the normal case. Only the anomaly (the promoted object was not the live profile) earns its place. Returns null when every value is default, so the log line stays one line for a routine promotion.
      Parameters:
      bonus - the capacity bonus applied
      raw - the unclamped bonus the bonus was derived from
      promotedIsLive - whether the promoted object was the live profile
      Returns:
      a "\n* " continuation line, or null when all default
    • describeTierFill

      static String describeTierFill(String where, int fast, int fastTarget, int highCap, int highCapTarget, int examined, int alreadyTiered, int heldNoAddress, String skips)
      Summarise why the selection tiers could not be filled.

      Short because there were no candidates left to try is a discovery problem. Short because every candidate was gated out is a policy problem. Those call for different fixes, and from outside the reorg they look identical, so the breakdown is reported rather than inferred. How to read it: held-no-address above zero is a policy gate; examined zero means no candidates were found. That guide lives here, not in the emitted line. Zero counters report the absence of an event and stay out; the skip tally rides along as evidence for this same shortfall.

      Parameters:
      where - the caller, for attribution
      fast - the fast-tier size achieved
      fastTarget - the fast-tier size wanted
      highCap - the high-capacity-tier size achieved
      highCapTarget - the high-capacity-tier size wanted
      examined - candidates walked, including those rejected by a gate
      alreadyTiered - candidates skipped because already in both tiers, omitted when zero
      heldNoAddress - candidates that cleared every gate except having no usable address, omitted when zero
      skips - the drained skip tally with its own "\n* " prefix, or empty
      Returns:
      the shortfall and its causes, wrapped onto continuation lines
    • demoteIfStale

      public void demoteIfStale(Hash peer)
      Immediately demote a peer from fast/high-cap tiers if its RouterInfo is stale and it has no recent proof of life (fails isSelectable). Non-blocking — only acts if the peer is currently in those tiers.
      Parameters:
      peer - hash of the peer to demote
    • demoteIfHighLatency

      public void demoteIfHighLatency(Hash peer)
      Immediately demote a peer from fast/high-cap tiers. The caller must have already judged the peer high-latency; this only performs the tier removal. Non-blocking.
      Parameters:
      peer - hash of the peer to demote
    • demoteIfCongested

      public void demoteIfCongested(Hash peer)
      Immediately demote a peer from fast/high-cap tiers. The caller must have already judged the peer congested (cap D/E); this only performs the tier removal. Non-blocking - only acts if the peer is currently in those tiers.
      Parameters:
      peer - hash of the peer to demote
    • demoteIfNotLowLatency

      public void demoteIfNotLowLatency(Hash peer)
      Immediately demote a peer from the fast tier when a peer test shows it is no longer low-latency. Called from PeerTestJob when a test result arrives that contradicts the peer's tier membership. Non-blocking — only acts if the peer is currently in the fast tier.

      High-capacity membership is deliberately left alone. It is earned from capacity and throughput rather than latency, so a latency judgement does not speak to it; see the comment in the body.

      Parameters:
      peer - hash of the peer to demote
    • demotesFastTier

      static boolean demotesFastTier(boolean inFast, boolean lowLatency)
      Whether losing the low-latency flag revokes membership of the fast tier.

      Fast-tier membership is the latency promotion, so losing the flag revokes it. High-capacity membership is not revoked by this signal: it is earned from advertised capacity and sustained throughput, so a peer that has stopped being low latency has not stopped being high capacity. This method used to evict from both tiers, which with a calibrated per-transport floor meant a transport whose baseline rose during congestion could strip bandwidth-qualified peers out of the tier they had been admitted to.

      Parameters:
      inFast - whether the peer is currently in the fast tier
      lowLatency - whether the peer still holds the low-latency flag
      Returns:
      true if the peer should leave the fast tier
    • demoteIfBanned

      public void demoteIfBanned(Hash peer)
      Immediately demote a peer from fast/high-cap tiers. The caller must have already confirmed the ban; this only performs the tier removal. Non-blocking - only acts if the peer is currently in those tiers.
      Parameters:
      peer - hash of the peer to demote
    • noteFirstHopRtt

      public void noteFirstHopRtt(Hash peer, int rtt, long when)
      Record a measured direct-link RTT against a peer, by hash.
      Parameters:
      peer - the measured peer
      rtt - the measured round trip time in ms
      when - timestamp of the measurement
    • demoteIfUnreachableNow

      public void demoteIfUnreachableNow(Hash peer)
      Immediately demote a peer from fast/high-cap tiers on a single unreachable first hop, skipping the DEMOTE_STRIKE_THRESHOLD strikes and the cooldown that demoteIfUnreachable(Hash) requires. Non-blocking — only acts if the peer is currently in those tiers.
      Parameters:
      peer - hash of the peer to demote
    • demoteIfNoTunnel

      public void demoteIfNoTunnel(Hash peer)
      Immediately demote a peer from fast/high-cap tiers. The caller must have already judged the peer to have built no tunnel recently. This only performs the tier removal. Non-blocking - only acts if the peer is currently in those tiers.
      Parameters:
      peer - hash of the peer to demote
    • demoteIfUnreachable

      public void demoteIfUnreachable(Hash peer)
      Immediately demote a peer from fast/high-cap tiers when our transport connection to it failed as a tunnel first hop (unreachable). Uses a 3-strike threshold within the decay window to avoid premature demotion. A transient failure (e.g. pre-connect race) should not remove a peer from tiers, and strikes older than the window expire so a peer that recovered is not demoted by one later failure. Does not touch the tunnel failure counter. The caller records the failure blame (e.g. profileManager().tunnelFailed()).
      Parameters:
      peer - hash of the peer that failed as a first hop
    • noteMissingRouterInfo

      boolean noteMissingRouterInfo(Hash peer)
      Record that a stored profile was loaded for a peer the netdb cannot resolve.
      Parameters:
      peer - the peer whose RouterInfo is missing
      Returns:
      true if recorded, false if the recovery list was already full
    • mayDrainMissingRouterInfo

      boolean mayDrainMissingRouterInfo(long now)
      Whether enough time has passed to request the next batch of missing RouterInfos.
      Parameters:
      now - current time in milliseconds
      Returns:
      true if the drain interval has elapsed
    • takeMissingRouterInfoBatch

      List<Hash> takeMissingRouterInfoBatch(long now)
      Hand over the next batch of peers whose RouterInfo should be requested.
      Parameters:
      now - current time in milliseconds
      Returns:
      the peers to look up, possibly empty
    • getMissingRouterInfoPending

      int getMissingRouterInfoPending()
      Peers still waiting for their RouterInfo to be requested.
      Returns:
      the number pending
    • getMissingRouterInfoDropped

      int getMissingRouterInfoDropped()
      Peers not recorded because the recovery list was full.
      Returns:
      the number dropped
    • demoteBatch

      public void demoteBatch(Set<Hash> peers)
      Batch-demote peers from fast/high-cap tiers under a single write lock. Peers not currently in any tier are silently skipped. One promoteToFillTiers() call after all removals.
      Parameters:
      peers - peers to evict — may be empty (no-op, no lock)
    • demoteFastOnlyBatch

      public void demoteFastOnlyBatch(Set<Hash> peers)
      Batch-remove peers from fast tier only, keeping them in high-cap. Used to demote peers with test failures from fast to high cap. Does NOT call promoteToFillTiers() — re-promotion would undo the demotion. The next full reorganize() fills any gaps.
      Parameters:
      peers - peers to remove from fast tier — may be empty (no-op, no lock)
    • nextStrikeCount

      static int nextStrikeCount(int previousStrikes, long lastStrikeTime, long now)
      Compute the next strike count after a failure, applying time-window decay. A previous strike older than DEMOTE_STRIKE_DECAY_MS no longer counts, so a peer that recovered is not demoted by one later failure.
      Parameters:
      previousStrikes - strike count before this failure (0 if none)
      lastStrikeTime - time of the previous strike (0 if none)
      now - the current clock reading in milliseconds, compared against DEMOTE_STRIKE_DECAY_MS
      Returns:
      the new strike count, at least 1
    • demoteIfHighRTT

      void demoteIfHighRTT(Hash peer, long responseTimeMs)
      Demote a peer from fast/high-cap tiers when its direct-link latency is poor.

      responseTimeMs is the round trip through an entire multi-hop tunnel, which TestJob.noteSuccess attributes to every peer in that tunnel. That is a reasonable profile statistic but the wrong input for first-hop selection: a peer with a fast direct link is blamed for the other hops it happened to be a member of, and the result is compared against a first-hop threshold. In production that evicted a large share of the fast tier on a latency distribution taken across the wrong hops, shrinking the candidate pool and leaving slower survivors.

      The tier decision therefore uses PeerProfile.getFirstHopRtt(long), measured on the direct link. The passed-in tunnel time is not consulted. A peer with no recorded first-hop RTT is left alone: unknown is not slow.

      Parameters:
      peer - the peer to evaluate
      responseTimeMs - full-tunnel test round trip, unused by the tier decision
    • firstHopRttIsSlow

      static boolean firstHopRttIsSlow(int firstHopRttMs, int thresholdMs)
      Whether a measured first-hop RTT warrants removal from the fast tiers.

      Pure so the policy is testable without a populated profile. An unknown measurement (negative) is never slow: we have not probed the peer, and evicting on absent evidence would drain the tier of exactly the peers we have not looked at yet.

      Parameters:
      firstHopRttMs - direct-link RTT in ms, negative when unknown
      thresholdMs - the latency ceiling in ms
      Returns:
      true if the peer should be evicted from the fast/high-cap tiers
    • demoteIfSlowFirstHop

      void demoteIfSlowFirstHop(Hash peer, int firstHopRttMs)
      Remove a peer from the fast/high-cap tiers if its measured direct-link RTT reaches the low-latency threshold.

      The threshold is unchanged at router.peerTestTimeout * 2; only the measurement changed, from a whole tunnel to one hop.

      Parameters:
      peer - the peer to evaluate
      firstHopRttMs - direct-link RTT in ms, negative when unknown
    • excludedOnAcceptance

      static boolean excludedOnAcceptance(long agreed, long rejected, int minRequests, boolean highStress)
      Whether a peer's tunnel acceptance is bad enough to exclude it, given its counts and the sample floor the tier in question applies.

      Pure decision. No context access, safe for unit tests. The tiers differ in the floor they pass, and that difference is the whole point: high capacity is the reservoir the fast tier seeds from and cannot afford to judge a peer on a handful of requests, while the fast tier is what build selection draws from and can. Both bars fall under stress, because a peer rejecting our requests during network-wide congestion has not demonstrated anything about itself.

      Parameters:
      agreed - lifetime requests the peer accepted
      rejected - lifetime requests the peer declined
      minRequests - samples required before acceptance may exclude at all
      highStress - whether build success is below ATTACK_THRESHOLD
      Returns:
      true if the peer should be excluded on acceptance
    • lossyReadmitAllowed

      static boolean lossyReadmitAllowed(float lossRatio, long ratioLastUpdate, long lossySince, long now, long freshWindowMs, long minAgeMs, float threshold, float fastTrackRatio, boolean tiersShort)
      Pure decision behind shouldReadmitLossy(PeerProfile, long), pinned by tests. A peer never demoted is always allowed. Otherwise the transport must have reported within the freshness window a ratio below the demotion threshold; that fresh-clean evidence admits immediately when the ratio is near-spotless (fastTrackRatio) or when the tiers are short (tiersShort) — a short tier cannot afford to hold a peer out for a clean-but-not-spotless measurement — and otherwise only after the minimum age has passed. A stale or absent report is never evidence of recovery.
      Parameters:
      lossRatio - last loss ratio reported by the transport, 0.0 = healthy
      ratioLastUpdate - when that ratio was reported, in ms
      lossySince - when the peer was demoted for loss, 0 if never
      now - current time in ms
      freshWindowMs - how old the last report may be and still count as fresh
      minAgeMs - minimum time since demotion before a not-spotless report admits
      threshold - the lossy demotion threshold the ratio must fall below
      fastTrackRatio - ratio below which the minimum age is skipped
      tiersShort - whether either tier is under target, widening the fast track
      Returns:
      true if the peer may be re-admitted
    • demoteIfLossy

      public void demoteIfLossy(Hash peer)
      Instantly remove a peer from the fast/high-capacity tiers when its decayed loss score exceeds the threshold, and mark it for loss probation. Called from the transport path via ProfileManagerImpl so a lossy peer is demoted as soon as its retransmit ratio crosses the bar, instead of waiting for the next reorganize cycle. Non-blocking: if a reorganize currently holds the write lock, the reorganize purge catches the peer instead.
      Parameters:
      peer - hash of the peer to demote and place into loss probation
    • getModerateLossyThreshold

      public static float getModerateLossyThreshold(RouterContext ctx)
      The moderate de-prioritization threshold in effect, read straight from config (there is no Tuner override, unlike getLossyThreshold(RouterContext)). Separate so a caller walking a whole candidate list can resolve both thresholds once instead of paying two config lookups per candidate.
      Parameters:
      ctx - the router context
      Returns:
      the loss score at or above which a peer is de-prioritized at selection
    • isModeratelyLossy

      static boolean isModeratelyLossy(float score, float moderateThreshold, float demoteThreshold)
      Whether a decayed loss score falls in the moderate band: at or above the moderate threshold but below the demotion threshold. Such peers remain eligible for the tiers. They never crossed the hard bar — but are de-prioritized at selection time (see LOSSY_SELECTION_PENALTY).

      Pure decision — the score and both thresholds are passed in so a caller scanning a candidate list resolves them once, safe for unit tests.

      Parameters:
      score - the peer's decayed loss score
      moderateThreshold - lower bound of the band, inclusive
      demoteThreshold - upper bound of the band, exclusive
      Returns:
      whether the score is in the moderate band
    • getAverageLossRatio

      public float getAverageLossRatio()
      Average loss ratio across the fast and high-capacity tiers with a fresh measurement, as a fraction (0.0 - 1.0). Peers whose loss data is older than PROP_LOSSY_WINDOW are skipped; 0.0 if no fresh data. The tiers are the baseline because the threshold governs demotion FROM them: as lossy peers are evicted the average drops and the bar tightens. Used by the Tuner to adapt PROP_LOSSY_THRESHOLD to the network.
      Returns:
      the mean loss ratio as a fraction of 1.0, or 0.0 if no fresh data
    • getFastAverageLossRatio

      public float getFastAverageLossRatio()
      Average loss ratio across the fast tier with a fresh measurement, as a fraction (0.0 - 1.0); 0.0 if none. See getAverageLossRatio().
      Returns:
      the mean fast-tier loss ratio as a fraction of 1.0, or 0.0 if no fresh data
    • getHighCapAverageLossRatio

      public float getHighCapAverageLossRatio()
      Average loss ratio across the high-capacity tier with a fresh measurement, as a fraction (0.0 - 1.0); 0.0 if none. See getAverageLossRatio().
      Returns:
      the mean high-capacity-tier loss ratio as a fraction of 1.0, or 0.0 if no fresh data
    • getMedianLossRatio

      public float getMedianLossRatio()
      Median loss ratio of the union of the fast and high-capacity tiers with a fresh measurement, as a fraction (0.0 - 1.0). 0.0 if none. The median is robust to the worst peers dragging the mean up, so the auto-tuned demotion threshold tracks the typical tier member. See getAverageLossRatio().
      Returns:
      the median tier loss ratio as a fraction of 1.0, or 0.0 if no fresh data
    • defaultTierSize

      static int defaultTierSize(int known, int base, int divisor)
      Fallback tier size for a threshold that scales with network size.

      Networks at or below SCALING_THRESHOLD known routers use the configured base; above it the base scales with a fraction of the network.

      Parameters:
      known - routers in the network database
      base - configured size to use, and the floor once scaling applies
      divisor - network size is divided by this once scaling applies
      Returns:
      the size to use unless a property overrides it
    • fastActiveCap

      static int fastActiveCap(int active, int base)
      Ceiling on the fast tier from the number of reachable peers.

      1.5x headroom over active for near-active peers, never below base.

      Parameters:
      active - peers reachable over any transport
      base - floor to keep even when very few peers are reachable
      Returns:
      the fast tier ceiling
    • highCapActiveCap

      static int highCapActiveCap(int active, int base)
      Ceiling on the high-capacity tier from the number of reachable peers.

      One per reachable peer, never below base.

      Was active * 2. That asks for more members than there are peers to put in them: at 1221 active peers it set a target of 2442 for a tier that tops out around 700, so the target could never be met, the early return in promoteToFillTiers() could never fire, and every demotion walked the whole capacity-ordered profile set looking for peers to seat in a tier that had already run out of candidates. A high-capacity member that is not reachable is not reservoir depth, it is a slot that cannot be used.

      Parameters:
      active - peers reachable over any transport
      base - floor to keep even when very few peers are reachable
      Returns:
      the high-capacity tier ceiling
    • getMinimumFastPeers

      protected int getMinimumFastPeers()
      Minimum number of peers to keep in the fast tier.
      Returns:
      the minimum fast peers
    • getMinimumFastPeers

      protected int getMinimumFastPeers(int known)
      Variant taking the network size, for callers that already know it.

      getKnownRouters() walks every entry in the network database, which is far too expensive to repeat once per candidate.

      Parameters:
      known - routers in the network database
      Returns:
      the minimum fast peers
    • getMaximumFastPeers

      protected int getMaximumFastPeers()
      Maximum number of peers to keep in the fast tier, capped by active peers.
      Returns:
      the maximum fast peers
    • getMaximumFastPeers

      protected int getMaximumFastPeers(int known, int active)
      Variant taking both expensive inputs, for callers that already have them.
      Parameters:
      known - routers in the network database
      active - peers currently reachable over any transport
      Returns:
      the maximum fast peers
    • getFastPeerCount

      public int getFastPeerCount()
      Current number of peers in the fast tier. Used by selectors to decide cross-pool diversity mode.
      Returns:
      fast tier size
    • getHighCapPeerCount

      public int getHighCapPeerCount()
      Current high-capacity tier population. Paired with getFastPeerCount() so first-hop selection can report the pool it drew from: a 256-candidate sample means something very different against a 200-peer tier (the whole pool) than a 1500-peer one (a fraction), and the two call for different responses.
      Returns:
      the number of peers in the high-capacity tier
    • getEffectiveCandidateSample

      public int getEffectiveCandidateSample(RouterContext ctx)
      The candidate-sample floor currently in effect, for logging.
      Parameters:
      ctx - the router context
      Returns:
      the floor passed to maxCandidateSample(int, int)
    • getMaximumHighCapPeers

      protected int getMaximumHighCapPeers()
      Maximum number of peers to keep in the high-capacity tier, capped by active peers.
      Returns:
      the maximum high cap peers
    • getMaximumHighCapPeers

      protected int getMaximumHighCapPeers(int known, int active)
      Variant taking both expensive inputs, for callers that already have them.
      Parameters:
      known - routers in the network database
      active - peers currently reachable over any transport
      Returns:
      the maximum high cap peers
    • getMinimumHighCapacityPeers

      protected int getMinimumHighCapacityPeers()
      Minimum number of peers to keep in the high-capacity tier.
      Returns:
      the minimum high capacity peers
    • getMinimumHighCapacityPeers

      protected int getMinimumHighCapacityPeers(int known)
      Variant taking the network size, for callers that already know it.
      Parameters:
      known - routers in the network database
      Returns:
      the minimum high capacity peers
    • main

      public static void main(String[] args)
      Command-line entry point; reads profile dump files and prints thresholds.
      Parameters:
      args - paths to gzipped profile dump files
    • neutraliseUnknownBuildSuccess

      static double neutraliseUnknownBuildSuccess(double ratio)
      Maps an unknown build-success reading onto a neutral 1.0.

      An absent stat, or a window in which nothing has settled yet, is not evidence of failure. Reading it as anything else would trip isLowBuildSuccess() and switch off profile eviction, lengthen ghost cooldowns and put the first-hop selector into its defensive path for no reason - so "unknown" has to arrive upstream of every one of those as 1.0.

      Parameters:
      ratio - the raw ratio, or NaN when unknown
      Returns:
      ratio, or 1.0 when it is NaN
    • getTunnelBuildSuccess

      public double getTunnelBuildSuccess()
      Tunnel build success ratio across the whole router, cached for BUILD_SUCCESS_CACHE_MS because a single lookup costs several rate reads. 1.0 (neutral) when the window is absent or empty.
      Returns:
      the build success ratio as a fraction of 1.0
    • isLowBuildSuccess

      public boolean isLowBuildSuccess()
      Whether recent tunnel build success is below the attack threshold.
      Returns:
      whether low build success
    • writeProfile

      public void writeProfile(PeerProfile profile)
      Persist the given profile to disk.
      Parameters:
      profile - profile to write
    • getAverageLowLatencyRTT

      public float getAverageLowLatencyRTT()
      Calibrated latency floor across fast peers with data, computed during each reorganize() as the mean of the fastest samples rather than of the whole population.

      This is a second bound on the low-latency judgement, not a second judgement: a peer must satisfy both the per-transport calibrated floor and this cohort floor. It is measured from peer-test response times, a different quantity from the direct-link RTT behind the per-transport floor, so the two are never averaged together and this one cannot stand in for the other.

      Returns:
      the cohort floor in ms, 0 when fewer than ProtocolRttBaseline.SAMPLES_FOR_BASELINE peers have data