Page MenuHomePhabricator

Use Iceberg branches (i.e WAP) to write atomically
Closed, ResolvedPublic

Description

Problem

MWHistoryDeltaWriter issues 8 sequential MERGE INTOs (M1–M7b) and MWHistorySnapshotMerger issues a DELETE followed by two INSERTs. Between any two mutations, intermediate state is visible to downstream readers — e.g. revision rows present but page_is_deleted not yet back-patched, or a gap where all snapshot rows are absent. The SnapshotMerger code had an explicit NOTE comment flagging this gap and naming WAP as the fix.

Solution

Add optional Iceberg WAP (Write-Audit-Publish) branching to both jobs. When --wap_branch <name> is supplied, all reads and writes target a private Iceberg branch via the dot-suffix notation (table.branch_<name>). On success, a single CALL catalog.system.fast_forward(...) atomically advances main. Downstream readers see only the pre-run state or the fully-written state.

Design notes

  • Branch-suffix approach (not spark.wap.branch session conf): reads and writes are explicit in every SQL string, so intra-run reads — including revert_seed (M1/M2) and user_provenance (M7b) — are also scoped to the branch. M7b in particular must read the branch to see user create events inserted by M7 in the same run.
  • --wap_branch is optional (no default). Old Airflow DAGs without the flag continue writing directly to main unchanged.
  • Branch naming convention is left to Airflow (the job does not construct the name).
  • DROP BRANCH IF EXISTS before CREATE BRANCH makes retries idempotent after a failed run.
  • No write.wap.enabled table property needed — branch-suffix approach does not require it.

Remaining work

  • Airflow DAG changes: pass --wap_branch <generated_name> to both Spark jobs
  • Cluster smoke test: verify branch appears/disappears cleanly in Iceberg branch listing during a real daily run

Event Timeline

Change #1298333 had a related patch set uploaded (by Xcollazo; author: Xcollazo):

[analytics/refinery/source@master] Add Iceberg WAP branching to MWHistoryDeltaWriter and MWHistorySnapshotMerger

https://gerrit.wikimedia.org/r/1298333

Implemented WAP (Write-Audit-Publish) branching for both MWHistoryDeltaWriter and MWHistorySnapshotMerger.

  • Added --catalog and --iceberg_branch optional params to both jobs. When omitted, jobs write directly to main (backwards compatible).
  • All SQL mutations (MERGEs, INSERTs, DELETE) and intra-run reads target the branch; CALL fast_forward atomically publishes to main on success.
  • Extracted IcebergBranchOps.targetRef() shared helper to avoid duplication.
  • 113/113 tests pass, including a real Iceberg integration test (Hadoop catalog) validating the full branch lifecycle.
  • Validated on stat1011 against 5 days (2026-06-01 through 2026-06-05): all runs successful, no orphaned branches, elapsed 56–126 min/day.

Change #1298378 had a related patch set uploaded (by Xcollazo; author: Xcollazo):

[analytics/refinery/source@master] Fix control_map timestamps: use ISO-8601 UTC format (yyyy-MM-dd'T'HH:mm:ss.SSS'Z') uniformly

https://gerrit.wikimedia.org/r/1298378

Change #1298333 merged by jenkins-bot:

[analytics/refinery/source@master] Add Iceberg WAP branching to MWHistoryDeltaWriter and MWHistorySnapshotMerger

https://gerrit.wikimedia.org/r/1298333

Change #1298378 merged by jenkins-bot:

[analytics/refinery/source@master] Fix control_map timestamps: use ISO-8601 UTC format (yyyy-MM-dd'T'HH:mm:ss.SSS'Z') uniformly

https://gerrit.wikimedia.org/r/1298378

WAD in production. Love the new branching pattern, we should do similarly for MWCH, and for any new Iceberg tables that have multi-step data ingest!