This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 1fbbae4c fix: read updated props when trimming metadata log (#639)
1fbbae4c is described below

commit 1fbbae4cf55d955863e059859e17e8230f503798
Author: Shubhendu <[email protected]>
AuthorDate: Tue Dec 9 23:06:56 2025 +0530

    fix: read updated props when trimming metadata log (#639)
    
    The metadata-log trimming logic was reading
    write.metadata.previous-versions-max from the base metadata instead of
    the updated properties being built. This caused the property to always
    use the default value (100) even when explicitly set to a different
    value during table updates.
    
    ## Motivation and Context
    Fixes metadata file retention - when clients set
    write.metadata.previous-versions-max=2, the metadata-log should contain
    only 2 previous entries, not all historical entries.
    
    ---------
    
    Signed-off-by: Shubhendu Ram Tripathi <[email protected]>
---
 table/metadata.go                       |  2 +-
 table/metadata_builder_internal_test.go | 79 +++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/table/metadata.go b/table/metadata.go
index 7dd803c8..d47d27ec 100644
--- a/table/metadata.go
+++ b/table/metadata.go
@@ -796,7 +796,7 @@ func (b *MetadataBuilder) buildCommonMetadata() 
(*commonMetadata, error) {
 
        if b.previousFileEntry != nil && b.HasChanges() {
                maxMetadataLogEntries := max(1,
-                       b.base.Properties().GetInt(
+                       b.props.GetInt(
                                MetadataPreviousVersionsMaxKey, 
MetadataPreviousVersionsMaxDefault))
                b.AppendMetadataLog(*b.previousFileEntry)
                b.TrimMetadataLogs(maxMetadataLogEntries)
diff --git a/table/metadata_builder_internal_test.go 
b/table/metadata_builder_internal_test.go
index 24e80e0e..28f62984 100644
--- a/table/metadata_builder_internal_test.go
+++ b/table/metadata_builder_internal_test.go
@@ -656,6 +656,85 @@ func TestExpireMetadataLog(t *testing.T) {
        require.Len(t, meta.(*metadataV2).MetadataLog, 2)
 }
 
+func TestMetadataLogTrimsWithUpdatedProperty(t *testing.T) {
+       // This test validates that when write.metadata.previous-versions-max is
+       // updated during a metadata build, the trimming logic uses the NEW 
value
+       // from b.props, not the old value from b.base.Properties()
+
+       // Create initial metadata with default retention (100)
+       builder1 := builderWithoutChanges(2)
+       meta1, err := builder1.Build()
+       require.NoError(t, err)
+       require.Empty(t, meta1.(*metadataV2).MetadataLog)
+
+       // Build metadata #2 - this should create first metadata log entry
+       builder2, err := MetadataBuilderFromBase(meta1, 
"s3://bucket/test/location/metadata/v2.json")
+       require.NoError(t, err)
+       err = builder2.SetProperties(map[string]string{
+               "test.prop": "value1",
+       })
+       require.NoError(t, err)
+       meta2, err := builder2.Build()
+       require.NoError(t, err)
+       require.Len(t, meta2.(*metadataV2).MetadataLog, 1)
+
+       // Build metadata #3 - this should have 2 entries
+       builder3, err := MetadataBuilderFromBase(meta2, 
"s3://bucket/test/location/metadata/v3.json")
+       require.NoError(t, err)
+       err = builder3.SetProperties(map[string]string{
+               "test.prop": "value2",
+       })
+       require.NoError(t, err)
+       meta3, err := builder3.Build()
+       require.NoError(t, err)
+       require.Len(t, meta3.(*metadataV2).MetadataLog, 2)
+
+       // Build metadata #4 - this should have 3 entries
+       builder4, err := MetadataBuilderFromBase(meta3, 
"s3://bucket/test/location/metadata/v4.json")
+       require.NoError(t, err)
+       err = builder4.SetProperties(map[string]string{
+               "test.prop": "value3",
+       })
+       require.NoError(t, err)
+       meta4, err := builder4.Build()
+       require.NoError(t, err)
+       require.Len(t, meta4.(*metadataV2).MetadataLog, 3)
+
+       // Build metadata #5 - NOW set write.metadata.previous-versions-max=2
+       // This is the key test: the trimming should happen immediately using 
the
+       // NEW value (2), not the old/default value (100)
+       builder5, err := MetadataBuilderFromBase(meta4, 
"s3://bucket/test/location/metadata/v5.json")
+       require.NoError(t, err)
+       err = builder5.SetProperties(map[string]string{
+               MetadataPreviousVersionsMaxKey: "2",
+               "test.prop":                    "value4",
+       })
+       require.NoError(t, err)
+       meta5, err := builder5.Build()
+       require.NoError(t, err)
+
+       // The bug was that it would keep all 4 entries because it read the 
property
+       // from base metadata (which didn't have it set). After the fix, it 
should
+       // correctly trim to 2 entries immediately.
+       require.Len(t, meta5.(*metadataV2).MetadataLog, 2,
+               "metadata log should be trimmed to 2 entries based on updated 
property value")
+
+       // Verify the property was actually set
+       require.Equal(t, "2", 
meta5.Properties()[MetadataPreviousVersionsMaxKey])
+
+       // Verify subsequent builds continue to respect the property
+       builder6, err := MetadataBuilderFromBase(meta5, 
"s3://bucket/test/location/metadata/v6.json")
+       require.NoError(t, err)
+       err = builder6.SetProperties(map[string]string{
+               "test.prop": "value5",
+       })
+       require.NoError(t, err)
+       meta6, err := builder6.Build()
+       require.NoError(t, err)
+       require.Len(t, meta6.(*metadataV2).MetadataLog, 2,
+               "subsequent builds should continue to respect the max versions 
limit")
+}
+
 func TestV2SequenceNumberCannotDecrease(t *testing.T) {
        builder := builderWithoutChanges(2)
        schemaID := 0

Reply via email to