java.lang.Object
net.i2p.router.JobImpl
net.i2p.router.networkdb.kademlia.SearchJob
All Implemented Interfaces:
Job
Direct Known Subclasses:
ExploreJob

public class SearchJobextends JobImpl
Base class for iterative network database search operations.

Searches for a specific key by querying peers iteratively until either the value is found or all available peers are exhausted. Manages search state, timeout handling, and peer selection with configurable concurrency levels.

Note that this is rarely used directly and primarily serves as a base for ExploreJob. FloodOnlySearchJob and FloodSearchJob do not extend this class. Does not update peer profile statistics.

  • Field Details

    • _log

      protected final Log _log
      Class logger.
    • _facade

      protected final KademliaNetworkDatabaseFacade _facade
      Network database facade for peer lookups and storage.
    • _state

      private final SearchState _state
      Search state.
    • _onSuccess

      private final Job _onSuccess
      Success job.
    • _onFailure

      private final Job _onFailure
      Failure job.
    • _expiration

      private final long _expiration
      Expiration time.
    • _timeoutMs

      private final long _timeoutMs
      Timeout in ms.
    • _keepStats

      private final boolean _keepStats
      Keep stats flag.
    • _isLease

      private final boolean _isLease
      Is lease flag.
    • _pendingRequeueJob

      private Job _pendingRequeueJob
      Pending requeue job.
    • _peerSelector

      private final PeerSelector _peerSelector
      Peer selector.
    • _deferredSearches

      private final List<SearchJob.Search> _deferredSearches
      Deferred searches list.
    • _deferredCleared

      private boolean _deferredCleared
      Deferred cleared flag.
    • _startedOn

      private long _startedOn
      Start time.
    • _floodfillPeersExhausted

      private boolean _floodfillPeersExhausted
      FF peers exhausted flag.
    • _floodfillSearchesOutstanding

      private int _floodfillSearchesOutstanding
      Outstanding FF searches.
    • _msgIDBloomXor

      private final long _msgIDBloomXor
      Message ID bloom XOR.
    • SEARCH_BREDTH

      private static int SEARCH_BREDTH
      Max concurrent non-lease iterative searches.
    • SEARCH_BREDTH_LEASE

      private static int SEARCH_BREDTH_LEASE
      Max concurrent lease search queries.
    • MAX_CLOSEST

      static final int MAX_CLOSEST
      Only send the 10 closest "don't tell me about" refs.
      See Also:
    • PER_PEER_TIMEOUT

      private static final int PER_PEER_TIMEOUT
      How long will we give each peer to reply to our search?
      See Also:
    • RESEND_TIMEOUT

      private static volatile long RESEND_TIMEOUT
      Give ourselves 30 seconds to send out the value found to the closest peers /after/ we get a successful match. If this fails, no biggie, but this'll help heal the network so subsequent searches will find the data. Tunable via the Tuner (netdb.resendTimeout).
    • REQUEUE_DELAY

      private static final long REQUEUE_DELAY
      When we're just waiting for something to change, requeue the search status test every second.
      See Also:
    • DEFAULT_FLOODFILL_ONLY

      private static final boolean DEFAULT_FLOODFILL_ONLY
      Whether to query only floodfill peers by default.
      See Also:
    • PER_FLOODFILL_PEER_TIMEOUT

      static final int PER_FLOODFILL_PEER_TIMEOUT
      Timeout per floodfill peer in ms.
      See Also:
    • MIN_TIMEOUT

      static final long MIN_TIMEOUT
      Minimum timeout in ms.
      See Also:
    • MAX_PEERS_QUERIED

      private static final int MAX_PEERS_QUERIED
      Hard limit on total peers to query before giving up.
      See Also:
    • MAX_LEASE_RESEND

      private static volatile int MAX_LEASE_RESEND
      After a successful search for a leaseSet, we resend that leaseSet to all of the peers we tried and failed to query. This var bounds how many of those peers will get the data, in case a search had to crawl about substantially. Tunable via the Tuner (netdb.leaseResendCount).
    • SHOULD_RESEND_ROUTERINFO

      private static final boolean SHOULD_RESEND_ROUTERINFO
      Should we republish a routerInfo received? Probably not worthwhile, since routerInfo entries should be very easy to find.
      See Also:
  • Constructor Details

    • SearchJob

      public SearchJob(RouterContext context, KademliaNetworkDatabaseFacade facade, Hash key, Job onSuccess, Job onFailure, long timeoutMs, boolean keepStats, boolean isLease, long msgIDBloomXor)
      Create a new search for the routingKey specified.
      Parameters:
      context - router context supplying the clock, log and job queue
      facade - network database the search reads peers and entries from
      key - hash being searched for; a null hash, or one with no data, is rejected
      onSuccess - job queued once the value is found, may be null
      onFailure - job queued once the search is abandoned, may be null
      timeoutMs - milliseconds before the search gives up; the expiration is computed as now plus this
      keepStats - true to record this search's outcome and duration in the success/failure rate stats
      isLease - true when the target is a LeaseSet, selecting the wider breadth, tunnel-routed queries and LeaseSet storage on success; false for exploratory searches
      msgIDBloomXor - value XOR'ed with the message ID of each outgoing message, so it does not match the peer's bloom filter
      Throws:
      IllegalArgumentException - if the key is null or has no data
  • Method Details

    • getResendTimeout

      public static long getResendTimeout()
      The current lease republish message window.
      Returns:
      the window in ms
    • setResendTimeout

      public static void setResendTimeout(int val)
      Lease republish message window. Tuner may call this.
      Parameters:
      val - ms, clamped to [10s, 30s]
    • runJob

      public void runJob()
      Execute the next step of the iterative search.
    • getState

      protected SearchState getState()
      Get the per-search record of which peers have been tried.
      Returns:
      the state with the attempted, pending and failed peers, never null
    • getFacade

      protected KademliaNetworkDatabaseFacade getFacade()
      Get the netdb that started this search.
      Returns:
      the facade, used for local lookups, storing results and peer selection
    • getExpiration

      public long getExpiration()
      When this search gives up if no peer has answered.
      Returns:
      absolute adjusted time in ms, the creation time plus the timeout
    • getTimeoutMs

      public long getTimeoutMs()
      How long the search is allowed to run before it is abandoned.
      Returns:
      the duration in ms given to the constructor
    • onlyQueryFloodfillPeers

      static boolean onlyQueryFloodfillPeers(RouterContext ctx)
      This is now misnamed, as it is only used to determine whether to return floodfill peers only.
      Parameters:
      ctx - router context whose properties decide the floodfill restriction
      Returns:
      false whenever floodfill is enabled or the explore-when-floodfill property is not "true", otherwise the netDb.floodfillOnly property
    • getPerPeerTimeoutMs

      protected int getPerPeerTimeoutMs(Hash peer)
      Per-peer timeout adjusted for floodfill and remaining time.
      Parameters:
      peer - router hash whose peer timeout is being looked up, used only once floodfill peers are exhausted
      Returns:
      the peer's own timeout in ms, or the fixed floodfill timeout while floodfill queries remain, shortened so it never runs past the search deadline but never below 2s
    • getPerPeerTimeoutMs

      protected int getPerPeerTimeoutMs()
      Let each peer take up to the average successful search RTT.
      Returns:
      the per peer timeout ms
    • searchNext

      protected void searchNext()
      Send the next search, or stop if its completed.
    • isLocal

      private boolean isLocal()
      True if the data is already locally stored.
      Returns:
      true if the target is already in the local data store
    • isExpired

      private boolean isExpired()
      Whether the search deadline has passed.
      Returns:
      true if the search deadline has passed
    • getBredth

      protected int getBredth()
      Max # of concurrent searches.
      Returns:
      how many peers may be queried at once: 1 while overloaded (job queue lag above 500ms, message delay above 800ms or CPU load above 80), else the greater of half the cores and 8 for a LeaseSet search, or a third of the cores and 3 otherwise
    • continueSearch

      protected void continueSearch()
      Send a series of searches to the next available peers as selected by the routing table, but making sure no more than SEARCH_BREDTH are outstanding at any time.
    • requeuePending

      private void requeuePending()
      Requeue pending.
    • requeuePending

      private void requeuePending(long ms)
      Requeue pending.
      Parameters:
      ms - delay from now before the requeue job runs, in milliseconds
    • getClosestRouters

      private List<Hash> getClosestRouters(Hash key, int numClosest, Set<Hash> alreadyChecked)
      Hash structures for routers we want to check next. This is the 'interesting' part of the algorithm. But to keep you on your toes, we've refactored it to the PeerSelector.selectNearestExplicit.
      Parameters:
      key - the hash being searched for, converted to a routing key first
      numClosest - maximum number of routers to return
      alreadyChecked - routers already queried, excluded from the result
      Returns:
      ordered list of Hash objects
    • sendSearch

      protected void sendSearch(RouterInfo router)
      Send a search to the given peer.
      Parameters:
      router - peer to query; ignored if it is us, and otherwise routed through a tunnel unless an established session to it makes a direct send cheaper
    • sendLeaseSearch

      protected void sendLeaseSearch(RouterInfo router)
      We're (probably) searching for a LeaseSet, so to be (overly) cautious, we're sending the request out through a tunnel w/ reply back through another tunnel.
      Parameters:
      router - peer to query, which must have both an inbound exploratory tunnel for replies and an outbound exploratory tunnel available or the peer is marked failed
    • sendRouterSearch

      protected void sendRouterSearch(RouterInfo router)
      We're searching for a router, so we can just send direct.
      Parameters:
      router - peer to query directly, using its own recorded timeout and sending no reply tunnel
    • buildMessage

      protected I2NPMessage buildMessage(TunnelId replyTunnelId, Hash replyGateway, long expiration, RouterInfo peer)
      Build the database search message.
      Parameters:
      replyTunnelId - tunnel to receive replies through
      replyGateway - gateway for the reply tunnel
      expiration - when the search should stop
      peer - unused here; see ExploreJob extension
      Returns:
      the message to send to the peer; the base implementation always throws, while ExploreJob returns a lookup message for the search key, wrapped for encryption when the reply tunnel requires it
    • replyFound

      void replyFound(DatabaseSearchReplyMessage message, Hash peer)
      Found a reply.
      Parameters:
      message - search reply received from the peer
      peer - router hash that sent it, which is cleared from the pending set and recorded as having replied
    • newPeersFound

      protected void newPeersFound(int numNewPeers)
      We've gotten a search reply that contained the specified number of peers that we didn't know about before.
      Parameters:
      numNewPeers - count of previously unknown peers the reply carried; ignored here, subclasses use it to record the discovery
    • succeed

      private void succeed()
      Search was totally successful.
    • getLeaseResendCount

      public static int getLeaseResendCount()
      The current max peers that get a lease republish after a search.
      Returns:
      the max peers
    • setLeaseResendCount

      public static void setLeaseResendCount(int val)
      Max peers that get a lease republish after a search. Tuner may call this.
      Parameters:
      val - clamped to [5, 10]
    • resend

      private void resend()
      After we get the data we were searching for, rebroadcast it to the peers we would query first if we were to search for it again (healing the network).
    • resend

      private boolean resend(RouterInfo toPeer, LeaseSet ls)
      Resend the leaseSet to the peer who had previously failed to provide us with the data when we asked them.
      Parameters:
      toPeer - the peer that previously failed to store the lease set
      ls - the lease set to resend to that peer
      Returns:
      true if dispatched via an outbound exploratory tunnel, false if none was available
    • fail

      protected void fail()
      Search totally failed.
    • addDeferred

      public int addDeferred(Job onFind, Job onFail, long expiration, boolean isLease)
      Add a deferred search to run on completion of this search.
      Parameters:
      onFind - job to run if this search succeeds
      onFail - job to run if this search fails, or is still unfinished when the deadline passes
      expiration - absolute time in ms since the epoch after which the deferred search is failed rather than waited on
      isLease - whether the deferred search targets a LeaseSet, forwarded to the replacement search if this one has already completed
      Returns:
      how many searches are now deferred, or 0 if this search had already completed, in which case a replacement search is started instead
    • handleDeferred

      private void handleDeferred(boolean success)
      Handle deferred.
      Parameters:
      success - true if the search that just finished succeeded, deciding whether the deferred searches run their find or fail callbacks
    • getName

      public String getName()
      Description copied from interface: Job
      Descriptive name of the task.
      Returns:
      the descriptive name of the task
    • toString

      public String toString()
      Describe the search, and how long it has been running, for the logs.
      Overrides:
      toString in class JobImpl
      Returns:
      the job id and class name, then the time since the search started
    • wasAttempted

      boolean wasAttempted(Hash peer)
      Whether the peer was already queried.
      Parameters:
      peer - router hash to look for in the attempted set
      Returns:
      true if peer was already queried
    • timeoutMs

      long timeoutMs()
      The timeout this search was created with, for other netdb classes.
      Returns:
      the duration in ms, added to the start time to get the expiration
    • add

      boolean add(Hash peer)
      Adds a peer to the search.
      Parameters:
      peer - router hash to add to the kbuckets, and to queue for exploration if it was not already there
      Returns:
      true if peer was new
    • decrementOutstandingFloodfillSearches

      void decrementOutstandingFloodfillSearches()
      Decrement the count of outstanding floodfill searches.