1
0
forked from extern/smegmesh
smegmesh/pkg/crdt/vector_clock.go
Tim Beatham 64885f1055 45-use-statistical-testing
Using statistical testing to test whether the node has failed.
2023-12-07 01:44:54 +00:00

81 lines
1.5 KiB
Go

package crdt
import (
"sync"
"github.com/tim-beatham/wgmesh/pkg/lib"
)
// Vector clock defines an abstract data type
// for a vector clock implementation
type VectorClock[K comparable] struct {
vectors map[K]uint64
lock sync.RWMutex
processID K
}
// IncrementClock: increments the node's value in the vector clock
func (m *VectorClock[K]) IncrementClock() uint64 {
maxClock := uint64(0)
m.lock.Lock()
for _, value := range m.vectors {
maxClock = max(maxClock, value)
}
m.vectors[m.processID] = maxClock + 1
m.lock.Unlock()
return maxClock
}
// GetHash: gets the hash of the vector clock used to determine if there
// are any changes
func (m *VectorClock[K]) GetHash() uint64 {
m.lock.RLock()
sum := lib.Reduce(uint64(0), lib.MapValues(m.vectors), func(sum uint64, current uint64) uint64 {
return current + sum
})
m.lock.RUnlock()
return sum
}
func (m *VectorClock[K]) Prune() {
outliers := lib.GetOutliers(m.vectors, 0.05)
m.lock.Lock()
for _, outlier := range outliers {
delete(m.vectors, outlier)
}
m.lock.Unlock()
}
func (m *VectorClock[K]) Put(key K, value uint64) {
m.lock.Lock()
m.vectors[key] = max(value, m.vectors[key])
m.lock.Unlock()
}
func (m *VectorClock[K]) GetClock() map[K]uint64 {
clock := make(map[K]uint64)
m.lock.RLock()
for key, value := range clock {
clock[key] = value
}
m.lock.RUnlock()
return clock
}
func NewVectorClock[K comparable](processID K) *VectorClock[K] {
return &VectorClock[K]{
vectors: make(map[K]uint64),
processID: processID,
}
}