feat: Honor write.metadata.path for metadata file locations#2776
feat: Honor write.metadata.path for metadata file locations#2776zakariya-s wants to merge 5 commits into
Conversation
Metadata files (manifest lists, manifests, and the table metadata JSON) were always written under `<table-location>/metadata`, ignoring the `write.metadata.path` table property. iceberg-java honors it via `metadataFileLocation`; this brings iceberg-rust in line, mirroring how `write.data.path` is already honored for data files. Add `TableMetadata::metadata_location_root()`, returning `write.metadata.path` (trailing slash trimmed) when set, otherwise `<location>/metadata`. Use it in `SnapshotProducer` for the manifest and manifest-list paths, and in `MetadataLocation` for the metadata JSON. `MetadataLocation` now stores the resolved metadata directory rather than the table location. On commit the directory is re-derived from the metadata being committed (the version is still parsed from the previous file name), matching iceberg-java. As a result `MetadataLocation::from_str` no longer requires the file to live under a `/metadata` directory; file-name validation is unchanged.
|
Thank you for the review @andybradshaw! I think I've addressed them so far, please do let me know if there are any other flags you can see |
andybradshaw
left a comment
There was a problem hiding this comment.
Seems fine to me, but will need to get another review/approval from a maintainer.
xanderbailey
left a comment
There was a problem hiding this comment.
Thanks for the PR, just one comment I think
|
Thanks @xanderbailey! I think I've addressed the comment. I did notice though that Might create an issue for this later if you think it's worth it |
|
It's a new(ish) struct in the repo so we haven't moved everything there yet but I think typically having it strongly typed is preferable. |
CTTY
left a comment
There was a problem hiding this comment.
Thanks for the contribution! Just took a quick look, the logic looks correct but feels like we are overcomplicating this a bit: The core logic is "use write.metadata.path if set, else {table_location}/metadata", which fits in a single function metadata_location() in table_metadata.rs
- collapse the three metadata-dir helpers into a single TableMetadata::metadata_location(), mirroring the encryption-key-id style of an optional strongly-typed property - parse write.metadata.path inline in TableProperties (typed field), dropping PROPERTY_WRITE_METADATA_PATH_DEFAULT_DIR - MetadataLocation::new_with_metadata defaults under the passed table location; drop the redundant new_with_table_location constructor
|
Thanks for the review @CTTY! I've gone over the comments, would really appreciate another review when you have time! |
CTTY
left a comment
There was a problem hiding this comment.
Just took another pass and it looks much better! I have left some questions
| pub fn with_new_metadata(&self, new_metadata: &TableMetadata) -> Self { | ||
| Self { | ||
| table_location: self.table_location.clone(), | ||
| location: self.location.clone(), |
There was a problem hiding this comment.
Should we honor the metadata path here as well? What's the expected behavior when new_metadata has a new metadata path?
I haven't checked how it's like in java tho
| let table_location = table_location.to_string(); | ||
| let location = metadata | ||
| .table_properties() | ||
| .ok() |
There was a problem hiding this comment.
We should throw error here, let's change the current method to try_new_with_metadata if needed
There was a problem hiding this comment.
we can also reuse the table_metadata::metadata_location() after refactoring
Which issue does this PR close?
write.metadata.pathtable property for metadata file locations #2775.What changes are included in this PR?
Metadata files were always written under
<table-location>/metadata, ignoring thewrite.metadata.pathtable property. Iceberg Java honors it (viaBaseMetastoreTableOperations.metadataFileLocation); this brings iceberg-rust in line and mirrors the existingwrite.data.pathhandling for data files.TableMetadata::metadata_location_root(), returningwrite.metadata.path(trailing slash trimmed) when set, otherwise<location>/metadata.SnapshotProducerfor the manifest and manifest-list paths, and inMetadataLocationfor the table metadata JSON.MetadataLocationnow stores the resolved metadata directory rather than the table location. On commit, the directory is re-derived from the metadata being committed (the version is still parsed from the previous file name), matching Iceberg Java. As a resultMetadataLocation::from_strno longer requires the file to live under a/metadatadirectory (a customwrite.metadata.pathdoes not have to); file-name validation is unchanged.Are these changes tested?
Unit tests:
TableMetadata::metadata_location_root(): default, configuredwrite.metadata.path, and trailing-slash trimming.MetadataLocation: create (new_with_metadata) and commit (with_new_metadata) honorwrite.metadata.path;from_strround-trip cases updated for arbitrary metadata dirs.fast_appendtransaction test asserting the manifest list and manifests are written under a configuredwrite.metadata.path.catalog::tests::test_table_committo reflect the new metadata file following the updated table location.