github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/internal/batchskl/skl_test.go (about) 1 /* 2 * Copyright 2017 Dgraph Labs, Inc. and Contributors 3 * Modifications copyright (C) 2017 Andy Kimball and Contributors 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package batchskl 19 20 import ( 21 "bytes" 22 "encoding/binary" 23 "fmt" 24 "testing" 25 "time" 26 27 "github.com/cockroachdb/errors" 28 "github.com/cockroachdb/pebble/internal/base" 29 "github.com/stretchr/testify/require" 30 "golang.org/x/exp/rand" 31 ) 32 33 // iterAdapter adapts the new Iterator API which returns the key and value from 34 // positioning methods (Seek*, First, Last, Next, Prev) to the old API which 35 // returned a boolean corresponding to Valid. Only used by test code. 36 type iterAdapter struct { 37 Iterator 38 } 39 40 func (i *iterAdapter) verify(key *base.InternalKey) bool { 41 valid := key != nil 42 if valid != i.Valid() { 43 panic(fmt.Sprintf("inconsistent valid: %t != %t", valid, i.Valid())) 44 } 45 if valid { 46 if base.InternalCompare(bytes.Compare, *key, i.Key()) != 0 { 47 panic(fmt.Sprintf("inconsistent key: %s != %s", *key, i.Key())) 48 } 49 } 50 return valid 51 } 52 53 func (i *iterAdapter) SeekGE(key []byte) bool { 54 return i.verify(i.Iterator.SeekGE(key, base.SeekGEFlagsNone)) 55 } 56 57 func (i *iterAdapter) SeekLT(key []byte) bool { 58 return i.verify(i.Iterator.SeekLT(key)) 59 } 60 61 func (i *iterAdapter) First() bool { 62 return i.verify(i.Iterator.First()) 63 } 64 65 func (i *iterAdapter) Last() bool { 66 return i.verify(i.Iterator.Last()) 67 } 68 69 func (i *iterAdapter) Next() bool { 70 return i.verify(i.Iterator.Next()) 71 } 72 73 func (i *iterAdapter) Prev() bool { 74 return i.verify(i.Iterator.Prev()) 75 } 76 77 func (i *iterAdapter) Key() base.InternalKey { 78 return *i.Iterator.Key() 79 } 80 81 // length iterates over skiplist to give exact size. 82 func length(s *Skiplist) int { 83 count := 0 84 85 it := iterAdapter{s.NewIter(nil, nil)} 86 for valid := it.First(); valid; valid = it.Next() { 87 count++ 88 } 89 90 return count 91 } 92 93 // length iterates over skiplist in reverse order to give exact size. 94 func lengthRev(s *Skiplist) int { 95 count := 0 96 97 it := iterAdapter{s.NewIter(nil, nil)} 98 for valid := it.Last(); valid; valid = it.Prev() { 99 count++ 100 } 101 102 return count 103 } 104 105 func makeKey(s string) []byte { 106 return []byte(s) 107 } 108 109 type testStorage struct { 110 data []byte 111 } 112 113 func (d *testStorage) add(key string) uint32 { 114 offset := uint32(len(d.data)) 115 d.data = append(d.data, uint8(base.InternalKeyKindSet)) 116 var buf [binary.MaxVarintLen64]byte 117 n := binary.PutUvarint(buf[:], uint64(len(key))) 118 d.data = append(d.data, buf[:n]...) 119 d.data = append(d.data, key...) 120 return offset 121 } 122 123 func (d *testStorage) addBytes(key []byte) uint32 { 124 offset := uint32(len(d.data)) 125 d.data = append(d.data, uint8(base.InternalKeyKindSet)) 126 var buf [binary.MaxVarintLen64]byte 127 n := binary.PutUvarint(buf[:], uint64(len(key))) 128 d.data = append(d.data, buf[:n]...) 129 d.data = append(d.data, key...) 130 return offset 131 } 132 133 func newTestSkiplist(storage *testStorage) *Skiplist { 134 return NewSkiplist(&storage.data, base.DefaultComparer.Compare, 135 base.DefaultComparer.AbbreviatedKey) 136 } 137 138 func TestEmpty(t *testing.T) { 139 key := makeKey("aaa") 140 l := newTestSkiplist(&testStorage{}) 141 it := iterAdapter{l.NewIter(nil, nil)} 142 143 require.False(t, it.Valid()) 144 145 it.First() 146 require.False(t, it.Valid()) 147 148 it.Last() 149 require.False(t, it.Valid()) 150 151 require.False(t, it.SeekGE(key)) 152 require.False(t, it.Valid()) 153 } 154 155 // TestBasic tests seeks and adds. 156 func TestBasic(t *testing.T) { 157 d := &testStorage{} 158 l := newTestSkiplist(d) 159 it := iterAdapter{l.NewIter(nil, nil)} 160 161 // Try adding values. 162 require.Nil(t, l.Add(d.add("key1"))) 163 require.Nil(t, l.Add(d.add("key2"))) 164 require.Nil(t, l.Add(d.add("key3"))) 165 166 require.True(t, it.SeekGE(makeKey("key"))) 167 require.EqualValues(t, "key1", it.Key().UserKey) 168 169 require.True(t, it.SeekGE(makeKey("key1"))) 170 require.EqualValues(t, "key1", it.Key().UserKey) 171 172 require.True(t, it.SeekGE(makeKey("key2"))) 173 require.EqualValues(t, "key2", it.Key().UserKey) 174 175 require.True(t, it.SeekGE(makeKey("key3"))) 176 require.EqualValues(t, "key3", it.Key().UserKey) 177 178 require.True(t, it.SeekGE(makeKey("key2"))) 179 require.True(t, it.SeekGE(makeKey("key3"))) 180 } 181 182 func TestSkiplistAdd(t *testing.T) { 183 d := &testStorage{} 184 l := newTestSkiplist(d) 185 it := iterAdapter{l.NewIter(nil, nil)} 186 187 // Add empty key. 188 require.Nil(t, l.Add(d.add(""))) 189 require.EqualValues(t, []byte(nil), it.Key().UserKey) 190 require.True(t, it.First()) 191 require.EqualValues(t, []byte{}, it.Key().UserKey) 192 193 // Add to empty list. 194 require.Nil(t, l.Add(d.add("00002"))) 195 require.True(t, it.SeekGE(makeKey("00002"))) 196 require.EqualValues(t, "00002", it.Key().UserKey) 197 198 // Add first element in non-empty list. 199 require.Nil(t, l.Add(d.add("00001"))) 200 require.True(t, it.SeekGE(makeKey("00001"))) 201 require.EqualValues(t, "00001", it.Key().UserKey) 202 203 // Add last element in non-empty list. 204 require.Nil(t, l.Add(d.add("00004"))) 205 require.True(t, it.SeekGE(makeKey("00004"))) 206 require.EqualValues(t, "00004", it.Key().UserKey) 207 208 // Add element in middle of list. 209 require.Nil(t, l.Add(d.add("00003"))) 210 require.True(t, it.SeekGE(makeKey("00003"))) 211 require.EqualValues(t, "00003", it.Key().UserKey) 212 213 // Try to add element that already exists. 214 require.Nil(t, l.Add(d.add("00002"))) 215 require.Equal(t, 6, length(l)) 216 require.Equal(t, 6, lengthRev(l)) 217 } 218 219 func TestSkiplistAdd_Overflow(t *testing.T) { 220 // Regression test for cockroachdb/pebble#1258. The length of the nodes buffer 221 // cannot exceed the maximum allowable size. 222 d := &testStorage{} 223 l := newTestSkiplist(d) 224 225 // Simulate a full nodes slice. This speeds up the test significantly, as 226 // opposed to adding data to the list. 227 l.nodes = make([]byte, maxNodesSize) 228 229 // Adding a new node to the list would overflow the nodes slice. Note that it 230 // is the size of a new node struct that is relevant here, rather than the 231 // size of the data being added to the list. 232 err := l.Add(d.add("too much!")) 233 require.Error(t, err) 234 require.True(t, errors.Is(err, ErrTooManyRecords)) 235 } 236 237 // TestIteratorNext tests a basic iteration over all nodes from the beginning. 238 func TestIteratorNext(t *testing.T) { 239 const n = 100 240 d := &testStorage{} 241 l := newTestSkiplist(d) 242 it := iterAdapter{l.NewIter(nil, nil)} 243 244 require.False(t, it.Valid()) 245 246 it.First() 247 require.False(t, it.Valid()) 248 249 for i := n - 1; i >= 0; i-- { 250 require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i)))) 251 } 252 253 it.First() 254 for i := 0; i < n; i++ { 255 require.True(t, it.Valid()) 256 require.EqualValues(t, fmt.Sprintf("%05d", i), it.Key().UserKey) 257 it.Next() 258 } 259 require.False(t, it.Valid()) 260 } 261 262 // // TestIteratorPrev tests a basic iteration over all nodes from the end. 263 func TestIteratorPrev(t *testing.T) { 264 const n = 100 265 d := &testStorage{} 266 l := newTestSkiplist(d) 267 it := iterAdapter{l.NewIter(nil, nil)} 268 269 require.False(t, it.Valid()) 270 271 it.Last() 272 require.False(t, it.Valid()) 273 274 for i := 0; i < n; i++ { 275 l.Add(d.add(fmt.Sprintf("%05d", i))) 276 } 277 278 it.Last() 279 for i := n - 1; i >= 0; i-- { 280 require.True(t, it.Valid()) 281 require.EqualValues(t, fmt.Sprintf("%05d", i), string(it.Key().UserKey)) 282 it.Prev() 283 } 284 require.False(t, it.Valid()) 285 } 286 287 func TestIteratorSeekGE(t *testing.T) { 288 const n = 1000 289 d := &testStorage{} 290 l := newTestSkiplist(d) 291 it := iterAdapter{l.NewIter(nil, nil)} 292 293 require.False(t, it.Valid()) 294 it.First() 295 require.False(t, it.Valid()) 296 // 1000, 1010, 1020, ..., 1990. 297 for i := n - 1; i >= 0; i-- { 298 require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i*10+1000)))) 299 } 300 301 require.True(t, it.SeekGE(makeKey(""))) 302 require.True(t, it.Valid()) 303 require.EqualValues(t, "01000", it.Key().UserKey) 304 305 require.True(t, it.SeekGE(makeKey("01000"))) 306 require.True(t, it.Valid()) 307 require.EqualValues(t, "01000", it.Key().UserKey) 308 309 require.True(t, it.SeekGE(makeKey("01005"))) 310 require.True(t, it.Valid()) 311 require.EqualValues(t, "01010", it.Key().UserKey) 312 313 require.True(t, it.SeekGE(makeKey("01010"))) 314 require.True(t, it.Valid()) 315 require.EqualValues(t, "01010", it.Key().UserKey) 316 317 require.False(t, it.SeekGE(makeKey("99999"))) 318 require.False(t, it.Valid()) 319 320 // Test seek for empty key. 321 require.Nil(t, l.Add(d.add(""))) 322 require.True(t, it.SeekGE([]byte{})) 323 require.True(t, it.Valid()) 324 325 require.True(t, it.SeekGE(makeKey(""))) 326 require.True(t, it.Valid()) 327 } 328 329 func TestIteratorSeekLT(t *testing.T) { 330 const n = 100 331 d := &testStorage{} 332 l := newTestSkiplist(d) 333 it := iterAdapter{l.NewIter(nil, nil)} 334 335 require.False(t, it.Valid()) 336 it.First() 337 require.False(t, it.Valid()) 338 // 1000, 1010, 1020, ..., 1990. 339 for i := n - 1; i >= 0; i-- { 340 require.Nil(t, l.Add(d.add(fmt.Sprintf("%05d", i*10+1000)))) 341 } 342 343 require.False(t, it.SeekLT(makeKey(""))) 344 require.False(t, it.Valid()) 345 346 require.False(t, it.SeekLT(makeKey("01000"))) 347 require.False(t, it.Valid()) 348 349 require.True(t, it.SeekLT(makeKey("01001"))) 350 require.EqualValues(t, "01000", it.Key().UserKey) 351 require.True(t, it.Valid()) 352 353 require.True(t, it.SeekLT(makeKey("01005"))) 354 require.EqualValues(t, "01000", it.Key().UserKey) 355 require.True(t, it.Valid()) 356 357 require.True(t, it.SeekLT(makeKey("01991"))) 358 require.EqualValues(t, "01990", it.Key().UserKey) 359 require.True(t, it.Valid()) 360 361 require.True(t, it.SeekLT(makeKey("99999"))) 362 require.True(t, it.Valid()) 363 require.EqualValues(t, "01990", it.Key().UserKey) 364 365 // Test seek for empty key. 366 require.Nil(t, l.Add(d.add(""))) 367 require.False(t, it.SeekLT([]byte{})) 368 require.False(t, it.Valid()) 369 require.True(t, it.SeekLT(makeKey("\x01"))) 370 require.True(t, it.Valid()) 371 require.EqualValues(t, "", it.Key().UserKey) 372 } 373 374 // TODO(peter): test First and Last. 375 func TestIteratorBounds(t *testing.T) { 376 d := &testStorage{} 377 l := newTestSkiplist(d) 378 for i := 1; i < 10; i++ { 379 require.NoError(t, l.Add(d.add(fmt.Sprintf("%05d", i)))) 380 } 381 382 it := iterAdapter{l.NewIter(makeKey("00003"), makeKey("00007"))} 383 384 // SeekGE within the lower and upper bound succeeds. 385 for i := 3; i <= 6; i++ { 386 key := makeKey(fmt.Sprintf("%05d", i)) 387 require.True(t, it.SeekGE(key)) 388 require.EqualValues(t, string(key), string(it.Key().UserKey)) 389 } 390 391 // SeekGE before the lower bound still succeeds (only the upper bound is 392 // checked). 393 for i := 1; i < 3; i++ { 394 key := makeKey(fmt.Sprintf("%05d", i)) 395 require.True(t, it.SeekGE(key)) 396 require.EqualValues(t, string(key), string(it.Key().UserKey)) 397 } 398 399 // SeekGE beyond the upper bound fails. 400 for i := 7; i < 10; i++ { 401 key := makeKey(fmt.Sprintf("%05d", i)) 402 require.False(t, it.SeekGE(key)) 403 } 404 405 require.True(t, it.SeekGE(makeKey("00006"))) 406 require.EqualValues(t, "00006", it.Key().UserKey) 407 408 // Next into the upper bound fails. 409 require.False(t, it.Next()) 410 411 // SeekLT within the lower and upper bound succeeds. 412 for i := 4; i <= 7; i++ { 413 key := makeKey(fmt.Sprintf("%05d", i)) 414 require.True(t, it.SeekLT(key)) 415 require.EqualValues(t, fmt.Sprintf("%05d", i-1), string(it.Key().UserKey)) 416 } 417 418 // SeekLT beyond the upper bound still succeeds (only the lower bound is 419 // checked). 420 for i := 8; i < 9; i++ { 421 key := makeKey(fmt.Sprintf("%05d", i)) 422 require.True(t, it.SeekLT(key)) 423 require.EqualValues(t, fmt.Sprintf("%05d", i-1), string(it.Key().UserKey)) 424 } 425 426 // SeekLT before the lower bound fails. 427 for i := 1; i < 4; i++ { 428 key := makeKey(fmt.Sprintf("%05d", i)) 429 require.False(t, it.SeekLT(key)) 430 } 431 432 require.True(t, it.SeekLT(makeKey("00004"))) 433 require.EqualValues(t, "00003", it.Key().UserKey) 434 435 // Prev into the lower bound fails. 436 require.False(t, it.Prev()) 437 } 438 439 func randomKey(rng *rand.Rand, b []byte) []byte { 440 key := rng.Uint32() 441 key2 := rng.Uint32() 442 binary.LittleEndian.PutUint32(b, key) 443 binary.LittleEndian.PutUint32(b[4:], key2) 444 return b 445 } 446 447 // Standard test. Some fraction is read. Some fraction is write. Writes have 448 // to go through mutex lock. 449 func BenchmarkReadWrite(b *testing.B) { 450 for i := 0; i <= 10; i++ { 451 readFrac := float32(i) / 10.0 452 b.Run(fmt.Sprintf("frac_%d", i*10), func(b *testing.B) { 453 var buf [8]byte 454 d := &testStorage{ 455 data: make([]byte, 0, b.N*10), 456 } 457 l := newTestSkiplist(d) 458 it := l.NewIter(nil, nil) 459 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 460 461 b.ResetTimer() 462 for i := 0; i < b.N; i++ { 463 key := randomKey(rng, buf[:]) 464 if rng.Float32() < readFrac { 465 _ = it.SeekGE(key, base.SeekGEFlagsNone) 466 } else { 467 offset := d.addBytes(buf[:]) 468 _ = l.Add(offset) 469 } 470 } 471 b.StopTimer() 472 }) 473 } 474 } 475 476 func BenchmarkOrderedWrite(b *testing.B) { 477 var buf [8]byte 478 d := &testStorage{ 479 data: make([]byte, 0, b.N*10), 480 } 481 l := newTestSkiplist(d) 482 483 b.ResetTimer() 484 for i := 0; i < b.N; i++ { 485 binary.BigEndian.PutUint64(buf[:], uint64(i)) 486 offset := d.addBytes(buf[:]) 487 _ = l.Add(offset) 488 } 489 } 490 491 func BenchmarkIterNext(b *testing.B) { 492 var buf [8]byte 493 d := &testStorage{ 494 data: make([]byte, 0, 64<<10), 495 } 496 l := newTestSkiplist(d) 497 498 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 499 for len(d.data)+20 < cap(d.data) { 500 key := randomKey(rng, buf[:]) 501 offset := d.addBytes(key) 502 err := l.Add(offset) 503 require.NoError(b, err) 504 } 505 506 it := l.NewIter(nil, nil) 507 b.ResetTimer() 508 for i := 0; i < b.N; i++ { 509 if !it.Valid() { 510 it.First() 511 } 512 it.Next() 513 } 514 } 515 516 func BenchmarkIterPrev(b *testing.B) { 517 var buf [8]byte 518 d := &testStorage{ 519 data: make([]byte, 0, 64<<10), 520 } 521 l := newTestSkiplist(d) 522 523 rng := rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) 524 for len(d.data)+20 < cap(d.data) { 525 key := randomKey(rng, buf[:]) 526 offset := d.addBytes(key) 527 err := l.Add(offset) 528 require.NoError(b, err) 529 } 530 531 it := l.NewIter(nil, nil) 532 b.ResetTimer() 533 for i := 0; i < b.N; i++ { 534 if !it.Valid() { 535 it.Last() 536 } 537 it.Prev() 538 } 539 }