github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/mem_table_test.go (about) 1 // Copyright 2011 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 pebble 6 7 import ( 8 "bytes" 9 "context" 10 "fmt" 11 "strconv" 12 "strings" 13 "sync/atomic" 14 "testing" 15 "time" 16 17 "github.com/cockroachdb/datadriven" 18 "github.com/cockroachdb/errors" 19 "github.com/cockroachdb/pebble/internal/arenaskl" 20 "github.com/cockroachdb/pebble/internal/base" 21 "github.com/cockroachdb/pebble/internal/itertest" 22 "github.com/cockroachdb/pebble/internal/rangekey" 23 "github.com/stretchr/testify/require" 24 "golang.org/x/exp/rand" 25 "golang.org/x/sync/errgroup" 26 ) 27 28 // get gets the value for the given key. It returns ErrNotFound if the DB does 29 // not contain the key. 30 func (m *memTable) get(key []byte) (value []byte, err error) { 31 it := m.skl.NewIter(nil, nil) 32 ikey, val := it.SeekGE(key, base.SeekGEFlagsNone) 33 if ikey == nil { 34 return nil, ErrNotFound 35 } 36 if !m.equal(key, ikey.UserKey) { 37 return nil, ErrNotFound 38 } 39 switch ikey.Kind() { 40 case InternalKeyKindDelete, InternalKeyKindSingleDelete, InternalKeyKindDeleteSized: 41 return nil, ErrNotFound 42 default: 43 return val.InPlaceValue(), nil 44 } 45 } 46 47 // Set sets the value for the given key. It overwrites any previous value for 48 // that key; a DB is not a multi-map. NB: this might have unexpected 49 // interaction with prepare/apply. Caveat emptor! 50 func (m *memTable) set(key InternalKey, value []byte) error { 51 if key.Kind() == InternalKeyKindRangeDelete { 52 if err := m.rangeDelSkl.Add(key, value); err != nil { 53 return err 54 } 55 m.tombstones.invalidate(1) 56 return nil 57 } 58 if rangekey.IsRangeKey(key.Kind()) { 59 if err := m.rangeKeySkl.Add(key, value); err != nil { 60 return err 61 } 62 m.rangeKeys.invalidate(1) 63 return nil 64 } 65 return m.skl.Add(key, value) 66 } 67 68 // count returns the number of entries in a DB. 69 func (m *memTable) count() (n int) { 70 x := newInternalIterAdapter(m.newIter(nil)) 71 for valid := x.First(); valid; valid = x.Next() { 72 n++ 73 } 74 if x.Close() != nil { 75 return -1 76 } 77 return n 78 } 79 80 // bytesIterated returns the number of bytes iterated in a DB. 81 func (m *memTable) bytesIterated(t *testing.T) (bytesIterated uint64) { 82 x := newInternalIterAdapter(m.newFlushIter(nil, &bytesIterated)) 83 var prevIterated uint64 84 for valid := x.First(); valid; valid = x.Next() { 85 if bytesIterated < prevIterated { 86 t.Fatalf("bytesIterated moved backward: %d < %d", bytesIterated, prevIterated) 87 } 88 prevIterated = bytesIterated 89 } 90 if x.Close() != nil { 91 return 0 92 } 93 return bytesIterated 94 } 95 96 func ikey(s string) InternalKey { 97 return base.MakeInternalKey([]byte(s), 0, InternalKeyKindSet) 98 } 99 100 func TestMemTableBasic(t *testing.T) { 101 // Check the empty DB. 102 m := newMemTable(memTableOptions{}) 103 if got, want := m.count(), 0; got != want { 104 t.Fatalf("0.count: got %v, want %v", got, want) 105 } 106 v, err := m.get([]byte("cherry")) 107 if string(v) != "" || err != ErrNotFound { 108 t.Fatalf("1.get: got (%q, %v), want (%q, %v)", v, err, "", ErrNotFound) 109 } 110 // Add some key/value pairs. 111 m.set(ikey("cherry"), []byte("red")) 112 m.set(ikey("peach"), []byte("yellow")) 113 m.set(ikey("grape"), []byte("red")) 114 m.set(ikey("grape"), []byte("green")) 115 m.set(ikey("plum"), []byte("purple")) 116 if got, want := m.count(), 4; got != want { 117 t.Fatalf("2.count: got %v, want %v", got, want) 118 } 119 // Get keys that are and aren't in the DB. 120 v, err = m.get([]byte("plum")) 121 if string(v) != "purple" || err != nil { 122 t.Fatalf("6.get: got (%q, %v), want (%q, %v)", v, err, "purple", error(nil)) 123 } 124 v, err = m.get([]byte("lychee")) 125 if string(v) != "" || err != ErrNotFound { 126 t.Fatalf("7.get: got (%q, %v), want (%q, %v)", v, err, "", ErrNotFound) 127 } 128 // Check an iterator. 129 s, x := "", newInternalIterAdapter(m.newIter(nil)) 130 for valid := x.SeekGE([]byte("mango"), base.SeekGEFlagsNone); valid; valid = x.Next() { 131 s += fmt.Sprintf("%s/%s.", x.Key().UserKey, x.Value()) 132 } 133 if want := "peach/yellow.plum/purple."; s != want { 134 t.Fatalf("8.iter: got %q, want %q", s, want) 135 } 136 if err = x.Close(); err != nil { 137 t.Fatalf("9.close: %v", err) 138 } 139 // Check some more sets and deletes. 140 if err := m.set(ikey("apricot"), []byte("orange")); err != nil { 141 t.Fatalf("12.set: %v", err) 142 } 143 if got, want := m.count(), 5; got != want { 144 t.Fatalf("13.count: got %v, want %v", got, want) 145 } 146 } 147 148 func TestMemTableCount(t *testing.T) { 149 m := newMemTable(memTableOptions{}) 150 for i := 0; i < 200; i++ { 151 if j := m.count(); j != i { 152 t.Fatalf("count: got %d, want %d", j, i) 153 } 154 m.set(InternalKey{UserKey: []byte{byte(i)}}, nil) 155 } 156 } 157 158 func TestMemTableBytesIterated(t *testing.T) { 159 m := newMemTable(memTableOptions{}) 160 for i := 0; i < 200; i++ { 161 bytesIterated := m.bytesIterated(t) 162 expected := m.inuseBytes() 163 if bytesIterated != expected { 164 t.Fatalf("bytesIterated: got %d, want %d", bytesIterated, expected) 165 } 166 m.set(InternalKey{UserKey: []byte{byte(i)}}, nil) 167 } 168 } 169 170 func TestMemTableEmpty(t *testing.T) { 171 m := newMemTable(memTableOptions{}) 172 if !m.empty() { 173 t.Errorf("got !empty, want empty") 174 } 175 // Add one key/value pair with an empty key and empty value. 176 m.set(InternalKey{}, nil) 177 if m.empty() { 178 t.Errorf("got empty, want !empty") 179 } 180 } 181 182 func TestMemTable1000Entries(t *testing.T) { 183 // Initialize the DB. 184 const N = 1000 185 m0 := newMemTable(memTableOptions{}) 186 for i := 0; i < N; i++ { 187 k := ikey(strconv.Itoa(i)) 188 v := []byte(strings.Repeat("x", i)) 189 m0.set(k, v) 190 } 191 // Check the DB count. 192 if got, want := m0.count(), 1000; got != want { 193 t.Fatalf("count: got %v, want %v", got, want) 194 } 195 // Check random-access lookup. 196 r := rand.New(rand.NewSource(0)) 197 for i := 0; i < 3*N; i++ { 198 j := r.Intn(N) 199 k := []byte(strconv.Itoa(j)) 200 v, err := m0.get(k) 201 require.NoError(t, err) 202 if len(v) != cap(v) { 203 t.Fatalf("get: j=%d, got len(v)=%d, cap(v)=%d", j, len(v), cap(v)) 204 } 205 var c uint8 206 if len(v) != 0 { 207 c = v[0] 208 } else { 209 c = 'x' 210 } 211 if len(v) != j || c != 'x' { 212 t.Fatalf("get: j=%d, got len(v)=%d,c=%c, want %d,%c", j, len(v), c, j, 'x') 213 } 214 } 215 // Check that iterating through the middle of the DB looks OK. 216 // Keys are in lexicographic order, not numerical order. 217 // Multiples of 3 are not present. 218 wants := []string{ 219 "499", 220 "5", 221 "50", 222 "500", 223 "501", 224 "502", 225 "503", 226 "504", 227 "505", 228 "506", 229 "507", 230 } 231 x := newInternalIterAdapter(m0.newIter(nil)) 232 x.SeekGE([]byte(wants[0]), base.SeekGEFlagsNone) 233 for _, want := range wants { 234 if !x.Valid() { 235 t.Fatalf("iter: next failed, want=%q", want) 236 } 237 if got := string(x.Key().UserKey); got != want { 238 t.Fatalf("iter: got %q, want %q", got, want) 239 } 240 if k := x.Key().UserKey; len(k) != cap(k) { 241 t.Fatalf("iter: len(k)=%d, cap(k)=%d", len(k), cap(k)) 242 } 243 if v := x.Value(); len(v) != cap(v) { 244 t.Fatalf("iter: len(v)=%d, cap(v)=%d", len(v), cap(v)) 245 } 246 x.Next() 247 } 248 if err := x.Close(); err != nil { 249 t.Fatalf("close: %v", err) 250 } 251 } 252 253 func TestMemTableIter(t *testing.T) { 254 var mem *memTable 255 for _, testdata := range []string{ 256 "testdata/internal_iter_next", "testdata/internal_iter_bounds"} { 257 datadriven.RunTest(t, testdata, func(t *testing.T, d *datadriven.TestData) string { 258 switch d.Cmd { 259 case "define": 260 mem = newMemTable(memTableOptions{}) 261 for _, key := range strings.Split(d.Input, "\n") { 262 j := strings.Index(key, ":") 263 if err := mem.set(base.ParseInternalKey(key[:j]), []byte(key[j+1:])); err != nil { 264 return err.Error() 265 } 266 } 267 return "" 268 269 case "iter": 270 var options IterOptions 271 for _, arg := range d.CmdArgs { 272 switch arg.Key { 273 case "lower": 274 if len(arg.Vals) != 1 { 275 return fmt.Sprintf( 276 "%s expects at most 1 value for lower", d.Cmd) 277 } 278 options.LowerBound = []byte(arg.Vals[0]) 279 case "upper": 280 if len(arg.Vals) != 1 { 281 return fmt.Sprintf( 282 "%s expects at most 1 value for upper", d.Cmd) 283 } 284 options.UpperBound = []byte(arg.Vals[0]) 285 default: 286 return fmt.Sprintf("unknown arg: %s", arg.Key) 287 } 288 } 289 iter := mem.newIter(&options) 290 defer iter.Close() 291 return itertest.RunInternalIterCmd(t, d, iter) 292 293 default: 294 return fmt.Sprintf("unknown command: %s", d.Cmd) 295 } 296 }) 297 } 298 } 299 300 func TestMemTableDeleteRange(t *testing.T) { 301 var mem *memTable 302 var seqNum uint64 303 304 datadriven.RunTest(t, "testdata/delete_range", func(t *testing.T, td *datadriven.TestData) string { 305 switch td.Cmd { 306 case "clear": 307 mem = nil 308 seqNum = 0 309 return "" 310 311 case "define": 312 b := newBatch(nil) 313 if err := runBatchDefineCmd(td, b); err != nil { 314 return err.Error() 315 } 316 if mem == nil { 317 mem = newMemTable(memTableOptions{}) 318 } 319 if err := mem.apply(b, seqNum); err != nil { 320 return err.Error() 321 } 322 seqNum += uint64(b.Count()) 323 return "" 324 325 case "scan": 326 var buf bytes.Buffer 327 if td.HasArg("range-del") { 328 iter := mem.newRangeDelIter(nil) 329 defer iter.Close() 330 scanKeyspanIterator(&buf, iter) 331 } else { 332 iter := mem.newIter(nil) 333 defer iter.Close() 334 scanInternalIter(&buf, iter) 335 } 336 return buf.String() 337 338 default: 339 return fmt.Sprintf("unknown command: %s", td.Cmd) 340 } 341 }) 342 } 343 344 func TestMemTableConcurrentDeleteRange(t *testing.T) { 345 // Concurrently write and read range tombstones. Workers add range 346 // tombstones, and then immediately retrieve them verifying that the 347 // tombstones they've added are all present. 348 349 m := newMemTable(memTableOptions{Options: &Options{MemTableSize: 64 << 20}}) 350 351 const workers = 10 352 eg, _ := errgroup.WithContext(context.Background()) 353 var seqNum atomic.Uint64 354 seqNum.Store(1) 355 for i := 0; i < workers; i++ { 356 i := i 357 eg.Go(func() error { 358 start := ([]byte)(fmt.Sprintf("%03d", i)) 359 end := ([]byte)(fmt.Sprintf("%03d", i+1)) 360 for j := 0; j < 100; j++ { 361 b := newBatch(nil) 362 b.DeleteRange(start, end, nil) 363 n := seqNum.Add(1) - 1 364 require.NoError(t, m.apply(b, n)) 365 b.release() 366 367 var count int 368 it := m.newRangeDelIter(nil) 369 for s := it.SeekGE(start); s != nil; s = it.Next() { 370 if m.cmp(s.Start, end) >= 0 { 371 break 372 } 373 count += len(s.Keys) 374 } 375 if j+1 != count { 376 return errors.Errorf("%d: expected %d tombstones, but found %d", i, j+1, count) 377 } 378 } 379 return nil 380 }) 381 } 382 err := eg.Wait() 383 if err != nil { 384 t.Error(err) 385 } 386 } 387 388 func TestMemTableReserved(t *testing.T) { 389 m := newMemTable(memTableOptions{size: 5000}) 390 // Increase to 2 references. 391 m.writerRef() 392 // The initial reservation accounts for the already allocated bytes from the 393 // arena. 394 require.Equal(t, m.reserved, m.skl.Arena().Size()) 395 b := newBatch(nil) 396 b.Set([]byte("blueberry"), []byte("pie"), nil) 397 require.NotEqual(t, 0, int(b.memTableSize)) 398 prevReserved := m.reserved 399 m.prepare(b) 400 require.Equal(t, int(m.reserved), int(b.memTableSize)+int(prevReserved)) 401 } 402 403 func buildMemTable(b *testing.B) (*memTable, [][]byte) { 404 m := newMemTable(memTableOptions{}) 405 var keys [][]byte 406 var ikey InternalKey 407 for i := 0; ; i++ { 408 key := []byte(fmt.Sprintf("%08d", i)) 409 keys = append(keys, key) 410 ikey = base.MakeInternalKey(key, 0, InternalKeyKindSet) 411 if m.set(ikey, nil) == arenaskl.ErrArenaFull { 412 break 413 } 414 } 415 return m, keys 416 } 417 418 func BenchmarkMemTableIterSeekGE(b *testing.B) { 419 m, keys := buildMemTable(b) 420 iter := m.newIter(nil) 421 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 422 423 b.ResetTimer() 424 for i := 0; i < b.N; i++ { 425 iter.SeekGE(keys[rng.Intn(len(keys))], base.SeekGEFlagsNone) 426 } 427 } 428 429 func BenchmarkMemTableIterNext(b *testing.B) { 430 m, _ := buildMemTable(b) 431 iter := m.newIter(nil) 432 _, _ = iter.First() 433 b.ResetTimer() 434 for i := 0; i < b.N; i++ { 435 key, _ := iter.Next() 436 if key == nil { 437 key, _ = iter.First() 438 } 439 _ = key 440 } 441 } 442 443 func BenchmarkMemTableIterPrev(b *testing.B) { 444 m, _ := buildMemTable(b) 445 iter := m.newIter(nil) 446 _, _ = iter.Last() 447 b.ResetTimer() 448 for i := 0; i < b.N; i++ { 449 key, _ := iter.Prev() 450 if key == nil { 451 key, _ = iter.Last() 452 } 453 _ = key 454 } 455 }