Repository navigation
Conversation
The latest_* columns were derived from the current snapshot log, which expiring snapshots trims, so older entries started returning null. Read them from the metadata file each entry points to, only when one of those columns is projected. If that file is gone, fall back to the previous lookup instead of failing the scan. Co-authored-by: yangshangqing95 <yangshangqing_tx@126.com>
|
PTAL @uros-b |
uros-b
left a comment
There was a problem hiding this comment.
The expire-snapshots fix is the right direction: latest_* from each entry's metadata file, last snapshot-log entry rather than currentSnapshot() (so REPLACE still works), and historical IO only when a latest_* field is projected.
Two things before merge:
-
Missing-file policy.
NotFoundExceptioncurrently falls back tosnapshotIdAsOfTimewith no log, so one result mixes file-derived and time-derived rows and a missing file looks like a real no-snapshot row. An up-to-date handle cannot hit this (CatalogUtil.deleteRemovedMetadataFilesonly deletes files already pruned from the log); a staleCachingCataloghandle can, after another writer committed withwrite.metadata.delete-after-commit.enabled. Fail-fast would break aSELECT *that works on main, so I would not go back to unguarded #17762. Prefer #16859:NotFoundException→ null +LOG.warn; keepRuntimeIOExceptionpropagating. If you want to keep the time-based value, log it and say so in the description. -
Tests.
snapshotColumnsNotProjectedcannot fail: deleting the files only takes theNotFoundExceptionpath, andtimestamp/filedo not use it. Spy theFileIOandverify(io, never()).newInputFile(previous.file()), like #16859doesNotLoadPropertiesWhenNotProjected(overwriting with invalid JSON also works). OnsnapshotDetailsAfterExpiration,after.subList(0, before.size()).isEqualTo(before)already pins the expired row from values captured before expire; replaceafter.get(1)assertingfirstwithsecond's id / schema id / sequence number on the row written while it was current.
Not asking here: Tasks.foreach / planExecutor() prefetch. That's a follow-up and should be shared with #16859 so SELECT * does not parse every retained file twice. Do not skip file reads for rows at or after the oldest retained snapshot-log timestamp — that recreates #17761 when a middle snapshot is expired.
|
Thanks @uros-b, both points make sense.
I'll leave the prefetch for a follow-up shared with #16859, and I won't skip reads at or after the oldest retained snapshot-log timestamp, since that would bring back #17761. |
…iles Falling back to the time-based lookup when an entry's metadata file is gone mixed file-derived and time-derived rows in one result, and a missing file looked like a real entry without a snapshot. Return null and log a warning instead. Tighten the tests: verify historical metadata files are never opened when no latest_* column is projected, and assert the expired snapshot's details on the row written while it was current.
|
done with it 792b300, now let's wait for the CI to be green and ig will be ready to merge |
The
latest_*columns were derived from the current snapshot log, which expiring snapshots trims, so older entries started returning null. Read them from the metadata file each entry points to, only when one of those columns is projected. If that file is gone, thelatest_*columns are null and a warning is logged.Fixes #17761