Skip to content

Commit d04070b

Browse files
andrescrzclaude
andcommitted
docs(cutover): correct verify version-check + finalize crash-recovery comments
Two comment accuracy fixes from a colleague review (JetoPistola). 000005_verify_migration.sql — the version-collapse guard comment claimed it detects legacy sub-microsecond version-selection on pre-000019 parts. It cannot: ClickHouse coerces last_updated_at to its DECLARED DateTime64(6) at read time, so raw ns digits are unrecoverable through the column and uniqExact(last_updated_at) == uniqExact(toDateTime64(last_updated_at,6)) always — collapse_keys is structurally 0 on a (6)-declared schema (empirically confirmed; inert since #7572). Reword to say it is inert defense-in-depth that can only fire if the column is ever re-declared at higher precision, and note that dropping the guard + --allow-version-collapse as dead code is a reasonable follow-up (kept out of scope here). finalize.sh — the recycle comment said re-running finalize "recovers" a crash between the ordered TRUNCATE and RENAME. That's only true single-host; under partial ON CLUSTER propagation the re-run's cluster-wide classify sees a mixed state and refuses loudly (finish the RENAME by hand), never silently corrupting. Reword to reflect both. Comment-only; no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 1917e63 commit d04070b

2 files changed

Lines changed: 14 additions & 10 deletions

File tree

apps/opik-backend/data-migrations/traces-local-v2-cutover/scripts/db-app-analytics/000005_verify_migration.sql

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,16 @@ SETTINGS join_use_nulls = 1, use_skip_indexes_if_final = 1;
188188
-- >>> END drill-down
189189

190190
-- >>> BEGIN version-check
191-
-- Legacy sub-microsecond version-selection backstop. last_updated_at (the ReplacingMergeTree version) is DateTime64(6)
192-
-- on BOTH tables since migration 000019 reduced the source column to micros — but on-disk parts written BEFORE 000019
193-
-- can still carry sub-microsecond precision until they are merged/rewritten. Two such source part-versions of the same
194-
-- key that differ ONLY in sub-microsecond digits would collapse to one version on the successor (stored at us), which
195-
-- may then keep different column values than source FINAL — a divergence the microsecond-normalized fingerprint above
196-
-- cannot detect. This surfaces the PRECONDITION: old-schema keys in the window with more distinct raw last_updated_at
197-
-- values than us-truncated ones. 0 => truncation cannot change version selection (safe). > 0 => investigate those keys
198-
-- before trusting the compare.
191+
-- Version-selection backstop — INERT on a fully-000019 schema; kept as defense-in-depth only. last_updated_at (the
192+
-- ReplacingMergeTree version) is DateTime64(6) on BOTH tables since migration 000019 reduced the source column to micros.
193+
-- ClickHouse coerces a column to its DECLARED type at READ time, so even an on-disk part physically written BEFORE 000019
194+
-- at (9) surfaces its value already truncated to us — the raw sub-microsecond digits are unrecoverable through the
195+
-- column. So uniqExact(last_updated_at) and uniqExact(toDateTime64(last_updated_at, 6)) are ALWAYS equal on a
196+
-- (6)-declared column and collapse_keys is structurally 0: this can only ever fire if last_updated_at is later re-declared
197+
-- at higher precision than (6). It would then surface keys whose sub-us-distinct versions collapse to one us version on
198+
-- the successor (a divergence the us-normalized fingerprint above cannot detect). 0 => truncation cannot change version
199+
-- selection (safe / expected). Dropping this guard and --allow-version-collapse as dead code is a reasonable follow-up;
200+
-- left in place here to keep this PR scoped to the cutover rollback tooling.
199201
SELECT count() AS collapse_keys
200202
FROM (
201203
SELECT workspace_id, project_id, id

apps/opik-backend/data-migrations/traces-local-v2-cutover/scripts/finalize.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,10 @@ if [[ "$BACKUP" == "traces_post_rollback_backup" ]]; then
125125
# Rollback finalize: recycle the parked successor — physically the 000101 `traces_local_v2` object (its replica path
126126
# is fixed at CREATE and unchanged by the rename) — back into an empty `traces_local_v2`. ClickHouse has no single
127127
# truncate-and-rename, so this is two statements, each atomic PER HOST and ON CLUSTER; ordered TRUNCATE-then-RENAME so
128-
# the only state a crash between them can leave is an empty `traces_post_rollback_backup`, which re-running finalize
129-
# recovers (RENAME-first could strand a populated `traces_local_v2` that a retry backfill would mis-skip). ACROSS the
128+
# the only state a crash between them can leave is an empty `traces_post_rollback_backup` — which re-running finalize
129+
# recovers on a single host, and under partial ON CLUSTER propagation (applied on some replicas, not all)
130+
# detects-and-refuses (cluster-wide `classify` sees a mixed state — finish the RENAME by hand, then re-run), never
131+
# silently corrupting (RENAME-first could strand a populated `traces_local_v2` that a retry backfill would mis-skip). ACROSS the
130132
# shard's replicas ON CLUSTER runs synchronously (the client blocks until every reachable replica applies it, or throws
131133
# naming a laggard that then converges via the DDL queue), NOT globally atomic. Both statements touch only the parked
132134
# backup / disposable shadow — never the live `traces` — so unlike the rollback promote and the wrap (which rename live

0 commit comments

Comments
 (0)