iceberg.append only ever adds: its manifest list is the new manifest plus
the parent's, carried by reference. Everything else — delete, overwrite,
replace, compaction — has to rewrite the manifests that mention a file it is
removing, and that is what this module does.
prepare_commit(io, metadata, operation, files, extra)
files says what the snapshot adds (data files, delete files) and what it
removes (by path). The parent's manifest list is then walked once:
- a manifest that mentions none of the removed paths is carried by
reference — same path, same counts, same
sequence_number,
min_sequence_number and first_row_id. Nothing is rewritten that does not
have to be, which is what keeps a delete from touching the whole table;
- a manifest that mentions one is rewritten. Every live entry it keeps
becomes
EXISTING with its sequence_number, file_sequence_number,
snapshot_id and (v3) first_row_id written out explicitly — sequence
inheritance is ADDED-only, so an EXISTING entry that left them null would be
silently re-dated. Every live entry it drops becomes DELETED, with the
same numbers, so an expiry can still find the file. Entries that were
already DELETED in the parent belong to an older snapshot and are dropped;
- a rewritten manifest with nothing live left is dropped from the list
entirely rather than written as an empty file.
The rewritten manifest's list entry is credited to the new snapshot
(added_snapshot_id, sequence_number) while its min_sequence_number stays
whatever its oldest surviving file says — which is what makes the delete scope
rules keep working across a rewrite.
Totals. The total-* summary keys are carried forward from the parent
snapshot and adjusted by what this commit added and removed, because the
manifest list does not record file sizes and a scan of every manifest to
recompute them would defeat the point of carrying most of them by reference.
Row lineage (v3). Added data files get the table's next-row-id through
their manifest, exactly as an append does. A rewritten manifest keeps the
first_row_id it was assigned, and its entries carry theirs explicitly, so no
range moves and none overlap. Rows in a data file this commit rewrites
(copy-on-write) do get new ids — see the README's gaps table.