laskoviymishka commented on code in PR #2109:
URL: https://github.com/apache/iceberg-go/pull/2109#discussion_r4207021451


##########
table/metadata.go:
##########
@@ -1555,7 +1560,10 @@ func (b *MetadataBuilder) buildCommonMetadata() 
(*commonMetadata, error) {
        }, nil
 }
 
-func (b *MetadataBuilder) updateSnapshotLog() error {
+// updatedSnapshotLog returns the snapshot log with intermediate and removed

Review Comment:
   The property this whole fix leans on is that the result is always a fresh 
slice that never aliases `b.snapshotLog`. I'd state that in the doc so nobody 
optimizes the fall-through `slices.Clone` away later. Worth noting too that 
pruning is re-derived from `b.updates` on every Build, so the output quietly 
depends on `b.updates` staying the full change history (a future 
reset-after-commit would silently change it).



##########
table/metadata.go:
##########
@@ -1509,10 +1509,15 @@ func (b *MetadataBuilder) buildCommonMetadata() 
(*commonMetadata, error) {
        }
        defaultSpecID := b.defaultSpecID
 
-       if err := b.updateSnapshotLog(); err != nil {
+       snapshotLog, err := b.updatedSnapshotLog()
+       if err != nil {
                return nil, fmt.Errorf("%w: %w", ErrInvalidMetadata, err)
        }
 
+       // If no change has set lastUpdatedMS yet, the first Build sets it and 
keeps it on
+       // the builder on purpose (Java's TableMetadata.Builder does the same), 
so repeated
+       // builds of the same changes report the same time. Adding a snapshot 
or moving

Review Comment:
   The last sentence claims more than the code does. Only `AddSnapshot` and 
`SetSnapshotRef` set `lastUpdatedMS`, so after a first Build a non-snapshot 
edit (`AddSchema`, `SetProperties`) followed by a second Build still reports 
the first build's time. I'd narrow it to say the timestamp is latched by the 
first Build unless a snapshot or ref change moves it, so nobody reads it as 
"any later mutation refreshes it."



##########
table/metadata_builder_internal_test.go:
##########
@@ -1060,6 +1060,45 @@ func TestSnapshotLogSkipsIntermediate(t *testing.T) {
                TimestampMs: snapshot2.TimestampMs,
        }, "expected snapshot to match added snapshot")
        require.True(t, res.CurrentSnapshot().Equals(snapshot2))
+
+       require.Len(t, builder.snapshotLog, 2, "Build must not prune the 
builder's own log")
+       again, err := builder.Build()
+       require.NoError(t, err)
+       require.Equal(t, res.(*metadataV2).SnapshotLog, 
again.(*metadataV2).SnapshotLog)
+}
+
+func TestSnapshotLogAfterMovingMainBackAfterBuild(t *testing.T) {
+       // add A, set main to A, add B, set main to B, build, set main back to 
A, build.
+       // B is intermediate in the first build, so it is skipped, and the 
second build

Review Comment:
   The comment says B is intermediate "in the first build," but there it's A 
that was current and then replaced by B, so A is the one collapsed in that 
build; B only becomes the skipped intermediate once main moves back to A for 
the second build. The `[1, 1]` assertion looks right; it's the explanation that 
names the wrong snapshot, and as written the next reader can't tell `[A, A]` is 
deliberate. While rewording, running the same sequence through 
`UpdateTableMetadata` and comparing logs would actually pin the parity the 
comment claims.



##########
view/metadata_builder_test.go:
##########
@@ -97,6 +97,84 @@ func TestBuild_NullAndMissingFields(t *testing.T) {
        assert.ErrorContains(t, err, "cannot set uuid to null")
 }
 
+func TestBuild_DoesNotGrowVersionLog(t *testing.T) {
+       b := newTestBuilder().
+               SetLoc("location").
+               AddSchema(newTestSchema(1)).
+               AddVersion(newTestVersion(1, LastAddedID)).
+               SetCurrentVersionID(LastAddedID)
+
+       for range 3 {
+               res, err := b.Build()
+               require.NoError(t, err)
+               require.Len(t, res.VersionLog(), 1)
+               require.Empty(t, b.versionLog, "Build must not append to the 
builder's own log")
+       }
+}
+
+func TestBuild_DoesNotGrowVersionLogWhenExpiringVersions(t *testing.T) {

Review Comment:
   The comment says `updateHistory` prunes the log on every Build, but with a 
fresh builder the log only ever holds the entry for version 3, the retained 
version, so it always takes the retained branch and the clear path never runs. 
It passes for the right reason (no growth), but it doesn't prove pruning on the 
clone; `TestBuild_FromBaseDoesNotGrowVersionLog` is the one that actually 
exercises the clear branch. I'd either fold this into the from-base case or 
rename it and fix the comment, and assert the exact first log (`Len` 1, 
`VersionID` 3) so it pins what it's really checking.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to