java.lang.Object
net.i2p.router.networkdb.kademlia.NegativeLookupCache

class NegativeLookupCacheextends Object
Negative cache for network database lookup operations.

Caches failed lookup attempts to prevent repeated queries to unavailable or malicious peers. Uses per-entry TTL with backoff instead of a wholesale counter wipe: a key that trips the threshold stays cached for entryTtl(tripGeneration) from its last fail, and re-trips extend that hold up to ENTRY_TTL_MAX_MS. Clearing all keys on a timer synchronized re-probe storms across every recently-failed destination at once.

Partial (below-threshold) fail streaks still expire after netdb.negativeCache.cleanupInterval so the historical contract "N fails within the cleaner window" is preserved per key, without resetting unrelated keys.

Thread-safe implementation with atomic counters and scheduled cleanup operations for reliable concurrent access in multi-threaded environments.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    private class 
    Timer event expiring the cached lookups.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private final RouterContext
    The router context.
    private final int
    Failed lookups before a destination is bad.
    private final int
    Timed out lookups before a destination is bad.
    private final Map<Hash, Destination>
    The destinations known to be bad.
    private final Map<Hash,Long>
    Epoch ms until which a tripped key remains negatively cached.
    private static final long
    Default interval between the cleanup runs.
    Timer event expiring the cached entries.
    private final long
    Interval between the cleanup runs.
    private final ObjectCounter<Hash>
    Failed lookups per hash.
    (package private) static final long
    First-trip hold once the threshold is crossed (ms).
    (package private) static final long
    Cap on entry TTL after backoff (ms).
    private final long
    Base lifetime of a cached entry.
    private final long
    Longest lifetime of a cached entry.
    private final Map<Hash,Long>
    Last time a fail was recorded for the key (streak / age tracking).
    private static final int
    Most bad destinations remembered.
    (package private) static final int
    Maximum failures before caching (definitive peer replies, zero-lease).
    (package private) static final int
    Pure-timeout failures trip at a higher bar so a brief outage doesn't lock a live key.
    private static final int
    Backoff shift per trip generation before hitting the cap (2^n).
    private final ObjectCounter<Hash>
    Timed out lookups per hash.
    private final Map<Hash,Integer>
    How many times the key has tripped the threshold (TTL backoff).
  • Constructor Summary

    Constructors
    Constructor
    Description
    Creates a new NegativeLookupCache.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Negative cache the hash for one entry-TTL generation.
    void
    Clears the negative cache and bad destinations.
    void
    Clears the transient failure count for the given hash only, including its trip generation (next trip starts at base TTL).
    (package private) static boolean
    countsAsDefinitiveFail(int peersQueried)
    Pure decision: does this failure count toward the strict threshold? Zero-peer failures are local (job drop, no tunnels) and must not poison the key.
    (package private) static long
    entryTtlMs(int tripGeneration)
    Pure decision: TTL for a key that has tripped the threshold tripGeneration times (1 = first trip).
    private void
    expireDue(Hash h, long now)
    If the key already has a per-entry TTL, drop counts when due (lazy expire).
    void
    Negative cache the hash permanently until restart, but cache the destination.
    Cached bad destination for the given hash.
    boolean
    Check if the hash is in the negative cache.
    (package private) static boolean
    isEntryExpired(long cachedUntil, long now)
    Pure decision: has a tripped entry's TTL expired?
    (package private) static boolean
    isStreakStale(long lastFailAt, long now, long streakWindowMs)
    Pure decision: has a below-threshold fail streak gone stale?
    private boolean
    Whether the cache is full enough to stop storing.
    void
    Record a failed lookup for the given hash.
    void
    Record a pure-timeout search failure (no peer ever replied).
    private void
    maybeTrip(Hash h, long now, boolean wasTripped)
    On the transition into the cached state, set a per-entry TTL with backoff from how many times this key has tripped before.
    private void
    refreshStreak(Hash h, long now)
    Discard a below-threshold fail streak that has outlived cleanTime so "N fails within the window" still holds without a global wipe.
    void
    Stops the timer.

    Methods inherited from class Object

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

    • counter

      private final ObjectCounter<Hash> counter
      Failed lookups per hash.
    • timeoutCounter

      private final ObjectCounter<Hash> timeoutCounter
      Timed out lookups per hash.
    • badDests

      private final Map<Hash, Destination> badDests
      The destinations known to be bad.
    • lastFailAt

      private final Map<Hash,Long> lastFailAt
      Last time a fail was recorded for the key (streak / age tracking).
    • cachedUntil

      private final Map<Hash,Long> cachedUntil
      Epoch ms until which a tripped key remains negatively cached.
    • tripCount

      private final Map<Hash,Integer> tripCount
      How many times the key has tripped the threshold (TTL backoff).
    • _maxFails

      private final int _maxFails
      Failed lookups before a destination is bad.
    • _maxTimeoutFails

      private final int _maxTimeoutFails
      Timed out lookups before a destination is bad.
    • cleaner

      private final SimpleTimer2.TimedEvent cleaner
      Timer event expiring the cached entries.
    • cleanTime

      private final long cleanTime
      Interval between the cleanup runs.
    • entryTtlBase

      private final long entryTtlBase
      Base lifetime of a cached entry.
    • entryTtlMax

      private final long entryTtlMax
      Longest lifetime of a cached entry.
    • _context

      private final RouterContext _context
      The router context.
    • MAX_FAILS

      static final int MAX_FAILS
      Maximum failures before caching (definitive peer replies, zero-lease).
      See Also:
    • MAX_TIMEOUT_FAILS

      static final int MAX_TIMEOUT_FAILS
      Pure-timeout failures trip at a higher bar so a brief outage doesn't lock a live key.
      See Also:
    • MAX_BAD_DESTS

      private static final int MAX_BAD_DESTS
      Most bad destinations remembered.
      See Also:
    • CLEAN_TIME

      private static final long CLEAN_TIME
      Default interval between the cleanup runs.
      See Also:
    • ENTRY_TTL_BASE_MS

      static final long ENTRY_TTL_BASE_MS
      First-trip hold once the threshold is crossed (ms).
      See Also:
    • ENTRY_TTL_MAX_MS

      static final long ENTRY_TTL_MAX_MS
      Cap on entry TTL after backoff (ms).
      See Also:
    • MAX_TTL_SHIFT

      private static final int MAX_TTL_SHIFT
      Backoff shift per trip generation before hitting the cap (2^n).
      See Also:
  • Constructor Details

    • NegativeLookupCache

      public NegativeLookupCache(RouterContext context)
      Creates a new NegativeLookupCache.
      Parameters:
      context - the router context
  • Method Details

    • entryTtlMs

      static long entryTtlMs(int tripGeneration)
      Pure decision: TTL for a key that has tripped the threshold tripGeneration times (1 = first trip). Doubling backoff, capped at ENTRY_TTL_MAX_MS (overridable max applies at call).
      Parameters:
      tripGeneration - how many times this key has tripped (0 or less treated as 1)
      Returns:
      hold time in ms for the first-trip base of 30s
    • isEntryExpired

      static boolean isEntryExpired(long cachedUntil, long now)
      Pure decision: has a tripped entry's TTL expired?
      Parameters:
      cachedUntil - epoch ms at which the entry becomes expired (inclusive)
      now - current epoch ms
      Returns:
      true if the entry should be expired
    • isStreakStale

      static boolean isStreakStale(long lastFailAt, long now, long streakWindowMs)
      Pure decision: has a below-threshold fail streak gone stale?
      Parameters:
      lastFailAt - epoch ms of the last fail for the key, or -1 if none
      now - current epoch ms
      streakWindowMs - how long a partial streak remains valid (age >= window marks stale)
      Returns:
      true if partial counts should be discarded
    • lookupFailed

      public void lookupFailed(Hash h)
      Record a failed lookup for the given hash. Counts toward the strict threshold (definitive peer replies).
      Parameters:
      h - the hash that failed lookup
    • lookupTimeout

      public void lookupTimeout(Hash h)
      Record a pure-timeout search failure (no peer ever replied). Uses a higher threshold so a brief tunnel outage doesn't lock a live key.
      Parameters:
      h - the hash that timed out
    • countsAsDefinitiveFail

      static boolean countsAsDefinitiveFail(int peersQueried)
      Pure decision: does this failure count toward the strict threshold? Zero-peer failures are local (job drop, no tunnels) and must not poison the key.
      Parameters:
      peersQueried - number of peers actually sent a query
      Returns:
      true if the failure should use lookupFailed(Hash)
    • cache

      public void cache(Hash h)
      Negative cache the hash for one entry-TTL generation.
      Parameters:
      h - the hash to cache
    • isCached

      public boolean isCached(Hash h)
      Check if the hash is in the negative cache. Lazily expires per-entry TTLs and stale fail streaks.
      Parameters:
      h - the hash to check
      Returns:
      true if the hash is cached
    • failPermanently

      public void failPermanently(Destination dest)
      Negative cache the hash permanently until restart, but cache the destination.
      Parameters:
      dest - the destination to permanently fail
    • getBadDest

      public Destination getBadDest(Hash h)
      Cached bad destination for the given hash.
      Parameters:
      h - the hash to look up
      Returns:
      the destination or null if not cached
    • clear

      public void clear(Hash h)
      Clears the transient failure count for the given hash only, including its trip generation (next trip starts at base TTL). Permanent negative entries (failPermanently(Destination)) are left intact, so a confirmed-bad destination cannot be re-probed into searching.
      Parameters:
      h - the hash to clear
    • clear

      public void clear()
      Clears the negative cache and bad destinations.
    • stop

      public void stop()
      Stops the timer. May not be restarted.
    • isTripped

      private boolean isTripped(Hash h)
      Whether the cache is full enough to stop storing.
      Parameters:
      h - the key whose fail counters are compared with the thresholds
      Returns:
      true if either counter is at or over its cache threshold.
    • expireDue

      private void expireDue(Hash h, long now)
      If the key already has a per-entry TTL, drop counts when due (lazy expire). Does not touch permanent badDests.
      Parameters:
      h - the key whose per-entry TTL is checked
      now - the current time in epoch milliseconds
    • refreshStreak

      private void refreshStreak(Hash h, long now)
      Discard a below-threshold fail streak that has outlived cleanTime so "N fails within the window" still holds without a global wipe.
      Parameters:
      h - the key whose fail streak may have gone stale
      now - the current time in epoch milliseconds
    • maybeTrip

      private void maybeTrip(Hash h, long now, boolean wasTripped)
      On the transition into the cached state, set a per-entry TTL with backoff from how many times this key has tripped before.
      Parameters:
      h - the key that may be entering the cached state
      now - the current time in epoch milliseconds, the base of the new TTL
      wasTripped - true if the key was already tripped, in which case nothing changes