feat: Incremental append scan - #2337
Conversation
e88d444 to
11cce80
Compare
| /// Filter applied to each [`ManifestFile`] before fetching it. | ||
| /// Returns `true` to include the manifest, `false` to skip it. | ||
| pub(crate) type ManifestFileFilter = Arc<dyn Fn(&ManifestFile) -> bool + Send + Sync>; | ||
|
|
||
| /// Filter applied to each manifest entry after loading a manifest. | ||
| /// Returns `true` to include the entry, `false` to skip it. | ||
| pub(crate) type ManifestEntryFilter = Arc<dyn Fn(&ManifestEntryRef) -> bool + Send + Sync>; | ||
|
|
There was a problem hiding this comment.
I think this is a nice way to inject these filters and should extend to other future scans
| pub manifest_entry_filter: Option<ManifestEntryFilter>, | ||
| } | ||
|
|
||
| impl std::fmt::Debug for PlanContext { |
There was a problem hiding this comment.
ManifestFileFilter and ManifestEntryFilter can't be debug
| pub(crate) struct AppendSnapshotSet { | ||
| /// Snapshot IDs in the range | ||
| snapshot_ids: HashSet<i64>, | ||
| } |
There was a problem hiding this comment.
There was a problem hiding this comment.
ancestors_between is used here. We need to add validation and operation-type checking on top of it, we're not re-implementing the traversal. Does that make sense?
| /// | ||
| /// Use [`Table::incremental_append_scan`] or | ||
| /// [`Table::incremental_append_scan_inclusive`] to create an instance. | ||
| pub struct IncrementalAppendScanBuilder<'a> { |
There was a problem hiding this comment.
There is duplication here between the scan builders which I've left for now until maybe we have a 3rd variant and we can pick out the common patterns a bit better.
|
@CTTY would you be open to giving a review here? |
3a4f875 to
489084d
Compare
Resolve conflicts in scan/context.rs and scan/mod.rs by combining the incremental-scan work (entry_filter, build_table_scan/ScanConfig refactor) with main's name_mapping support and metadata-column validation. Adapt incremental-scan test fixtures to the updated ManifestWriterBuilder::new and ManifestListWriter::v2 signatures from the encryption changes.
…er tests Arc<dyn ExecutionPlan> supports downcast_ref directly; the extra as_any() call resolved to the unrelated as-any crate trait (not in scope), which broke compilation and cascaded into spurious deref errors on the matched i64 fields. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the Java and PyIceberg implementations: an incremental append scan now projects onto the table's current schema rather than the to-snapshot's schema. Rows written under an older schema within the range are read against the current schema, so newer columns become NULL. Adds a schema_override to ScanConfig (None for regular scans, which keeps the correct per-snapshot schema for time-travel; current schema for incremental scans) and a stale-schema deep-history fixture plus a test asserting the projected schema is the current one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Incorporate the substantive reviewer feedback from the py-iceberg incremental append scan PR (apache/iceberg-python#3512): - Document that this is not a CDC/net-changes/changelog scan and that compaction (replace) output is skipped, so appended rows are never double-counted (kevinjqliu). - Document the ancestors_between footgun: a from-snapshot that is not in the lineage silently yields all ancestors of the to-snapshot, so callers must validate the lineage (kevinjqliu). - Add an explicit compaction (replace) end-to-end test proving the rewritten file is not picked up (rambleraptor). Deep-history fixture variants now share one helper and mutate the parsed serde_json::Value structurally by field, instead of fragile raw string substitution on the shared testdata file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the serde_json::Value mutation with dedicated templated metadata files for the stale-schema and compaction deep-history fixtures, matching the repo's existing testdata pattern. The three fixtures now share a filename-parameterized helper that renders the manifest-list paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
This follows the implementation in java and the more recent py-iceberg apache/iceberg-python#3512 |
Which issue does this PR close?
What changes are included in this PR?
Adds incremental append scan support to iceberg-rust, allowing users to read only newly added data files between two snapshots. This is the Rust equivalent of Java's
BaseIncrementalAppendScan.Are these changes tested?
Yes
Java comparison notes:
AppendSnapshotSet::buildmirrors Java'sBaseIncrementalAppendScan.snapshotsBetween()— only APPEND snapshots are collected, non-APPEND are silently skippedfrom_snapshotsemantics match Java's defaultIncrementalAppendScanbehavioradded_snapshot_id) and entry filtering (status == ADDED,snapshot_idin range) matchBaseIncrementalAppendScan.doPlanFiles()in Java