java.lang.Object
net.i2p.router.JobImpl
net.i2p.router.networkdb.kademlia.SearchJob
- All Implemented Interfaces:
Job
- Direct Known Subclasses:
ExploreJob
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.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprotected classCalled when a particular peer failed to respond before the timeout was reached, or if the peer could not be contacted at all.private classJob that re-invokes searchNext after a delay.private static classHolds callbacks and expiration for a deferred search.Field Summary
FieldsModifier and TypeFieldDescriptionprivate booleanDeferred cleared flag.private final List<SearchJob.Search> Deferred searches list.private final longExpiration time.protected final KademliaNetworkDatabaseFacadeNetwork database facade for peer lookups and storage.private booleanFF peers exhausted flag.private intOutstanding FF searches.private final booleanIs lease flag.private final booleanKeep stats flag.protected final LogClass logger.private final longMessage ID bloom XOR.private final JobFailure job.private final JobSuccess job.private final PeerSelectorPeer selector.private JobPending requeue job.private longStart time.private final SearchStateSearch state.private final longTimeout in ms.private static final booleanWhether to query only floodfill peers by default.(package private) static final intOnly send the 10 closest "don't tell me about" refs.private static intAfter a successful search for a leaseSet, we resend that leaseSet to all of the peers we tried and failed to query.private static final intHard limit on total peers to query before giving up.(package private) static final longMinimum timeout in ms.(package private) static final intTimeout per floodfill peer in ms.private static final intHow long will we give each peer to reply to our search?private static final longWhen we're just waiting for something to change, requeue the search status test every second.private static longGive ourselves 30 seconds to send out the value found to the closest peers /after/ we get a successful match.private static intMax concurrent non-lease iterative searches.private static intMax concurrent lease search queries.private static final booleanShould we republish a routerInfo received? Probably not worthwhile, since routerInfo entries should be very easy to find.Constructor Summary
ConstructorsConstructorDescriptionSearchJob(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.Method Summary
Modifier and TypeMethodDescription(package private) booleanAdds a peer to the search.intaddDeferred(Job onFind, Job onFail, long expiration, boolean isLease) Add a deferred search to run on completion of this search.protected I2NPMessagebuildMessage(TunnelId replyTunnelId, Hash replyGateway, long expiration, RouterInfo peer) Build the database search message.protected voidSend 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.(package private) voidDecrement the count of outstanding floodfill searches.protected voidfail()Search totally failed.protected intMax # of concurrent searches.getClosestRouters(Hash key, int numClosest, Set<Hash> alreadyChecked) Hash structures for routers we want to check next.longWhen this search gives up if no peer has answered.protected KademliaNetworkDatabaseFacadeGet the netdb that started this search.static intThe current max peers that get a lease republish after a search.getName()Descriptive name of the task.protected intLet each peer take up to the average successful search RTT.protected intgetPerPeerTimeoutMs(Hash peer) Per-peer timeout adjusted for floodfill and remaining time.static longThe current lease republish message window.protected SearchStategetState()Get the per-search record of which peers have been tried.longHow long the search is allowed to run before it is abandoned.private voidhandleDeferred(boolean success) Handle deferred.private booleanWhether the search deadline has passed.private booleanisLocal()True if the data is already locally stored.protected voidnewPeersFound(int numNewPeers) We've gotten a search reply that contained the specified number of peers that we didn't know about before.(package private) static booleanThis is now misnamed, as it is only used to determine whether to return floodfill peers only.(package private) voidreplyFound(DatabaseSearchReplyMessage message, Hash peer) Found a reply.private voidRequeue pending.private voidrequeuePending(long ms) Requeue pending.private voidresend()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).private booleanresend(RouterInfo toPeer, LeaseSet ls) Resend the leaseSet to the peer who had previously failed to provide us with the data when we asked them.voidrunJob()Execute the next step of the iterative search.protected voidSend the next search, or stop if its completed.protected voidsendLeaseSearch(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.protected voidsendRouterSearch(RouterInfo router) We're searching for a router, so we can just send direct.protected voidsendSearch(RouterInfo router) Send a search to the given peer.static voidsetLeaseResendCount(int val) Max peers that get a lease republish after a search.static voidsetResendTimeout(int val) Lease republish message window.private voidsucceed()Search was totally successful.(package private) longThe timeout this search was created with, for other netdb classes.toString()Describe the search, and how long it has been running, for the logs.(package private) booleanwasAttempted(Hash peer) Whether the peer was already queried.Methods inherited from class JobImpl
dropped, getContext, getJobId, getMadeReadyOn, getTiming, madeReady, requeueModifier and TypeMethodDescriptionvoiddropped()Default implementation does nothing.final RouterContextThe router context that this job belongs to.longgetJobId()The unique job ID for this job.longThe timestamp when this job was last made ready for execution.The timing object for this job.voidmadeReady(long now) For JobQueue only, not for external use.protected voidrequeue(long delayMs) Requeue this job to run after the specified delay.
Field Details
_log
Class logger._facade
Network database facade for peer lookups and storage._state
Search state._onSuccess
Success job._onFailure
Failure job._expiration
private final long _expirationExpiration time._timeoutMs
private final long _timeoutMsTimeout in ms._keepStats
private final boolean _keepStatsKeep stats flag._isLease
private final boolean _isLeaseIs lease flag._pendingRequeueJob
Pending requeue job._peerSelector
Peer selector._deferredSearches
Deferred searches list._deferredCleared
private boolean _deferredClearedDeferred cleared flag._startedOn
private long _startedOnStart time._floodfillPeersExhausted
private boolean _floodfillPeersExhaustedFF peers exhausted flag._floodfillSearchesOutstanding
private int _floodfillSearchesOutstandingOutstanding FF searches._msgIDBloomXor
private final long _msgIDBloomXorMessage ID bloom XOR.SEARCH_BREDTH
private static int SEARCH_BREDTHMax concurrent non-lease iterative searches.SEARCH_BREDTH_LEASE
private static int SEARCH_BREDTH_LEASEMax concurrent lease search queries.MAX_CLOSEST
static final int MAX_CLOSESTOnly send the 10 closest "don't tell me about" refs.- See Also:
PER_PEER_TIMEOUT
private static final int PER_PEER_TIMEOUTHow long will we give each peer to reply to our search?- See Also:
RESEND_TIMEOUT
private static volatile long RESEND_TIMEOUTGive 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_DELAYWhen 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_ONLYWhether to query only floodfill peers by default.- See Also:
PER_FLOODFILL_PEER_TIMEOUT
static final int PER_FLOODFILL_PEER_TIMEOUTTimeout per floodfill peer in ms.- See Also:
MIN_TIMEOUT
MAX_PEERS_QUERIED
private static final int MAX_PEERS_QUERIEDHard limit on total peers to query before giving up.- See Also:
MAX_LEASE_RESEND
private static volatile int MAX_LEASE_RESENDAfter 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_ROUTERINFOShould 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 queuefacade- network database the search reads peers and entries fromkey- hash being searched for; a null hash, or one with no data, is rejectedonSuccess- job queued once the value is found, may be nullonFailure- job queued once the search is abandoned, may be nulltimeoutMs- milliseconds before the search gives up; the expiration is computed as now plus thiskeepStats- true to record this search's outcome and duration in the success/failure rate statsisLease- true when the target is a LeaseSet, selecting the wider breadth, tunnel-routed queries and LeaseSet storage on success; false for exploratory searchesmsgIDBloomXor- 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
Get the per-search record of which peers have been tried.- Returns:
- the state with the attempted, pending and failed peers, never null
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
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.floodfillOnlyproperty
getPerPeerTimeoutMs
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
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 firstnumClosest- maximum number of routers to returnalreadyChecked- routers already queried, excluded from the result- Returns:
- ordered list of Hash objects
sendSearch
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
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
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 throughreplyGateway- gateway for the reply tunnelexpiration- when the search should stoppeer- unused here; seeExploreJobextension- 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
Found a reply.- Parameters:
message- search reply received from the peerpeer- 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
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 setls- 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
Add a deferred search to run on completion of this search.- Parameters:
onFind- job to run if this search succeedsonFail- job to run if this search fails, or is still unfinished when the deadline passesexpiration- absolute time in ms since the epoch after which the deferred search is failed rather than waited onisLease- 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
toString
wasAttempted
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
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.