From 09acfa0546297722e4a69968489afd6eee96c75c Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Thu, 28 Sep 2023 17:52:19 -0400 Subject: [PATCH] Add incarnation field --- store/multiversion/data_structures.go | 60 +++++++++++++--------- store/multiversion/data_structures_test.go | 36 ++++++++----- 2 files changed, 57 insertions(+), 39 deletions(-) diff --git a/store/multiversion/data_structures.go b/store/multiversion/data_structures.go index a382a6f0a..c4ca7b995 100644 --- a/store/multiversion/data_structures.go +++ b/store/multiversion/data_structures.go @@ -15,15 +15,16 @@ const ( type MultiVersionValue interface { GetLatest() (value MultiVersionValueItem, found bool) GetLatestBeforeIndex(index int) (value MultiVersionValueItem, found bool) - Set(index int, value []byte) - SetEstimate(index int) - Delete(index int) + Set(index int, incarnation int, value []byte) + SetEstimate(index int, incarnation int) + Delete(index int, incarnation int) } type MultiVersionValueItem interface { IsDeleted() bool IsEstimate() bool Value() []byte + Incarnation() int Index() int } @@ -63,7 +64,7 @@ func (item *multiVersionItem) GetLatestBeforeIndex(index int) (MultiVersionValue defer item.mtx.RUnlock() // we want to find the value at the index that is LESS than the current index - pivot := NewDeletedItem(index - 1) + pivot := &valueItem{index: index - 1} var vItem *valueItem var found bool @@ -77,35 +78,36 @@ func (item *multiVersionItem) GetLatestBeforeIndex(index int) (MultiVersionValue return vItem, found } -func (item *multiVersionItem) Set(index int, value []byte) { +func (item *multiVersionItem) Set(index int, incarnation int, value []byte) { types.AssertValidValue(value) item.mtx.Lock() defer item.mtx.Unlock() - valueItem := NewValueItem(index, value) + valueItem := NewValueItem(index, incarnation, value) item.valueTree.ReplaceOrInsert(valueItem) } -func (item *multiVersionItem) Delete(index int) { +func (item *multiVersionItem) Delete(index int, incarnation int) { item.mtx.Lock() defer item.mtx.Unlock() - deletedItem := NewDeletedItem(index) + deletedItem := NewDeletedItem(index, incarnation) item.valueTree.ReplaceOrInsert(deletedItem) } -func (item *multiVersionItem) SetEstimate(index int) { +func (item *multiVersionItem) SetEstimate(index int, incarnation int) { item.mtx.Lock() defer item.mtx.Unlock() - estimateItem := NewEstimateItem(index) + estimateItem := NewEstimateItem(index, incarnation) item.valueTree.ReplaceOrInsert(estimateItem) } type valueItem struct { - index int - value []byte - estimate bool + index int + incarnation int + value []byte + estimate bool } var _ MultiVersionValueItem = (*valueItem)(nil) @@ -115,6 +117,11 @@ func (v *valueItem) Index() int { return v.index } +// Incarnation implements MultiVersionValueItem. +func (v *valueItem) Incarnation() int { + return v.incarnation +} + // IsDeleted implements MultiVersionValueItem. func (v *valueItem) IsDeleted() bool { return v.value == nil && !v.estimate @@ -135,26 +142,29 @@ func (i *valueItem) Less(other btree.Item) bool { return i.index < other.(*valueItem).index } -func NewValueItem(index int, value []byte) *valueItem { +func NewValueItem(index int, incarnation int, value []byte) *valueItem { return &valueItem{ - index: index, - value: value, - estimate: false, + index: index, + incarnation: incarnation, + value: value, + estimate: false, } } -func NewEstimateItem(index int) *valueItem { +func NewEstimateItem(index int, incarnation int) *valueItem { return &valueItem{ - index: index, - value: nil, - estimate: true, + index: index, + incarnation: incarnation, + value: nil, + estimate: true, } } -func NewDeletedItem(index int) *valueItem { +func NewDeletedItem(index int, incarnation int) *valueItem { return &valueItem{ - index: index, - value: nil, - estimate: false, + index: index, + incarnation: incarnation, + value: nil, + estimate: false, } } diff --git a/store/multiversion/data_structures_test.go b/store/multiversion/data_structures_test.go index 92975462d..31696d366 100644 --- a/store/multiversion/data_structures_test.go +++ b/store/multiversion/data_structures_test.go @@ -16,20 +16,22 @@ func TestMultiversionItemGetLatest(t *testing.T) { // assert that we find a value after it's set one := []byte("one") - mvItem.Set(1, one) + mvItem.Set(1, 0, one) value, found = mvItem.GetLatest() require.True(t, found) require.Equal(t, one, value.Value()) // assert that we STILL get the "one" value since it is the latest zero := []byte("zero") - mvItem.Set(0, zero) + mvItem.Set(0, 0, zero) value, found = mvItem.GetLatest() require.True(t, found) require.Equal(t, one, value.Value()) + require.Equal(t, 1, value.Index()) + require.Equal(t, 0, value.Incarnation()) // we should see a deletion as the latest now, aka nil value and found == true - mvItem.Delete(2) + mvItem.Delete(2, 0) value, found = mvItem.GetLatest() require.True(t, found) require.True(t, value.IsDeleted()) @@ -37,10 +39,12 @@ func TestMultiversionItemGetLatest(t *testing.T) { // Overwrite the deleted value with some data two := []byte("two") - mvItem.Set(2, two) + mvItem.Set(2, 3, two) value, found = mvItem.GetLatest() require.True(t, found) require.Equal(t, two, value.Value()) + require.Equal(t, 2, value.Index()) + require.Equal(t, 3, value.Incarnation()) } func TestMultiversionItemGetByIndex(t *testing.T) { @@ -52,7 +56,7 @@ func TestMultiversionItemGetByIndex(t *testing.T) { // assert that we find a value after it's set one := []byte("one") - mvItem.Set(1, one) + mvItem.Set(1, 0, one) // should not be found because we specifically search "LESS THAN" value, found = mvItem.GetLatestBeforeIndex(1) require.False(t, found) @@ -69,7 +73,7 @@ func TestMultiversionItemGetByIndex(t *testing.T) { // assert that we STILL get the "one" value when querying with a later index zero := []byte("zero") - mvItem.Set(0, zero) + mvItem.Set(0, 0, zero) // verify that querying for zero should ALWAYS return nil value, found = mvItem.GetLatestBeforeIndex(0) require.False(t, found) @@ -84,7 +88,7 @@ func TestMultiversionItemGetByIndex(t *testing.T) { require.Equal(t, zero, value.Value()) // we should see a deletion as the latest now, aka nil value and found == true, but index 4 still returns `one` - mvItem.Delete(4) + mvItem.Delete(4, 0) value, found = mvItem.GetLatestBeforeIndex(4) require.True(t, found) require.Equal(t, one, value.Value()) @@ -100,7 +104,7 @@ func TestMultiversionItemGetByIndex(t *testing.T) { // Overwrite the deleted value with some data and verify we read it properly four := []byte("four") - mvItem.Set(4, four) + mvItem.Set(4, 0, four) // also reads the four value, found = mvItem.GetLatestBeforeIndex(6) require.True(t, found) @@ -120,7 +124,7 @@ func TestMultiversionItemEstimate(t *testing.T) { // assert that we find a value after it's set one := []byte("one") - mvItem.Set(1, one) + mvItem.Set(1, 0, one) // should not be found because we specifically search "LESS THAN" value, found = mvItem.GetLatestBeforeIndex(1) require.False(t, found) @@ -131,7 +135,7 @@ func TestMultiversionItemEstimate(t *testing.T) { require.False(t, value.IsEstimate()) require.Equal(t, one, value.Value()) // set as estimate - mvItem.SetEstimate(1) + mvItem.SetEstimate(1, 2) // should not be found because we specifically search "LESS THAN" value, found = mvItem.GetLatestBeforeIndex(1) require.False(t, found) @@ -140,6 +144,8 @@ func TestMultiversionItemEstimate(t *testing.T) { value, found = mvItem.GetLatestBeforeIndex(2) require.True(t, found) require.True(t, value.IsEstimate()) + require.Equal(t, 1, value.Index()) + require.Equal(t, 2, value.Incarnation()) // verify that querying for an earlier index returns nil value, found = mvItem.GetLatestBeforeIndex(0) @@ -148,7 +154,7 @@ func TestMultiversionItemEstimate(t *testing.T) { // assert that we STILL get the "one" value when querying with a later index zero := []byte("zero") - mvItem.Set(0, zero) + mvItem.Set(0, 0, zero) // verify that querying for zero should ALWAYS return nil value, found = mvItem.GetLatestBeforeIndex(0) require.False(t, found) @@ -162,9 +168,9 @@ func TestMultiversionItemEstimate(t *testing.T) { require.True(t, found) require.Equal(t, zero, value.Value()) // reset one to no longer be an estiamte - mvItem.Set(1, one) + mvItem.Set(1, 0, one) // we should see a deletion as the latest now, aka nil value and found == true, but index 4 still returns `one` - mvItem.Delete(4) + mvItem.Delete(4, 1) value, found = mvItem.GetLatestBeforeIndex(4) require.True(t, found) require.Equal(t, one, value.Value()) @@ -172,6 +178,8 @@ func TestMultiversionItemEstimate(t *testing.T) { value, found = mvItem.GetLatestBeforeIndex(5) require.True(t, found) require.True(t, value.IsDeleted()) + require.Equal(t, 4, value.Index()) + require.Equal(t, 1, value.Incarnation()) // verify that we still read the proper underlying item for an older index value, found = mvItem.GetLatestBeforeIndex(3) @@ -179,7 +187,7 @@ func TestMultiversionItemEstimate(t *testing.T) { require.Equal(t, one, value.Value()) // Overwrite the deleted value with an estimate and verify we read it properly - mvItem.SetEstimate(4) + mvItem.SetEstimate(4, 0) // also reads the four value, found = mvItem.GetLatestBeforeIndex(6) require.True(t, found)