java.lang.Object
net.i2p.router.transport.ReverseDnsLookup

public class ReverseDnsLookupextends Object
Reverse-DNS resolver and cache for the comm system.

Owns all reverse-DNS state that previously lived in CommSystemFacadeImpl: the size-limited in-memory IP-to-hostname cache with persistent file backup, the background lookup executor used by the non-blocking getCanonicalHostName(String) and getLocalHostName(String) lookups, and the periodic cache file writer. The facade retains thin delegation stubs so external callers are unaffected.

The cache is backed by a disk file that is safely read and written using the writer's own snapshot, so a crash mid-write cannot corrupt existing entries. Entries expire in memory after EXPIRE_TIME and are evicted from disk if older than EVICT_THRESHOLD. Cache size is bounded by memory-based limits (see maxCacheSize(boolean, boolean)) with automatic eviction of expired and then oldest entries.

Supports migration from older cache file formats missing timestamps.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static class 
    Cache entry for IP address and hostname mappings.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    (package private) static final int
    Cleanup frequency once the cache is at or over its cap: a full sweep runs on every 1<<CLEANUP_BITS puts that happen while over/at the cap, instead of on every put.
    (package private) static final int
    How many cache entries the map may exceed its cap by before a sweep runs immediately.
    (package private) static final String
    Property that enables reverse lookups; the single source of truth.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Create the resolver and its background executor.
  • Method Summary

    Modifier and Type
    Method
    Description
    (package private) static boolean
    accelerateEviction(int size, int maxSize)
    Whether a full cache should evict entries at an accelerated rate.
    void
    adjustPool(int coreSize)
    Adjust the running rDNS executor pool sizes.
    (package private) static boolean
    cacheFileEntryFresh(long ageMs, long evictThresholdMs)
    Whether an entry read from the persistence file is fresh enough to reuse.
    static int
    The number of entries in the rDNS cache.
    boolean
    Whether reverse lookups are enabled.
    (package private) static boolean
    entryExpired(long ageMs, long baseExpireMs, boolean isUnknown)
    Whether a cache entry has outlived its permitted lifetime.
    (package private) static int
    expireHours(boolean has512MB, boolean has1GB)
    RDNS cache entry lifetime in hours, based on available memory.
    int
    Returns rDNS executor active thread count, or 0 if not running.
    Canonical hostname for the given IP address from cache or DNS.
    The canonical host name for the given IP address, resolved synchronously.
    static int
    The rDNS executor core pool size.
    Fast hostname lookup that never blocks on I/O (MMDB or network).
    static int
    The rDNS executor max pool size.
    static int
    The computed maximum rDNS cache size based on available memory.
    int
    Returns rDNS executor total thread count, or 0 if not running.
    int
    Returns rDNS executor pending lookup count, or 0 if not running.
    static String
    Cache statistics for monitoring.
    double
    Returns rDNS executor utilization as a ratio (0.0-1.0), or Double.NaN if not running.
    (package private) static int
    maxCacheSize(boolean has512MB, boolean has1GB)
    Maximum rDNS cache size, based on available memory.
    (package private) static boolean
    needRdnscacheSweep(int size, int maxSize, int counter)
    Decide whether a cache insert must run a full-cache cleanup sweep.
    static String
    The size of the rDNS cache file, in KB.
    (package private) static ReverseDnsLookup.CacheEntry
    Parse a persisted line back into a cache entry.
    (package private) static String
    Serialize a cache entry for persistence.
    (package private) static void
    Load the persistence file into the in-memory cache at startup.
    static void
    setCorePoolSize(int size)
    The rDNS executor core pool size, bounded 2-8.
    static void
    setMaxPoolSize(int size)
    The rDNS executor max pool size, bounded 2-8.
    void
    Stop the periodic cache writer and shut down the lookup executor.

    Methods inherited from class Object

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

    • PROP_ENABLE_REVERSE_LOOKUPS

      static final String PROP_ENABLE_REVERSE_LOOKUPS
      Property that enables reverse lookups; the single source of truth.
      See Also:
    • MAX_SLACK

      static final int MAX_SLACK
      How many cache entries the map may exceed its cap by before a sweep runs immediately. Trades a few hundred surplus entries (CHM node wins are negligible) for avoiding a synchronous full-map sweep on every put.
      See Also:
    • CLEANUP_BITS

      static final int CLEANUP_BITS
      Cleanup frequency once the cache is at or over its cap: a full sweep runs on every 1<<CLEANUP_BITS puts that happen while over/at the cap, instead of on every put.
      See Also:
  • Constructor Details

    • ReverseDnsLookup

      public ReverseDnsLookup(RouterContext ctx, GeoIP geoIP)
      Create the resolver and its background executor.

      The executor is started eagerly so the queue-size rate stat is ready before the first lookup, avoiding a first-hit initialization stall on the page-rendering path.

      Parameters:
      ctx - the router context
      geoIP - already-constructed GeoIP database for ASN fallback
  • Method Details

    • expireHours

      static int expireHours(boolean has512MB, boolean has1GB)
      RDNS cache entry lifetime in hours, based on available memory.

      Routers with less than 512 MB keep entries for 24 h; routers with at least 1 GB keep them for 48 h; everything else for 36 h. This bounds how stale a cached hostname may be before it is re-resolved, trading freshness against load on small memory-constrained routers.

      Parameters:
      has512MB - true if the router has at least 512 MB of max memory
      has1GB - true if the router has at least 1 GB of max memory
      Returns:
      entry lifetime in hours (24, 36, or 48)
    • maxCacheSize

      static int maxCacheSize(boolean has512MB, boolean has1GB)
      Maximum rDNS cache size, based on available memory.

      Caches 8000 entries on very limited routers, 24000 on routers with at least 1 GB, and 16000 otherwise. The bound prevents the persistence file and the in-memory map from growing without limit on the control path.

      Parameters:
      has512MB - true if the router has at least 512 MB of max memory
      has1GB - true if the router has at least 1 GB of max memory
      Returns:
      maximum number of cached entries (8000, 16000, or 24000)
    • accelerateEviction

      static boolean accelerateEviction(int size, int maxSize)
      Whether a full cache should evict entries at an accelerated rate.

      When the cache exceeds 90% of its maximum size, the TTL applied by entryExpired(long, long, boolean) is halved so eviction keeps up with insertion load. Choosing the threshold as a percentage of the max (not an absolute number) keeps behavior consistent across the memory-dependent cache sizes.

      Parameters:
      size - current cache entry count
      maxSize - maximum cache entry count
      Returns:
      true if the cache is more than 90% full
    • entryExpired

      static boolean entryExpired(long ageMs, long baseExpireMs, boolean isUnknown)
      Whether a cache entry has outlived its permitted lifetime.

      "unknown" entries (failed lookups) expire after a short fixed window so dead IPs are re-probed; all other entries use the caller-supplied base TTL, which itself may be halved by accelerateEviction(int, int).

      Parameters:
      ageMs - age of the entry in milliseconds
      baseExpireMs - normal entry TTL in milliseconds
      isUnknown - true if the cached hostname is the "unknown" marker
      Returns:
      true if the entry should be evicted
    • cacheFileEntryFresh

      static boolean cacheFileEntryFresh(long ageMs, long evictThresholdMs)
      Whether an entry read from the persistence file is fresh enough to reuse.

      Applies only at startup when the file is loaded. Entries older than the eviction threshold are skipped so a long-idle router does not resurrect months-old hostnames.

      Parameters:
      ageMs - age of the entry in milliseconds
      evictThresholdMs - maximum age accepted at load time
      Returns:
      true if the entry is fresh enough to cache
    • enableReverseLookups

      public boolean enableReverseLookups()
      Whether reverse lookups are enabled.
      Returns:
      true if reverse lookups are enabled
    • getCorePoolSize

      public static int getCorePoolSize()
      The rDNS executor core pool size.
      Returns:
      the core pool size, bounded 2-8
    • setCorePoolSize

      public static void setCorePoolSize(int size)
      The rDNS executor core pool size, bounded 2-8.
      Parameters:
      size - the new core pool size
    • getMaxPoolSize

      public static int getMaxPoolSize()
      The rDNS executor max pool size.
      Returns:
      the max pool size, bounded 2-8
    • setMaxPoolSize

      public static void setMaxPoolSize(int size)
      The rDNS executor max pool size, bounded 2-8.
      Parameters:
      size - the new max pool size
    • rdnsCacheSize

      public static String rdnsCacheSize()
      The size of the rDNS cache file, in KB.
      Returns:
      the file size in KB, suffixed with "KB"
    • countRdnsCacheEntries

      public static int countRdnsCacheEntries()
      The number of entries in the rDNS cache.
      Returns:
      the number of cached IP address to host name mappings
    • getRdnsCacheStats

      public static String getRdnsCacheStats()
      Cache statistics for monitoring.
      Returns:
      formatted string with cache stats
    • getMaxRdnsCacheSize

      public static int getMaxRdnsCacheSize()
      The computed maximum rDNS cache size based on available memory.
      Returns:
      the computed maximum rDNS cache size based on available memory
    • adjustPool

      public void adjustPool(int coreSize)
      Adjust the running rDNS executor pool sizes. Called by the Tuner when queue depth signals scaling.
      Parameters:
      coreSize - new core pool size (bounded 2-8)
    • getQueueSize

      public int getQueueSize()
      Returns rDNS executor pending lookup count, or 0 if not running.
      Returns:
      the rdns queue size
    • getActiveCount

      public int getActiveCount()
      Returns rDNS executor active thread count, or 0 if not running.
      Returns:
      the rdns active count
    • getPoolSize

      public int getPoolSize()
      Returns rDNS executor total thread count, or 0 if not running.
      Returns:
      the rdns pool size
    • getUtilization

      public double getUtilization()
      Returns rDNS executor utilization as a ratio (0.0-1.0), or Double.NaN if not running.
      Returns:
      the rdns utilization
    • shutdown

      public void shutdown()
      Stop the periodic cache writer and shut down the lookup executor.

      Cancels the background cache-file timer and the rDNS executor, waiting up to 5 seconds for in-flight lookups to drain before force-interrupting them, and clears the in-flight marker set so a later restart does not inherit stale pending state.

    • readRDNSCacheFromFile

      static void readRDNSCacheFromFile()
      Load the persistence file into the in-memory cache at startup.

      Skips "#" comment lines and entries older than the eviction threshold, then schedules the periodic cache-file writer task (RDNSCacheFileWriter). A missing file is created so the periodic writer always has a valid target. Invoked from the facade once reverse lookups are enabled after the netdb settles.

    • rdnsEntryToString

      static String rdnsEntryToString(ReverseDnsLookup.CacheEntry entry)
      Serialize a cache entry for persistence.

      Format is "ip,hostname,timestamp". One line per entry. The timestamp enables expiration and startup filtering, and distinguishes the current format from the two-part legacy format (see rdnsEntryFromString(String)).

      Parameters:
      entry - the entry to serialize
      Returns:
      the serialized entry line
    • rdnsEntryFromString

      static ReverseDnsLookup.CacheEntry rdnsEntryFromString(String s)
      Parse a persisted line back into a cache entry.

      Three-part lines carry an explicit timestamp. Two-part lines are the pre-timestamp legacy format and are migrated with the current time. Any other shape returns null and the caller skips the line.

      Parameters:
      s - the persisted line
      Returns:
      the parsed entry, or null if the line is malformed
    • needRdnscacheSweep

      static boolean needRdnscacheSweep(int size, int maxSize, int counter)
      Decide whether a cache insert must run a full-cache cleanup sweep. See needRdnscacheSweep(int, int, int) for the amortization rule.

      Sweeping on every put when the cache sits at its cap is O(n) per insert and shows up as CHM iterator churn on the rDNS hot path. Instead the sweep is amortized: once the map is at/over its cap it runs at most once every CLEANUP_BITS inserts (it usually stays pegged at the cap in steady state), while exceeding the cap by more than MAX_SLACK entries still sweeps immediately so the memory bound stays hard.

      A benign race on the shared _rdnsCleanupCounter only changes which insert triggers the sweep; it never under-sweeps below the slack guard (the size check is made against the live map by the caller).

      Parameters:
      size - current cache size; use rdnsCache.size()
      maxSize - the cache cap, e.g. MAX_RDNS_CACHE_SIZE
      counter - a per-put counter, e.g. an incrementing static int
      Returns:
      true if a cleanup sweep must run before the insert
    • getCanonicalHostName

      public String getCanonicalHostName(String ipAddress)
      Canonical hostname for the given IP address from cache or DNS. If RDNS is enabled, performs a reverse DNS lookup first. Falls back to local ASN database if DNS fails, returning the org name.
      Parameters:
      ipAddress - IP address to resolve, or null/"null" to return null
      Returns:
      hostname, org name from ASN database, or null for invalid input
    • getCanonicalHostNameSync

      public String getCanonicalHostNameSync(String ipAddress)
      The canonical host name for the given IP address, resolved synchronously.
      Parameters:
      ipAddress - the peer IP address to resolve, a null or literal "null" yields "unknown"
      Returns:
      the canonical host name
    • getLocalHostName

      public String getLocalHostName(String ipAddress)
      Fast hostname lookup that never blocks on I/O (MMDB or network). Returns cached result if available and useful. On cache miss, queues a background job that does ASN org name lookup (MMDB file read + regex normalization) and optional RDNS, then returns null immediately — page rendering is never blocked.
      Parameters:
      ipAddress - the peer IP address to name, a null or literal "null" yields null
      Returns:
      cached hostname/ASN org name, or null if not yet resolved