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",