Skip to content
File

Blob: chord/node_state.go

go63 lines
1package chord
2 
3import (
4 "runtime"
5 "sync/atomic"
6 
7 "go.miragespace.co/specter/spec/chord"
8 
9 "github.com/zhangyunhao116/skipmap"
10)
11 
12type nodeState struct {
13 state atomic.Uint64
14 history *skipmap.Uint64Map[chord.State]
15}
16 
17func newNodeState(initial chord.State) *nodeState {
18 s := &nodeState{
19 state: atomic.Uint64{},
20 history: skipmap.NewUint64[chord.State](),
21 }
22 var index uint64 = 0
23 var state uint64 = (uint64)(initial)
24 s.state.Store((index << 4) | state)
25 s.history.Store(0, initial)
26 return s
27}
28 
29func (s *nodeState) Transition(exp chord.State, nxt chord.State) (chord.State, bool) {
30 curr := s.state.Load()
31 currIndex := curr >> 4
32 prev := (currIndex << 4) | (uint64)(exp)
33 nextIndex := currIndex + 1
34 next := (nextIndex << 4) | (uint64)(nxt)
35 if s.state.CompareAndSwap(prev, next) {
36 s.history.Store(nextIndex, nxt)
37 return nxt, true
38 }
39 return chord.State(curr & 0b1111), false
40}
41 
42func (s *nodeState) Set(val chord.State) {
43 for {
44 if _, ok := s.Transition(s.Get(), val); ok {
45 break
46 }
47 runtime.Gosched()
48 }
49}
50 
51func (s *nodeState) Get() chord.State {
52 return chord.State(s.state.Load() & 0b1111)
53}
54 
55func (s *nodeState) History() []chord.State {
56 h := make([]chord.State, 0)
57 s.history.Range(func(_ uint64, state chord.State) bool {
58 h = append(h, state)
59 return true
60 })
61 return h
62}