Added more vector clock functionality

drew/mqtt-clients
Drew Bednar 4 months ago
parent e04ca2f136
commit e05c1fd788

@ -1,8 +1,20 @@
package clock
import (
"errors"
)
func max(x, y uint) uint {
if x >= y {
return x
} else {
return y
}
}
// VectorClock type is used for determining the partial ordering of events in a distributed system.
type VectorClock struct {
clock []int
clock []uint
}
// GetClock returns a copy of the internal vector clock.
@ -16,12 +28,26 @@ type VectorClock struct {
//
// []int: A copy of the internal vector clock slice, where each element
// represents the logical time for a corresponding process.
func (vc *VectorClock) GetClock() []int {
clock := make([]int, len(vc.clock))
func (vc *VectorClock) GetClock() []uint {
clock := make([]uint, len(vc.clock))
copy(clock, vc.clock)
return clock
}
func (vc *VectorClock) Sync(v VectorClock) ([]uint, error) {
compClock := v.GetClock()
if len(vc.clock) != len(compClock) {
return nil, errors.New("VectorClocks are of different lengths.")
}
for i := range vc.clock {
vc.clock[i] = max(vc.clock[i], compClock[i])
}
return vc.GetClock(), nil
}
// NewVectorClock creates a new VectorClock initialized to zero.
//
// Parameters:
@ -33,9 +59,9 @@ func (vc *VectorClock) GetClock() []int {
//
// *VectorClock: A pointer to the newly created VectorClock instance, with all
// elements of the clock initialized to zero.
func NewVectorClock(size int) *VectorClock {
func NewVectorClock(size uint) *VectorClock {
return &VectorClock{
clock: make([]int, size),
clock: make([]uint, size),
}
}
@ -47,15 +73,15 @@ func NewVectorClock(size int) *VectorClock {
//
// Parameters:
//
// a []int: An array of integers representing logical times for each process.
// a []uint: An array of integers representing logical times for each process.
//
// Returns:
//
// *VectorClock: A pointer to a newly created VectorClock instance where the
// internal clock is a copy of the provided array.
func ArrayToVectorClock(a []int) *VectorClock {
func ArrayToVectorClock(a []uint) *VectorClock {
vc := &VectorClock{
clock: make([]int, len(a)),
clock: make([]uint, len(a)),
}
copy(vc.clock, a)
return vc

@ -5,7 +5,7 @@ import (
"testing"
)
func assertClocksEqual(t testing.TB, got, want []int) {
func assertClocksEqual(t testing.TB, got, want []uint) {
t.Helper()
if !reflect.DeepEqual(got, want) {
@ -15,8 +15,69 @@ func assertClocksEqual(t testing.TB, got, want []int) {
}
func TestVectorClock(t *testing.T) {
t.Run("start value sync", func(t *testing.T) {
testCases := []struct {
a []uint
b []uint
expected []uint
}{
{[]uint{0, 0}, []uint{0, 0}, []uint{0, 0}},
{[]uint{2, 0}, []uint{0, 2}, []uint{2, 2}},
{[]uint{4, 11}, []uint{3, 10}, []uint{4, 11}},
{[]uint{5, 9}, []uint{8, 12}, []uint{8, 12}},
{[]uint{1, 1}, []uint{1, 1}, []uint{1, 1}},
// {[]uint{math.MaxUint32, 1}, []uint{(math.MaxUint32 + 1), 1}, []uint{1, 1}},
}
for _, tc := range testCases {
vc := VectorClock{clock: tc.a}
clock, err := vc.Sync(VectorClock{clock: tc.b})
if err != nil {
t.Errorf("Sync should not have errored")
}
assertClocksEqual(t, clock, tc.expected)
}
})
t.Run("basic sync 2", func(t *testing.T) {
vc := VectorClock{clock: []uint{4, 11}}
clock, err := vc.Sync(VectorClock{clock: []uint{4, 10}})
if err != nil {
t.Errorf("Sync should not have errored")
}
assertClocksEqual(t, clock, []uint{4, 11})
})
t.Run("basic sync", func(t *testing.T) {
})
t.Run("basic sync", func(t *testing.T) {
})
vc := VectorClock{clock: []uint{2, 0}}
clock, err := vc.Sync(VectorClock{clock: []uint{0, 2}})
if err != nil {
t.Errorf("Sync should not have errored")
}
assertClocksEqual(t, clock, []uint{2, 2})
}
func TestNewVectorClock(t *testing.T) {
got := NewVectorClock(2)
want := VectorClock{clock: []int{0, 0}}
want := VectorClock{clock: []uint{0, 0}}
assertClocksEqual(t, got.GetClock(), want.GetClock())
@ -25,9 +86,9 @@ func TestVectorClock(t *testing.T) {
func TestArrayToVectorClock(t *testing.T) {
t.Run("from empty slice", func(t *testing.T) {
got := ArrayToVectorClock([]int{})
got := ArrayToVectorClock([]uint{})
want := VectorClock{
clock: []int{},
clock: []uint{},
}
if len(got.GetClock()) != 0 {
@ -40,9 +101,9 @@ func TestArrayToVectorClock(t *testing.T) {
})
t.Run("from zero slice", func(t *testing.T) {
got := ArrayToVectorClock(make([]int, 6))
got := ArrayToVectorClock(make([]uint, 6))
want := VectorClock{
clock: []int{0, 0, 0, 0, 0, 0},
clock: []uint{0, 0, 0, 0, 0, 0},
}
assertClocksEqual(t, got.GetClock(), want.GetClock())
@ -57,17 +118,17 @@ func TestArrayToVectorClock(t *testing.T) {
t.Run("from a populated clock", func(t *testing.T) {
want := VectorClock{
clock: []int{2, 3},
clock: []uint{2, 3},
}
got := ArrayToVectorClock(want.GetClock())
assertClocksEqual(t, got.GetClock(), want.GetClock())
})
t.Run("from a slice that is then modified", func(t *testing.T) {
initial_a := []int{1, 2, 3, 4}
initial_a := []uint{1, 2, 3, 4}
got := ArrayToVectorClock(initial_a)
want := make([]int, len(initial_a))
want := make([]uint, len(initial_a))
copy(want, initial_a)
initial_a[0] = 12

Loading…
Cancel
Save