fix: Move cluster.LiveLock.generation to first field fix 32bit alignment (#11028)

On 32-bit systems the generation fields becomes unaligned. Not an issue
on 64bit.

Discovered on 32bit raspbian, validated by manual patch (in addition to
test).
This commit is contained in:
Lorentz Kinde
2026-08-29 11:38:16 -07:00
committed by GitHub
parent 88c873ecd4
commit 83a929720a
2 changed files with 17 additions and 2 deletions
+2 -2
View File
@@ -117,6 +117,7 @@ func (lc *LockClient) PriorOwnerForKey(key string) pb.ServerAddress {
}
type LiveLock struct {
generation int64 // fencing token from the lock server; MUST stay first so the 64-bit atomic ops stay 8-byte aligned on 32-bit ARM
key string
renewToken string
expireAtNs int64
@@ -129,8 +130,7 @@ type LiveLock struct {
lc *LockClient
owner string
lockTTL time.Duration
consecutiveFailures int // Track connection failures to trigger fallback
generation int64 // fencing token from the lock server
consecutiveFailures int // Track connection failures to trigger fallback
}
// NewShortLivedLock creates a lock with a 5-second duration
+15
View File
@@ -2,6 +2,7 @@ package cluster
import (
"fmt"
"sync/atomic"
"testing"
"time"
@@ -150,3 +151,17 @@ func TestLockClientPriorOwnerForKeyExpires(t *testing.T) {
}
}
}
// LiveLock.generation is a fencing token written and read with 64-bit atomic
// operations. On 32-bit platforms (GOARCH=386 and GOARCH=arm) a 64-bit atomic
// op requires an 8-byte-aligned address, which Go only guarantees for the
// first field of an allocated struct. generation must therefore stay first:
// a misaligned field makes StoreInt64 panic with "unaligned 64-bit atomic
// operation" the moment this test runs on a 32-bit target.
func TestLiveLockGenerationIsAligned(t *testing.T) {
var lock LiveLock
atomic.StoreInt64(&lock.generation, 42)
if got := lock.Generation(); got != 42 {
t.Fatalf("generation = %d, want 42", got)
}
}