Repository navigation
Tracking: remove duplicate, over-abstracted, and dead code in Stages 0–2 #1096
Description
Audit of main @ 4edb47be for duplicate, over-abstracted, dead and overly complex code in Stages 0–2, plus the parts of types and accuracy they use.
Out of scope: executor, plan-selection, cost and the vendored MetricsQL parser. They were only grepped to find callers.
Every "dead" claim was checked by grepping crates/**/*.rs. LOC figures are rough estimates.
Tags: ⭐ high value · (H/M/L) confidence that the change is safe
Stage 0: frontends
Bug
- MetricsQL lowers vector negation as
x * -1(frontend-metricsql/src/lib.rs:157), while PromQL usesPromqlMap{Negative}(promql.rs:396). The comment saying they match is stale, and the mismatch breaks cross-language CSE. (H)
Duplicate
- ⭐ PromQL's range-function table is written twice (
promql.rs:564,:1630). Merge it, and drop theInnerFuncenum, which exists only to be mapped toAggIntent. ~150 LOC (H) - The 3
Outerarms differ only by intent; make themOuter::Reduce(AggIntent). Also dedupe the 2 TopK literals (promql.rs:98). ~60 LOC (H) - The SQL conjunct/disjunct split and rebuild code repeats DataFusion's
split_conjunction,split_binaryandconjunction(sql/expr.rs:14,314,sql/mod.rs:2095,2118). ~40 LOC (H) - PromQL and MetricsQL repeat the workload preamble, the selector lowering, and the single-measure
Aggregateliteral (6 copies). Share them via frontend-common. ~60 LOC (M) - 4 hand-written
Exprdescents; replace them with onechildren(). Also check whethercollect_metric_namesskippingagg.paramloses sample intervals. ~30 LOC (M) - Small repeats: blocks in
resolve.rs(:153/:171,:575/:627) and theMatchOpmapping written twice inpromql.rs. ~20 LOC
Over-abstracted
- SQL: the
ACCURACYthread-local and its guard should be a field onSqlLowerer(sql/mod.rs:85-115). ~30 LOC (H) - PromQL: the 3 thread-locals (accuracy, sample intervals, histogram catalog) should become a
Lowererstruct like MetricsQL's. ~70 LOC (M, a lot of signature churn) -
Option<HistogramCatalog>behaves the same as an empty catalog, so the extra entry points and the_innerforwarders can go (frontend-promql/src/lib.rs:56-161,planner/src/lib.rs:99). ~35 LOC (H) - The
SchemaCatalogtrait andSchemaResolver<C>exist for a future registry; production only uses the catalog that returnsNone. Replace them with a free fn. ~45 LOC (H) -
pub mods with no users outside the crate; make them private. Also fix stale or misplaced docs (mark_without,histogram_arg_is_sketchable,current_accuracy). ~20 LOC
Dead / test-only
- No callers:
UnresolvedOp::scalar_exprs,HistogramCatalog::is_empty,NativeFunction.arity, and the identity fnquantile_param. ~65 LOC (H) - Test-only API:
lower_sql_batch(known to be wrong, and the only constructor ofSqlError::WrongLanguage),lookup_clickhouse_{scalar,window}_builtin, and MetricsQL'slower_metricsql,lower_metricsql_queryandcanonical_metricsql. ~85 LOC (H/M) - Needs a human decision: production never sets
discriminator_unique_keytoSome. It is a deliberate hook from the Concat drops unique_keys unconditionally — no way for a producer to assert cross-branch disjointness #228 design. Keep it or drop it? ~50 LOC
Unnecessarily complex
-
walkchecksis_*_fnguards and then matches the same names again; use a single name match (promql.rs:370-394). ~35 LOC (M)
Stage 1: logical-asap-optimization
Duplicate
- ⭐ The old whole-DAG Pass 2 enumerator (
pass2/workload_candidates.rsand most ofpass2/asap_aware_cse.rs) runs in parallel with the memo rules. Its only production caller isplan-selection/.../query_pruning.rs:326; move that to the memo path and retire the old enumerator. ~1000 production + ~500 test LOC (M: check that pruning verdicts don't change) -
same_familyappears twice; usecse::same_value. Separately, renameasap_aware_cse.rs:758 same_family, which shares the name but has a different meaning. ~10 LOC (H) - The memo rules repeat the same boundary and DAG-walk code; add
boundary_ptrsandnodes_withinhelpers. ~60 LOC (M)
Over-abstracted
-
memo/window_candidates.rsandmemo/shared_configurations.rshave chains of public wrappers that only tests use; collapse each to one entry. ~45 LOC (H) - The
viable: &dyn Fnparameter is always|_| true. This goes away if the enumerator is retired. ~25 LOC (H) - Small items, ~25 LOC (H):
PrunedCandidate<C>has one instantiation and its name collides with plan-selection's; make it concrete.computation_choices_cacheshould be a local instead of a parameter.memo/candidates.rsis only a re-export shim.
Dead / test-only
-
with_shared_candidates,StateGroupExpansionError::InvalidReaderBoundary, and the test-onlymay_change_rollup_candidate. ~20 LOC (H)
Unnecessarily complex
-
rules/rollup.rsadd_rollup_candidatesis 207 lines and rediscovers facts the tree rule already knows; split it up. ~40 LOC (M) - About 100
check_generation_deadlinecalls are nested at every level; one per outer loop is enough. ~40 LOC (M) - The root-dependency check and
validate_structureeach run twice. ~10 LOC (M)
Layering
-
pass2/memo.rsandpass2/cse.rsrun before Pass 1, so pass1 currently imports pass2; move both out ofpass2. 0 LOC (H)
Stage 2: physical-asap-optimization
Duplicate
- The prologue is copied 4× in
lib.rs; extract it into a helper. ~30 LOC (H) - Use the helpers already in types:
QueryRoot::operator_refsinstead ofroot_operators, andstages::output_referencesinstead ofordered_output_references. ~20 LOC (H) - The five-arm
ReaderConstraintmatch appears 5×, one of them in plan-selection; addReaderConstraint::candidate_mut(). ~45 LOC (H) -
inventory.rshas an inline copy ofordered_inputs. ~5 LOC (H)
Over-abstracted
- ⭐
summary_window.rsdefinesPaneLayout,WindowEdgeCoverage,PaneCoverageErrorand serde support for one call site that always passesSome(0). Replace it with oneschedule_phasefn. ~140 LOC (H) -
catalog/realize.rstakesmaterializationsas a parameter, but it can be derived from the selected candidates. ~15 LOC (M)
Dead / test-only
-
optimize_physical_asap_assignedhas one devtools caller andphysical_candidate_countis used by one test. ~25 LOC (H)
Unnecessarily complex
- The
summary_materialization_eligibilitywrapper andSummaryEligibilityErroradd nothing; callsummary_reader_eligibilitydirectly. ~45 LOC (H) - The catalog is validated 2–3× per stage, and
reconstruction.rsre-validates per plan inside the refinement loop; validate once per stage. Also fix the stale doc at plan-selectiondag.rs:322. ~30 LOC (M-H) - The boundary checks in
lib.rs:1017-1043are redundant, and theImplementationBoundaryerror is never matched. ~22 LOC (M) -
configurations.rshas a timing-indexed array plus a second cache. ~20 LOC (L-M)
Shared code (types, accuracy)
Duplicate
-
reads_only_time_serieshas 3 identical copies (types, Stage 1, Stage 2); keep one onOperatorNode. ~12 LOC (H) - The deadline checker is reimplemented in about 8 places; add one
check(deadline)helper. ~50 LOC (H) -
rolled_up_buildandsummary_coverage::regroupedbuild the same rolled-upSummaryAgg; share the builder. ~25 LOC (M)
Over-abstracted
- ⭐ Accuracy has about 20
test_supportforwarders anddefault_size_params. Move the propagation tests intocrates/accuracy, then delete them. ~150 LOC (M-H) - Small items, ~25 LOC (L-M):
MemoGrouphas public fields and getters; keep one.ColStateis a marker trait; inline its serde bounds.- The
physical/module holds one file.
Dead / test-only
- ⭐ Deadline plumbing production never uses:
flatten_before,compile_physical_asap_workload_with_node_ids_before,expand_pane_chains_in_workload_before, theset_retentiondeadline param (every caller passesNone), and their error enums. ~200 LOC (H) - ⭐ Reserved
ASAPOpvariantsSummarySubtract,SummaryDelete,SummaryJoin,ExtensionandUNIMPLEMENTED_ASAP_OP. Nothing constructs them; their match arms only reject them. ~100 LOC (H) - ⭐ Speculative
FieldDataType::SummarySample,WaveletandStatModel, plus their Kind/Params types. ~110 LOC (H) - Test-only
OperatorNode::validate_execution_timingrepeats the ingestion-timing rule intiming.rs. ~25 LOC (H)
Unnecessarily complex
-
PhysicalASAPDAGEdgestores copies of schema and state and then validates them (~70 lines); slim it to(producer, consumer, role). This changes the wire format, so snapshots and the dag-viewer need updating. ~100 LOC (M) - The same invariants are checked in both
timing.rsandvalidate_inputs. Also, there are twoselects_stateswith different meanings; rename one. ~30 LOC (M)
Residue
- The serde name
ExactBoundaryResidualdoesn't match the Rust variant nameExactWindowEdgeResidual.
Totals
About 2,900 production LOC in all. About 1,000 of that is the Pass 2 enumerator. About 900 is high-confidence deletion that should need no behavior change.
Activity
zzylol commentedon Oct 30, 2026
Status of this audit against the #1047/#1054/#1095 refactor. That work lands on the integration branch
refactor/stage-boundaries(#1098–#1105, not yet onmain), which then merges tomainafter one test phase.When to start
refactor/stage-boundaries, notmain: the branch is 8 PRs ahead ofmain, and frontend visibility already changed there (refactor: narrow asap-types test-only fields and frontend visibility (#1054 step 8b, part 2) #1099). The in-flight work ([Refactor] One named type per stage boundary: PerComputationLogicalMemoCandidates → LogicalASAPMemoCandidates → PhysicalASAPMemoCandidates #1047 P3c, P7) does not touch the frontends.refactor/stage-boundariesmerges tomain. P3c (Pass 1 walks memo groups) and P7 (facade, realizer,asap_types::stages) are rewriting exactly these files. A heads-up will be posted here when the merge happens.Items already done on
refactor/stage-boundariesworkload_candidates.rs, theasap_aware_cse.rswhole-workload entry points), together with its callerquery_pruning.rsviable: &dyn FnparameterUnresolvedOp::scalar_exprs,HistogramCatalog::is_emptyNativeFunction.arityandquantile_paramremainlower_metricsql,lower_metricsql_query,canonical_metricsqltest_support; not deletedpub mods with no outside users (frontends)optimize_physical_asap_assigned,physical_candidate_counttest-supportand#[cfg(test)]PrunedCandidate<C>collisionasap_types::stages(shared by Pass 1 and Stage 2). plan-selection's ownPrunedCandidateinsearch/pipeline.rsremains; #1047 P7 / #1095 replaces itsummary_materialization_eligibilitywrapperpub(crate). The wrapper andSummaryEligibilityErrorremaincatalog/realize.rsmaterializationsparameterrealize(physical, selected), which removes itordered_output_referencescatalog/mod.rsandcatalog/realize.rsmilindsrivastava1997 commentedon Oct 30, 2026
Stage 0 scope, all PRs based on
refactor/stage-boundariesand opened in parallel:PR A — MetricsQL negation. MetricsQL
-xlowers to the same IR as PromQL (PromqlMap{Negative}), and the stale comment is fixed. The regression test lowers-rate(m[5m])through both frontends and asserts theQueryRoots are equal. The impact is narrower than the audit states: a workload has exactly one language, so this isn't a cross-language CSE breakage. The two frontends just lower negation to different IR. No snapshot changes are expected (the corpus is PromQL only).PR B+C — deletions and indirection, no behavior change.
lower_promql_workload{,_with_histograms}, leaving onelower_promql_query_workload(workload, &HistogramCatalog). The histogram thread-local drops itsOption, and the_innerforwarders go. Test callers that need the operator node unwrap the root inline.FrontendInput::Promql { histograms: Option<_> }stays as it is.SchemaCatalog/UsageDerivedCatalog/SchemaResolver<C>become a free function; re-adding a registry later is tracked in Add a registry-backed SchemaCatalog to frontend-common schema resolution #1112.ACCURACYthread-local becomes a field onSqlLowerer.NativeFunction.arity,quantile_paramandlookup_clickhouse_{scalar,window}_builtin, and fix the stale docs.PR D — PromQL de-duplication, no behavior change.
InnerFunc.Outer::Reduce(AggIntent), and the TopK literals written once.walk, and oneMatchOpmapping.children()in place of the 4 hand-writtenExprdescents.PR 4 — SQL/resolve de-duplication, no behavior change. Use DataFusion's
split_conjunction/split_binary/conjunction, and remove the repeated blocks inresolve.rs.Not in this round:
test_supportfunctions andlower_sql_batch.Lowererstruct.discriminator_unique_key.Checked, not a bug:
collect_metric_namesskippingagg.param. Aggregate params can only be numeric or string literals, so no metric name is lost.