Skip to content
File

Blob: kv/memory/lease.go

go68 lines
1package memory
2 
3import (
4 "context"
5 "time"
6 
7 "go.miragespace.co/specter/spec/chord"
8)
9 
10var _ chord.LeaseKV = (*MemoryKV)(nil)
11 
12func durationGuard(t time.Duration) (time.Duration, bool) {
13 td := t.Truncate(time.Second)
14 if td < time.Second {
15 return 0, false
16 }
17 return td, true
18}
19 
20func (m *MemoryKV) Acquire(ctx context.Context, lease []byte, ttl time.Duration) (token uint64, err error) {
21 ttl, ok := durationGuard(ttl)
22 if !ok {
23 return 0, chord.ErrKVLeaseInvalidTTL
24 }
25 v, _ := m.fetchVal(lease)
26 curr := v.lease.Load()
27 ref := time.Now() // questionable
28 if curr > uint64(ref.UnixNano()) {
29 return 0, chord.ErrKVLeaseConflict
30 }
31 next := uint64(ref.Add(ttl).UnixNano())
32 if !v.lease.CompareAndSwap(curr, next) {
33 return 0, chord.ErrKVLeaseConflict
34 }
35 return next, nil
36}
37 
38func (m *MemoryKV) Renew(ctx context.Context, lease []byte, ttl time.Duration, prevToken uint64) (newToken uint64, err error) {
39 ttl, ok := durationGuard(ttl)
40 if !ok {
41 return 0, chord.ErrKVLeaseInvalidTTL
42 }
43 v, _ := m.fetchVal(lease)
44 curr := v.lease.Load()
45 if curr == 0 {
46 return 0, chord.ErrKVLeaseExpired
47 }
48 if time.Now().UnixNano() > int64(curr) {
49 return 0, chord.ErrKVLeaseExpired
50 }
51 if curr != prevToken {
52 return 0, chord.ErrKVLeaseExpired
53 }
54 next := uint64(time.Now().Add(ttl).UnixNano())
55 if !v.lease.CompareAndSwap(curr, next) {
56 return 0, chord.ErrKVLeaseExpired
57 }
58 return next, nil
59}
60 
61func (m *MemoryKV) Release(ctx context.Context, lease []byte, token uint64) error {
62 v, _ := m.fetchVal(lease)
63 if !v.lease.CompareAndSwap(token, 0) {
64 return chord.ErrKVLeaseExpired
65 }
66 return nil
67}