github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/graveler/committed/meta_range_writer_test.go (about) 1 package committed_test 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 8 "github.com/golang/mock/gomock" 9 "github.com/treeverse/lakefs/pkg/graveler" 10 "github.com/treeverse/lakefs/pkg/graveler/committed" 11 "github.com/treeverse/lakefs/pkg/graveler/committed/mock" 12 "github.com/treeverse/lakefs/pkg/testutil" 13 ) 14 15 func getExpected(t *testing.T, record graveler.ValueRecord) committed.Record { 16 t.Helper() 17 expectedValue, err := committed.MarshalValue(record.Value) 18 testutil.Must(t, err) 19 return committed.Record{Key: committed.Key(record.Key), Value: expectedValue} 20 } 21 22 var params = committed.Params{ 23 MinRangeSizeBytes: 0, 24 MaxRangeSizeBytes: 50_000, 25 RangeSizeEntriesRaggedness: 100, 26 MaxUploaders: 3, 27 } 28 29 func TestWriter_WriteRecords(t *testing.T) { 30 ctx := context.Background() 31 ctrl := gomock.NewController(t) 32 defer ctrl.Finish() 33 34 writeResult := committed.WriteResult{ 35 RangeID: committed.ID("id"), 36 First: committed.Key("a"), 37 Last: committed.Key("z"), 38 } 39 fakeWriter := NewFakeRangeWriter(&writeResult, nil) 40 41 rangeManager := mock.NewMockRangeManager(ctrl) 42 rangeManager.EXPECT().GetWriter(gomock.Any(), gomock.Any(), gomock.Any()).Return(fakeWriter, nil) 43 44 metaWriteResult := committed.WriteResult{ 45 RangeID: committed.ID("meta-range-id"), 46 First: committed.Key("a"), 47 Last: committed.Key("z"), 48 } 49 50 fakeMetaWriter := NewFakeRangeWriter(&metaWriteResult, nil) 51 fakeMetaWriter.ExpectAnyRecord() 52 53 rangeManagerMeta := mock.NewMockRangeManager(ctrl) 54 rangeManagerMeta.EXPECT().GetWriter(gomock.Any(), gomock.Any(), gomock.Any()).Return(fakeMetaWriter, nil) 55 namespace := committed.Namespace("ns") 56 w := committed.NewGeneralMetaRangeWriter(ctx, rangeManager, rangeManagerMeta, ¶ms, namespace, nil) 57 58 // Add first record 59 firstRecord := graveler.ValueRecord{ 60 Key: graveler.Key("c"), 61 Value: &graveler.Value{}, 62 } 63 expected := getExpected(t, firstRecord) 64 fakeWriter.ExpectWriteRecord(expected) 65 err := w.WriteRecord(firstRecord) 66 if err != nil { 67 t.Fatalf("unexpected error %s", err) 68 } 69 70 // Add second record 71 secondRecord := graveler.ValueRecord{ 72 Key: graveler.Key("d"), 73 Value: &graveler.Value{ 74 Identity: []byte("d"), 75 Data: nil, 76 }, 77 } 78 fakeWriter.ExpectWriteRecord(getExpected(t, secondRecord)) 79 err = w.WriteRecord(secondRecord) 80 if err != nil { 81 t.Errorf("unexpected error %s", err) 82 } 83 // Fail on adding record with smaller key than previous key 84 err = w.WriteRecord(graveler.ValueRecord{ 85 Key: graveler.Key("cat"), 86 Value: &graveler.Value{}, 87 }) 88 if !errors.Is(err, committed.ErrUnsortedKeys) { 89 t.Errorf("expected ErrUnsorted got = %s", err) 90 } 91 92 _, err = w.Close(ctx) 93 if err != nil { 94 t.Errorf("failed to close: %s", err) 95 } 96 } 97 98 func TestWriter_OverlappingRanges(t *testing.T) { 99 ctx := context.Background() 100 ctrl := gomock.NewController(t) 101 defer ctrl.Finish() 102 103 rangeManager := mock.NewMockRangeManager(ctrl) 104 namespace := committed.Namespace("ns") 105 rng := committed.Range{MinKey: committed.Key("a"), MaxKey: committed.Key("g")} 106 rng2 := committed.Range{MinKey: committed.Key("c"), MaxKey: committed.Key("l")} 107 w := committed.NewGeneralMetaRangeWriter(ctx, rangeManager, rangeManager, ¶ms, namespace, nil) 108 err := w.WriteRange(rng) 109 if err != nil { 110 t.Fatalf("unexpected error %s", err) 111 } 112 err = w.WriteRange(rng2) 113 if !errors.Is(err, committed.ErrUnsortedKeys) { 114 t.Fatalf("expected ErrUnsorted got = %s", err) 115 } 116 } 117 118 func TestWriter_RecordRangeAndClose(t *testing.T) { 119 ctx := context.Background() 120 ctrl := gomock.NewController(t) 121 defer ctrl.Finish() 122 123 rangeManager := mock.NewMockRangeManager(ctrl) 124 fakeWriter := NewFakeRangeWriter(&committed.WriteResult{ 125 RangeID: "rng-id", 126 First: []byte("a"), 127 Last: []byte("a"), 128 Count: 1, 129 }, nil) 130 131 rangeManagerMeta := mock.NewMockRangeManager(ctrl) 132 fakeMetaWriter := NewFakeRangeWriter(&committed.WriteResult{}, nil) 133 134 namespace := committed.Namespace("ns") 135 record := graveler.ValueRecord{Key: nil, Value: &graveler.Value{}} 136 rng := committed.Range{ID: "rng2-id", MinKey: committed.Key("a"), MaxKey: committed.Key("g"), Count: 4} 137 138 // get writer - once for record writer, once for range writer 139 rangeManager.EXPECT().GetWriter(gomock.Any(), gomock.Any(), gomock.Any()).Return(fakeWriter, nil) 140 rangeManagerMeta.EXPECT().GetWriter(gomock.Any(), gomock.Any(), gomock.Any()).Return(fakeMetaWriter, nil) 141 142 // Never attempt to split files: fake writers return size 0. 143 144 // write two records on MetaRange and one for Range 145 fakeWriter.ExpectAnyRecord() 146 147 fakeMetaWriter.ExpectWriteRecord(getExpected(t, graveler.ValueRecord{ 148 Key: []byte("a"), 149 Value: &graveler.Value{ 150 Identity: []byte("rng-id"), 151 Data: mustMarshalRange(committed.Range{ 152 ID: "rng-id", 153 MinKey: []byte("a"), 154 MaxKey: []byte("a"), 155 Count: 1, 156 }), 157 }, 158 })) 159 fakeMetaWriter.ExpectWriteRecord(getExpected(t, graveler.ValueRecord{ 160 Key: []byte("g"), 161 Value: &graveler.Value{ 162 Identity: []byte("rng2-id"), 163 Data: mustMarshalRange(rng), 164 }, 165 })) 166 167 w := committed.NewGeneralMetaRangeWriter(ctx, rangeManager, rangeManagerMeta, ¶ms, namespace, nil) 168 err := w.WriteRecord(record) 169 if err != nil { 170 t.Fatalf("unexpected error %s", err) 171 } 172 err = w.WriteRange(rng) 173 if err != nil { 174 t.Fatalf("unexpected error %s", err) 175 } 176 177 _, err = w.Close(ctx) 178 if err != nil { 179 t.Fatalf("unexpected error %s", err) 180 } 181 }