Repository navigation
feat(transaction): record the Iceberg-Rust writer version information in snapshot summaries - #3363
Conversation
A commit from iceberg-rust was indistinguishable from any other client that omits writer identity. Stamp engine-name, engine-version, and iceberg-version on every snapshot so mixed-writer tables can attribute the commit. Generated-by: Cursor Grok 4.7
Generated-by: Cursor Grok 4.7
iceberg-version still identifies this library. engine-name and engine-version are filled only when the caller did not set them, so an embedding engine can record itself through snapshot properties. Generated-by: Cursor Grok 4.7
A data file and an unrelated property do not affect those keys. Also list the new summary constants alphabetically. Generated-by: Cursor Grok 4.7
| let tx = Transaction::new(&table); | ||
|
|
||
| let mut snapshot_properties = HashMap::new(); | ||
| snapshot_properties.insert("key".to_string(), "val".to_string()); |
There was a problem hiding this comment.
Exists to force a commit
| const ICEBERG_VERSION_PROP: &str = "iceberg-version"; | ||
|
|
||
| fn apply_writer_identity(properties: &mut HashMap<String, String>) { | ||
| let version = env!("CARGO_PKG_VERSION"); |
There was a problem hiding this comment.
I don't know the convention here, but the LLMs tell me that this could be a crate level constant but recommended not doing that if we are only using it here.
There was a problem hiding this comment.
This is correct, when release a new version we will bump versions for all crates and they should be consistent: https://github.com/apache/iceberg-rust/blob/main/Cargo.toml#L91-L98
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The focused implementation and tests match the requested metadata precedence, with no blocking issues identified.
Review effort: Balanced
Findings: None
What changed in this PR
Adds writer identity to snapshot summaries so clients can identify snapshots created by iceberg-rust.
Changes:
- Defaults engine identity while preserving caller overrides; always records the library version.
- Adds tests for default identity and override precedence.
| File | Description |
|---|---|
| crates/iceberg/src/transaction/snapshot.rs | Applies writer identity after summary aggregation. |
| crates/iceberg/src/transaction/append.rs | Tests default metadata and caller override handling. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const ICEBERG_VERSION_PROP: &str = "iceberg-version"; | ||
|
|
||
| fn apply_writer_identity(properties: &mut HashMap<String, String>) { | ||
| let version = env!("CARGO_PKG_VERSION"); |
There was a problem hiding this comment.
This is correct, when release a new version we will bump versions for all crates and they should be consistent: https://github.com/apache/iceberg-rust/blob/main/Cargo.toml#L91-L98
engine-name and engine-version name the embedding engine, which this library does not know. Callers can still set them. iceberg-version remains the library identity, matching Java and Go. Generated-by: Cursor Grok 4.7
Those keys are ordinary snapshot properties now, so preserving a caller value is already covered by the existing property test. Generated-by: Cursor Grok 4.7
The snapshot summary no longer writes those keys, so the test only checks iceberg-version. Generated-by: Cursor Grok 4.7
mbutrovich
left a comment
There was a problem hiding this comment.
Thanks @RussellSpitzer, just minor stuff at this point from me.
| use crate::transaction::ActionCommit; | ||
| use crate::{Error, ErrorKind, TableRequirement, TableUpdate}; | ||
|
|
||
| const ICEBERG_VERSION_PROP: &str = "iceberg-version"; |
There was a problem hiding this comment.
Should ICEBERG_VERSION_PROP live in spec/snapshot_summary.rs with the other summary keys (snapshot_summary.rs#L27-L50)? That module defines every other key the library writes into additional_properties.
Co-authored-by: Matt Butrovich <mbutrovich@users.noreply.github.com>
The transaction path still writes the value. The property name now lives with the rest of the summary keys the library defines. Generated-by: Cursor Grok 4.7
The key stays private next to the other summary keys, and the commit path calls set_iceberg_version after the totals are computed. Generated-by: Cursor Grok 4.7
mbutrovich
left a comment
There was a problem hiding this comment.
Thanks @RussellSpitzer!
anoopj
left a comment
There was a problem hiding this comment.
LGTM. Left a couple of comments.
laskoviymishka
left a comment
There was a problem hiding this comment.
lgtm — nice that set_iceberg_version sits in SnapshotProducer::summary(), so every producer-based action picks it up for free. And overwriting a caller-supplied iceberg-version is the right call: Java (SnapshotProducer.summary applies EnvironmentContext.get() last) and Go (rebaseSummary) both apply environment context after user properties, so the library value wins.
A few notes, none blocking:
- The PR description says a value supplied through
set_snapshot_propertiesis kept, but the code (and the new test) overwrite it. The code's doing the right thing here — it's the description that's backwards, so I'd just fix the body, and maybe add a///on the helper noting it always overwrites. - The version string puts
Rustwhere Java/Go put the version number, which breaks anApache Iceberg <ver>prefix match across clients — left an inline with a suggestion. - One stray blank-line drop in the imports — minor, flagged inline.
mbutrovich
left a comment
There was a problem hiding this comment.
LGTM!
Could you restore the deleted blank like mentioned above? Would love to keep the format clean before merging
If a committer applies a suggestion that's one way to resolve it without the author. I think this would work.
Resolve the snapshot.rs conflict with the truncate_full_table() change, and commit the iceberg-version test through commit_with_fresh_state since TransactionAction is stateful after apache#3265. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
kevinjqliu
left a comment
There was a problem hiding this comment.
LGTM
i tested this locally by writing and it works!
{
"operation": "append",
"iceberg-version": "Apache Iceberg Rust 0.10.1",
"added-data-files": "1",
"added-records": "3",
"added-files-size": "890",
"total-data-files": "1",
"total-records": "3",
"total-files-size": "890",
"total-delete-files": "0",
"total-position-deletes": "0",
"total-equality-deletes": "0"
}
|
thanks for the reviews, everyone! |
… in snapshot summaries (apache#3363) * feat(transaction): record the Rust writer in snapshot summaries A commit from iceberg-rust was indistinguishable from any other client that omits writer identity. Stamp engine-name, engine-version, and iceberg-version on every snapshot so mixed-writer tables can attribute the commit. Generated-by: Cursor Grok 4.7 * Remove the writer-identity comments. Generated-by: Cursor Grok 4.7 * Keep a caller-supplied engine name and version. iceberg-version still identifies this library. engine-name and engine-version are filled only when the caller did not set them, so an embedding engine can record itself through snapshot properties. Generated-by: Cursor Grok 4.7 * Keep the writer-identity tests on snapshot properties. A data file and an unrelated property do not affect those keys. Also list the new summary constants alphabetically. Generated-by: Cursor Grok 4.7 * Write only iceberg-version into snapshot summaries. engine-name and engine-version name the embedding engine, which this library does not know. Callers can still set them. iceberg-version remains the library identity, matching Java and Go. Generated-by: Cursor Grok 4.7 * Drop the caller engine-identity snapshot test. Those keys are ordinary snapshot properties now, so preserving a caller value is already covered by the existing property test. Generated-by: Cursor Grok 4.7 * Stop asserting that engine identity keys are absent. The snapshot summary no longer writes those keys, so the test only checks iceberg-version. Generated-by: Cursor Grok 4.7 * Update crates/iceberg/src/transaction/append.rs Co-authored-by: Matt Butrovich <mbutrovich@users.noreply.github.com> * Move the iceberg-version summary key next to the other keys. The transaction path still writes the value. The property name now lives with the rest of the summary keys the library defines. Generated-by: Cursor Grok 4.7 * Set iceberg-version from the snapshot summary module. The key stays private next to the other summary keys, and the commit path calls set_iceberg_version after the totals are computed. Generated-by: Cursor Grok 4.7 * Restore the blank line before the SnapshotProduceOperation docs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Matt Butrovich <mbutrovich@users.noreply.github.com> Co-authored-by: Kevin Liu <kevin.jq.liu@gmail.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Which issue does this PR close?
Closes #3365
What changes are included in this PR?
Snapshots committed by iceberg-rust now record the library that wrote them:
iceberg-version=Apache Iceberg Rust <crate version>, alwaysengine-nameandengine-versionare left to the caller. Those name the embedding engine, which this library does not know. A value supplied throughset_snapshot_propertiesis kept. This matches Java and Go, whose default environment context contains onlyiceberg-version. PyIceberg also writesengine-nameandengine-version(apache/iceberg-python#3441).Other caller properties are unchanged. Existing snapshots are left alone.
Are these changes tested?
Yes. A unit test on
FastAppendActionchecks that a plain append recordsiceberg-version.cargo test -p iceberg --lib writer_identityandcargo clippy -p iceberg --lib --tests -- -D warningspass.AI Disclosure
Grok 4.7 in Cursor wrote the implementation, tests, and this description. The change has not been reviewed by a human yet.