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

laskoviymishka 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 4202f9712 fix(table): keep generated snapshot IDs non-negative (#1619)
4202f9712 is described below

commit 4202f9712cb0a73c97a47c283c553c2c03ece48f
Author: Minh Vu <[email protected]>
AuthorDate: Tue Aug 4 12:18:34 2026 +0200

    fix(table): keep generated snapshot IDs non-negative (#1619)
    
    ## What changed
    
    Clear the sign bit before converting the UUID-derived snapshot ID to
    `int64`. The UUID folding logic is extracted into a small deterministic
    helper for regression coverage.
    
    ## Why
    
    Negating a negative value does not make `math.MinInt64` positive because
    signed negation overflows back to the same value. Clearing the sign bit
    guarantees that generated snapshot IDs are nonnegative for every input.
    
    ## Testing
    
    - Added deterministic coverage for an XOR result with only the sign bit
    set
    - Added coverage showing the remaining value bits are preserved
    - `go test ./table`
    
    ---------
    
    Signed-off-by: Minh Vu <[email protected]>
---
 table/metadata.go               | 18 +++++++-----------
 table/metadata_internal_test.go | 14 ++++++++++++++
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/table/metadata.go b/table/metadata.go
index 439f4be5b..d6152a7d2 100644
--- a/table/metadata.go
+++ b/table/metadata.go
@@ -45,22 +45,18 @@ const (
 )
 
 func generateSnapshotID() int64 {
-       var (
-               rndUUID = uuid.New()
-               out     [8]byte
-       )
+       return snapshotIDFromUUID(uuid.New())
+}
+
+func snapshotIDFromUUID(id uuid.UUID) int64 {
+       var out [8]byte
 
        for i := range 8 {
-               lhs, rhs := rndUUID[i], rndUUID[i+8]
+               lhs, rhs := id[i], id[i+8]
                out[i] = lhs ^ rhs
        }
 
-       snapshotID := int64(binary.LittleEndian.Uint64(out[:]))
-       if snapshotID < 0 {
-               snapshotID = -snapshotID
-       }
-
-       return snapshotID
+       return int64(binary.LittleEndian.Uint64(out[:]) & math.MaxInt64)
 }
 
 // Metadata for an iceberg table as specified in the Iceberg spec
diff --git a/table/metadata_internal_test.go b/table/metadata_internal_test.go
index 88534b669..69cc5d57a 100644
--- a/table/metadata_internal_test.go
+++ b/table/metadata_internal_test.go
@@ -22,6 +22,7 @@ import (
        "encoding/json"
        "io"
        "maps"
+       "math"
        "os"
        "path"
        "slices"
@@ -37,6 +38,19 @@ import (
        "github.com/stretchr/testify/require"
 )
 
+func TestSnapshotIDFromUUIDClearsSignBit(t *testing.T) {
+       for _, id := range []uuid.UUID{
+               {7: 0x80},
+               {15: 0x80},
+       } {
+               require.Zero(t, snapshotIDFromUUID(id))
+       }
+
+       require.Equal(t, int64(math.MaxInt64), snapshotIDFromUUID(uuid.UUID{
+               0: 0xff, 1: 0xff, 2: 0xff, 3: 0xff, 4: 0xff, 5: 0xff, 6: 0xff, 
7: 0xff,
+       }))
+}
+
 const ExampleTableMetadataV2 = `{
     "format-version": 2,
     "table-uuid": "9c12d441-03fe-4693-9a96-a0705ddf69c1",

Reply via email to