- All Implemented Interfaces:
Job
Continues searching when initial lookup fails by iteratively querying closer-to-the-key peers returned in DatabaseSearchReplyMessages. Unlike traditional Kademlia, doesn't stop when no closer keys are available - keeps searching until timeout or maximum search limit is reached.
Key differences from FloodOnlySearchJob: - Chases peers in DSRM immediately rather than waiting - Searches one peer at a time with individual per-search timeouts - Uses total timeout rather than per-search timeouts - Longer overall timeout for better success rates - Reduces search traffic by half compared to parallel approaches
Advantages over flood-only approaches: - More robust in large networks with incomplete floodfill knowledge - Better success rates through sequential searching - Reduced network traffic through single-peer queries.
Field Summary
Modifier and TypeFieldDescriptionprivate static HashHash to always query first, set from a router property for testing.Query sent, failed, timed out, or got DSRM.The families the results must match.private StringThe one family option of the current candidate, or null.private intNumber of entries used in_fingerprintIPs.private final long[]Scratch buffers for one candidate's keys, filled bycollectFingerprint(RouterContext, Hash, int)and consumed byfingerprintClaimed()/claimFingerprint().private intNumber of entries used in_fingerprintPorts.private final int[]Ports used for the fingerprint matching.private final HashThe local destination to search from, null if none.private static longGrace period for late replies - dynamically loadable.Masked-IP keys, ports and family options of the peers already queried by this search, used to avoid querying several peers of one entity.private intUse instead of CONCURRENT_SEARCHES in super() which is final.private static intThe default _maxConcurrent, 4 on a slow system, otherwise 16.private static intAdaptive deadline cap (ms) for LeaseSet lookups only.private static intAdaptive deadline cap (ms) for RouterInfo lookups.private static longTotal search time cap - dynamically loadable.private OutNetMessageThis is a marker to register with the MessageRegistry, it is never sent.The service ports the results must match.Floodfill peers we've sent queries to in this search — for active-query tracking.private static final ConcurrentHashMap<Hash, Long> Static cache of recently completed searches: peer hash -> expiration timestamp.private final HashThe routing key.private booleanTrue once any peer replied (DSRM); distinguishes definitive fails from pure timeouts.The time the query was sent to a peer, which we need to update profiles correctly.private final longThe time before we give up and start a new search - much shorter than the message's expire time Longer than the typ.The peers left out of the search.private final intMax number of peers to query.Peers not sent to yet, sorted closest-to-the-routing-key.private static intTuner-set search limit, negative if unset.private static intTuner-set single search time, negative if unset.Query sent, no reply yet.private booleanSet once the candidate set has been widened for beta confirmation.private static final intKademlia's beta: before a search may die with candidates exhausted, at least this many of the closest known peers must have been actually queried.private static final intCache size for recently completed peer replies to avoid false positive bans.static final booleanOnly on fast boxes, for now.private static final intExtra peers to get from peer selector, as we may discard some before querying.private static final intLeading IP bytes counted as close.private static final longDefault grace period for late replies (5 min).private static final intFingerprint entries we can store in a reply.private static final intMost non-floodfill peers queried.private static final intUpper bound on the keys one peer can contribute: the comm system's address plus at mostMAX_RI_ADDRESSESnetDb addresses.private static final longDefault total search time cap (15s).private static final longSmallest single search time, in ms.static final StringProperty toggling encryption of the RouterInfo sent in a lookup.private static final StringConfig key for the late reply grace period.static final StringConfig key for the total search time cap.private static final longThe actual expire time for a search message.private static final longThe default single search time.private static final intMax number of peers to query.private static final intMax number of peers to query if we are ff.Fields inherited from class FloodSearchJob
_created, _dead, _expiration, _facade, _isLease, _key, _log, _lookupsRemaining, _onFailed, _onFind, _success, _timeoutMs, CONCURRENT_SEARCHESModifier and TypeFieldDescriptionprotected final longSystem time when this search was created.protected booleanWhether this search has been marked as completed.protected longDeadline after which the search expires.protected final FloodfillNetworkDatabaseFacadeFloodfill network database facade.protected final booleanWhether the target is a LeaseSet lookup.protected final HashTarget database entry hash being searched.protected final LogClass logger.protected final AtomicIntegerRemaining flood lookups before fallback to iterative search.Callbacks for search failure.Callbacks for successful search completion.protected booleanWhether the search completed successfully.protected intTimeout for the search in milliseconds.protected static final intMax simultaneous flood lookups before fallback.Constructor Summary
ConstructorsConstructorDescriptionIterativeSearchJob(RouterContext ctx, FloodfillNetworkDatabaseFacade facade, Hash key, Job onFind, Job onFailed, int timeoutMs, boolean isLease) Lookup using exploratory tunnels.IterativeSearchJob(RouterContext ctx, FloodfillNetworkDatabaseFacade facade, Hash key, Job onFind, Job onFailed, int timeoutMs, boolean isLease, Hash fromLocalDest) Lookup using the client's tunnels.Method Summary
Modifier and TypeMethodDescription(package private) static voidaddClosest(Collection<Hash> candidates, Collection<Hash> allRouters, Hash rkey, Hash us, Hash key, int cap) Add the closest cap peers of allRouters, by XOR distance from rkey, excluding us and key.(package private) voidCancels the search and delivers failure to all registered waiters.private voidClaim every key collected bycollectFingerprint(RouterContext, Hash, int), so later candidates of the same entity are skipped.static voidclearRecentlyQueried(Hash peer) Clear peer from grace period cache (received their response).private voidcollectFingerprint(RouterContext ctx, Hash peer, int mask) Collect one candidate's fingerprint keys into the reusable scratch buffers, without claiming them.voiddropped()Dropped by the job queue.(package private) voidfailed()Total failure.(package private) voidNote that the peer did not respond with a DSM (either a DSRM, timeout, or failure).private booleanIs any key of the candidate collected bycollectFingerprint(RouterContext, Hash, int)already claimed by a peer this search has queried?Hash of the dest this query is from.private static longReads the grace period for late replies.static intMaximum concurrent default value.static intThe LeaseSet lookup deadline cap in effect, adjusted live by the Tuner.static intThe RouterInfo lookup deadline cap in effect, adjusted live by the Tuner.static longThe current total search time cap.getName()Name of this job.static intgetSearchLimit(RouterContext ctx, int def) The search limit in effect, tuned value if set else config.static intgetSingleSearchTime(RouterContext ctx, int def) The single search time in effect, tuned value if set else config.private static RouterInfolookupRIUnvalidated(RouterContext ctx, Hash peer) Look up a peer's RouterInfo in the router's main NetDb, skipping the full validation performed byNetworkDatabaseFacade.lookupRouterInfoLocally(Hash).(package private) voidNote that a peer replied (DSRM processed); subsequent total failure counts as definitive toward the negative cache, not a pure timeout.(package private) voidnewPeerToTry(Hash peer) A new (floodfill) peer was discovered that may have the answer.private voidDecrement active floodfill query counters for all peers queried by this search.static longReload grace period from properties (for dynamic tuning).private voidretry()Send lookups to one or more peers, up to the configured concurrent and total limits.voidrunJob()Execute the iterative search, selecting floodfill peers from the k-buckets and sending DatabaseLookupMessages to each.private voidSend a DLM to the peer.static voidsetMaxConcurrentDefault(int val) Maximum concurrent default value, clamped to [1, 64].static voidsetMaxLeaseSetLookupTime(int val) Set the LeaseSet lookup deadline cap, normally called by the Tuner.static voidsetMaxRouterInfoLookupTime(int val) Set the RouterInfo lookup deadline cap, normally called by the Tuner.static voidsetMaxSearchTime(int val) Total search time cap.static voidsetSearchLimit(int limit) Set the search limit (called by Tuner).static voidsetSingleSearchTime(int ms) Set the single search time (called by Tuner).(package private) static booleanshouldSkipPeer(boolean recentlyQueried, boolean overloaded, boolean ipClose, int remainingCandidates) Skip policy for candidate floodfill peers: a peer is skipped only when at least one other candidate remains, so a starved search always makes progress.(package private) voidsuccess()Called when the search completes successfully.(package private) longWhen did we send the query to the peer?booleanwasQueried(Hash peer) Did we send a request to this peer?static booleanwasRecentlyQueried(Hash peer) Was this peer recently queried (within grace period)? Used to avoid false positive bans for late but legitimate replies.private voidWhen fewer thanBETA_CONFIRMpeers have been queried and the candidate list is exhausted, widen the candidate set once with the closest known non-floodfill peers, so a failure is confirmed against beta closest peers rather than declared after one or two misses.Methods inherited from class FloodSearchJob
addDeferred, decrementRemaining, getCreated, getExpiration, getKey, getLookupsRemainingModifier and TypeMethodDescription(package private) voidaddDeferred(Job onFind, Job onFailed, long timeoutMs, boolean isLease) Add jobs to an existing search.protected intNumber of lookups remaining after decrementing.longSystem time, NOT context time.longExpiration time from the context clock.getKey()The database entry hash being searched.protected intNumber of flood lookups still pending.Methods inherited from class JobImpl
getContext, getJobId, getMadeReadyOn, getTiming, madeReady, requeue, toStringModifier and TypeMethodDescriptionfinal 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.toString()
Field Details
_toTry
_unheardFrom
_failedPeers
_sawReply
private volatile boolean _sawReplyTrue once any peer replied (DSRM); distinguishes definitive fails from pure timeouts._sentTime
_rkey
The routing key._out
This is a marker to register with the MessageRegistry, it is never sent._fromLocalDest
The local destination to search from, null if none._alwaysQueryHash
Hash to always query first, set from a router property for testing._totalSearchLimit
private final int _totalSearchLimitMax number of peers to query._maskedIPs
Masked-IP keys, ports and family options of the peers already queried by this search, used to avoid querying several peers of one entity. The three key spaces stay separate, so a masked IP can never collide with a port or a family. SeecollectFingerprint(RouterContext, Hash, int)for the encoding._ports
_families
_fingerprintIPs
private final long[] _fingerprintIPsScratch buffers for one candidate's keys, filled bycollectFingerprint(RouterContext, Hash, int)and consumed byfingerprintClaimed()/claimFingerprint(). The IP and port key spaces are counted separately, so neither array can hold a stale entry from the previous candidate. Sized byMAX_FINGERPRINT_ENTRIES, a hard cap on the keys any one peer can contribute. Reused across candidates._fingerprintPorts
private final int[] _fingerprintPortsPorts used for the fingerprint matching._fingerprintFamily
The one family option of the current candidate, or null._fingerprintIPCount
private int _fingerprintIPCountNumber of entries used in_fingerprintIPs._fingerprintPortCount
private int _fingerprintPortCountNumber of entries used in_fingerprintPorts._skippedPeers
_queriedFloodfills
_widened
private boolean _widenedSet once the candidate set has been widened for beta confirmation. Guarded by this. @since 0.9.71+.MAX_NON_FF
TOTAL_SEARCH_LIMIT
private static final int TOTAL_SEARCH_LIMITMax number of peers to query.- See Also:
TOTAL_SEARCH_LIMIT_WHEN_FF
private static final int TOTAL_SEARCH_LIMIT_WHEN_FFMax number of peers to query if we are ff.- See Also:
EXTRA_PEERS
private static final int EXTRA_PEERSExtra peers to get from peer selector, as we may discard some before querying.- See Also:
IP_CLOSE_BYTES
private static final int IP_CLOSE_BYTESLeading IP bytes counted as close.- See Also:
BETA_CONFIRM
private static final int BETA_CONFIRMKademlia's beta: before a search may die with candidates exhausted, at least this many of the closest known peers must have been actually queried. When candidates run out first, the candidate set is widened once (seewidenCandidatesLocked()).- See Also:
PROP_MAX_SEARCH_TIME
Config key for the total search time cap.- See Also:
MAX_SEARCH_TIME_DEFAULT
private static final long MAX_SEARCH_TIME_DEFAULTDefault total search time cap (15s).- See Also:
_maxSearchTime
private static volatile long _maxSearchTimeTotal search time cap - dynamically loadable.MAX_RI_ADDRESSES
private static final int MAX_RI_ADDRESSESUpper bound on the keys one peer can contribute: the comm system's address plus at mostMAX_RI_ADDRESSESnetDb addresses. RouterInfo rejects a longer parsed or assigned address list, so this is a hard cap.- See Also:
MAX_FINGERPRINT_ENTRIES
private static final int MAX_FINGERPRINT_ENTRIESFingerprint entries we can store in a reply.- See Also:
COMPLETED_CACHE_SIZE
private static final int COMPLETED_CACHE_SIZECache size for recently completed peer replies to avoid false positive bans.- See Also:
PROP_LATE_REPLY_GRACE
Config key for the late reply grace period.- See Also:
LATE_REPLY_GRACE_PERIOD_DEFAULT
private static final long LATE_REPLY_GRACE_PERIOD_DEFAULTDefault grace period for late replies (5 min).- See Also:
_lateReplyGracePeriod
private static volatile long _lateReplyGracePeriodGrace period for late replies - dynamically loadable._recentlyCompleted
Static cache of recently completed searches: peer hash -> expiration timestamp._singleSearchTime
private final long _singleSearchTimeThe time before we give up and start a new search - much shorter than the message's expire time Longer than the typ. response time of 1.0 - 1.5 sec, but short enough that we move on to another peer quickly.SINGLE_SEARCH_TIME
private static final long SINGLE_SEARCH_TIMEThe default single search time.- See Also:
MIN_SINGLE_SEARCH_TIME
private static final long MIN_SINGLE_SEARCH_TIMESmallest single search time, in ms.- See Also:
SINGLE_SEARCH_MSG_TIME
private static final long SINGLE_SEARCH_MSG_TIMEThe actual expire time for a search message.- See Also:
_maxConcurrent
private int _maxConcurrentUse instead of CONCURRENT_SEARCHES in super() which is final. For now, we don't do concurrent, but we keep SINGLE_SEARCH_TIME very short, so we have effective concurrency in that we fail a search quickly._maxConcurrentDefault
private static volatile int _maxConcurrentDefaultThe default _maxConcurrent, 4 on a slow system, otherwise 16._maxLeaseSetLookupTime
private static volatile int _maxLeaseSetLookupTimeAdaptive deadline cap (ms) for LeaseSet lookups only. RouterInfo lookups continue to usegetMaxSearchTime(). Tuned live by the Tuner toward ~4x the observednetDb.successTime, floored so healthy-but-slow searches aren't abandoned. Defaults to the max search time so behavior is unchanged until the Tuner adjusts it._maxRouterInfoLookupTime
private static volatile int _maxRouterInfoLookupTimeAdaptive deadline cap (ms) for RouterInfo lookups. Used for transit next-hop lookups, where a message is held until the lookup completes or times out; a long hold during a spike tanks transit throughput. Defaults to a shorter cap than the max search time so a missing or unreachable RouterInfo fails fast and the source can reroute. Tuned live by the Tuner toward ~4x the observednetDb.successTime.PROP_ENCRYPT_RI
Property toggling encryption of the RouterInfo sent in a lookup.- See Also:
DEFAULT_ENCRYPT_RI
public static final boolean DEFAULT_ENCRYPT_RIOnly on fast boxes, for now._tunedSearchLimit
private static volatile int _tunedSearchLimitTuner-set search limit, negative if unset._tunedSingleSearchTime
private static volatile int _tunedSingleSearchTimeTuner-set single search time, negative if unset.
Constructor Details
IterativeSearchJob
public IterativeSearchJob(RouterContext ctx, FloodfillNetworkDatabaseFacade facade, Hash key, Job onFind, Job onFailed, int timeoutMs, boolean isLease) Lookup using exploratory tunnels.- Parameters:
ctx- the router contextfacade- the network database the key is looked up inkey- the hash to search for, a RouterInfo or LeaseSet hashonFind- run when the search returns a resultonFailed- run when the search fails or the timeout expirestimeoutMs- milliseconds to search for, before the per-type deadline caps are appliedisLease- true to search for a LeaseSet, false for a RouterInfo
IterativeSearchJob
public IterativeSearchJob(RouterContext ctx, FloodfillNetworkDatabaseFacade facade, Hash key, Job onFind, Job onFailed, int timeoutMs, boolean isLease, Hash fromLocalDest) Lookup using the client's tunnels. Do not use for RI lookups down client tunnels, as the response will be dropped in InboundMessageDistributor.- Parameters:
ctx- the router contextfacade- the network database the key is looked up inkey- the hash to search for, a RouterInfo or LeaseSet hashonFind- run when the search returns a resultonFailed- run when the search fails or the timeout expirestimeoutMs- milliseconds to search for, before the per-type deadline caps are appliedisLease- true to search for a LeaseSet, false for a RouterInfofromLocalDest- use these tunnels for the lookup, or null for exploratory
Method Details
shouldSkipPeer
static boolean shouldSkipPeer(boolean recentlyQueried, boolean overloaded, boolean ipClose, int remainingCandidates) Skip policy for candidate floodfill peers: a peer is skipped only when at least one other candidate remains, so a starved search always makes progress. Cooldown, overload, and IP-closeness are soft signals.- Parameters:
recentlyQueried- true if the peer was queried within the cooldown periodoverloaded- true if the peer already has MAX_CONCURRENT_PER_FLOODFILL active queriesipClose- true if the peer shares IPs with an already-queried peerremainingCandidates- number of candidate peers left after this one is removed- Returns:
- true if the peer should be skipped
lookupRIUnvalidated
Look up a peer's RouterInfo in the router's main NetDb, skipping the full validation performed byNetworkDatabaseFacade.lookupRouterInfoLocally(Hash). The main NetDb is used rather than this job's facade, which may be a client NetDb.- Parameters:
ctx- the router contextpeer- the peer hash- Returns:
- the RouterInfo, or null if not held as a RouterInfo
collectFingerprint
Collect one candidate's fingerprint keys into the reusable scratch buffers, without claiming them.Masked IPs are packed into a
longviaFloodfillPeerSelector.maskedIPKey(byte[], int)(whose IPv4/IPv6 marker bit keeps the address families apart), ports into anint, and the family option kept as the String it is.- Parameters:
ctx- the router contextpeer- hash of the candidate to fingerprintmask- byte count to match
fingerprintClaimed
private boolean fingerprintClaimed()Is any key of the candidate collected bycollectFingerprint(RouterContext, Hash, int)already claimed by a peer this search has queried?Test-only: the caller may still reject the candidate on other grounds and must then claim nothing.
- Returns:
- true if any key was already claimed
claimFingerprint
private void claimFingerprint()Claim every key collected bycollectFingerprint(RouterContext, Hash, int), so later candidates of the same entity are skipped.getMaxSearchTime
public static long getMaxSearchTime()The current total search time cap.- Returns:
- the cap in ms
setMaxSearchTime
public static void setMaxSearchTime(int val) Total search time cap. Tuner may call this.- Parameters:
val- ms, clamped to [10s, 30s]
reloadGracePeriod
Reload grace period from properties (for dynamic tuning). Console may call this.- Parameters:
ctx- router context for property lookup- Returns:
- current grace period in ms
getGracePeriod
private static long getGracePeriod()Reads the grace period for late replies.- Returns:
- the period, in ms
getMaxConcurrentDefault
public static int getMaxConcurrentDefault()Maximum concurrent default value.- Returns:
- the max concurrent default
setMaxConcurrentDefault
public static void setMaxConcurrentDefault(int val) Maximum concurrent default value, clamped to [1, 64].- Parameters:
val- the new default
getMaxRouterInfoLookupTime
public static int getMaxRouterInfoLookupTime()The RouterInfo lookup deadline cap in effect, adjusted live by the Tuner.- Returns:
- the current RouterInfo lookup deadline cap in ms
setMaxRouterInfoLookupTime
public static void setMaxRouterInfoLookupTime(int val) Set the RouterInfo lookup deadline cap, normally called by the Tuner.- Parameters:
val- RouterInfo lookup deadline cap in ms, clamped to [5000, max search time]
getMaxLeaseSetLookupTime
public static int getMaxLeaseSetLookupTime()The LeaseSet lookup deadline cap in effect, adjusted live by the Tuner.- Returns:
- the current LeaseSet lookup deadline cap in ms
setMaxLeaseSetLookupTime
public static void setMaxLeaseSetLookupTime(int val) Set the LeaseSet lookup deadline cap, normally called by the Tuner.- Parameters:
val- LeaseSet lookup deadline cap in ms, clamped to [3000, max search time]
setSearchLimit
public static void setSearchLimit(int limit) Set the search limit (called by Tuner).- Parameters:
limit- the total search request limit
setSingleSearchTime
public static void setSingleSearchTime(int ms) Set the single search time (called by Tuner).- Parameters:
ms- the single-search time in milliseconds
getSearchLimit
The search limit in effect, tuned value if set else config.- Parameters:
ctx- the router contextdef- fallback when neither tuned nor configured- Returns:
- the total search request limit
getSingleSearchTime
The single search time in effect, tuned value if set else config.- Parameters:
ctx- the router contextdef- fallback when neither tuned nor configured- Returns:
- the single-search time in milliseconds
runJob
public void runJob()Execute the iterative search, selecting floodfill peers from the k-buckets and sending DatabaseLookupMessages to each. Continues until a reply is received or the search time expires.- Specified by:
runJobin interfaceJob- Overrides:
runJobin classFloodSearchJob
retry
private void retry()Send lookups to one or more peers, up to the configured concurrent and total limits.widenCandidatesLocked
private void widenCandidatesLocked()When fewer thanBETA_CONFIRMpeers have been queried and the candidate list is exhausted, widen the candidate set once with the closest known non-floodfill peers, so a failure is confirmed against beta closest peers rather than declared after one or two misses. One-shot: a search widens at most once. Caller must hold this lock.addClosest
static void addClosest(Collection<Hash> candidates, Collection<Hash> allRouters, Hash rkey, Hash us, Hash key, int cap) Add the closest cap peers of allRouters, by XOR distance from rkey, excluding us and key. Package private for testing.Selects the cap closest rather than sorting everything: allRouters is the whole netdb (up to 10 000 hashes) and this runs on the first failed lookup of a key, so a full
O(n log n)sort bought an ordering of entries nobody reads. A bounded farthest-first heap keeps the cap closest inO(n log cap), and us and the target are skipped while walking instead of by twoO(n)list removals afterwards.- Parameters:
candidates- the search's candidate set to add toallRouters- known router hashesrkey- the routing key the search is chasingus- our router hashkey- the lookup targetcap- max peers to add; nothing is added when it is not positive
sendQuery
Send a DLM to the peer.- Parameters:
peer- who to send topreviouslyTried- how many did we send to before this one?
getName
Name of this job.- Specified by:
getNamein interfaceJob- Overrides:
getNamein classFloodSearchJob- Returns:
- the name this job is listed under in the job queue
markSawReply
void markSawReply()Note that a peer replied (DSRM processed); subsequent total failure counts as definitive toward the negative cache, not a pure timeout.failed
Note that the peer did not respond with a DSM (either a DSRM, timeout, or failure). This is not necessarily a total failure of the search.- Parameters:
peer- the peer that failedtimedOut- if true, will blame the peer's profile
newPeerToTry
A new (floodfill) peer was discovered that may have the answer.- Parameters:
peer- may not actually be new
getFromHash
wasQueried
Did we send a request to this peer?- Parameters:
peer- the peer hash to check- Returns:
- true if a query was sent to this peer
wasRecentlyQueried
Was this peer recently queried (within grace period)? Used to avoid false positive bans for late but legitimate replies.- Parameters:
peer- the peer hash to check- Returns:
- true if the peer was queried recently and is in the grace period
clearRecentlyQueried
Clear peer from grace period cache (received their response).- Parameters:
peer- the peer hash to forget
timeSent
When did we send the query to the peer?- Parameters:
peer- the peer to check- Returns:
- context time, or -1 if never sent
cancelJob
void cancelJob()Cancels the search and delivers failure to all registered waiters. Cancellation is terminal for callers - negative-cache skip, banlist skip, exhausted search window - so this fires the onFailed jobs.releaseFloodfillQueries
private void releaseFloodfillQueries()Decrement active floodfill query counters for all peers queried by this search. Called when the search completes, fails, or cancels.dropped
failed
success
void success()Called when the search completes successfully. Credits the responding peer in the profile manager, records timing stats, and queues any follow-up jobs.- Overrides:
successin classFloodSearchJob