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 }