github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/internal/manifest/version_edit_test.go (about) 1 // Copyright 2012 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package manifest 6 7 import ( 8 "bytes" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "os" 13 "reflect" 14 "strings" 15 "testing" 16 17 "github.com/kr/pretty" 18 "github.com/petermattis/pebble/internal/base" 19 "github.com/petermattis/pebble/internal/record" 20 ) 21 22 func checkRoundTrip(e0 VersionEdit) error { 23 var e1 VersionEdit 24 buf := new(bytes.Buffer) 25 if err := e0.Encode(buf); err != nil { 26 return fmt.Errorf("encode: %v", err) 27 } 28 if err := e1.Decode(buf); err != nil { 29 return fmt.Errorf("decode: %v", err) 30 } 31 if !reflect.DeepEqual(e1, e0) { 32 return fmt.Errorf("\n\tgot %#v\n\twant %#v", e1, e0) 33 } 34 return nil 35 } 36 37 func TestVersionEditRoundTrip(t *testing.T) { 38 testCases := []VersionEdit{ 39 // An empty version edit. 40 {}, 41 // A complete version edit. 42 { 43 ComparerName: "11", 44 LogNum: 22, 45 PrevLogNum: 33, 46 NextFileNum: 44, 47 LastSeqNum: 55, 48 DeletedFiles: map[DeletedFileEntry]bool{ 49 DeletedFileEntry{ 50 Level: 3, 51 FileNum: 703, 52 }: true, 53 DeletedFileEntry{ 54 Level: 4, 55 FileNum: 704, 56 }: true, 57 }, 58 NewFiles: []NewFileEntry{ 59 { 60 Level: 5, 61 Meta: FileMetadata{ 62 FileNum: 805, 63 Size: 8050, 64 Smallest: base.DecodeInternalKey([]byte("abc\x00\x01\x02\x03\x04\x05\x06\x07")), 65 Largest: base.DecodeInternalKey([]byte("xyz\x01\xff\xfe\xfd\xfc\xfb\xfa\xf9")), 66 }, 67 }, 68 { 69 Level: 6, 70 Meta: FileMetadata{ 71 FileNum: 806, 72 Size: 8060, 73 Smallest: base.DecodeInternalKey([]byte("A\x00\x01\x02\x03\x04\x05\x06\x07")), 74 Largest: base.DecodeInternalKey([]byte("Z\x01\xff\xfe\xfd\xfc\xfb\xfa\xf9")), 75 SmallestSeqNum: 3, 76 LargestSeqNum: 5, 77 MarkedForCompaction: true, 78 }, 79 }, 80 }, 81 }, 82 } 83 for _, tc := range testCases { 84 if err := checkRoundTrip(tc); err != nil { 85 t.Error(err) 86 } 87 } 88 } 89 90 func TestVersionEditDecode(t *testing.T) { 91 testCases := []struct { 92 filename string 93 encodedEdits []string 94 edits []VersionEdit 95 }{ 96 // db-stage-1 and db-stage-2 have the same manifest. 97 { 98 filename: "db-stage-1/MANIFEST-000001", 99 encodedEdits: []string{ 100 "\x02\x00\x03\x02\x04\x00", 101 }, 102 edits: []VersionEdit{ 103 { 104 NextFileNum: 2, 105 }, 106 }, 107 }, 108 // db-stage-3 and db-stage-4 have the same manifest. 109 { 110 filename: "db-stage-3/MANIFEST-000005", 111 encodedEdits: []string{ 112 "\x01\x1aleveldb.BytewiseComparator", 113 "\x02\x00", 114 "\x02\x04\t\x00\x03\x06\x04\x05d\x00\x04\xda\a\vbar" + 115 "\x00\x05\x00\x00\x00\x00\x00\x00\vfoo\x01\x04\x00" + 116 "\x00\x00\x00\x00\x00\x03\x05", 117 }, 118 edits: []VersionEdit{ 119 { 120 ComparerName: "leveldb.BytewiseComparator", 121 }, 122 {}, 123 { 124 LogNum: 4, 125 PrevLogNum: 0, 126 NextFileNum: 6, 127 LastSeqNum: 5, 128 NewFiles: []NewFileEntry{ 129 { 130 Level: 0, 131 Meta: FileMetadata{ 132 FileNum: 4, 133 Size: 986, 134 Smallest: base.MakeInternalKey([]byte("bar"), 5, base.InternalKeyKindDelete), 135 Largest: base.MakeInternalKey([]byte("foo"), 4, base.InternalKeyKindSet), 136 SmallestSeqNum: 3, 137 LargestSeqNum: 5, 138 }, 139 }, 140 }, 141 }, 142 }, 143 }, 144 } 145 146 for _, tc := range testCases { 147 t.Run("", func(t *testing.T) { 148 f, err := os.Open("../../testdata/" + tc.filename) 149 if err != nil { 150 t.Fatalf("filename=%q: open error: %v", tc.filename, err) 151 } 152 defer f.Close() 153 i, r := 0, record.NewReader(f, 0 /* logNum */) 154 for { 155 rr, err := r.Next() 156 if err == io.EOF { 157 break 158 } 159 if err != nil { 160 t.Fatalf("filename=%q i=%d: record reader error: %v", tc.filename, i, err) 161 } 162 if i >= len(tc.edits) { 163 t.Fatalf("filename=%q i=%d: too many version edits", tc.filename, i+1) 164 } 165 166 encodedEdit, err := ioutil.ReadAll(rr) 167 if err != nil { 168 t.Fatalf("filename=%q i=%d: read error: %v", tc.filename, i, err) 169 } 170 if s := string(encodedEdit); s != tc.encodedEdits[i] { 171 t.Fatalf("filename=%q i=%d: got encoded %q, want %q", tc.filename, i, s, tc.encodedEdits[i]) 172 } 173 174 var edit VersionEdit 175 err = edit.Decode(bytes.NewReader(encodedEdit)) 176 if err != nil { 177 t.Fatalf("filename=%q i=%d: decode error: %v", tc.filename, i, err) 178 } 179 if !reflect.DeepEqual(edit, tc.edits[i]) { 180 t.Fatalf("filename=%q i=%d: decode\n\tgot %#v\n\twant %#v\n%s", tc.filename, i, edit, tc.edits[i], 181 strings.Join(pretty.Diff(edit, tc.edits[i]), "\n")) 182 } 183 if err := checkRoundTrip(edit); err != nil { 184 t.Fatalf("filename=%q i=%d: round trip: %v", tc.filename, i, err) 185 } 186 187 i++ 188 } 189 if i != len(tc.edits) { 190 t.Fatalf("filename=%q: got %d edits, want %d", tc.filename, i, len(tc.edits)) 191 } 192 }) 193 } 194 }