github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/storage/pebble_file_registry_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  
    11  package storage
    12  
    13  import (
    14  	"runtime/debug"
    15  	"strings"
    16  	"testing"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/storage/enginepb"
    19  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    20  	"github.com/cockroachdb/pebble/vfs"
    21  	"github.com/kr/pretty"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  func checkEquality(t *testing.T, fs vfs.FS, expected map[string]*enginepb.FileEntry) {
    26  	registry := &PebbleFileRegistry{FS: fs, DBDir: "/mydb"}
    27  	require.NoError(t, registry.Load())
    28  	registry.mu.Lock()
    29  	defer registry.mu.Unlock()
    30  	if diff := pretty.Diff(registry.mu.currProto.Files, expected); diff != nil {
    31  		t.Log(string(debug.Stack()))
    32  		t.Fatalf("%s\n%v", strings.Join(diff, "\n"), registry.mu.currProto.Files)
    33  	}
    34  }
    35  
    36  func TestFileRegistryRelativePaths(t *testing.T) {
    37  	defer leaktest.AfterTest(t)()
    38  
    39  	mem := vfs.NewMem()
    40  	fileEntry :=
    41  		&enginepb.FileEntry{EnvType: enginepb.EnvType_Data, EncryptionSettings: []byte("foo")}
    42  	type TestCase struct {
    43  		dbDir            string
    44  		filename         string
    45  		expectedFilename string
    46  	}
    47  	testCases := []TestCase{
    48  		{"/", "/foo", "foo"},
    49  		{"/rocksdir", "/rocksdirfoo", "/rocksdirfoo"},
    50  		{"/rocksdir", "/rocksdir/foo", "foo"},
    51  		// We get the occasional double-slash.
    52  		{"/rocksdir", "/rocksdir//foo", "foo"},
    53  		{"/mydir", "/mydir", ""},
    54  		{"/mydir", "/mydir/", ""},
    55  		{"/mydir", "/mydir//", ""},
    56  		{"/mnt/otherdevice/", "/mnt/otherdevice/myfile", "myfile"},
    57  		{"/mnt/otherdevice/myfile", "/mnt/otherdevice/myfile", ""},
    58  	}
    59  
    60  	for _, tc := range testCases {
    61  		require.NoError(t, mem.MkdirAll(tc.dbDir, 0755))
    62  		registry := &PebbleFileRegistry{FS: mem, DBDir: tc.dbDir}
    63  		require.NoError(t, registry.Load())
    64  		require.NoError(t, registry.SetFileEntry(tc.filename, fileEntry))
    65  		entry := registry.GetFileEntry(tc.expectedFilename)
    66  		if diff := pretty.Diff(entry, fileEntry); diff != nil {
    67  			t.Fatalf("filename: %s: %s\n%v", tc.filename, strings.Join(diff, "\n"), entry)
    68  		}
    69  	}
    70  }
    71  
    72  func TestFileRegistryOps(t *testing.T) {
    73  	defer leaktest.AfterTest(t)()
    74  
    75  	mem := vfs.NewMem()
    76  	fooFileEntry :=
    77  		&enginepb.FileEntry{EnvType: enginepb.EnvType_Data, EncryptionSettings: []byte("foo")}
    78  	barFileEntry :=
    79  		&enginepb.FileEntry{EnvType: enginepb.EnvType_Store, EncryptionSettings: []byte("bar")}
    80  	bazFileEntry :=
    81  		&enginepb.FileEntry{EnvType: enginepb.EnvType_Data, EncryptionSettings: []byte("baz")}
    82  
    83  	require.NoError(t, mem.MkdirAll("/mydb", 0755))
    84  	registry := &PebbleFileRegistry{FS: mem, DBDir: "/mydb"}
    85  	require.NoError(t, registry.Load())
    86  	require.Nil(t, registry.GetFileEntry("file1"))
    87  
    88  	// {file1 => foo}
    89  	require.NoError(t, registry.SetFileEntry("file1", fooFileEntry))
    90  	expected := make(map[string]*enginepb.FileEntry)
    91  	expected["file1"] = fooFileEntry
    92  	checkEquality(t, mem, expected)
    93  
    94  	// {file1 => foo, file2 => bar}
    95  	require.NoError(t, registry.SetFileEntry("file2", barFileEntry))
    96  	expected["file2"] = barFileEntry
    97  	checkEquality(t, mem, expected)
    98  
    99  	// {file3 => foo, file2 => bar}
   100  	require.NoError(t, registry.MaybeRenameEntry("file1", "file3"))
   101  	expected["file3"] = fooFileEntry
   102  	delete(expected, "file1")
   103  	checkEquality(t, mem, expected)
   104  
   105  	// {file3 => foo, file2 => bar, file4 => bar}
   106  	require.NoError(t, registry.MaybeLinkEntry("file2", "file4"))
   107  	expected["file4"] = barFileEntry
   108  	checkEquality(t, mem, expected)
   109  
   110  	// {file3 => foo, file4 => bar}
   111  	require.NoError(t, registry.MaybeLinkEntry("file5", "file2"))
   112  	delete(expected, "file2")
   113  	checkEquality(t, mem, expected)
   114  
   115  	// {file3 => foo}
   116  	require.NoError(t, registry.MaybeRenameEntry("file7", "file4"))
   117  	delete(expected, "file4")
   118  	checkEquality(t, mem, expected)
   119  
   120  	// {file3 => foo, blue/baz => baz} (since latter file uses relative path).
   121  	require.NoError(t, registry.SetFileEntry("/mydb/blue/baz", bazFileEntry))
   122  	expected["blue/baz"] = bazFileEntry
   123  	checkEquality(t, mem, expected)
   124  
   125  	entry := registry.GetFileEntry("/mydb/blue/baz")
   126  	if diff := pretty.Diff(entry, bazFileEntry); diff != nil {
   127  		t.Fatalf("%s\n%v", strings.Join(diff, "\n"), entry)
   128  	}
   129  
   130  	// {file3 => foo}
   131  	require.NoError(t, registry.MaybeDeleteEntry("/mydb/blue/baz"))
   132  	delete(expected, "blue/baz")
   133  	checkEquality(t, mem, expected)
   134  
   135  	// {file3 => foo, green/baz => baz} (since latter file uses relative path).
   136  	require.NoError(t, registry.SetFileEntry("/mydb//green/baz", bazFileEntry))
   137  	expected["green/baz"] = bazFileEntry
   138  	checkEquality(t, mem, expected)
   139  
   140  	// Noops
   141  	require.NoError(t, registry.MaybeDeleteEntry("file1"))
   142  	require.NoError(t, registry.MaybeRenameEntry("file4", "file5"))
   143  	require.NoError(t, registry.MaybeLinkEntry("file6", "file7"))
   144  	checkEquality(t, mem, expected)
   145  
   146  	// Open a read-only registry. All updates should fail.
   147  	roRegistry := &PebbleFileRegistry{FS: mem, DBDir: "/mydb", ReadOnly: true}
   148  	require.NoError(t, roRegistry.Load())
   149  	require.Error(t, roRegistry.SetFileEntry("file3", bazFileEntry))
   150  	require.Error(t, roRegistry.MaybeDeleteEntry("file3"))
   151  	require.Error(t, roRegistry.MaybeRenameEntry("file3", "file4"))
   152  	require.Error(t, roRegistry.MaybeLinkEntry("file3", "file4"))
   153  }
   154  
   155  func TestFileRegistryCheckNoFile(t *testing.T) {
   156  	defer leaktest.AfterTest(t)()
   157  
   158  	mem := vfs.NewMem()
   159  	fileEntry :=
   160  		&enginepb.FileEntry{EnvType: enginepb.EnvType_Data, EncryptionSettings: []byte("foo")}
   161  	registry := &PebbleFileRegistry{FS: mem}
   162  	require.NoError(t, registry.checkNoRegistryFile())
   163  	require.NoError(t, registry.Load())
   164  	require.NoError(t, registry.SetFileEntry("/foo", fileEntry))
   165  	registry = &PebbleFileRegistry{FS: mem}
   166  	require.Error(t, registry.checkNoRegistryFile())
   167  }