From 346391d683a59b7cd4eaf7f1ef1a545b23064076 Mon Sep 17 00:00:00 2001 From: johnnyaug Date: Thu, 28 Apr 2022 05:07:24 -0400 Subject: [PATCH] fix bug in merge (#3270) --- pkg/graveler/committed/manager.go | 2 +- pkg/graveler/committed/merge_test.go | 570 ++++++++++++++++----------- 2 files changed, 331 insertions(+), 241 deletions(-) diff --git a/pkg/graveler/committed/manager.go b/pkg/graveler/committed/manager.go index b6528b1a226..218d297bb73 100644 --- a/pkg/graveler/committed/manager.go +++ b/pkg/graveler/committed/manager.go @@ -182,7 +182,7 @@ func (c *committedManager) Diff(ctx context.Context, ns graveler.StorageNamespac func (c *committedManager) Merge(ctx context.Context, ns graveler.StorageNamespace, destination, source, base graveler.MetaRangeID, strategy graveler.MergeStrategy) (graveler.MetaRangeID, error) { if source == base { // no changes on source - return "", nil + return "", graveler.ErrNoChanges } if destination == base { // changes introduced only on source diff --git a/pkg/graveler/committed/merge_test.go b/pkg/graveler/committed/merge_test.go index 9a71412420f..83c387ce631 100644 --- a/pkg/graveler/committed/merge_test.go +++ b/pkg/graveler/committed/merge_test.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "strings" "testing" "github.com/golang/mock/gomock" @@ -66,18 +67,35 @@ type testRunResult struct { expectedErr error } +type testMetaRange struct { + ranges []testRange +} + +func (t *testMetaRange) GetMetaRangeID() graveler.MetaRangeID { + var sb strings.Builder + for _, rng := range t.ranges { + sb.WriteString(string(rng.rng.ID)) + sb.WriteString("#") + } + return graveler.MetaRangeID(sb.String()) +} + +func newTestMetaRange(ranges []testRange) *testMetaRange { + return &testMetaRange{ranges: ranges} +} + type testCase struct { - baseRange []testRange - sourceRange []testRange - destRange []testRange + baseRange *testMetaRange + sourceRange *testMetaRange + destRange *testMetaRange expectedResult []testRunResult } type testCases map[string]testCase -func createIter(tr []testRange) committed.Iterator { +func createIter(tr *testMetaRange) committed.Iterator { iter := testutil.NewFakeIterator() - for _, rng := range tr { + for _, rng := range tr.ranges { addRange := rng.rng iter.AddRange(&addRange) for _, record := range rng.records { @@ -96,18 +114,21 @@ func createIter(tr []testRange) committed.Iterator { func Test_merge(t *testing.T) { tests := testCases{ "dest range added before": { - baseRange: []testRange{{ + baseRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}, records: nil, + }, {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, }}, - sourceRange: []testRange{{ + }), + sourceRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}, records: nil, - }}, - destRange: []testRange{ + }}), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "dest:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -124,16 +145,17 @@ func Test_merge(t *testing.T) { }}, }, "source range added before": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1024}}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k7-k8", MinKey: committed.Key("k7"), MaxKey: committed.Key("k8"), Count: 2, EstimatedSize: 1024}}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "source:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1024}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1024}}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1024}}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -149,17 +171,20 @@ func Test_merge(t *testing.T) { }}, }, "source range removed before": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1024}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1024}}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1024}}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1024}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1024}}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -171,22 +196,25 @@ func Test_merge(t *testing.T) { }}, }, "source range inner change": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3"), EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, }}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k4", MinKey: committed.Key("k4"), EstimatedSize: 1024}, records: []testValueRecord{ + {"k4", "base:k4"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "source:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3"), EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k2", "source:k2"}, {"k3", "source:k3"}, }}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3"), EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, }}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -198,25 +226,28 @@ func Test_merge(t *testing.T) { }}, }, "dest range inner change": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3"), EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, }}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3"), EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, }}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "dest:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3"), EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k2", "dest:k2"}, {"k3", "dest:k3"}, }}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -229,26 +260,29 @@ func Test_merge(t *testing.T) { }}, }, "source range append after": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, }}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "source:k1-k5", MinKey: committed.Key("k1"), MaxKey: committed.Key("k5"), Count: 4, EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k4", "source:k4"}, {"k5", "source:k5"}, }}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, }}, - }, + }), expectedResult: []testRunResult{ { mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, @@ -278,7 +312,7 @@ func Test_merge(t *testing.T) { }, }, "source range append and remove after": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3")}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, }}, @@ -287,13 +321,16 @@ func Test_merge(t *testing.T) { {"k4", "base:k4"}, {"k6", "base:k6"}, }, }, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "source:k1-k5", MinKey: committed.Key("k1"), MaxKey: committed.Key("k5")}, records: []testValueRecord{ {"k1", "base:k1"}, {"k2", "source:k2"}, {"k3", "base:k3"}, {"k4", "base:k4"}, {"k5", "source:k5"}, }}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k3", MinKey: committed.Key("k1"), MaxKey: committed.Key("k3")}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, }}, @@ -302,7 +339,7 @@ func Test_merge(t *testing.T) { {"k4", "base:k4"}, {"k6", "base:k6"}, }, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -336,21 +373,24 @@ func Test_merge(t *testing.T) { }}, }, "source range - overlapping ranges": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 4444}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "source:k1-k10", MinKey: committed.Key("k1"), MaxKey: committed.Key("k10"), Count: 6, EstimatedSize: 66666}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k4", "source:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, {"k10", "source:k10"}, }}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 4444}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -364,21 +404,24 @@ func Test_merge(t *testing.T) { }}, }, "dest range - overlapping ranges": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 4444}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 4444}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "dest:k1-k10", MinKey: committed.Key("k1"), MaxKey: committed.Key("k10"), Count: 6, EstimatedSize: 66666}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k4", "dest:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, {"k10", "dest:k10"}, }}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -393,21 +436,24 @@ func Test_merge(t *testing.T) { }}, }, "source - remove at end of range": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 4444}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 4444}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "dest:k1-k10", MinKey: committed.Key("k1"), MaxKey: committed.Key("k10"), Count: 6, EstimatedSize: 66666}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "base:k3"}, {"k4", "dest:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, {"k10", "dest:k10"}, }}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -422,26 +468,26 @@ func Test_merge(t *testing.T) { }}, }, "both added key to range": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6")}, records: []testValueRecord{ {"k1", "base:k1"}, {"k6", "base:k6"}, }}, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "source:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6")}, records: []testValueRecord{ {"k1", "base:k1"}, {"k2", "source:k2"}, {"k6", "base:k6"}, }}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "dest:k1-k6", MinKey: committed.Key("k1"), MaxKey: committed.Key("k6")}, records: []testValueRecord{ {"k1", "base:k1"}, {"k3", "dest:k3"}, {"k6", "base:k6"}, }}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -469,18 +515,21 @@ func Test_merge(t *testing.T) { }}, }, "source range removed": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}}, - }, - sourceRange: []testRange{{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}, records: nil, - }}, - destRange: []testRange{ + }}), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -493,17 +542,20 @@ func Test_merge(t *testing.T) { }}, }, "dest range removed": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}}, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}}, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -516,7 +568,7 @@ func Test_merge(t *testing.T) { }}, }, "source key removed from range - same bounds": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 1234}, @@ -524,8 +576,11 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k4", "base:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }, }, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "source:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}, @@ -533,8 +588,8 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k6", "base:k6"}, }, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 1234}, @@ -542,7 +597,7 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k4", "base:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -552,7 +607,7 @@ func Test_merge(t *testing.T) { }}, }, "source key removed from range": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 1234}, @@ -560,8 +615,11 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k4", "base:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }, }, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "source:k3-k5", MinKey: committed.Key("k3"), MaxKey: committed.Key("k5"), Count: 2, EstimatedSize: 1234}, @@ -569,8 +627,8 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k5", "base:k5"}, }, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 1234}, @@ -578,7 +636,7 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k4", "base:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -589,7 +647,7 @@ func Test_merge(t *testing.T) { }}, }, "dest key removed from range": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 1234}, @@ -597,8 +655,11 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k4", "base:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }, }, - }, - sourceRange: []testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 4, EstimatedSize: 1234}, @@ -606,8 +667,8 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k4", "base:k4"}, {"k5", "base:k5"}, {"k6", "base:k6"}, }, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "base:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, { rng: committed.Range{ID: "dest:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}, @@ -615,7 +676,7 @@ func Test_merge(t *testing.T) { {"k3", "base:k3"}, {"k6", "base:k6"}, }, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -626,29 +687,20 @@ func Test_merge(t *testing.T) { }}, }, "empty source and base": { - baseRange: []testRange{}, - sourceRange: []testRange{}, - destRange: []testRange{ + baseRange: newTestMetaRange([]testRange{}), + sourceRange: newTestMetaRange([]testRange{}), + destRange: newTestMetaRange([]testRange{ {rng: committed.Range{ID: "dest:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}}, {rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}}, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, - expectedActions: []writeAction{ - { - action: actionTypeWriteRange, - rng: committed.Range{ID: "dest:k1-k2", MinKey: committed.Key("k1"), MaxKey: committed.Key("k2"), Count: 2, EstimatedSize: 1234}, - }, - { - action: actionTypeWriteRange, - rng: committed.Range{ID: "base:k3-k6", MinKey: committed.Key("k3"), MaxKey: committed.Key("k6"), Count: 2, EstimatedSize: 1234}, - }, - }, - expectedErr: nil, + expectedActions: []writeAction{}, + expectedErr: graveler.ErrNoChanges, }}, }, "dest removed range and added range after source removed range edges": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:k1-k5", MinKey: committed.Key("k1"), MaxKey: committed.Key("k5"), Count: 5, EstimatedSize: 1234}, records: []testValueRecord{ @@ -659,23 +711,23 @@ func Test_merge(t *testing.T) { {"k5", "base:k5"}, }, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:k3-k4", MinKey: committed.Key("k3"), MaxKey: committed.Key("k4"), Count: 2, EstimatedSize: 1234}, records: []testValueRecord{ {"k3", "base:k3"}, {"k4", "base:k4"}, }, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "dest:k6-k7", MinKey: committed.Key("k6"), MaxKey: committed.Key("k7"), Count: 2, EstimatedSize: 1234}, records: []testValueRecord{ {"k6", "dest:k6"}, {"k7", "dest:k7"}, }, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -686,43 +738,38 @@ func Test_merge(t *testing.T) { }}, }, "no changes": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:k3-k4", MinKey: committed.Key("k3"), MaxKey: committed.Key("k4"), Count: 2, EstimatedSize: 1234}, records: []testValueRecord{ {"k3", "base:k3"}, {"k4", "base:k4"}, }, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:k3-k4", MinKey: committed.Key("k3"), MaxKey: committed.Key("k4"), Count: 2, EstimatedSize: 1234}, records: []testValueRecord{ {"k3", "base:k3"}, {"k4", "base:k4"}, }, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:k3-k4", MinKey: committed.Key("k3"), MaxKey: committed.Key("k4"), Count: 2, EstimatedSize: 1234}, records: []testValueRecord{ {"k3", "base:k3"}, {"k4", "base:k4"}, }, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, - expectedActions: []writeAction{ - { - action: actionTypeWriteRange, - rng: committed.Range{ID: "base:k3-k4", MinKey: committed.Key("k3"), MaxKey: committed.Key("k4"), Count: 2, EstimatedSize: 1234}, - }, - }, - expectedErr: nil, + expectedActions: []writeAction{}, + expectedErr: graveler.ErrNoChanges, }}, }, "source and dest changed record identity": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:b-c", MinKey: committed.Key("b"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "b", identity: "b"}, {key: "c", identity: "c"}}, @@ -731,8 +778,8 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "base:d-e", MinKey: committed.Key("d"), MaxKey: committed.Key("e"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "d", identity: "d"}, {key: "e", identity: "e"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "d", identity: "d"}}, @@ -741,8 +788,8 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "source:e", MinKey: committed.Key("e"), MaxKey: committed.Key("e"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "e", identity: "e1"}}, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:b-c", MinKey: committed.Key("b"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "b", identity: "b"}, {key: "c", identity: "c"}}, @@ -751,7 +798,7 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "dest:d-e", MinKey: committed.Key("d"), MaxKey: committed.Key("e"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "d", identity: "d1"}, {key: "e", identity: "e"}}, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -780,19 +827,19 @@ func Test_merge(t *testing.T) { }}, }, "dest removed all source added": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "d", identity: "d"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 4, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}, {key: "d", identity: "d"}}, }, - }, - destRange: []testRange{}, + }), + destRange: newTestMetaRange([]testRange{}), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -811,24 +858,24 @@ func Test_merge(t *testing.T) { }}, }, "same identity different key": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "d", identity: "d"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 4, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "a1", identity: "a"}, {key: "c", identity: "c"}}, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "dest:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "d", identity: "d"}}, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -852,19 +899,19 @@ func Test_merge(t *testing.T) { }}, }, "dest removed all source range before base": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:c-d", MinKey: committed.Key("c"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "c", identity: "c"}, {key: "d", identity: "d"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}}, }, - }, - destRange: []testRange{}, + }), + destRange: newTestMetaRange([]testRange{}), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -877,19 +924,19 @@ func Test_merge(t *testing.T) { }}, }, "dest removed all different key different identity": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "a2", identity: "a2"}, {key: "b", identity: "b"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "a1", identity: "a1"}, {key: "b", identity: "b"}}, }, - }, - destRange: []testRange{}, + }), + destRange: newTestMetaRange([]testRange{}), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -903,7 +950,7 @@ func Test_merge(t *testing.T) { }}, }, "dest removed all base and source same identity": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}}, @@ -912,8 +959,8 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "base:d-f", MinKey: committed.Key("d"), MaxKey: committed.Key("f"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "d", identity: "d"}, {key: "f", identity: "f"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}}, @@ -922,8 +969,8 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "source:c-e", MinKey: committed.Key("c"), MaxKey: committed.Key("e"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "c", identity: "c"}, {key: "e", identity: "e"}}, }, - }, - destRange: []testRange{}, + }), + destRange: newTestMetaRange([]testRange{}), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -942,19 +989,19 @@ func Test_merge(t *testing.T) { }}, }, "source key before dest range": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}, {key: "d", identity: "d"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}, {key: "d", identity: "d"}}, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "dest:b-c", MinKey: committed.Key("b"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "b", identity: "b"}, {key: "c", identity: "c"}}, @@ -963,7 +1010,7 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "dest:e-f", MinKey: committed.Key("e"), MaxKey: committed.Key("f"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "e", identity: "e"}, {key: "f", identity: "f"}}, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -986,13 +1033,13 @@ func Test_merge(t *testing.T) { }}, }, "dest key before source range": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}, {key: "d", identity: "d"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:b-c", MinKey: committed.Key("b"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "b", identity: "b"}, {key: "c", identity: "c"}}, @@ -1001,13 +1048,13 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "source:e-f", MinKey: committed.Key("e"), MaxKey: committed.Key("f"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "e", identity: "e"}, {key: "f", identity: "f"}}, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "dest:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}, {key: "d", identity: "d"}}, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -1030,19 +1077,19 @@ func Test_merge(t *testing.T) { }}, }, "dest range before source key": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:c-c", MinKey: committed.Key("c"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "c", identity: "c"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "d", identity: "d"}}, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "dest:a-a", MinKey: committed.Key("a"), MaxKey: committed.Key("a"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}}, @@ -1055,7 +1102,7 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "base:c-c", MinKey: committed.Key("c"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "c", identity: "c"}}, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -1078,13 +1125,13 @@ func Test_merge(t *testing.T) { }}, }, "source range before dest key": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:c-c", MinKey: committed.Key("c"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "c", identity: "c"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-a", MinKey: committed.Key("a"), MaxKey: committed.Key("a"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}}, @@ -1097,13 +1144,13 @@ func Test_merge(t *testing.T) { rng: committed.Range{ID: "base:c-c", MinKey: committed.Key("c"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "c", identity: "c"}}, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "dest:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "d", identity: "d"}}, }, - }, + }), expectedResult: []testRunResult{{ mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, expectedActions: []writeAction{ @@ -1125,6 +1172,49 @@ func Test_merge(t *testing.T) { expectedErr: nil, }}, }, + "dest and base are the same": { + baseRange: newTestMetaRange([]testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ + {rng: committed.Range{ID: "source:k13-k14", MinKey: committed.Key("k13"), MaxKey: committed.Key("k14"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k13", "base:k13"}, {"k14", "base:k14"}, + }}, + }), + destRange: newTestMetaRange([]testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + expectedResult: []testRunResult{{ + mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, + expectedActions: []writeAction{}, + }}, + }, + "source and dest are the same": { + baseRange: newTestMetaRange([]testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + sourceRange: newTestMetaRange([]testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + destRange: newTestMetaRange([]testRange{ + {rng: committed.Range{ID: "base:k11-k12", MinKey: committed.Key("k11"), MaxKey: committed.Key("k12"), Count: 2, EstimatedSize: 4444}, records: []testValueRecord{ + {"k11", "base:k11"}, {"k12", "base:k12"}, + }}, + }), + expectedResult: []testRunResult{{ + mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone, graveler.MergeStrategyDest, graveler.MergeStrategySource}, + expectedActions: []writeAction{}, + expectedErr: graveler.ErrNoChanges, + }}, + }, } runMergeTests(tests, t) @@ -1140,19 +1230,19 @@ func TestMergeStrategies(t *testing.T) { // - Source strategy - favors source branch, so record 'a', with the modified value, is written, ignoring its deletion on dest. Record b // is still deleted as there is no conflict involving it "dest removed all same key different identity": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a1"}, {key: "b", identity: "b"}}, }, - }, - destRange: []testRange{}, + }), + destRange: newTestMetaRange([]testRange{}), expectedResult: []testRunResult{ { mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone}, @@ -1188,7 +1278,7 @@ func TestMergeStrategies(t *testing.T) { // of record 'k1', 'k2' 'k3' and 'k5' are still deleted as there is no conflict involving them. Same goes for 'k6' and 'k7' which are // written on both 'dest-wins' and 'source-wins' strategies "source and dest change same range conflict": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:k1-k5", MinKey: committed.Key("k1"), MaxKey: committed.Key("k5"), Count: 5, EstimatedSize: 1234}, records: []testValueRecord{ @@ -1199,23 +1289,23 @@ func TestMergeStrategies(t *testing.T) { {"k5", "base:k5"}, }, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:k3-k4", MinKey: committed.Key("k3"), MaxKey: committed.Key("k4"), Count: 2, EstimatedSize: 1234}, records: []testValueRecord{ {"k3", "base:k3"}, {"k4", "source:k4"}, }, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "dest:k6-k7", MinKey: committed.Key("k6"), MaxKey: committed.Key("k7"), Count: 2, EstimatedSize: 1234}, records: []testValueRecord{ {"k6", "dest:k6"}, {"k7", "dest:k7"}, }, }, - }, + }), expectedResult: []testRunResult{ { mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone}, @@ -1270,24 +1360,24 @@ func TestMergeStrategies(t *testing.T) { // Record 'b' is deleted for both strategies as there is no conflict invloving it. Same goes for records 'c' and 'd' that are written, // regardless of merge strategy "dest range before source": { - baseRange: []testRange{ + baseRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "base:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}}, }, - }, - sourceRange: []testRange{ + }), + sourceRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "source:c-d", MinKey: committed.Key("c"), MaxKey: committed.Key("d"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "c", identity: "c"}, {key: "d", identity: "d"}}, }, - }, - destRange: []testRange{ + }), + destRange: newTestMetaRange([]testRange{ { rng: committed.Range{ID: "dest:a-b", MinKey: committed.Key("a"), MaxKey: committed.Key("b"), Count: 2, EstimatedSize: 1024}, records: []testValueRecord{{key: "a", identity: "a1"}, {key: "b", identity: "b"}}, }, - }, + }), expectedResult: []testRunResult{ { mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone}, @@ -1334,18 +1424,18 @@ func TestMergeStrategies(t *testing.T) { }, }, "source change and dest delete same entry": { - baseRange: []testRange{{ + baseRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "base:a-c", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 3, EstimatedSize: 333}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}}, - }}, - sourceRange: []testRange{{ + }}), + sourceRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "source:a-c", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 3, EstimatedSize: 123}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b1"}, {key: "c", identity: "c"}}, - }}, - destRange: []testRange{{ + }}), + destRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "dest:a-c", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 321}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "c", identity: "c"}}, - }}, + }}), expectedResult: []testRunResult{ { mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone}, @@ -1399,18 +1489,18 @@ func TestMergeStrategies(t *testing.T) { }, "source delete and dest change same entry": { - baseRange: []testRange{{ + baseRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "base:a-c", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 3, EstimatedSize: 333}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}}, - }}, - sourceRange: []testRange{{ + }}), + sourceRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "source:a-c", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 2, EstimatedSize: 123}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "c", identity: "c"}}, - }}, - destRange: []testRange{{ + }}), + destRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "dest:a-c", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 3, EstimatedSize: 321}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b1"}, {key: "c", identity: "c"}}, - }}, + }}), expectedResult: []testRunResult{ { mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone}, @@ -1464,18 +1554,18 @@ func TestMergeStrategies(t *testing.T) { }, "source and dest delete from same range": { - baseRange: []testRange{{ + baseRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "base:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 4, EstimatedSize: 4444}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}, {key: "d", identity: "d"}}, - }}, - sourceRange: []testRange{{ + }}), + sourceRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "source:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 3, EstimatedSize: 1234}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "c", identity: "c1"}, {key: "d", identity: "d"}}, - }}, - destRange: []testRange{{ + }}), + destRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "dest:a-d", MinKey: committed.Key("a"), MaxKey: committed.Key("d"), Count: 3, EstimatedSize: 4321}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b1"}, {key: "d", identity: "d"}}, - }}, + }}), expectedResult: []testRunResult{ { mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone}, @@ -1533,18 +1623,18 @@ func TestMergeStrategies(t *testing.T) { }, }, "source and dest change same entry": { - baseRange: []testRange{{ + baseRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "base:a-a", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 3, EstimatedSize: 1234}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b"}, {key: "c", identity: "c"}}, - }}, - sourceRange: []testRange{{ + }}), + sourceRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "source:a-a", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 3, EstimatedSize: 1234}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b1"}, {key: "c", identity: "c"}}, - }}, - destRange: []testRange{{ + }}), + destRange: newTestMetaRange([]testRange{{ rng: committed.Range{ID: "dest:a-a", MinKey: committed.Key("a"), MaxKey: committed.Key("c"), Count: 3, EstimatedSize: 1234}, records: []testValueRecord{{key: "a", identity: "a"}, {key: "b", identity: "b2"}, {key: "c", identity: "c"}}, - }}, + }}), expectedResult: []testRunResult{ { mergeStrategies: []graveler.MergeStrategy{graveler.MergeStrategyNone}, @@ -1624,21 +1714,21 @@ func runMergeTests(tests testCases, t *testing.T) { } } metaRangeManager := mock.NewMockMetaRangeManager(ctrl) - metaRangeManager.EXPECT().NewWriter(gomock.Any(), gomock.Any(), gomock.Any()).Return(writer) - sourceKey := graveler.MetaRangeID("source") - destKey := graveler.MetaRangeID("dest") - baseKey := graveler.MetaRangeID("base") - metaRangeManager.EXPECT().NewMetaRangeIterator(gomock.Any(), gomock.Any(), baseKey).Return(createIter(tst.baseRange), nil) - metaRangeManager.EXPECT().NewMetaRangeIterator(gomock.Any(), gomock.Any(), sourceKey).Return(createIter(tst.sourceRange), nil) - metaRangeManager.EXPECT().NewMetaRangeIterator(gomock.Any(), gomock.Any(), destKey).Return(createIter(tst.destRange), nil) + metaRangeManager.EXPECT().NewWriter(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(writer) + sourceMetaRangeID := tst.sourceRange.GetMetaRangeID() + destMetaRangeID := tst.destRange.GetMetaRangeID() + baseMetaRangeID := tst.baseRange.GetMetaRangeID() + metaRangeManager.EXPECT().NewMetaRangeIterator(gomock.Any(), gomock.Any(), baseMetaRangeID).AnyTimes().Return(createIter(tst.baseRange), nil) + metaRangeManager.EXPECT().NewMetaRangeIterator(gomock.Any(), gomock.Any(), sourceMetaRangeID).AnyTimes().Return(createIter(tst.sourceRange), nil) + metaRangeManager.EXPECT().NewMetaRangeIterator(gomock.Any(), gomock.Any(), destMetaRangeID).AnyTimes().Return(createIter(tst.destRange), nil) rangeManager := mock.NewMockRangeManager(ctrl) - writer.EXPECT().Abort() + writer.EXPECT().Abort().AnyTimes() metaRangeId := graveler.MetaRangeID("merge") writer.EXPECT().Close().Return(&metaRangeId, nil).AnyTimes() committedManager := committed.NewCommittedManager(metaRangeManager, rangeManager, params) - _, err := committedManager.Merge(ctx, "ns", "dest", "source", "base", graveler.MergeStrategy(mergeStrategy)) + _, err := committedManager.Merge(ctx, "ns", destMetaRangeID, sourceMetaRangeID, baseMetaRangeID, mergeStrategy) if err != expectedResult.expectedErr { t.Fatal(err) }