github.com/ledgerwatch/erigon-lib@v1.0.0/kv/memdb/memory_mutation_test.go (about) 1 /* 2 Copyright 2022 Erigon contributors 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package memdb 15 16 import ( 17 "testing" 18 19 "github.com/stretchr/testify/assert" 20 "github.com/stretchr/testify/require" 21 22 "github.com/ledgerwatch/erigon-lib/kv" 23 ) 24 25 func initializeDbNonDupSort(rwTx kv.RwTx) { 26 rwTx.Put(kv.HashedAccounts, []byte("AAAA"), []byte("value")) 27 rwTx.Put(kv.HashedAccounts, []byte("CAAA"), []byte("value1")) 28 rwTx.Put(kv.HashedAccounts, []byte("CBAA"), []byte("value2")) 29 rwTx.Put(kv.HashedAccounts, []byte("CCAA"), []byte("value3")) 30 } 31 32 func TestPutAppendHas(t *testing.T) { 33 _, rwTx := NewTestTx(t) 34 35 initializeDbNonDupSort(rwTx) 36 37 batch := NewMemoryBatch(rwTx, "") 38 require.NoError(t, batch.Append(kv.HashedAccounts, []byte("AAAA"), []byte("value1.5"))) 39 require.Error(t, batch.Append(kv.HashedAccounts, []byte("AAAA"), []byte("value1.3"))) 40 require.NoError(t, batch.Put(kv.HashedAccounts, []byte("AAAA"), []byte("value1.3"))) 41 require.NoError(t, batch.Append(kv.HashedAccounts, []byte("CBAA"), []byte("value3.5"))) 42 require.Error(t, batch.Append(kv.HashedAccounts, []byte("CBAA"), []byte("value3.1"))) 43 require.NoError(t, batch.AppendDup(kv.HashedAccounts, []byte("CBAA"), []byte("value3.1"))) 44 require.Error(t, batch.Append(kv.HashedAccounts, []byte("AAAA"), []byte("value1.3"))) 45 46 require.Nil(t, batch.Flush(rwTx)) 47 48 exist, err := batch.Has(kv.HashedAccounts, []byte("AAAA")) 49 require.Nil(t, err) 50 require.Equal(t, exist, true) 51 52 val, err := batch.GetOne(kv.HashedAccounts, []byte("AAAA")) 53 require.Nil(t, err) 54 require.Equal(t, val, []byte("value1.3")) 55 56 exist, err = batch.Has(kv.HashedAccounts, []byte("KKKK")) 57 require.Nil(t, err) 58 require.Equal(t, exist, false) 59 } 60 61 func TestLastMiningDB(t *testing.T) { 62 _, rwTx := NewTestTx(t) 63 64 initializeDbNonDupSort(rwTx) 65 66 batch := NewMemoryBatch(rwTx, "") 67 batch.Put(kv.HashedAccounts, []byte("BAAA"), []byte("value4")) 68 batch.Put(kv.HashedAccounts, []byte("BCAA"), []byte("value5")) 69 70 cursor, err := batch.Cursor(kv.HashedAccounts) 71 require.NoError(t, err) 72 73 key, value, err := cursor.Last() 74 require.NoError(t, err) 75 76 require.Equal(t, key, []byte("CCAA")) 77 require.Equal(t, value, []byte("value3")) 78 79 key, value, err = cursor.Next() 80 require.NoError(t, err) 81 require.Equal(t, key, []byte(nil)) 82 require.Equal(t, value, []byte(nil)) 83 } 84 85 func TestLastMiningMem(t *testing.T) { 86 _, rwTx := NewTestTx(t) 87 88 initializeDbNonDupSort(rwTx) 89 90 batch := NewMemoryBatch(rwTx, "") 91 batch.Put(kv.HashedAccounts, []byte("BAAA"), []byte("value4")) 92 batch.Put(kv.HashedAccounts, []byte("DCAA"), []byte("value5")) 93 94 cursor, err := batch.Cursor(kv.HashedAccounts) 95 require.NoError(t, err) 96 97 key, value, err := cursor.Last() 98 require.NoError(t, err) 99 100 require.Equal(t, key, []byte("DCAA")) 101 require.Equal(t, value, []byte("value5")) 102 103 key, value, err = cursor.Next() 104 require.NoError(t, err) 105 require.Equal(t, key, []byte(nil)) 106 require.Equal(t, value, []byte(nil)) 107 } 108 109 func TestDeleteMining(t *testing.T) { 110 _, rwTx := NewTestTx(t) 111 112 initializeDbNonDupSort(rwTx) 113 batch := NewMemoryBatch(rwTx, "") 114 batch.Put(kv.HashedAccounts, []byte("BAAA"), []byte("value4")) 115 batch.Put(kv.HashedAccounts, []byte("DCAA"), []byte("value5")) 116 batch.Put(kv.HashedAccounts, []byte("FCAA"), []byte("value5")) 117 118 batch.Delete(kv.HashedAccounts, []byte("BAAA")) 119 batch.Delete(kv.HashedAccounts, []byte("CBAA")) 120 121 cursor, err := batch.Cursor(kv.HashedAccounts) 122 require.NoError(t, err) 123 124 key, value, err := cursor.SeekExact([]byte("BAAA")) 125 require.NoError(t, err) 126 require.Equal(t, key, []byte(nil)) 127 require.Equal(t, value, []byte(nil)) 128 129 key, value, err = cursor.SeekExact([]byte("CBAA")) 130 require.NoError(t, err) 131 require.Equal(t, key, []byte(nil)) 132 require.Equal(t, value, []byte(nil)) 133 } 134 135 func TestFlush(t *testing.T) { 136 _, rwTx := NewTestTx(t) 137 138 initializeDbNonDupSort(rwTx) 139 batch := NewMemoryBatch(rwTx, "") 140 batch.Put(kv.HashedAccounts, []byte("BAAA"), []byte("value4")) 141 batch.Put(kv.HashedAccounts, []byte("AAAA"), []byte("value5")) 142 batch.Put(kv.HashedAccounts, []byte("FCAA"), []byte("value5")) 143 144 require.NoError(t, batch.Flush(rwTx)) 145 146 value, err := rwTx.GetOne(kv.HashedAccounts, []byte("BAAA")) 147 require.NoError(t, err) 148 require.Equal(t, value, []byte("value4")) 149 150 value, err = rwTx.GetOne(kv.HashedAccounts, []byte("AAAA")) 151 require.NoError(t, err) 152 require.Equal(t, value, []byte("value5")) 153 } 154 155 func TestForEach(t *testing.T) { 156 _, rwTx := NewTestTx(t) 157 158 initializeDbNonDupSort(rwTx) 159 160 batch := NewMemoryBatch(rwTx, "") 161 batch.Put(kv.HashedAccounts, []byte("FCAA"), []byte("value5")) 162 require.NoError(t, batch.Flush(rwTx)) 163 164 var keys []string 165 var values []string 166 err := batch.ForEach(kv.HashedAccounts, []byte("XYAZ"), func(k, v []byte) error { 167 keys = append(keys, string(k)) 168 values = append(values, string(v)) 169 return nil 170 }) 171 require.Nil(t, err) 172 require.Nil(t, keys) 173 require.Nil(t, values) 174 175 err = batch.ForEach(kv.HashedAccounts, []byte("CC"), func(k, v []byte) error { 176 keys = append(keys, string(k)) 177 values = append(values, string(v)) 178 return nil 179 }) 180 require.Nil(t, err) 181 require.Equal(t, []string{"CCAA", "FCAA"}, keys) 182 require.Equal(t, []string{"value3", "value5"}, values) 183 184 var keys1 []string 185 var values1 []string 186 187 err = batch.ForEach(kv.HashedAccounts, []byte("A"), func(k, v []byte) error { 188 keys1 = append(keys1, string(k)) 189 values1 = append(values1, string(v)) 190 return nil 191 }) 192 require.Nil(t, err) 193 require.Equal(t, []string{"AAAA", "CAAA", "CBAA", "CCAA", "FCAA"}, keys1) 194 require.Equal(t, []string{"value", "value1", "value2", "value3", "value5"}, values1) 195 } 196 197 func TestForPrefix(t *testing.T) { 198 _, rwTx := NewTestTx(t) 199 200 initializeDbNonDupSort(rwTx) 201 202 batch := NewMemoryBatch(rwTx, "") 203 var keys1 []string 204 var values1 []string 205 206 err := batch.ForPrefix(kv.HashedAccounts, []byte("AB"), func(k, v []byte) error { 207 keys1 = append(keys1, string(k)) 208 values1 = append(values1, string(v)) 209 return nil 210 }) 211 require.Nil(t, err) 212 require.Nil(t, keys1) 213 require.Nil(t, values1) 214 215 err = batch.ForPrefix(kv.HashedAccounts, []byte("AAAA"), func(k, v []byte) error { 216 keys1 = append(keys1, string(k)) 217 values1 = append(values1, string(v)) 218 return nil 219 }) 220 require.Nil(t, err) 221 require.Equal(t, []string{"AAAA"}, keys1) 222 require.Equal(t, []string{"value"}, values1) 223 224 var keys []string 225 var values []string 226 err = batch.ForPrefix(kv.HashedAccounts, []byte("C"), func(k, v []byte) error { 227 keys = append(keys, string(k)) 228 values = append(values, string(v)) 229 return nil 230 }) 231 require.Nil(t, err) 232 require.Equal(t, []string{"CAAA", "CBAA", "CCAA"}, keys) 233 require.Equal(t, []string{"value1", "value2", "value3"}, values) 234 } 235 236 func TestForAmount(t *testing.T) { 237 _, rwTx := NewTestTx(t) 238 239 initializeDbNonDupSort(rwTx) 240 241 batch := NewMemoryBatch(rwTx, "") 242 defer batch.Close() 243 244 var keys []string 245 var values []string 246 err := batch.ForAmount(kv.HashedAccounts, []byte("C"), uint32(3), func(k, v []byte) error { 247 keys = append(keys, string(k)) 248 values = append(values, string(v)) 249 return nil 250 }) 251 252 require.Nil(t, err) 253 require.Equal(t, []string{"CAAA", "CBAA", "CCAA"}, keys) 254 require.Equal(t, []string{"value1", "value2", "value3"}, values) 255 256 var keys1 []string 257 var values1 []string 258 err = batch.ForAmount(kv.HashedAccounts, []byte("C"), uint32(10), func(k, v []byte) error { 259 keys1 = append(keys1, string(k)) 260 values1 = append(values1, string(v)) 261 return nil 262 }) 263 264 require.Nil(t, err) 265 require.Equal(t, []string{"CAAA", "CBAA", "CCAA"}, keys1) 266 require.Equal(t, []string{"value1", "value2", "value3"}, values1) 267 } 268 269 func TestGetOneAfterClearBucket(t *testing.T) { 270 _, rwTx := NewTestTx(t) 271 272 initializeDbNonDupSort(rwTx) 273 274 batch := NewMemoryBatch(rwTx, "") 275 defer batch.Close() 276 277 err := batch.ClearBucket(kv.HashedAccounts) 278 require.Nil(t, err) 279 280 cond := batch.isTableCleared(kv.HashedAccounts) 281 require.True(t, cond) 282 283 val, err := batch.GetOne(kv.HashedAccounts, []byte("A")) 284 require.Nil(t, err) 285 require.Nil(t, val) 286 287 val, err = batch.GetOne(kv.HashedAccounts, []byte("AAAA")) 288 require.Nil(t, err) 289 require.Nil(t, val) 290 } 291 292 func TestSeekExactAfterClearBucket(t *testing.T) { 293 _, rwTx := NewTestTx(t) 294 295 initializeDbNonDupSort(rwTx) 296 297 batch := NewMemoryBatch(rwTx, "") 298 defer batch.Close() 299 300 err := batch.ClearBucket(kv.HashedAccounts) 301 require.Nil(t, err) 302 303 cond := batch.isTableCleared(kv.HashedAccounts) 304 require.True(t, cond) 305 306 cursor, err := batch.RwCursor(kv.HashedAccounts) 307 require.NoError(t, err) 308 309 key, val, err := cursor.SeekExact([]byte("AAAA")) 310 require.Nil(t, err) 311 assert.Nil(t, key) 312 assert.Nil(t, val) 313 314 err = cursor.Put([]byte("AAAA"), []byte("valueX")) 315 require.Nil(t, err) 316 317 key, val, err = cursor.SeekExact([]byte("AAAA")) 318 require.Nil(t, err) 319 assert.Equal(t, []byte("AAAA"), key) 320 assert.Equal(t, []byte("valueX"), val) 321 322 key, val, err = cursor.SeekExact([]byte("BBBB")) 323 require.Nil(t, err) 324 assert.Nil(t, key) 325 assert.Nil(t, val) 326 } 327 328 func TestFirstAfterClearBucket(t *testing.T) { 329 _, rwTx := NewTestTx(t) 330 331 initializeDbNonDupSort(rwTx) 332 333 batch := NewMemoryBatch(rwTx, "") 334 defer batch.Close() 335 336 err := batch.ClearBucket(kv.HashedAccounts) 337 require.Nil(t, err) 338 339 err = batch.Put(kv.HashedAccounts, []byte("BBBB"), []byte("value5")) 340 require.Nil(t, err) 341 342 cursor, err := batch.Cursor(kv.HashedAccounts) 343 require.NoError(t, err) 344 345 key, val, err := cursor.First() 346 require.Nil(t, err) 347 assert.Equal(t, []byte("BBBB"), key) 348 assert.Equal(t, []byte("value5"), val) 349 350 key, val, err = cursor.Next() 351 require.Nil(t, err) 352 assert.Nil(t, key) 353 assert.Nil(t, val) 354 } 355 356 func TestIncReadSequence(t *testing.T) { 357 _, rwTx := NewTestTx(t) 358 359 initializeDbNonDupSort(rwTx) 360 361 batch := NewMemoryBatch(rwTx, "") 362 defer batch.Close() 363 364 _, err := batch.IncrementSequence(kv.HashedAccounts, uint64(12)) 365 require.Nil(t, err) 366 367 val, err := batch.ReadSequence(kv.HashedAccounts) 368 require.Nil(t, err) 369 require.Equal(t, val, uint64(12)) 370 } 371 372 func initializeDbDupSort(rwTx kv.RwTx) { 373 rwTx.Put(kv.AccountChangeSet, []byte("key1"), []byte("value1.1")) 374 rwTx.Put(kv.AccountChangeSet, []byte("key3"), []byte("value3.1")) 375 rwTx.Put(kv.AccountChangeSet, []byte("key1"), []byte("value1.3")) 376 rwTx.Put(kv.AccountChangeSet, []byte("key3"), []byte("value3.3")) 377 } 378 379 func TestNext(t *testing.T) { 380 _, rwTx := NewTestTx(t) 381 382 initializeDbDupSort(rwTx) 383 384 batch := NewMemoryBatch(rwTx, "") 385 defer batch.Close() 386 387 batch.Put(kv.AccountChangeSet, []byte("key1"), []byte("value1.2")) 388 389 cursor, err := batch.CursorDupSort(kv.AccountChangeSet) 390 require.NoError(t, err) 391 392 k, v, err := cursor.First() 393 require.Nil(t, err) 394 assert.Equal(t, []byte("key1"), k) 395 assert.Equal(t, []byte("value1.1"), v) 396 397 k, v, err = cursor.Next() 398 require.Nil(t, err) 399 assert.Equal(t, []byte("key1"), k) 400 assert.Equal(t, []byte("value1.2"), v) 401 402 k, v, err = cursor.Next() 403 require.Nil(t, err) 404 assert.Equal(t, []byte("key1"), k) 405 assert.Equal(t, []byte("value1.3"), v) 406 407 k, v, err = cursor.Next() 408 require.Nil(t, err) 409 assert.Equal(t, []byte("key3"), k) 410 assert.Equal(t, []byte("value3.1"), v) 411 412 k, v, err = cursor.Next() 413 require.Nil(t, err) 414 assert.Equal(t, []byte("key3"), k) 415 assert.Equal(t, []byte("value3.3"), v) 416 417 k, v, err = cursor.Next() 418 require.Nil(t, err) 419 assert.Nil(t, k) 420 assert.Nil(t, v) 421 } 422 423 func TestNextNoDup(t *testing.T) { 424 _, rwTx := NewTestTx(t) 425 426 initializeDbDupSort(rwTx) 427 428 batch := NewMemoryBatch(rwTx, "") 429 defer batch.Close() 430 431 batch.Put(kv.AccountChangeSet, []byte("key2"), []byte("value2.1")) 432 batch.Put(kv.AccountChangeSet, []byte("key2"), []byte("value2.2")) 433 434 cursor, err := batch.CursorDupSort(kv.AccountChangeSet) 435 require.NoError(t, err) 436 437 k, _, err := cursor.First() 438 require.Nil(t, err) 439 assert.Equal(t, []byte("key1"), k) 440 441 k, _, err = cursor.NextNoDup() 442 require.Nil(t, err) 443 assert.Equal(t, []byte("key2"), k) 444 445 k, _, err = cursor.NextNoDup() 446 require.Nil(t, err) 447 assert.Equal(t, []byte("key3"), k) 448 } 449 450 func TestDeleteCurrentDuplicates(t *testing.T) { 451 _, rwTx := NewTestTx(t) 452 453 initializeDbDupSort(rwTx) 454 455 batch := NewMemoryBatch(rwTx, "") 456 defer batch.Close() 457 458 cursor, err := batch.RwCursorDupSort(kv.AccountChangeSet) 459 require.NoError(t, err) 460 461 require.NoError(t, cursor.Put([]byte("key3"), []byte("value3.2"))) 462 463 key, _, err := cursor.SeekExact([]byte("key3")) 464 require.NoError(t, err) 465 require.Equal(t, []byte("key3"), key) 466 467 require.NoError(t, cursor.DeleteCurrentDuplicates()) 468 469 require.NoError(t, batch.Flush(rwTx)) 470 471 var keys []string 472 var values []string 473 err = rwTx.ForEach(kv.AccountChangeSet, nil, func(k, v []byte) error { 474 keys = append(keys, string(k)) 475 values = append(values, string(v)) 476 return nil 477 }) 478 require.NoError(t, err) 479 480 require.Equal(t, []string{"key1", "key1"}, keys) 481 require.Equal(t, []string{"value1.1", "value1.3"}, values) 482 } 483 484 func TestSeekBothRange(t *testing.T) { 485 _, rwTx := NewTestTx(t) 486 487 rwTx.Put(kv.AccountChangeSet, []byte("key1"), []byte("value1.1")) 488 rwTx.Put(kv.AccountChangeSet, []byte("key3"), []byte("value3.3")) 489 490 batch := NewMemoryBatch(rwTx, "") 491 defer batch.Close() 492 493 cursor, err := batch.RwCursorDupSort(kv.AccountChangeSet) 494 require.NoError(t, err) 495 496 require.NoError(t, cursor.Put([]byte("key3"), []byte("value3.1"))) 497 require.NoError(t, cursor.Put([]byte("key1"), []byte("value1.3"))) 498 499 v, err := cursor.SeekBothRange([]byte("key2"), []byte("value1.2")) 500 require.NoError(t, err) 501 // SeekBothRange does exact match of the key, but range match of the value, so we get nil here 502 require.Nil(t, v) 503 504 v, err = cursor.SeekBothRange([]byte("key3"), []byte("value3.2")) 505 require.NoError(t, err) 506 require.Equal(t, "value3.3", string(v)) 507 } 508 509 func initializeDbAutoConversion(rwTx kv.RwTx) { 510 rwTx.Put(kv.PlainState, []byte("A"), []byte("0")) 511 rwTx.Put(kv.PlainState, []byte("A..........................._______________________________A"), []byte("1")) 512 rwTx.Put(kv.PlainState, []byte("A..........................._______________________________C"), []byte("2")) 513 rwTx.Put(kv.PlainState, []byte("B"), []byte("8")) 514 rwTx.Put(kv.PlainState, []byte("C"), []byte("9")) 515 rwTx.Put(kv.PlainState, []byte("D..........................._______________________________A"), []byte("3")) 516 rwTx.Put(kv.PlainState, []byte("D..........................._______________________________C"), []byte("4")) 517 } 518 519 func TestAutoConversion(t *testing.T) { 520 _, rwTx := NewTestTx(t) 521 522 initializeDbAutoConversion(rwTx) 523 524 batch := NewMemoryBatch(rwTx, "") 525 defer batch.Close() 526 527 c, err := batch.RwCursor(kv.PlainState) 528 require.NoError(t, err) 529 530 // key length conflict 531 require.Error(t, c.Put([]byte("A..........................."), []byte("?"))) 532 533 require.NoError(t, c.Delete([]byte("A..........................._______________________________A"))) 534 require.NoError(t, c.Put([]byte("B"), []byte("7"))) 535 require.NoError(t, c.Delete([]byte("C"))) 536 require.NoError(t, c.Put([]byte("D..........................._______________________________C"), []byte("6"))) 537 require.NoError(t, c.Put([]byte("D..........................._______________________________E"), []byte("5"))) 538 539 k, v, err := c.First() 540 require.NoError(t, err) 541 assert.Equal(t, []byte("A"), k) 542 assert.Equal(t, []byte("0"), v) 543 544 k, v, err = c.Next() 545 require.NoError(t, err) 546 assert.Equal(t, []byte("A..........................._______________________________C"), k) 547 assert.Equal(t, []byte("2"), v) 548 549 k, v, err = c.Next() 550 require.NoError(t, err) 551 assert.Equal(t, []byte("B"), k) 552 assert.Equal(t, []byte("7"), v) 553 554 k, v, err = c.Next() 555 require.NoError(t, err) 556 assert.Equal(t, []byte("D..........................._______________________________A"), k) 557 assert.Equal(t, []byte("3"), v) 558 559 k, v, err = c.Next() 560 require.NoError(t, err) 561 assert.Equal(t, []byte("D..........................._______________________________C"), k) 562 assert.Equal(t, []byte("6"), v) 563 564 k, v, err = c.Next() 565 require.NoError(t, err) 566 assert.Equal(t, []byte("D..........................._______________________________E"), k) 567 assert.Equal(t, []byte("5"), v) 568 569 k, v, err = c.Next() 570 require.NoError(t, err) 571 assert.Nil(t, k) 572 assert.Nil(t, v) 573 } 574 575 func TestAutoConversionDelete(t *testing.T) { 576 _, rwTx := NewTestTx(t) 577 578 initializeDbAutoConversion(rwTx) 579 580 batch := NewMemoryBatch(rwTx, "") 581 defer batch.Close() 582 583 c, err := batch.RwCursor(kv.PlainState) 584 require.NoError(t, err) 585 586 require.NoError(t, c.Delete([]byte("A..........................._______________________________A"))) 587 require.NoError(t, c.Delete([]byte("A..........................._______________________________C"))) 588 require.NoError(t, c.Delete([]byte("B"))) 589 require.NoError(t, c.Delete([]byte("C"))) 590 591 k, v, err := c.First() 592 require.NoError(t, err) 593 assert.Equal(t, []byte("A"), k) 594 assert.Equal(t, []byte("0"), v) 595 596 k, v, err = c.Next() 597 require.NoError(t, err) 598 assert.Equal(t, []byte("D..........................._______________________________A"), k) 599 assert.Equal(t, []byte("3"), v) 600 601 k, v, err = c.Next() 602 require.NoError(t, err) 603 assert.Equal(t, []byte("D..........................._______________________________C"), k) 604 assert.Equal(t, []byte("4"), v) 605 606 k, v, err = c.Next() 607 require.NoError(t, err) 608 assert.Nil(t, k) 609 assert.Nil(t, v) 610 } 611 612 func TestAutoConversionSeekBothRange(t *testing.T) { 613 _, rwTx := NewTestTx(t) 614 615 initializeDbAutoConversion(rwTx) 616 617 batch := NewMemoryBatch(rwTx, "") 618 defer batch.Close() 619 620 c, err := batch.RwCursorDupSort(kv.PlainState) 621 require.NoError(t, err) 622 623 require.NoError(t, c.Delete([]byte("A..........................._______________________________A"))) 624 require.NoError(t, c.Put([]byte("D..........................._______________________________C"), []byte("6"))) 625 require.NoError(t, c.Put([]byte("D..........................._______________________________E"), []byte("5"))) 626 627 v, err := c.SeekBothRange([]byte("A..........................."), []byte("_______________________________A")) 628 require.NoError(t, err) 629 assert.Equal(t, []byte("_______________________________C2"), v) 630 631 _, v, err = c.NextDup() 632 require.NoError(t, err) 633 assert.Nil(t, v) 634 635 v, err = c.SeekBothRange([]byte("A..........................."), []byte("_______________________________X")) 636 require.NoError(t, err) 637 assert.Nil(t, v) 638 639 v, err = c.SeekBothRange([]byte("B..........................."), []byte("")) 640 require.NoError(t, err) 641 assert.Nil(t, v) 642 643 v, err = c.SeekBothRange([]byte("C..........................."), []byte("")) 644 require.NoError(t, err) 645 assert.Nil(t, v) 646 647 v, err = c.SeekBothRange([]byte("D..........................."), []byte("")) 648 require.NoError(t, err) 649 assert.Equal(t, []byte("_______________________________A3"), v) 650 651 _, v, err = c.NextDup() 652 require.NoError(t, err) 653 assert.Equal(t, []byte("_______________________________C6"), v) 654 655 _, v, err = c.NextDup() 656 require.NoError(t, err) 657 assert.Equal(t, []byte("_______________________________E5"), v) 658 659 _, v, err = c.NextDup() 660 require.NoError(t, err) 661 assert.Nil(t, v) 662 663 v, err = c.SeekBothRange([]byte("X..........................."), []byte("_______________________________Y")) 664 require.NoError(t, err) 665 assert.Nil(t, v) 666 }