Skip to content

ducklink: update to v4.2.0#2207

Closed
zacharywhitley wants to merge 1 commit into
duckdb:mainfrom
zacharywhitley:ducklink-v4.2.0
Closed

ducklink: update to v4.2.0#2207
zacharywhitley wants to merge 1 commit into
duckdb:mainfrom
zacharywhitley:ducklink-v4.2.0

Conversation

@zacharywhitley

Copy link
Copy Markdown
Contributor

Six perf batches + a cold-start UX fix + an optional binary-size feature since v4.1.1. No API breaks, no WIT contract changes — additive minor bump.

User-visible wins

Measured on darwin/aarch64 with lto=true, strip=true:

Metric Before After Δ
Aggregate 1M rows (sample_sum(v) FROM range(1M)) 82 ms 38 ms -54%
Parallel scalar (2-thread cross-extension) 12.9 ms 5.75 ms -55%
Serial scalar dispatch 42 ms 11.2 ms -73%
Cold-start on offline / bad-DNS 15 s 3 s -80%
Binary size (offline build variant) 25.9 MB 21.7 MB -4 MB

What's new architecturally

Dispatch (F/G/H/I/L batches)

  • Column-native aggregate UPDATE: AggState is per-column typed accumulators picked at agg_init. Ungrouped chunks bulk-copy the whole input via extend_from_slice. Eliminates ~10M outer Vec allocs + boxed enum variants per 10M-row aggregate.
  • CallbackRegistry Mutex → RwLock; Weak<Instance> on CallbackEntry so dispatch prologue is one atomic upgrade instead of HashMap<name, _>::get + Arc clone.
  • Per-thread SCALAR_ARGS_SCRATCH: refill_colvec reuses Colvec buffers across chunks; TEXT/BLOB reuse via String::clear + push_str.
  • write_colvec skips a redundant 2048-byte null-mask scan.

Discovery / docs (F1, F2, G4)

  • Arc<CachedDocs> with generation-counter invalidation for the docs pipeline. render_help, ducklink.docs, and ducklink_search no longer rebuild ~639 DocRows per query.
  • flat_vector handles hoisted out of every discovery TF's row loop.

Load-time (H4, J3)

  • Base component-linker template cached per Engine: ~25 add_to_linker calls run ONCE per process instead of once per component load.
  • Wasm bytes read ONCE per load and shared between Component::from_binary and parse_docs_from_bytes.
  • wasmtime::Config::memory_may_move(false) (K1): 1-2% real per-row gain via base-pointer LICM.

Cold-start UX (J1)

The single most user-visible slow path in the codebase: opening DuckDB on hotel-WiFi / offline, running SELECT * FROM ducklink.modules, and staring at a black cursor for 15 seconds while a network fetch times out before the bundled snapshot loads.

  • Catalog HTTP fetch timeout: 15 s → 3 s. The graceful fallback (bundled snapshot) is already in the binary.
  • Async prewarm: Engine2::new spawns a background thread that populates the catalog OnceLock while DuckDB is still finishing extension setup. By the time the first user query arrives the catalog is usually already resolved. Best-effort; races are resolved via OnceLock::get_or_init's barrier.

Optional binary-size feature (J2)

New default-enabled network feature gates reqwest + rustls + webpki-roots + sha2:

cargo build --release                                     # 25.9 MB (with network)
cargo build --release --no-default-features \
            --features loadable,advanced                  # 21.7 MB (offline)

The offline variant is for air-gapped / minimum-size deployments; it serves only names in the bundled snapshot and refuses to download uncached blobs.

Community-extensions CI runs cargo build --release (default features) so this PR's distributed artifact keeps full network support — no change for end users of the CI-built extension.

Retracted design docs

docs/perf-ceiling-measurement.md, docs/wit-streaming-scalar-dispatch.md (RETRACTED), docs/wit-shared-memory-result.md (CANCELLED), and docs/guest-simd-investigation.md capture the measurement work behind this release and the reasoning behind rejecting several proposed architectural changes (~30% streaming projection turned out to be ~1.3%; ~27% zero-copy projection turned out to be <1%). New benches (streaming_validation, memcpy_floor) let anyone reproduce the findings.

PR history

Supersedes v4.1.1 (merged as #2201). All changes are on top of v4.1.1.

Six perf batches + a cold-start UX fix + an optional binary-size
feature since v4.1.1. No API breaks, no WIT contract changes.

USER-VISIBLE WINS (measured on darwin/aarch64):
  - Aggregate throughput on 1M-row workloads:  82 ms -> 38 ms (-54%)
  - Parallel scalar dispatch:                  12.9 ms -> 5.75 ms (-55%)
  - Cold-start (offline / bad-DNS):            15 s -> 3 s
  - Extension binary (offline build variant):  25.9 MB -> 21.7 MB (-4 MB)

Dispatch architecture: column-native aggregate UPDATE (G1/H1) with
per-column typed accumulators; Weak<Instance> on CallbackEntry so
dispatch prologue is one atomic upgrade instead of HashMap lookup;
per-thread scratch reuse for Colvec buffers (F4, G2, I1); every
docs/discovery TF caches flat_vector handles above its row loop
(F2, G4).

Cold-start: catalog HTTP fetch timeout shortened from 15 s to 3 s;
Engine2::new spawns a background thread that populates the catalog
OnceLock so the first query usually pays zero wait.

New optional `network` feature (default enabled) gates
reqwest + rustls + sha2 out; `--no-default-features --features
loadable,advanced` sheds 4 MB from the binary for air-gapped /
minimum-size distributions. The community-extensions CI runs
default features so the distributed artifact keeps network
support.
@zacharywhitley

Copy link
Copy Markdown
Contributor Author

Superseded by #2214 (v4.3.0).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant