Repository navigation
[Kernel] Allow time travel across catalogManaged transitions - #7645
PatrickJin-db wants to merge 5 commits into
Conversation
| * path-based read of a current catalogManaged table. In that case only, load the latest protocol | ||
| * to distinguish the two. | ||
| */ | ||
| private void validateMaxCatalogVersionPresence(Engine engine, Protocol snapshotProtocol) { |
There was a problem hiding this comment.
is snapshotProtocol really the target version's protocol? maybe targetProtocol would be better.
|
|
||
| SnapshotQueryContext latestContext = | ||
| SnapshotQueryContext.forLatestSnapshot(tablePath.toString()); | ||
| Protocol latestProtocol = |
There was a problem hiding this comment.
The validation's latest protocol load only reads the on disk delta log and ignores the caller's staged commits, so it can misjudge whether the table is catalogManaged.
There was a problem hiding this comment.
fixed by supplying ctx.logDatas
| SnapshotQueryContext latestContext = | ||
| SnapshotQueryContext.forLatestSnapshot(tablePath.toString()); | ||
| Protocol latestProtocol = | ||
| new SnapshotManager(tablePath).buildLatestSnapshot(engine, latestContext).getProtocol(); |
There was a problem hiding this comment.
also, do we need to load the full snapshot? Don't we only need the latest log segment + P&M here?
There was a problem hiding this comment.
IIUC, this method only reads P&M, but i refactored to make it more explicit that we are only loading P&M here
Keeps the maxCatalogVersion presence rule in one place instead of splitting timestamp queries into SnapshotBuilderImpl. Co-authored-by: Isaac <no-reply@databricks.com>
91214eb to
4c17a33
Compare
…ck-jin/relax-max-catalog-version-time-travel Co-authored-by: Isaac <no-reply@databricks.com>
| private void validateMaxCatalogVersionPresence(Protocol protocol) { | ||
| boolean isCatalogManaged = TableFeatures.isCatalogManagedSupported(protocol); | ||
| /** | ||
| * Validates maxCatalogVersion presence for the current query. |
There was a problem hiding this comment.
I'm questioning the design decision here: when we're time traveling to a non-catalogManaged historical version, why do we need to validate the max catalog version?
Example:
v0 - not catalog managed
v1 - upgrade to catalog managed
v2 - catalog managed
Say we're trying to time travel to v0, do we really need to validate v2 (max catalog version)? This opens up some issues:
scenario 1) attempt to time travel to v0
v0 - not catalog managed, published
v1 - upgrade to catalog managed (ratified, not published)
v2 - catalog managed (ratified, not published)
scenario 2) attempt to time travel to v0
v0 - not catalog managed, published
v1 - upgrade to catalog managed (ratified, not published)
v2 - catalog managed -- introduces a table feature that kernel does not understand (ratified, not published)
Will the above fail? I think we need to think more about whether or not we want to load the protocol for the max catalog version.
There was a problem hiding this comment.
Good point, in that case I think it makes sense not to validate maxCatalogVersion if the target protocol is not CCv2.
That said, the issue of Kernel failing to load a past version if it cannot read the current protocol already exists today for timestamp-based time travel right? Since timestamp-based time travel requires loading the latest snapshot.
|
|
||
| package io.delta.kernel.defaults.catalogManaged | ||
|
|
||
| import java.io.File |
There was a problem hiding this comment.
Can we please add the following test cases?
-
A later change above the catalog limit:
• v0: non-catalog-managed.
• v1: catalog-managed.
• v2: published downgrade to non-catalog-managed.
• Request v0 with maxCatalogVersion= 1. -
An unpublished downgrade
• v0: catalog-managed.
• v1: downgrade to non-catalog-managed, approved but unpublished.
• Supply v1’s commit; request v0 without a maxCatalogVersion -
Only supply history needed for the requested version
Request published v0 with maxCatalogVersion=2, supplying only unpublished v1.
-
A newer version has an unsupported reader feature
Request readable v0; v2 introduces a feature Kernel cannot read.
There was a problem hiding this comment.
Could we add an upgrade → downgrade → upgrade sequence, checking historical targets from each period with and without maxCatalogVersion? This would verify that an earlier downgrade doesn’t incorrectly allow a missing limit after a subsequent upgrade.
There was a problem hiding this comment.
v0 — filesystem-managed
v1 — upgrade to catalog-managed
v2 — downgrade to filesystem-managed
v3 — upgrade to catalog-managed again ← latest
Expected reads:
v0/v2: filesystem-managed targets: succeeds without maxCatalogVersion
v1: catalog-managed target: fails without maxCatalogVersion
A file-system managed target version is fully published and below any catalog ratified version, so maxCatalogVersion cannot change what is read. Skipping it avoids loading the latest version, which failed when catalog commits above the target were not provided or the latest version had a reader feature Kernel does not support. A catalogManaged target without maxCatalogVersion still checks the latest version so that versions from before a downgrade can be read by path. That check uses a new ProtocolMetadataLogReplay.isCatalogManaged, which stops at the latest protocol and skips the readability check. Adds the requested tests for later downgrades, unpublished downgrades, partial catalog commits, and unreadable later versions. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Patrick Jin <patrick.jin@databricks.com>
rliao147
left a comment
There was a problem hiding this comment.
Many comments around test coverage. Could you also update the PR description? thanks!
|
|
||
| Version time travel across a catalog-managed upgrade or downgrade is now allowed. `atVersion` | ||
| queries no longer reject `maxCatalogVersion` for filesystem-managed versions, and require it for | ||
| catalog-managed versions only while the table is still catalog-managed. Latest and timestamp |
There was a problem hiding this comment.
Latest and timestamp queries are unchanged
Could we update this sentence?
"For timestamp-based time travel, provide maxCatalogVersion if the supplied latest snapshot is catalog-managed; omit it otherwise."
Also, the user guide should not have comments like X no longer does Y. That information should be in a changlog, and we should have the user guide reflect the current state of the codebase.
| val tablePath = tempDir.getCanonicalPath | ||
| // inCommitTimestamp of the catalog-owned-preview table's version 0 | ||
| val v0Timestamp = 1749830855993L | ||
| val parsedLogData = writeCommit( |
There was a problem hiding this comment.
Could we also test a downgrade with checkpoint protection? This helper only removes catalogManaged. Please add coverage preserving checkpointProtection, delta.requireCheckpointProtectionBeforeVersion, and protected checkpoints, then verify latest and pre-downgrade reads return the expected data and schema.
| } else if (!ctx.versionOpt.isPresent()) { | ||
| validateMaxCatalogVersionPresenceAgainst(targetProtocol); | ||
| } else if (TableFeatures.isCatalogManagedSupported(targetProtocol) | ||
| && !ctx.maxCatalogVersion.isPresent()) { |
There was a problem hiding this comment.
Could we add comments here? A published catalogManaged downgrade follows publication of earlier commits, allowing catalogManaged Delta Log history to be read without invoking the catalog.
|
|
||
| package io.delta.kernel.defaults.catalogManaged | ||
|
|
||
| import java.io.File |
There was a problem hiding this comment.
Could we add an upgrade → downgrade → upgrade sequence, checking historical targets from each period with and without maxCatalogVersion? This would verify that an earlier downgrade doesn’t incorrectly allow a missing limit after a subsequent upgrade.
|
|
||
| package io.delta.kernel.defaults.catalogManaged | ||
|
|
||
| import java.io.File |
There was a problem hiding this comment.
v0 — filesystem-managed
v1 — upgrade to catalog-managed
v2 — downgrade to filesystem-managed
v3 — upgrade to catalog-managed again ← latest
Expected reads:
v0/v2: filesystem-managed targets: succeeds without maxCatalogVersion
v1: catalog-managed target: fails without maxCatalogVersion
| } | ||
| } | ||
|
|
||
| test("time travel across unpublished catalogManaged downgrade") { |
There was a problem hiding this comment.
Can we extend this test?
v0 — catalog-managed, published
v1 — catalog-managed data write, published
v2 — downgrade, ratified but unpublished
We should also check:
- v2 is recognized as the latest, filesystem-managed snapshot.
- using that latest snapshot, a timestamp selecting v1 returns v1’s expected data without
maxCatalogVersion.
| } | ||
| } | ||
|
|
||
| test("time travel across catalogManaged upgrade") { |
There was a problem hiding this comment.
Could we also test reading commit ranges across an upgrade and downgrade? For example:
v0: filesystem-managed
v1: upgrade to catalog-managed
v2: catalog-managed data write
v3: downgrade to filesystem-managed
v4: filesystem-managed data write
- Before writing v3: supply v2’s ratified commit and maxCatalogVersion=2. Request v0–v2 and verify all three commits are returned.
- After writing v4: without catalog inputs, request v3 onward with no ending version. Verify v3 and v4 are returned.
- Request v0–v4 and verify every version is returned in order, once each.
Which Delta project/connector is this regarding?
Description
Previously, the
validateMaxCatalogVersionPresencecheck was too restrictive. If a table was upgraded from path-based to catalog-managed, then using Kernel to time travel to a version before the upgrade would fail because maxCatalogVersion would be present but catalogManaged is missing in that snapshot's Protocol. Similarly, if a table was downgraded from catalog-managed to path-based, then using Kernel to time travel to a version before the downgrade would fail because maxCatalogVersion would be missing but catalogManaged was present in that snapshot's Protocol.In principle, we need to relax those checks to validate maxCatalogVersion presence against the latest protocol, not the target snapshot protocol. In other words, enforce
maxCatalogVersionPresent == latestSnapshot.isCatalogManaged. However, for version-based time travel, this would require extra I/O to load the P&M for the latest version. To reduce unnecessary P&M loads, version-based time travel will only load the latest protocol if maxCatalogVersion presence disagrees with the target version's P&M. In other words:maxCatalogVersionPresent != targetSnapshot.isCatalogManagedThe resulting behavior for time travel queries is:
How was this patch tested?
Added unit tests and e2e tests for time travel across catalogManaged upgrade/downgrade versions
Does this PR introduce any user-facing changes?
No