github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/sstable/block_test.go (about) 1 // Copyright 2018 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 sstable 6 7 import ( 8 "bytes" 9 "fmt" 10 "strconv" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/petermattis/pebble/internal/base" 16 "github.com/petermattis/pebble/internal/datadriven" 17 "github.com/stretchr/testify/require" 18 "golang.org/x/exp/rand" 19 ) 20 21 func TestBlockWriter(t *testing.T) { 22 ikey := func(s string) InternalKey { 23 return InternalKey{UserKey: []byte(s)} 24 } 25 26 w := &rawBlockWriter{ 27 blockWriter: blockWriter{restartInterval: 16}, 28 } 29 w.add(ikey("apple"), nil) 30 w.add(ikey("apricot"), nil) 31 w.add(ikey("banana"), nil) 32 block := w.finish() 33 34 expected := []byte( 35 "\x00\x05\x00apple" + 36 "\x02\x05\x00ricot" + 37 "\x00\x06\x00banana" + 38 "\x00\x00\x00\x00\x01\x00\x00\x00") 39 if !bytes.Equal(expected, block) { 40 t.Fatalf("expected\n%q\nfound\n%q", expected, block) 41 } 42 } 43 44 func TestBlockIter(t *testing.T) { 45 // k is a block that maps three keys "apple", "apricot", "banana" to empty strings. 46 k := block([]byte( 47 "\x00\x05\x00apple" + 48 "\x02\x05\x00ricot" + 49 "\x00\x06\x00banana" + 50 "\x00\x00\x00\x00\x01\x00\x00\x00")) 51 var testcases = []struct { 52 index int 53 key string 54 }{ 55 {0, ""}, 56 {0, "a"}, 57 {0, "aaaaaaaaaaaaaaa"}, 58 {0, "app"}, 59 {0, "apple"}, 60 {1, "appliance"}, 61 {1, "apricos"}, 62 {1, "apricot"}, 63 {2, "azzzzzzzzzzzzzz"}, 64 {2, "b"}, 65 {2, "banan"}, 66 {2, "banana"}, 67 {3, "banana\x00"}, 68 {3, "c"}, 69 } 70 for _, tc := range testcases { 71 i, err := newRawBlockIter(bytes.Compare, k) 72 if err != nil { 73 t.Fatal(err) 74 } 75 i.SeekGE([]byte(tc.key)) 76 for j, kWant := range []string{"apple", "apricot", "banana"}[tc.index:] { 77 if !i.Valid() { 78 t.Fatalf("key=%q, index=%d, j=%d: Valid got false, want true", tc.key, tc.index, j) 79 } 80 if kGot := string(i.Key().UserKey); kGot != kWant { 81 t.Fatalf("key=%q, index=%d, j=%d: got %q, want %q", tc.key, tc.index, j, kGot, kWant) 82 } 83 i.Next() 84 } 85 if i.Valid() { 86 t.Fatalf("key=%q, index=%d: Valid got true, want false", tc.key, tc.index) 87 } 88 if err := i.Close(); err != nil { 89 t.Fatalf("key=%q, index=%d: got err=%v", tc.key, tc.index, err) 90 } 91 } 92 93 { 94 i, err := newRawBlockIter(bytes.Compare, k) 95 if err != nil { 96 t.Fatal(err) 97 } 98 i.Last() 99 for j, kWant := range []string{"banana", "apricot", "apple"} { 100 if !i.Valid() { 101 t.Fatalf("j=%d: Valid got false, want true", j) 102 } 103 if kGot := string(i.Key().UserKey); kGot != kWant { 104 t.Fatalf("j=%d: got %q, want %q", j, kGot, kWant) 105 } 106 i.Prev() 107 } 108 if i.Valid() { 109 t.Fatalf("Valid got true, want false") 110 } 111 if err := i.Close(); err != nil { 112 t.Fatalf("got err=%v", err) 113 } 114 } 115 } 116 117 func TestBlockIter2(t *testing.T) { 118 makeIkey := func(s string) InternalKey { 119 j := strings.Index(s, ":") 120 seqNum, err := strconv.Atoi(s[j+1:]) 121 if err != nil { 122 panic(err) 123 } 124 return base.MakeInternalKey([]byte(s[:j]), uint64(seqNum), InternalKeyKindSet) 125 } 126 127 var block []byte 128 129 for _, r := range []int{1, 2, 3, 4} { 130 t.Run(fmt.Sprintf("restart=%d", r), func(t *testing.T) { 131 datadriven.RunTest(t, "testdata/block", func(d *datadriven.TestData) string { 132 switch d.Cmd { 133 case "build": 134 w := &blockWriter{restartInterval: r} 135 for _, e := range strings.Split(strings.TrimSpace(d.Input), ",") { 136 w.add(makeIkey(e), nil) 137 } 138 block = w.finish() 139 return "" 140 141 case "iter": 142 iter, err := newBlockIter(bytes.Compare, block) 143 if err != nil { 144 return err.Error() 145 } 146 147 for _, arg := range d.CmdArgs { 148 switch arg.Key { 149 case "globalSeqNum": 150 if len(arg.Vals) != 1 { 151 return fmt.Sprintf("%s: arg %s expects 1 value", d.Cmd, arg.Key) 152 } 153 v, err := strconv.Atoi(arg.Vals[0]) 154 if err != nil { 155 return err.Error() 156 } 157 iter.globalSeqNum = uint64(v) 158 default: 159 return fmt.Sprintf("%s: unknown arg: %s", d.Cmd, arg.Key) 160 } 161 } 162 163 var b bytes.Buffer 164 for _, line := range strings.Split(d.Input, "\n") { 165 parts := strings.Fields(line) 166 if len(parts) == 0 { 167 continue 168 } 169 switch parts[0] { 170 case "seek-ge": 171 if len(parts) != 2 { 172 return fmt.Sprintf("seek-ge <key>\n") 173 } 174 iter.SeekGE([]byte(strings.TrimSpace(parts[1]))) 175 case "seek-lt": 176 if len(parts) != 2 { 177 return fmt.Sprintf("seek-lt <key>\n") 178 } 179 iter.SeekLT([]byte(strings.TrimSpace(parts[1]))) 180 case "first": 181 iter.First() 182 case "last": 183 iter.Last() 184 case "next": 185 iter.Next() 186 case "prev": 187 iter.Prev() 188 } 189 if iter.Valid() { 190 fmt.Fprintf(&b, "<%s:%d>", iter.Key().UserKey, iter.Key().SeqNum()) 191 } else if err := iter.Error(); err != nil { 192 fmt.Fprintf(&b, "<err=%v>", err) 193 } else { 194 fmt.Fprintf(&b, ".") 195 } 196 } 197 b.WriteString("\n") 198 return b.String() 199 200 default: 201 return fmt.Sprintf("unknown command: %s", d.Cmd) 202 } 203 }) 204 }) 205 } 206 } 207 208 func TestBlockIterKeyStability(t *testing.T) { 209 w := &blockWriter{restartInterval: 1} 210 expected := [][]byte{ 211 []byte("apple"), 212 []byte("apricot"), 213 []byte("banana"), 214 } 215 for i := range expected { 216 w.add(InternalKey{UserKey: expected[i]}, nil) 217 } 218 block := w.finish() 219 220 i, err := newBlockIter(bytes.Compare, block) 221 if err != nil { 222 t.Fatal(err) 223 } 224 // Loop over the block entries, storing each key slice. 225 var keys [][]byte 226 for key, _ := i.First(); key != nil; key, _ = i.Next() { 227 keys = append(keys, key.UserKey) 228 } 229 230 // Check that the slices match our expected values. Note that this is only 231 // guaranteed because of the usage of a restart-interval of 1 so that prefix 232 // compression was not performed. 233 require.EqualValues(t, expected, keys) 234 } 235 236 func BenchmarkBlockIterSeekGE(b *testing.B) { 237 const blockSize = 32 << 10 238 239 for _, restartInterval := range []int{16} { 240 b.Run(fmt.Sprintf("restart=%d", restartInterval), 241 func(b *testing.B) { 242 w := &blockWriter{ 243 restartInterval: restartInterval, 244 } 245 246 var ikey InternalKey 247 var keys [][]byte 248 for i := 0; w.estimatedSize() < blockSize; i++ { 249 key := []byte(fmt.Sprintf("%05d", i)) 250 keys = append(keys, key) 251 ikey.UserKey = key 252 w.add(ikey, nil) 253 } 254 255 it, err := newBlockIter(bytes.Compare, w.finish()) 256 if err != nil { 257 b.Fatal(err) 258 } 259 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 260 261 b.ResetTimer() 262 for i := 0; i < b.N; i++ { 263 k := keys[rng.Intn(len(keys))] 264 it.SeekGE(k) 265 if testing.Verbose() { 266 if !it.Valid() { 267 b.Fatal("expected to find key") 268 } 269 if !bytes.Equal(k, it.Key().UserKey) { 270 b.Fatalf("expected %s, but found %s", k, it.Key().UserKey) 271 } 272 } 273 } 274 }) 275 } 276 } 277 278 func BenchmarkBlockIterSeekLT(b *testing.B) { 279 const blockSize = 32 << 10 280 281 for _, restartInterval := range []int{16} { 282 b.Run(fmt.Sprintf("restart=%d", restartInterval), 283 func(b *testing.B) { 284 w := &blockWriter{ 285 restartInterval: restartInterval, 286 } 287 288 var ikey InternalKey 289 var keys [][]byte 290 for i := 0; w.estimatedSize() < blockSize; i++ { 291 key := []byte(fmt.Sprintf("%05d", i)) 292 keys = append(keys, key) 293 ikey.UserKey = key 294 w.add(ikey, nil) 295 } 296 297 it, err := newBlockIter(bytes.Compare, w.finish()) 298 if err != nil { 299 b.Fatal(err) 300 } 301 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 302 303 b.ResetTimer() 304 for i := 0; i < b.N; i++ { 305 j := rng.Intn(len(keys)) 306 it.SeekLT(keys[j]) 307 if testing.Verbose() { 308 if j == 0 { 309 if it.Valid() { 310 b.Fatal("unexpected key") 311 } 312 } else { 313 if !it.Valid() { 314 b.Fatal("expected to find key") 315 } 316 k := keys[j-1] 317 if !bytes.Equal(k, it.Key().UserKey) { 318 b.Fatalf("expected %s, but found %s", k, it.Key().UserKey) 319 } 320 } 321 } 322 } 323 }) 324 } 325 } 326 327 func BenchmarkBlockIterNext(b *testing.B) { 328 const blockSize = 32 << 10 329 330 for _, restartInterval := range []int{16} { 331 b.Run(fmt.Sprintf("restart=%d", restartInterval), 332 func(b *testing.B) { 333 w := &blockWriter{ 334 restartInterval: restartInterval, 335 } 336 337 var ikey InternalKey 338 for i := 0; w.estimatedSize() < blockSize; i++ { 339 ikey.UserKey = []byte(fmt.Sprintf("%05d", i)) 340 w.add(ikey, nil) 341 } 342 343 it, err := newBlockIter(bytes.Compare, w.finish()) 344 if err != nil { 345 b.Fatal(err) 346 } 347 348 b.ResetTimer() 349 for i := 0; i < b.N; i++ { 350 if !it.Valid() { 351 it.First() 352 } 353 it.Next() 354 } 355 }) 356 } 357 } 358 359 func BenchmarkBlockIterPrev(b *testing.B) { 360 const blockSize = 32 << 10 361 362 for _, restartInterval := range []int{16} { 363 b.Run(fmt.Sprintf("restart=%d", restartInterval), 364 func(b *testing.B) { 365 w := &blockWriter{ 366 restartInterval: restartInterval, 367 } 368 369 var ikey InternalKey 370 for i := 0; w.estimatedSize() < blockSize; i++ { 371 ikey.UserKey = []byte(fmt.Sprintf("%05d", i)) 372 w.add(ikey, nil) 373 } 374 375 it, err := newBlockIter(bytes.Compare, w.finish()) 376 if err != nil { 377 b.Fatal(err) 378 } 379 380 b.ResetTimer() 381 for i := 0; i < b.N; i++ { 382 if !it.Valid() { 383 it.Last() 384 } 385 it.Prev() 386 } 387 }) 388 } 389 }