github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/replica_sst_snapshot_storage_test.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  package kvserver
    11  
    12  import (
    13  	"context"
    14  	"io/ioutil"
    15  	"os"
    16  	"testing"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/rditer"
    19  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    20  	"github.com/cockroachdb/cockroach/pkg/storage"
    21  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    22  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    23  	"github.com/stretchr/testify/require"
    24  	"golang.org/x/time/rate"
    25  )
    26  
    27  func TestSSTSnapshotStorage(t *testing.T) {
    28  	defer leaktest.AfterTest(t)()
    29  
    30  	ctx := context.Background()
    31  	testRangeID := roachpb.RangeID(1)
    32  	testSnapUUID := uuid.Must(uuid.FromBytes([]byte("foobar1234567890")))
    33  	testLimiter := rate.NewLimiter(rate.Inf, 0)
    34  
    35  	cleanup, eng := newEngine(t)
    36  	defer cleanup()
    37  	defer eng.Close()
    38  
    39  	sstSnapshotStorage := NewSSTSnapshotStorage(eng, testLimiter)
    40  	scratch := sstSnapshotStorage.NewScratchSpace(testRangeID, testSnapUUID)
    41  
    42  	// Check that the storage lazily creates the directories on first write.
    43  	_, err := os.Stat(scratch.snapDir)
    44  	if !os.IsNotExist(err) {
    45  		t.Fatalf("expected %s to not exist", scratch.snapDir)
    46  	}
    47  
    48  	f, err := scratch.NewFile(ctx, 0)
    49  	require.NoError(t, err)
    50  	defer func() {
    51  		require.NoError(t, f.Close())
    52  	}()
    53  
    54  	// Check that even though the files aren't created, they are still recorded in SSTs().
    55  	require.Equal(t, len(scratch.SSTs()), 1)
    56  
    57  	// Check that the storage lazily creates the files on write.
    58  	for _, fileName := range scratch.SSTs() {
    59  		_, err := os.Stat(fileName)
    60  		if !os.IsNotExist(err) {
    61  			t.Fatalf("expected %s to not exist", fileName)
    62  		}
    63  	}
    64  
    65  	_, err = f.Write([]byte("foo"))
    66  	require.NoError(t, err)
    67  
    68  	// After writing to files, check that they have been flushed to disk.
    69  	for _, fileName := range scratch.SSTs() {
    70  		require.FileExists(t, fileName)
    71  		data, err := ioutil.ReadFile(fileName)
    72  		require.NoError(t, err)
    73  		require.Equal(t, data, []byte("foo"))
    74  	}
    75  
    76  	// Check that closing is idempotent.
    77  	require.NoError(t, f.Close())
    78  	require.NoError(t, f.Close())
    79  
    80  	// Check that writing to a closed file is an error.
    81  	_, err = f.Write([]byte("foo"))
    82  	require.EqualError(t, err, "file has already been closed")
    83  
    84  	// Check that closing an empty file is an error.
    85  	f, err = scratch.NewFile(ctx, 0)
    86  	require.NoError(t, err)
    87  	require.EqualError(t, f.Close(), "file is empty")
    88  	_, err = f.Write([]byte("foo"))
    89  	require.NoError(t, err)
    90  
    91  	// Check that Clear removes the directory.
    92  	require.NoError(t, scratch.Clear())
    93  	_, err = os.Stat(scratch.snapDir)
    94  	if !os.IsNotExist(err) {
    95  		t.Fatalf("expected %s to not exist", scratch.snapDir)
    96  	}
    97  	require.NoError(t, sstSnapshotStorage.Clear())
    98  	_, err = os.Stat(sstSnapshotStorage.dir)
    99  	if !os.IsNotExist(err) {
   100  		t.Fatalf("expected %s to not exist", sstSnapshotStorage.dir)
   101  	}
   102  }
   103  
   104  // TestMultiSSTWriterInitSST tests that multiSSTWriter initializes each of the
   105  // SST files associated with the three replicated key ranges by writing a range
   106  // deletion tombstone that spans the entire range of each respectively.
   107  func TestMultiSSTWriterInitSST(t *testing.T) {
   108  	defer leaktest.AfterTest(t)()
   109  
   110  	ctx := context.Background()
   111  	testRangeID := roachpb.RangeID(1)
   112  	testSnapUUID := uuid.Must(uuid.FromBytes([]byte("foobar1234567890")))
   113  	testLimiter := rate.NewLimiter(rate.Inf, 0)
   114  
   115  	cleanup, eng := newEngine(t)
   116  	defer cleanup()
   117  	defer eng.Close()
   118  
   119  	sstSnapshotStorage := NewSSTSnapshotStorage(eng, testLimiter)
   120  	scratch := sstSnapshotStorage.NewScratchSpace(testRangeID, testSnapUUID)
   121  	desc := roachpb.RangeDescriptor{
   122  		StartKey: roachpb.RKey("d"),
   123  		EndKey:   roachpb.RKeyMax,
   124  	}
   125  	keyRanges := rditer.MakeReplicatedKeyRanges(&desc)
   126  
   127  	msstw, err := newMultiSSTWriter(ctx, scratch, keyRanges, 0)
   128  	require.NoError(t, err)
   129  	err = msstw.Finish(ctx)
   130  	require.NoError(t, err)
   131  
   132  	var actualSSTs [][]byte
   133  	fileNames := msstw.scratch.SSTs()
   134  	for _, file := range fileNames {
   135  		sst, err := eng.ReadFile(file)
   136  		require.NoError(t, err)
   137  		actualSSTs = append(actualSSTs, sst)
   138  	}
   139  
   140  	// Construct an SST file for each of the key ranges and write a rangedel
   141  	// tombstone that spans from Start to End.
   142  	var expectedSSTs [][]byte
   143  	for _, r := range keyRanges {
   144  		func() {
   145  			sstFile := &storage.MemFile{}
   146  			sst := storage.MakeIngestionSSTWriter(sstFile)
   147  			defer sst.Close()
   148  			err := sst.ClearRange(r.Start, r.End)
   149  			require.NoError(t, err)
   150  			err = sst.Finish()
   151  			require.NoError(t, err)
   152  			expectedSSTs = append(expectedSSTs, sstFile.Data())
   153  		}()
   154  	}
   155  
   156  	require.Equal(t, len(actualSSTs), len(expectedSSTs))
   157  	for i := range fileNames {
   158  		require.Equal(t, actualSSTs[i], expectedSSTs[i])
   159  	}
   160  }