Repository navigation
refactor(physical-operators): one asap_sketchlib pin, library-owned sketch checks, dead portable heap updaters removed - #721
Merged
Conversation
…brary's shape, weight and memory checks One workspace pin for every crate: asap-physical-operators inherits the workspace asap_sketchlib (3f44cf1, a pin branch merging the upstream fixes onto 9415c5b) instead of its own rev. The planner stops restating sketch-library rules: - WeightedFrequency::configuration and plan validation of a plain CountSketch ask WeightedFrequency::check_shape (odd depth, positive dimensions); empirical cost evidence does the same. - UnivMonAccumulator, plan validation and the accuracy model's hash_independent ask UnivMon::check_shape, which also carries the 20-row wire bound the accuracy model did not check. - KMV reads its estimate and merges by reference and reports its own memory, so the adapter no longer clones a state to read or merge it and no longer guesses k * 8 bytes.
…ead portable sketch workarounds WeightedFrequencyUpdater keeps only its state: it validates a sample with the kernel's check_weight, resets with clear, and keys a label vector with update_labels, one String per label instead of an Arc<str> and a String. Removed, since no workspace code builds them after #706 moved the factory to the per-row-seeded weighted frequency kernel: - CmsHeapAccumulatorUpdater, CountSketchWithHeapAccumulatorUpdater and TopkWeight (factory.rs); - CountMinSketchWithHeapAccumulator (count_min_sketch_with_heap.rs) and CountSketchWithHeapAccumulator (count_sketch_with_heap.rs), which wrapped sketchlib's integer heaps that round and drop weights. DatasketchesKLLAccumulator drops its unsafe Send and Sync impls: asap_sketchlib's KllSketch is already Send and Sync.
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.
Why
#706 found that
asap_sketchlib's portable frequency sketches broke the planner's guarantees (one shared hash across CountSketch rows,SEEDLIST[r % 20]row seeds in the integer heaps, rounded and dropped weights) and fixed it by building those families on the library's per-row-seeded weighted frequency kernel. The planner still kept sketch-library behavior of its own: copies of the kernel's shape and weight rules in four places, a copy of UnivMon's hash-budget rule in two (one of them missing the 20-row bound), a guessed KMV footprint, clones to work around&mut selfreads,unsafeSend/Syncimpls, and the dead portable heap updaters "for callers that construct them directly" (there are none in the workspace). The standing rule is that accumulators wrapasap_sketchliband gaps are fixed upstream.What
Moved upstream (each with failing-first tests; none merged yet):
configuration,capability,empirical_cost)WeightedFrequency::check_shapeWeightedFrequencyUpdater::validate_single_input)WeightedFrequency::check_weight(algorithm, width, depth, capacity)kept beside each state to rebuild it on resetWeightedFrequency::cleark * 8footprint;O(k)per insert in the librarycheck_dimensions(executor) andhash_independent(accuracy model)UnivMon::check_shapeCountSketchsharing one 64-bit hash across rows (#706's item a; no planner caller left)Already upstream before this PR: per-row seeding, exact Float64 weights and the odd-depth error in the weighted frequency kernel (ProjectASAP/asap_sketchlib#160, #225).
In this repo:
asap_sketchlibpin for the workspace:asap-physical-operatorsinherits the workspace dependency (withexperimentalfor KMV) instead of its own rev. The rev moves from831a504(workspace) and9415c5b(physical operators) to3f44cf1on branchplanner-pin/sketch-library-fixes:9415c5bwith refactor: rename PromQL-specific QueryExpr nodes (and Merge/Distinct/WindowFunc/EvalTime) for clarity #226 to SQL: generalize the ClickHouse-builtin stub-registration mechanism from AggregateUDF to ScalarUDF #230 merged in. Once those PRs and controller-OMP #160/SQL: extract dialect builtin-function catalog into independent, generatable data (inspired by polyglot-sql-function-catalogs) #225 merge, the pin must move to upstreammain.WeightedFrequency::check_shapeandcheck_weight,UnivMon::check_shape,KMV::approx_memory_bytes, andKMV::estimate/mergeby reference.WeightedFrequencyUpdaterkeeps only its state.CmsHeapAccumulatorUpdater,CountSketchWithHeapAccumulatorUpdater,TopkWeight,CountMinSketchWithHeapAccumulator(count_min_sketch_with_heap.rs),CountSketchWithHeapAccumulator(count_sketch_with_heap.rs), UnivMoncheck_dimensions, the accuracy model'scolumn_bits, andDatasketchesKLLAccumulator'sunsafe impl Send/Sync(KllSketchis already both).Behavior changes: the accuracy model now refuses a UnivMon with more than 20 rows, which the executor already refused. A rejected sample's message is now the kernel's ("weighted frequency requires finite weights; CMS additionally requires nonnegative weights"). KMV memory is the library's allocated footprint, which grows from 1024 slots toward
kinstead of a flatk * 8.How
Each planner check becomes one library call.
asap-physical-operatorsandasap-aware-mappingboth already depend onasap_sketchlib, so no new dependency edges.update_keyedbuilds the kernel identity directly from the label strings (update_labels) instead of going throughValue::Utf8(Arc<str>).Key code interfaces added / modified
crates/asap-physical-operators/src/summary_kernels/factory.rssummary_kernels/count_min_sketch_with_heap.rs,summary_kernels/count_sketch_with_heap.rs,summary_kernels/mod.rs(files removed; links at the base)summary_kernels/weighted_frequency.rssummary_kernels/kmv.rs,summary_kernels/univmon.rs,summary_kernels/datasketches_kll.rs,capability.rscrates/asap-aware-mapping/src/accuracy/estimators/univmon.rs,empirical_cost.rsCargo.toml,crates/asap-physical-operators/Cargo.tomlUsage, end to end (a top-k over raw samples; checked by a scratch test on
precompute_raw_samples.rs's harness at this PR's head):Before this PR
asap_sketchlibrevs in one workspace (831a504and9415c5b), so two copies of the library compiled.khashes each; its footprint was guessed.After this PR
SketchParamsto constructors, turning labels andValues into sketchlib identities, theAggregateCore/AccumulatorUpdateradapters, and the accuracy model's sizing.Interface simplifications (author's choice)
WeightedFrequency(planner) is a newtype overasap_sketchlib::WeightedFrequencyonly to implementAggregateCoreand convertValues.AggregateCoreis a local trait, so it could be implemented on the library type directly and the newtype removed;rows/point_estimate/update(&[Value])would become an extension trait. Trade-off: everydowncast_ref::<WeightedFrequency>()(values.rs, operators/summary, tests) changes type; smaller code, one fewer name.WeightedFrequency::configuration(kind) -> (FrequencyAlgorithm, usize, usize, usize)could return(FrequencyAlgorithm, (usize, usize, usize)), matching the kernel'sshape()tuple thatvalidate_statecompares against. Trade-off: purely cosmetic.WeightedFrequencyUpdater::new(algorithm, width, depth, capacity)could beFrom<WeightedFrequency>; its only caller builds the state anyway. Trade-off: one less constructor, slightly less obvious call site.hash_independent(rows, cols, layers)passes a dummy heap size of 1 toUnivMon::check_shape; its two callers could callcheck_shapewith their real heap size and drop the helper. Trade-off: two call sites name the library directly.Efficiency
update_keyed(per sample): was 1Vec<Value>+ 1Arc<str>per label in the planner, then 1Vec+ 1Stringper label in the adapter; now 1Vec+ 1Stringper label. Inside the kernel,normalizestill clones the identity again and serializes a keyVec, so about 2Strings per label and 3Vecs per sample remain. Cheaper option (follow-up, upstream): an update that takes the identity by value or hashes borrowed&strs, removing the clone.capacity x depth) and sorts the candidates (capacity log capacity). feat(sql): extract function-name catalog, generalize uniqExact/countIf rewrite #227 removes the per-update clone of every candidate: 66 to 33 us (Count-Min) and 77 to 43 us (CountSketch) per update at capacity 100. Caching each candidate's cells would remove the hashing atcapacity x depth x 16bytes; follow-up.reset: zero-fills in place. Before, it allocated a freshwidth x depthstate per window: 637,500 cells (5.1 MB) for the 7500 x 85 CountSketch above.k = 4096: inserts 2.43 us to 37 ns (Concat drops unique_keys unconditionally — no way for a producer to assert cross-branch disjointness #228, the early return for hashes past the k-th);estimateandmerge_withno longer copy up to 4096 hashes.O(1).Verification
cargo nextest run -p asap-physical-operators -p asap-aware-mapping -p asap-integration-tests: 1075 passed, 30 skipped; at the new head,cargo nextest run -p asap-physical-operators -p asap-aware-mapping: 803 passed, 4 skipped.cargo test --doc -p asap-physical-operators -p asap-aware-mapping;cargo fmt --all -- --check;cargo clippy --workspace --all-targets --all-features --locked -- -D warnings;tools/verify_metricsql_external_consumer.sh: all pass on the head.univmon_past_twenty_rows_is_not_hash_independent(accuracy/estimators/univmon.rs):hash_independent(20, 8, 1)is true,hash_independent(21, 8, 1)is false, and a 21-row, 8-column UnivMon certifies no L2 guarantee. Against main's rule (rows · (⌈log2 cols⌉ + 1) ≤ 128with no row bound, restored temporarily in place of thecheck_shapecall) it fails withassertion failed: !hash_independent(21, 8, 1), since 21 · 4 = 84 hash bits fit the budget; with this PR it passes.adoption_rejects_terminal_or_invalid_sketchescan no longer build a 21-row UnivMon (the library refuses it), so it setssketch_row = 21on a built state to checkfrom_sketchstill refuses it.memory_counts_the_k_reserved_hashesbecamememory_covers_the_retained_hashes.cargo test --all-features --lockedinasap_sketchlib.Limitations and follow-ups
mainonce feat: own Float64 weighted CMS and CountSketch kernels in sketchlib asap_sketchlib#160, SQL: extract dialect builtin-function catalog into independent, generatable data (inspired by polyglot-sql-function-catalogs) #225, refactor: rename PromQL-specific QueryExpr nodes (and Merge/Distinct/WindowFunc/EvalTime) for clarity #226, feat(sql): extract function-name catalog, generalize uniqExact/countIf rewrite #227, Concat drops unique_keys unconditionally — no way for a producer to assert cross-branch disjointness #228, docs(asap-aware-mapping): correct module doc on where CSE detection runs #229 and SQL: generalize the ClickHouse-builtin stub-registration mechanism from AggregateUDF to ScalarUDF #230 merge. docs(asap-aware-mapping): correct module doc on where CSE detection runs #229 merged ontomainafter QueryExpr has duplicate relational/scalar-language shapes for the same semantics (Scalar/Literal, BinaryOp/Compare/Arith) #220; the pin carries its identical pre-rebase commit.Cmsfamily (CmsAccumulatorUpdater,CountMinSketchAccumulator) still wraps the portableCountMinSketch, which drops nonpositive weights silently, wraps row seeds past 20 rows in per-row mode, reports a constant 16 KiB, and reads its bare count by copying the whole matrix. Moving it onto the weighted frequency kernel at capacity 0 would change the DAG's stored plain-Cms state type, so it needs a design decision.CountMin/Count/CMSHeap/CSHeapstill repeat rowras rowr + 20past 20 rows. The wire refuses those states; whether constructors should refuse them or derive more seeds is an upstream design question (raised in SQL: generalize the ClickHouse-builtin stub-registration mechanism from AggregateUDF to ScalarUDF #230). The planner no longer builds them.HydraCmstracks itsi32counter total andDatasketchesKLL/DDSketchupdaters charge a fixed 4 KiB; both could become library reports in a follow-up.MAX_L2_ROWS,HASH_BITSinl2_shape) stay: they choose shapes, which is planner logic.