@@ -50,13 +50,60 @@ func reorderStorers(storers []types.Storer, expectedStorers []string) []types.St
5050 return newStorers
5151}
5252
53+ const (
54+ evictionLockKey = "eviction-lock"
55+ evictionLockTTL = 2 * time .Minute
56+ )
57+
58+ // evictionLockHolder is a unique identifier for this instance, used for distributed lock ownership.
59+ var evictionLockHolder = uuid .NewString ()
60+
61+ func tryAcquireEvictionLock (storer types.Storer ) bool {
62+ now := time .Now ()
63+ existing := storer .Get (evictionLockKey )
64+
65+ if len (existing ) > 0 {
66+ // Lock value format: "holder_id|expiry_timestamp"
67+ parts := strings .SplitN (string (existing ), "|" , 2 )
68+ if len (parts ) == 2 {
69+ holderID := parts [0 ]
70+ lockedUntil , err := time .Parse (time .RFC3339 , parts [1 ])
71+ if err == nil && now .Before (lockedUntil ) {
72+ // Lock is still valid - check if we own it
73+ if holderID == evictionLockHolder {
74+ return true
75+ }
76+ return false
77+ }
78+ }
79+ }
80+
81+ // Lock expired or doesn't exist - attempt to claim it using optimistic locking
82+ newLockExpiry := now .Add (evictionLockTTL )
83+ lockValue := evictionLockHolder + "|" + newLockExpiry .Format (time .RFC3339 )
84+ if err := storer .Set (evictionLockKey , []byte (lockValue ), evictionLockTTL ); err != nil {
85+ return false
86+ }
87+
88+ // Verify we actually got the lock (optimistic locking)
89+ // Another instance might have written between our check and set
90+ time .Sleep (10 * time .Millisecond )
91+ verifyValue := storer .Get (evictionLockKey )
92+ return string (verifyValue ) == lockValue
93+ }
94+
5395func registerMappingKeysEviction (logger core.Logger , storers []types.Storer ) {
5496 for _ , storer := range storers {
5597 logger .Debugf ("registering mapping eviction for storer %s" , storer .Name ())
5698 go func (current types.Storer ) {
5799 for {
58- logger .Debugf ("run mapping eviction for storer %s" , current .Name ())
100+ if ! tryAcquireEvictionLock (current ) {
101+ logger .Debugf ("skipping mapping eviction for storer %s, another instance holds the lock" , current .Name ())
102+ time .Sleep (time .Minute )
103+ continue
104+ }
59105
106+ logger .Debugf ("run mapping eviction for storer %s" , current .Name ())
60107 api .EvictMapping (current )
61108 }
62109 }(storer )
0 commit comments