Conversation
Bumps [actions/github-script](https://github.com/actions/github-script) from 8 to 9. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](actions/github-script@v8...v9) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
…tions/dev/actions/github-script-9 Bump actions/github-script from 8 to 9
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.185 to 0.2.186. - [Release notes](https://github.com/rust-lang/libc/releases) - [Changelog](https://github.com/rust-lang/libc/blob/0.2.186/CHANGELOG.md) - [Commits](rust-lang/libc@0.2.185...0.2.186) --- updated-dependencies: - dependency-name: libc dependency-version: 0.2.186 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [lru](https://github.com/jeromefroe/lru-rs) from 0.16.4 to 0.18.0. - [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md) - [Commits](jeromefroe/lru-rs@0.16.4...0.18.0) --- updated-dependencies: - dependency-name: lru dependency-version: 0.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.52.0 to 1.52.3. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](tokio-rs/tokio@tokio-1.52.0...tokio-1.52.3) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.52.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.149 to 1.0.150. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](serde-rs/json@v1.0.149...v1.0.150) --- updated-dependencies: - dependency-name: serde_json dependency-version: 1.0.150 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…v/serde_json-1.0.150 Bump serde_json from 1.0.149 to 1.0.150
…/tokio-1.52.3 Bump tokio from 1.52.0 to 1.52.3
…/libc-0.2.186 Bump libc from 0.2.185 to 0.2.186
…/lru-0.18.0 Bump lru from 0.16.4 to 0.18.0
Bumps [regex](https://github.com/rust-lang/regex) from 1.12.3 to 1.12.4. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](rust-lang/regex@1.12.3...1.12.4) --- updated-dependencies: - dependency-name: regex dependency-version: 1.12.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…v/regex-1.12.4 Bump regex from 1.12.3 to 1.12.4
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.102 to 1.0.103. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](dtolnay/anyhow@1.0.102...1.0.103) --- updated-dependencies: - dependency-name: anyhow dependency-version: 1.0.103 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…v/anyhow-1.0.103 Bump anyhow from 1.0.102 to 1.0.103
Bumps [lru](https://github.com/jeromefroe/lru-rs) from 0.18.0 to 0.18.1. - [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md) - [Commits](jeromefroe/lru-rs@0.18.0...0.18.1) --- updated-dependencies: - dependency-name: lru dependency-version: 0.18.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.32 to 0.3.33. - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/main/CHANGELOG.md) - [Commits](rust-lang/futures-rs@0.3.32...0.3.33) --- updated-dependencies: - dependency-name: futures dependency-version: 0.3.33 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [regex](https://github.com/rust-lang/regex) from 1.12.4 to 1.13.1. - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](rust-lang/regex@1.12.4...1.13.1) --- updated-dependencies: - dependency-name: regex dependency-version: 1.13.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [clap](https://github.com/clap-rs/clap) from 4.6.1 to 4.6.2. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](clap-rs/clap@clap_complete-v4.6.1...clap_complete-v4.6.2) --- updated-dependencies: - dependency-name: clap dependency-version: 4.6.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [serde](https://github.com/serde-rs/serde) from 1.0.228 to 1.0.229. - [Commits](serde-rs/serde@v1.0.228...v1.0.229) --- updated-dependencies: - dependency-name: serde dependency-version: 1.0.229 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.52.3 to 1.53.0. - [Commits](tokio-rs/tokio@tokio-1.52.3...tokio-1.53.0) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.53.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6 to 7. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](actions/setup-python@v6...v7) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Workers were pinned one-per-resolver, each owning its own UDP socket, so total concurrency was the derived quantity resolvers x threads_per_resolver and the only way to go faster was to add resolvers. That also made sockets scale with resolvers x workers, which put a large resolver pool out of reach. Workers are now unpinned and pull from a shared pool, so concurrency is set directly via max_concurrency while max_inflight_per_resolver keeps the per-resolver politeness bound. One socket per resolver is shared by whoever selects it, created on first use. Adds: - RateLimiter with an adjustable rate, ported from blasthttp - per-resolver health: shared client, in-flight permits, RTT, counters, purgatory moved out of worker locals - optional startup probe that drops resolvers which never answer - per-resolver stats where attempted == answered + empty + timeout + error - adaptive controller (on by default): finds the rate at which a resolver starts losing queries and holds below it, bounded by any configured rate_limit as a hard cap - simulated resolver harness for deterministic convergence tests Loss on one resolver throttles only that resolver. Only resolvers that have delivered a clean tick can vote that our own rate is the bottleneck, so a mostly-dead public resolver list does not read as congestion. Renames threads_per_resolver to max_inflight_per_resolver.
Rewrites the Architecture section, which still described the pinned worker-per-resolver model, and documents the three dispatch limits, adaptive backoff, the startup probe, and stats(). Major bump: threads_per_resolver is renamed, BlastDNSConfig gained fields and is not non_exhaustive so struct-literal construction breaks, check_ulimits changed signature, and adaptive backoff is on by default. Benchmarks now honor num_workers via --max-concurrency, with adaptive backoff and caching off so they measure dispatch throughput rather than features the other engines don't have.
…ctions/dev/actions/setup-python-7 Bump actions/setup-python from 6 to 7
…v/lru-0.18.1 Bump lru from 0.18.0 to 0.18.1
…v/regex-1.13.1 Bump regex from 1.12.4 to 1.13.1
…v/futures-0.3.33 Bump futures from 0.3.32 to 0.3.33
…v/tokio-1.53.0 Bump tokio from 1.52.3 to 1.53.0
…v/serde-1.0.229 Bump serde from 1.0.228 to 1.0.229
…v/clap-4.6.2 Bump clap from 4.6.1 to 4.6.2
Bumps [clap](https://github.com/clap-rs/clap) from 4.6.2 to 4.6.3. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](clap-rs/clap@clap_complete-v4.6.2...clap_complete-v4.6.3) --- updated-dependencies: - dependency-name: clap dependency-version: 4.6.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.53.0 to 1.53.1. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](tokio-rs/tokio@tokio-1.53.0...tokio-1.53.1) --- updated-dependencies: - dependency-name: tokio dependency-version: 1.53.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
The per-resolver loss ratio needed MIN_SAMPLES within a single tick, but the in-flight cap holds a resolver to inflight/RTT queries per second -- 5 per tick at 2 permits and 200ms -- so the branch could never fire and every resolver took the relax path. Samples now carry across ticks until there are enough to trust, and a window that cannot fill within WINDOW_TTL is discarded rather than judged on samples spanning unrelated conditions. The window's span is accumulated from each tick's reported elapsed time instead of read off the clock, so a caller driving tick() directly gets deterministic behavior rather than wall-clock timing mixed into the rate.
Growth was the fall-through for anything that was not congestion, so a tick that finished fewer than MIN_AGGREGATE_SAMPLES queries raised the limit on no evidence. Between two congested ticks that inflated it faster than the retreat lowered it: against a pool losing every query the limit climbed 5,088 -> 8,441 instead of converging. It now steps 5,088 -> 4,325 -> 3,676, one RETREAT per well-sampled tick.
The probe queried each resolver directly, so it never picked up the deadline the worker applies. On a persistent socket, which carries no per-request deadline of its own, every dead entry held its slot for ~5s instead of the configured timeout: probing 8,149 resolvers took 36s against 4s for the per-query transport. Both callers now go through one bounded query on ResolverHealth rather than each arranging its own deadline. Probe time drops to 4.3s, matching per-query.
Nothing the engine logged was reachable from Python: no subscriber was ever installed, so resolver diagnostics, purgatory sentences, TCP refetches, and adaptive rate changes all went nowhere. Every embedding, including BBOT, ran blind. Opt-in rather than automatic, because the subscriber is process-global and a library should not take it from whatever embeds it on import. A second call declines instead of replacing the first.
The engine reads a threshold of 0 as never bench, but the config surface required at least 1, so that behavior could not be reached from Python at all.
Making the per-resolver branch reachable turned out to cost far more than it bought. LOSS_THRESHOLD sits at 2% while real resolvers refuse or drop 5-9% of attempts as a matter of course, so once the branch could fire it throttled healthy resolvers -- all three of a small pool, and 65 of 68 in another. The main DNS client has the few-resolvers-many-in-flight shape that trips it hardest, and it gates the rest of a scan: 184s became 550s, against 287s for massdns in the same window. Attempts to make it safe each exposed the next problem: a relative threshold has nothing to compare against in a pool of one, pacing off the attempt rate settles above what a resolver can serve, pacing off the delivered rate compounds as the window stretches, and a warm-up period leaves the first tick unjudgeable. None of that is unsolvable, but none of it is a small change, and politeness does not depend on it: max_inflight_per_resolver already caps each resolver at inflight/RTT regardless. The global branch keeps the quiet-tick fix, which the bursty case cleared.
Deactivation lasts for the life of the client, so the probe decides pool membership on a single query. Judging that by the per-query timeout is too strict: a root-NS query to a cold resolver is slower than the cached lookups a scan mostly makes, and at a brute-force timeout of 500ms a passing latency spike evicts resolvers that would have served fine. The probe now allows at least two seconds. It stays bounded, which is what the earlier change was for.
…v/tokio-1.53.1 Bump tokio from 1.53.0 to 1.53.1
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.186 to 0.2.189. - [Release notes](https://github.com/rust-lang/libc/releases) - [Changelog](https://github.com/rust-lang/libc/blob/0.2.189/CHANGELOG.md) - [Commits](rust-lang/libc@0.2.186...0.2.189) --- updated-dependencies: - dependency-name: libc dependency-version: 0.2.189 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
A persistent socket routes every query for its resolver through one multiplexed client, and hickory bounds that client's request channel at CHANNEL_BUFFER_SIZE (32). Exceeding it does not degrade, it falls off a cliff: 45,018 qps at 32 in flight against a local resolver, 188 qps at 40. This also explains an earlier measurement read as an inherent limit of the persistent transport. It was this bound, hit at inflight 8 and above.
…v/clap-4.6.3 Bump clap from 4.6.2 to 4.6.3
…v/serde_json-1.0.151 Bump serde_json from 1.0.150 to 1.0.151
Backing off recovers queries when the rate is what caused the loss. A resolver dropping a fixed share, or one behind a lossy link, loses the same at any rate, and the controller retreated anyway on every tick -- walking the rate toward the floor without recovering anything. Under 10% rate-independent loss a 2,000 query workload stopped finishing at all, at every in-flight depth from 8 up, while the same workload with adaptation off finished in 15-29s. A resolver now earns its first retreat on sight of loss and further ones only while the loss is falling against the best of the episode. Two consecutive flat ticks hold the rate instead, since one flat reading is sampling noise rather than proof. Convergence toward a real capacity limit is unaffected: loss falls as the rate approaches capacity, so the evidence keeps arriving and the rate now settles at the capacity rather than overshooting beneath it.
The existing benchmark reports one number: queries per second against a single local resolver with no impairment. That number moved 21,750 -> 29,676 between two CI runs of identical code, so it cannot detect a regression, and no real workload resembles the regime. None of this release's defects would have shown up in it. Six regimes now, each reporting delivery, retry amplification, completion percentiles, and socket plus connection-tracking peaks. Throughput is printed but is not a number to gate on; the ratio against dnspython in the same run is stable across hardware where absolute rates are not, and the in-flight column is there so two engines are never silently compared at different depths. Loss and latency are injected in-process, deterministically and without root, by an impaired resolver on its own thread. High-throughput regimes point at a real resolver, since a Python one would be the ceiling. A regime that cannot finish is recorded as a result rather than hanging the run.
A pool regime printed its total in flight, so 8 per resolver across 32 resolvers read as 256 -- a figure that looks like it exceeds what one persistent socket can carry, when the limit is per resolver and 8 is well under it. The column now shows both, and run_blastdns refuses a persistent regime configured past the transport bound rather than reporting the resulting collapse as a measurement.
Drop-in: same invocation, same report heading the sticky-comment step matches on, same dnsmasq port the workflow starts. The old single-regime script is gone rather than left alongside, since its one number is the thing that could not detect a regression. Clients are now warmed before timing. Socket setup and probing cost the same whatever the query count, so leaving it inside the measurement made two runs at different sizes incomparable: the persistent pool regime read 3,694 qps at 4,000 queries and 16,485 at 20,000 with no config change.
A query counts as lost only when its timeout expires, so losses arrive later than the dispatches that caused them. The ratio was computed per 500ms tick against a 1s timeout, which put the two in different windows: cutting the rate dropped dispatches at once while the previous rate's losses were still landing, and the next tick read 118% then 152% loss. Those readings then looked like improvement on the way back down, so the retreat-must-help guard waved them through and the rate slid anyway. The window now accumulates until it is at least as long as the timeout, and the ratio is clamped, since a window whose rate was just cut can still absorb more losses than it sent. Under 10% rate-independent loss a 2,000 query workload goes from 41.8s at 34 qps to 11.9s at 197 qps, with every query still delivered. Judging on a window rather than a tick does not make the branch reachable at brute-force scale: the window resets once it covers the timeout, so a resolver drawing two queries a second still never reaches MIN_SAMPLES.
Two mechanisms it described no longer exist. Retries are not suppressed under correlated loss -- that was tried and measured, taking unanswered queries from 0% to 3.5% on a 5,000-name brute-force, and was removed. Resolvers do not vote on the global rate by having delivered a clean interval; the global signal is queries that failed after exhausting every retry. persistent_socket was absent entirely despite being a shipped option, so the architecture section still described one socket per resolver as the default when that is now the opt-in path. It has a section covering what it costs: bounded connection-tracking state against reduced spoofing entropy and a 32-query ceiling per socket. Also documents that retreat repeats only while loss is falling, that loss is measured over a window outlasting the request timeout, that the startup probe allows a looser deadline than a query, that stats().rate_qps is instantaneous rather than cumulative, and that per-resolver judgement does not engage at brute-force scale. CLI help regenerated from the binary, which was missing --persistent-socket.
…v/anyhow-1.0.104 Bump anyhow from 1.0.103 to 1.0.104
…v/libc-0.2.189 Bump libc from 0.2.186 to 0.2.189
Bumps [lru](https://github.com/jeromefroe/lru-rs) from 0.18.1 to 0.18.2. - [Changelog](https://github.com/jeromefroe/lru-rs/blob/master/CHANGELOG.md) - [Commits](jeromefroe/lru-rs@0.18.1...0.18.2) --- updated-dependencies: - dependency-name: lru dependency-version: 0.18.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Decouple concurrency from resolver count and add adaptive rate control
…v/lru-0.18.2 Bump lru from 0.18.1 to 0.18.2
DNS Resolver BenchmarkThroughput is reported, never gated: it moves with hardware. The stable ceiling/1-resolver
pool/32-resolvers
pool/32-persistent
impaired/10%-loss
impaired/20%-REFUSED
impaired/50ms-latency
|
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 2.0.19 to 2.0.20. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](dtolnay/thiserror@2.0.19...2.0.20) --- updated-dependencies: - dependency-name: thiserror dependency-version: 2.0.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.33 to 0.3.34. - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/main/CHANGELOG.md) - [Commits](rust-lang/futures-rs@0.3.33...0.3.34) --- updated-dependencies: - dependency-name: futures dependency-version: 0.3.34 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
…v/thiserror-2.0.20 Bump thiserror from 2.0.19 to 2.0.20
…v/futures-0.3.34 Bump futures from 0.3.33 to 0.3.34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.