Skip to content

fix(scan): preserve snapshot id for empty data evolution index plans - #258

Open
wangyong9999 wants to merge 3 commits into
apache:mainfrom
wangyong9999:fix/data-evolution-empty-plan-snapshot-20260828
Open

fix(scan): preserve snapshot id for empty data evolution index plans#258
wangyong9999 wants to merge 3 commits into
apache:mainfrom
wangyong9999:fix/data-evolution-empty-plan-snapshot-20260828

Conversation

@wangyong9999

@wangyong9999 wangyong9999 commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Purpose

Linked issue: none.

A global-index miss on a non-empty DataEvolution table returned a correct empty row set but lost the snapshot used by the index scan. A null snapshot is otherwise reserved for a table with no snapshot.

Snapshot and data-flow changes: the explicit or latest snapshot ID is resolved before the internal Global Index scan, and a zero-split miss plan carries that same ID. For a pre-supplied empty GlobalIndexResult, the fast path now loads the resolved snapshot through SnapshotManager before constructing the plan. Missing, expired, unreadable, or malformed snapshots therefore propagate an error instead of producing a successful plan with an unvalidated ID. A table with no snapshot still returns the null-snapshot empty plan.

Time-travel boundary: Global Index planning does not yet support tag- or timestamp-based time travel. Once evaluation or a pre-supplied result actually yields a range-based Global Index result, planning now returns NotImplemented: Global index scan does not support time travel instead of silently binding that result to the latest snapshot. If no usable index exists and the evaluator returns no result, the ordinary batch scan still handles tag/timestamp time travel normally.

The change adds no shared state or concurrency mechanism. Existing snapshot-manager I/O and error propagation are reused. The only compatibility change is that previously successful but semantically invalid Global Index plans now fail explicitly. Expected benefits are accurate empty-plan snapshot metadata, rejection of stale snapshot IDs, and prevention of Global Index/data-manifest snapshot mismatches.

Tests

  • Built paimon-global-index-test and paimon-core-test successfully with GCC 8.3 in Debug mode.
  • Full paimon-global-index-test: 138/138 passed.
  • Full paimon-core-test: 1863/1863 passed.
  • FileFormat/GlobalIndexTest.TestDataEvolution*: 54/54 parameterized cases passed.
  • DataEvolutionBatchScanTest.* and TableScanTest.TestNoSnapshot: 4/4 cases passed.
  • Regression coverage includes nonexistent snapshot 999, a deleted previously valid snapshot, evaluated and pre-supplied Global Index results with tag/timestamp options, and the no-index ordinary batch fallback.
  • clang-format 20.1.8 dry-run/Werror, cpplint 2.0.2, codespell 2.4.1, and git diff --check passed.

API and Format

No public API, ABI, storage-format, or protocol change. The modified scan helpers are private implementation details and no class data member is added.

Documentation

No new feature or user-facing configuration; no documentation change is required.

Generative AI tooling

Generated-by: OpenAI Codex (GPT-5)

std::optional<int64_t> snapshot_id = core_options_.GetScanSnapshotId();
if (snapshot_id) {
return snapshot_id;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please validate the snapshot before returning the empty plan. With a pre-supplied empty GlobalIndexResult, a nonexistent scan.snapshot-id (for example, 999) is currently copied directly into a successful plan. Please resolve/load the snapshot here and add a regression test for nonexistent or expired snapshot IDs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior seems to predate the PR: the global-index scan already appears to ignore tag- and timestamp-based time travel and fall back to the latest snapshot. What changes here is that the new resolver makes this more visible by attaching that latest snapshot ID to an empty plan. Since global-index time travel does not seem to be supported at the moment, would it make sense to reject these modes explicitly instead of silently scanning and reporting the latest snapshot?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, good catches — addressed in aeeb00a.

The pre-supplied empty-result fast path now loads the resolved snapshot through SnapshotManager before constructing the empty plan. Nonexistent, expired, unreadable, or malformed snapshots therefore propagate an error, while a table with no snapshot still returns the null-snapshot empty plan. The regression coverage includes both snapshot 999 and a previously valid snapshot whose file was removed.

Tag- and timestamp-based time travel now returns a single NotImplemented error (Global index scan does not support time travel) once planning actually obtains a Global Index result. This covers internally evaluated results and pre-supplied nonempty results, while preserving the ordinary batch-scan fallback when no usable index exists. The tests cover both options and the unindexed fallback boundary.

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.

2 participants