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, &params, 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, &params, 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, &params, 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  }