github.com/onflow/atree@v0.6.0/array_test.go (about) 1 /* 2 * Atree - Scalable Arrays and Ordered Maps 3 * 4 * Copyright 2021 Dapper Labs, Inc. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package atree 20 21 import ( 22 "errors" 23 "math" 24 "math/rand" 25 "reflect" 26 "strings" 27 "testing" 28 29 "github.com/stretchr/testify/require" 30 ) 31 32 func verifyEmptyArray( 33 t *testing.T, 34 storage *PersistentSlabStorage, 35 typeInfo TypeInfo, 36 address Address, 37 array *Array, 38 ) { 39 verifyArray(t, storage, typeInfo, address, array, nil, false) 40 } 41 42 // verifyArray verifies array elements and validates serialization and in-memory slab tree. 43 func verifyArray( 44 t *testing.T, 45 storage *PersistentSlabStorage, 46 typeInfo TypeInfo, 47 address Address, 48 array *Array, 49 values []Value, 50 hasNestedArrayMapElement bool, 51 ) { 52 require.True(t, typeInfoComparator(typeInfo, array.Type())) 53 require.Equal(t, address, array.Address()) 54 require.Equal(t, uint64(len(values)), array.Count()) 55 56 var err error 57 58 // Verify array elements 59 for i, v := range values { 60 s, err := array.Get(uint64(i)) 61 require.NoError(t, err) 62 63 e, err := s.StoredValue(array.Storage) 64 require.NoError(t, err) 65 66 valueEqual(t, typeInfoComparator, v, e) 67 } 68 69 // Verify array elements by iterator 70 i := 0 71 err = array.Iterate(func(v Value) (bool, error) { 72 valueEqual(t, typeInfoComparator, values[i], v) 73 i++ 74 return true, nil 75 }) 76 require.NoError(t, err) 77 require.Equal(t, len(values), i) 78 79 // Verify in-memory slabs 80 err = ValidArray(array, typeInfo, typeInfoComparator, hashInputProvider) 81 if err != nil { 82 PrintArray(array) 83 } 84 require.NoError(t, err) 85 86 // Verify slab serializations 87 err = ValidArraySerialization( 88 array, 89 storage.cborDecMode, 90 storage.cborEncMode, 91 storage.DecodeStorable, 92 storage.DecodeTypeInfo, 93 func(a, b Storable) bool { 94 return reflect.DeepEqual(a, b) 95 }, 96 ) 97 if err != nil { 98 PrintArray(array) 99 } 100 require.NoError(t, err) 101 102 // Check storage slab tree 103 rootIDSet, err := CheckStorageHealth(storage, 1) 104 require.NoError(t, err) 105 106 rootIDs := make([]StorageID, 0, len(rootIDSet)) 107 for id := range rootIDSet { 108 rootIDs = append(rootIDs, id) 109 } 110 require.Equal(t, 1, len(rootIDs)) 111 require.Equal(t, array.StorageID(), rootIDs[0]) 112 113 if !hasNestedArrayMapElement { 114 // Need to call Commit before calling storage.Count() for PersistentSlabStorage. 115 err = storage.Commit() 116 require.NoError(t, err) 117 118 stats, err := GetArrayStats(array) 119 require.NoError(t, err) 120 require.Equal(t, stats.SlabCount(), uint64(storage.Count())) 121 122 if len(values) == 0 { 123 // Verify slab count for empty array 124 require.Equal(t, uint64(1), stats.DataSlabCount) 125 require.Equal(t, uint64(0), stats.MetaDataSlabCount) 126 require.Equal(t, uint64(0), stats.StorableSlabCount) 127 } 128 } 129 } 130 131 func TestArrayAppendAndGet(t *testing.T) { 132 // With slab size 256 bytes, number of array elements equal 4096, 133 // element values equal 0-4095, array tree will be 3 levels, 134 // with 14 metadata slabs, and 109 data slabs. 135 136 SetThreshold(256) 137 defer SetThreshold(1024) 138 139 const arraySize = 4096 140 141 typeInfo := testTypeInfo{42} 142 storage := newTestPersistentStorage(t) 143 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 144 145 array, err := NewArray(storage, address, typeInfo) 146 require.NoError(t, err) 147 148 values := make([]Value, arraySize) 149 for i := uint64(0); i < arraySize; i++ { 150 v := Uint64Value(i) 151 values[i] = v 152 err := array.Append(v) 153 require.NoError(t, err) 154 } 155 156 storable, err := array.Get(array.Count()) 157 require.Nil(t, storable) 158 require.Equal(t, 1, errorCategorizationCount(err)) 159 160 var userError *UserError 161 var indexOutOfBoundsError *IndexOutOfBoundsError 162 require.ErrorAs(t, err, &userError) 163 require.ErrorAs(t, err, &indexOutOfBoundsError) 164 require.ErrorAs(t, userError, &indexOutOfBoundsError) 165 166 verifyArray(t, storage, typeInfo, address, array, values, false) 167 } 168 169 func TestArraySetAndGet(t *testing.T) { 170 171 t.Run("new elements with similar bytesize", func(t *testing.T) { 172 const arraySize = 4096 173 174 typeInfo := testTypeInfo{42} 175 storage := newTestPersistentStorage(t) 176 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 177 178 array, err := NewArray(storage, address, typeInfo) 179 require.NoError(t, err) 180 181 values := make([]Value, arraySize) 182 for i := uint64(0); i < arraySize; i++ { 183 v := Uint64Value(i) 184 values[i] = v 185 err := array.Append(v) 186 require.NoError(t, err) 187 } 188 189 verifyArray(t, storage, typeInfo, address, array, values, false) 190 191 for i := uint64(0); i < arraySize; i++ { 192 oldValue := values[i] 193 newValue := Uint64Value(i * 10) 194 values[i] = newValue 195 196 existingStorable, err := array.Set(i, newValue) 197 require.NoError(t, err) 198 199 existingValue, err := existingStorable.StoredValue(storage) 200 require.NoError(t, err) 201 valueEqual(t, typeInfoComparator, oldValue, existingValue) 202 } 203 204 verifyArray(t, storage, typeInfo, address, array, values, false) 205 }) 206 207 // This tests slabs splitting and root slab reassignment caused by Set operation. 208 t.Run("new elements with larger bytesize", func(t *testing.T) { 209 // With slab size 256 bytes, number of array elements equal 50, 210 // element values equal 0-49, array tree will be 1 level, 211 // with 0 metadata slab, and 1 data slab (root). 212 // When elements are overwritten with values from math.MaxUint64-49 to math.MaxUint64, 213 // array tree is 2 levels, with 1 metadata slab, and 2 data slabs. 214 215 const arraySize = 50 216 217 SetThreshold(256) 218 defer SetThreshold(1024) 219 220 typeInfo := testTypeInfo{42} 221 storage := newTestPersistentStorage(t) 222 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 223 224 array, err := NewArray(storage, address, typeInfo) 225 require.NoError(t, err) 226 227 values := make([]Value, arraySize) 228 for i := uint64(0); i < arraySize; i++ { 229 v := Uint64Value(i) 230 values[i] = v 231 err := array.Append(v) 232 require.NoError(t, err) 233 } 234 235 verifyArray(t, storage, typeInfo, address, array, values, false) 236 237 for i := uint64(0); i < arraySize; i++ { 238 oldValue := values[i] 239 newValue := Uint64Value(math.MaxUint64 - arraySize + i + 1) 240 values[i] = newValue 241 242 existingStorable, err := array.Set(i, newValue) 243 require.NoError(t, err) 244 245 existingValue, err := existingStorable.StoredValue(storage) 246 require.NoError(t, err) 247 valueEqual(t, typeInfoComparator, oldValue, existingValue) 248 } 249 250 verifyArray(t, storage, typeInfo, address, array, values, false) 251 }) 252 253 // This tests slabs merging and root slab reassignment caused by Set operation. 254 t.Run("new elements with smaller bytesize", func(t *testing.T) { 255 256 // With slab size 256 bytes, number of array elements equal 50, 257 // element values equal math.MaxUint64-49 to math.MaxUint64, 258 // array tree is 2 levels, with 1 metadata slab, and 2 data slabs. 259 // When elements are overwritten with values from 0-49, 260 // array tree will be 1 level, with 0 metadata slab, and 1 data slab (root). 261 262 const arraySize = 50 263 264 SetThreshold(256) 265 defer SetThreshold(1024) 266 267 typeInfo := testTypeInfo{42} 268 storage := newTestPersistentStorage(t) 269 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 270 271 array, err := NewArray(storage, address, typeInfo) 272 require.NoError(t, err) 273 274 values := make([]Value, arraySize) 275 for i := uint64(0); i < arraySize; i++ { 276 v := Uint64Value(math.MaxUint64 - arraySize + i + 1) 277 values[i] = v 278 err := array.Append(v) 279 require.NoError(t, err) 280 } 281 282 verifyArray(t, storage, typeInfo, address, array, values, false) 283 284 for i := uint64(0); i < arraySize; i++ { 285 oldValue := values[i] 286 newValue := Uint64Value(i) 287 values[i] = newValue 288 289 existingStorable, err := array.Set(i, newValue) 290 require.NoError(t, err) 291 292 existingValue, err := existingStorable.StoredValue(storage) 293 require.NoError(t, err) 294 valueEqual(t, typeInfoComparator, oldValue, existingValue) 295 } 296 297 verifyArray(t, storage, typeInfo, address, array, values, false) 298 }) 299 300 t.Run("index out of bounds", func(t *testing.T) { 301 302 const arraySize = 1024 303 304 typeInfo := testTypeInfo{42} 305 storage := newTestPersistentStorage(t) 306 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 307 308 array, err := NewArray(storage, address, typeInfo) 309 require.NoError(t, err) 310 311 values := make([]Value, 0, arraySize) 312 for i := uint64(0); i < arraySize; i++ { 313 v := Uint64Value(i) 314 values = append(values, v) 315 err := array.Append(v) 316 require.NoError(t, err) 317 } 318 319 r := newRand(t) 320 321 v := NewStringValue(randStr(r, 1024)) 322 storable, err := array.Set(array.Count(), v) 323 require.Nil(t, storable) 324 require.Equal(t, 1, errorCategorizationCount(err)) 325 326 var userError *UserError 327 var indexOutOfBoundsError *IndexOutOfBoundsError 328 require.ErrorAs(t, err, &userError) 329 require.ErrorAs(t, err, &indexOutOfBoundsError) 330 require.ErrorAs(t, userError, &indexOutOfBoundsError) 331 332 verifyArray(t, storage, typeInfo, address, array, values, false) 333 }) 334 } 335 336 func TestArrayInsertAndGet(t *testing.T) { 337 338 SetThreshold(256) 339 defer SetThreshold(1024) 340 341 t.Run("insert-first", func(t *testing.T) { 342 343 const arraySize = 4096 344 345 typeInfo := testTypeInfo{42} 346 storage := newTestPersistentStorage(t) 347 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 348 349 array, err := NewArray(storage, address, typeInfo) 350 require.NoError(t, err) 351 352 values := make([]Value, arraySize) 353 for i := uint64(0); i < arraySize; i++ { 354 v := Uint64Value(arraySize - i - 1) 355 values[arraySize-i-1] = v 356 err := array.Insert(0, v) 357 require.NoError(t, err) 358 } 359 360 verifyArray(t, storage, typeInfo, address, array, values, false) 361 }) 362 363 t.Run("insert-last", func(t *testing.T) { 364 365 const arraySize = 4096 366 367 typeInfo := testTypeInfo{42} 368 storage := newTestPersistentStorage(t) 369 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 370 371 array, err := NewArray(storage, address, typeInfo) 372 require.NoError(t, err) 373 374 values := make([]Value, arraySize) 375 for i := uint64(0); i < arraySize; i++ { 376 v := Uint64Value(i) 377 values[i] = v 378 err := array.Insert(i, v) 379 require.NoError(t, err) 380 } 381 382 verifyArray(t, storage, typeInfo, address, array, values, false) 383 }) 384 385 t.Run("insert", func(t *testing.T) { 386 387 const arraySize = 4096 388 389 typeInfo := testTypeInfo{42} 390 storage := newTestPersistentStorage(t) 391 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 392 393 array, err := NewArray(storage, address, typeInfo) 394 require.NoError(t, err) 395 396 values := make([]Value, 0, arraySize) 397 for i := uint64(0); i < arraySize; i += 2 { 398 v := Uint64Value(i) 399 values = append(values, v) 400 err := array.Append(v) 401 require.NoError(t, err) 402 } 403 404 for i := uint64(1); i < arraySize; i += 2 { 405 v := Uint64Value(i) 406 407 values = append(values, nil) 408 copy(values[i+1:], values[i:]) 409 values[i] = v 410 411 err := array.Insert(i, v) 412 require.NoError(t, err) 413 } 414 415 verifyArray(t, storage, typeInfo, address, array, values, false) 416 }) 417 418 t.Run("index out of bounds", func(t *testing.T) { 419 420 const arraySize = 1024 421 422 typeInfo := testTypeInfo{42} 423 storage := newTestPersistentStorage(t) 424 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 425 426 array, err := NewArray(storage, address, typeInfo) 427 require.NoError(t, err) 428 429 values := make([]Value, 0, arraySize) 430 for i := uint64(0); i < arraySize; i++ { 431 v := Uint64Value(i) 432 values = append(values, v) 433 err := array.Append(v) 434 require.NoError(t, err) 435 } 436 437 r := newRand(t) 438 439 v := NewStringValue(randStr(r, 1024)) 440 err = array.Insert(array.Count()+1, v) 441 require.Equal(t, 1, errorCategorizationCount(err)) 442 443 var userError *UserError 444 var indexOutOfBoundsError *IndexOutOfBoundsError 445 require.ErrorAs(t, err, &userError) 446 require.ErrorAs(t, err, &indexOutOfBoundsError) 447 require.ErrorAs(t, userError, &indexOutOfBoundsError) 448 449 verifyArray(t, storage, typeInfo, address, array, values, false) 450 }) 451 } 452 453 func TestArrayRemove(t *testing.T) { 454 SetThreshold(256) 455 defer SetThreshold(1024) 456 457 t.Run("remove-first", func(t *testing.T) { 458 459 const arraySize = 4096 460 461 typeInfo := testTypeInfo{42} 462 storage := newTestPersistentStorage(t) 463 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 464 465 array, err := NewArray(storage, address, typeInfo) 466 require.NoError(t, err) 467 468 values := make([]Value, arraySize) 469 for i := uint64(0); i < arraySize; i++ { 470 v := Uint64Value(i) 471 values[i] = v 472 err := array.Append(v) 473 require.NoError(t, err) 474 } 475 476 require.True(t, typeInfoComparator(typeInfo, array.Type())) 477 require.Equal(t, address, array.Address()) 478 require.Equal(t, uint64(arraySize), array.Count()) 479 480 for i := uint64(0); i < arraySize; i++ { 481 existingStorable, err := array.Remove(0) 482 require.NoError(t, err) 483 484 existingValue, err := existingStorable.StoredValue(array.Storage) 485 require.NoError(t, err) 486 487 valueEqual(t, typeInfoComparator, values[i], existingValue) 488 489 if id, ok := existingStorable.(StorageIDStorable); ok { 490 err = array.Storage.Remove(StorageID(id)) 491 require.NoError(t, err) 492 } 493 494 require.Equal(t, arraySize-i-1, array.Count()) 495 496 if i%256 == 0 { 497 verifyArray(t, storage, typeInfo, address, array, values[i+1:], false) 498 } 499 } 500 501 verifyEmptyArray(t, storage, typeInfo, address, array) 502 }) 503 504 t.Run("remove-last", func(t *testing.T) { 505 506 const arraySize = 4096 507 508 typeInfo := testTypeInfo{42} 509 storage := newTestPersistentStorage(t) 510 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 511 512 array, err := NewArray(storage, address, typeInfo) 513 require.NoError(t, err) 514 515 values := make([]Value, arraySize) 516 for i := uint64(0); i < arraySize; i++ { 517 v := Uint64Value(i) 518 values[i] = v 519 err := array.Append(v) 520 require.NoError(t, err) 521 } 522 523 require.True(t, typeInfoComparator(typeInfo, array.Type())) 524 require.Equal(t, address, array.Address()) 525 require.Equal(t, uint64(arraySize), array.Count()) 526 527 for i := arraySize - 1; i >= 0; i-- { 528 existingStorable, err := array.Remove(uint64(i)) 529 require.NoError(t, err) 530 531 existingValue, err := existingStorable.StoredValue(array.Storage) 532 require.NoError(t, err) 533 534 valueEqual(t, typeInfoComparator, values[i], existingValue) 535 536 if id, ok := existingStorable.(StorageIDStorable); ok { 537 err = array.Storage.Remove(StorageID(id)) 538 require.NoError(t, err) 539 } 540 541 require.Equal(t, uint64(i), array.Count()) 542 543 if i%256 == 0 { 544 verifyArray(t, storage, typeInfo, address, array, values[:i], false) 545 } 546 } 547 548 verifyEmptyArray(t, storage, typeInfo, address, array) 549 }) 550 551 t.Run("remove", func(t *testing.T) { 552 553 const arraySize = 4096 554 555 typeInfo := testTypeInfo{42} 556 storage := newTestPersistentStorage(t) 557 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 558 559 array, err := NewArray(storage, address, typeInfo) 560 require.NoError(t, err) 561 562 values := make([]Value, arraySize) 563 for i := uint64(0); i < arraySize; i++ { 564 v := Uint64Value(i) 565 values[i] = v 566 err := array.Append(v) 567 require.NoError(t, err) 568 } 569 570 require.True(t, typeInfoComparator(typeInfo, array.Type())) 571 require.Equal(t, address, array.Address()) 572 require.Equal(t, uint64(arraySize), array.Count()) 573 574 // Remove every other elements 575 for i := uint64(0); i < arraySize/2; i++ { 576 v := values[i] 577 578 existingStorable, err := array.Remove(i) 579 require.NoError(t, err) 580 581 existingValue, err := existingStorable.StoredValue(array.Storage) 582 require.NoError(t, err) 583 584 valueEqual(t, typeInfoComparator, v, existingValue) 585 586 if id, ok := existingStorable.(StorageIDStorable); ok { 587 err = array.Storage.Remove(StorageID(id)) 588 require.NoError(t, err) 589 } 590 591 copy(values[i:], values[i+1:]) 592 values = values[:len(values)-1] 593 594 require.Equal(t, uint64(len(values)), array.Count()) 595 596 if i%256 == 0 { 597 verifyArray(t, storage, typeInfo, address, array, values, false) 598 } 599 } 600 601 require.Equal(t, arraySize/2, len(values)) 602 603 verifyArray(t, storage, typeInfo, address, array, values, false) 604 }) 605 606 t.Run("index out of bounds", func(t *testing.T) { 607 608 const arraySize = 4096 609 610 typeInfo := testTypeInfo{42} 611 storage := newTestPersistentStorage(t) 612 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 613 614 array, err := NewArray(storage, address, typeInfo) 615 require.NoError(t, err) 616 617 values := make([]Value, arraySize) 618 for i := uint64(0); i < arraySize; i++ { 619 v := Uint64Value(i) 620 values[i] = v 621 err := array.Append(v) 622 require.NoError(t, err) 623 } 624 625 storable, err := array.Remove(array.Count()) 626 require.Nil(t, storable) 627 require.Equal(t, 1, errorCategorizationCount(err)) 628 629 var userError *UserError 630 var indexOutOfBounds *IndexOutOfBoundsError 631 require.ErrorAs(t, err, &userError) 632 require.ErrorAs(t, err, &indexOutOfBounds) 633 require.ErrorAs(t, userError, &indexOutOfBounds) 634 635 verifyArray(t, storage, typeInfo, address, array, values, false) 636 }) 637 } 638 639 func TestArrayIterate(t *testing.T) { 640 641 t.Run("empty", func(t *testing.T) { 642 typeInfo := testTypeInfo{42} 643 storage := newTestPersistentStorage(t) 644 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 645 646 array, err := NewArray(storage, address, typeInfo) 647 require.NoError(t, err) 648 649 i := uint64(0) 650 err = array.Iterate(func(v Value) (bool, error) { 651 i++ 652 return true, nil 653 }) 654 require.NoError(t, err) 655 require.Equal(t, uint64(0), i) 656 }) 657 658 t.Run("append", func(t *testing.T) { 659 SetThreshold(256) 660 defer SetThreshold(1024) 661 662 const arraySize = 4096 663 664 typeInfo := testTypeInfo{42} 665 storage := newTestPersistentStorage(t) 666 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 667 668 array, err := NewArray(storage, address, typeInfo) 669 require.NoError(t, err) 670 671 for i := uint64(0); i < arraySize; i++ { 672 err := array.Append(Uint64Value(i)) 673 require.NoError(t, err) 674 } 675 676 i := uint64(0) 677 err = array.Iterate(func(v Value) (bool, error) { 678 require.Equal(t, Uint64Value(i), v) 679 i++ 680 return true, nil 681 }) 682 require.NoError(t, err) 683 require.Equal(t, uint64(arraySize), i) 684 }) 685 686 t.Run("set", func(t *testing.T) { 687 SetThreshold(256) 688 defer SetThreshold(1024) 689 690 const arraySize = 4096 691 692 typeInfo := testTypeInfo{42} 693 storage := newTestPersistentStorage(t) 694 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 695 696 array, err := NewArray(storage, address, typeInfo) 697 require.NoError(t, err) 698 699 for i := uint64(0); i < arraySize; i++ { 700 err := array.Append(Uint64Value(0)) 701 require.NoError(t, err) 702 } 703 704 for i := uint64(0); i < arraySize; i++ { 705 existingStorable, err := array.Set(i, Uint64Value(i)) 706 require.NoError(t, err) 707 708 existingValue, err := existingStorable.StoredValue(storage) 709 require.NoError(t, err) 710 require.Equal(t, Uint64Value(0), existingValue) 711 } 712 713 i := uint64(0) 714 err = array.Iterate(func(v Value) (bool, error) { 715 require.Equal(t, Uint64Value(i), v) 716 i++ 717 return true, nil 718 }) 719 require.NoError(t, err) 720 require.Equal(t, uint64(arraySize), i) 721 }) 722 723 t.Run("insert", func(t *testing.T) { 724 SetThreshold(256) 725 defer SetThreshold(1024) 726 727 const arraySize = 4096 728 729 typeInfo := testTypeInfo{42} 730 storage := newTestPersistentStorage(t) 731 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 732 733 array, err := NewArray(storage, address, typeInfo) 734 require.NoError(t, err) 735 736 for i := uint64(0); i < arraySize; i += 2 { 737 err := array.Append(Uint64Value(i)) 738 require.NoError(t, err) 739 } 740 741 for i := uint64(1); i < arraySize; i += 2 { 742 err := array.Insert(i, Uint64Value(i)) 743 require.NoError(t, err) 744 } 745 746 i := uint64(0) 747 err = array.Iterate(func(v Value) (bool, error) { 748 require.Equal(t, Uint64Value(i), v) 749 i++ 750 return true, nil 751 }) 752 require.NoError(t, err) 753 require.Equal(t, uint64(arraySize), i) 754 }) 755 756 t.Run("remove", func(t *testing.T) { 757 SetThreshold(256) 758 defer SetThreshold(1024) 759 760 const arraySize = 4096 761 762 typeInfo := testTypeInfo{42} 763 storage := newTestPersistentStorage(t) 764 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 765 766 array, err := NewArray(storage, address, typeInfo) 767 require.NoError(t, err) 768 769 for i := uint64(0); i < arraySize; i++ { 770 err := array.Append(Uint64Value(i)) 771 require.NoError(t, err) 772 } 773 774 // Remove every other elements 775 for i := uint64(0); i < array.Count(); i++ { 776 storable, err := array.Remove(i) 777 require.NoError(t, err) 778 require.Equal(t, Uint64Value(i*2), storable) 779 } 780 781 i := uint64(0) 782 j := uint64(1) 783 err = array.Iterate(func(v Value) (bool, error) { 784 require.Equal(t, Uint64Value(j), v) 785 i++ 786 j += 2 787 return true, nil 788 }) 789 require.NoError(t, err) 790 require.Equal(t, uint64(arraySize/2), i) 791 }) 792 793 t.Run("stop", func(t *testing.T) { 794 795 typeInfo := testTypeInfo{42} 796 storage := newTestPersistentStorage(t) 797 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 798 799 array, err := NewArray(storage, address, typeInfo) 800 require.NoError(t, err) 801 802 const count = 10 803 for i := uint64(0); i < count; i++ { 804 err := array.Append(Uint64Value(i)) 805 require.NoError(t, err) 806 } 807 808 i := 0 809 err = array.Iterate(func(_ Value) (bool, error) { 810 if i == count/2 { 811 return false, nil 812 } 813 i++ 814 return true, nil 815 }) 816 require.NoError(t, err) 817 require.Equal(t, count/2, i) 818 }) 819 820 t.Run("error", func(t *testing.T) { 821 822 typeInfo := testTypeInfo{42} 823 storage := newTestPersistentStorage(t) 824 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 825 826 array, err := NewArray(storage, address, typeInfo) 827 require.NoError(t, err) 828 829 const count = 10 830 for i := uint64(0); i < count; i++ { 831 err := array.Append(Uint64Value(i)) 832 require.NoError(t, err) 833 } 834 835 testErr := errors.New("test") 836 837 i := 0 838 err = array.Iterate(func(_ Value) (bool, error) { 839 if i == count/2 { 840 return false, testErr 841 } 842 i++ 843 return true, nil 844 }) 845 // err is testErr wrapped in ExternalError. 846 require.Equal(t, 1, errorCategorizationCount(err)) 847 var externalError *ExternalError 848 require.ErrorAs(t, err, &externalError) 849 require.Equal(t, testErr, externalError.Unwrap()) 850 851 require.Equal(t, count/2, i) 852 }) 853 } 854 855 func testArrayIterateRange(t *testing.T, storage *PersistentSlabStorage, array *Array, values []Value) { 856 var i uint64 857 var err error 858 var sliceOutOfBoundsError *SliceOutOfBoundsError 859 var invalidSliceIndexError *InvalidSliceIndexError 860 861 count := array.Count() 862 863 // If startIndex > count, IterateRange returns SliceOutOfBoundsError 864 err = array.IterateRange(count+1, count+1, func(v Value) (bool, error) { 865 i++ 866 return true, nil 867 }) 868 require.Equal(t, 1, errorCategorizationCount(err)) 869 870 var userError *UserError 871 require.ErrorAs(t, err, &userError) 872 require.ErrorAs(t, err, &sliceOutOfBoundsError) 873 require.ErrorAs(t, userError, &sliceOutOfBoundsError) 874 require.Equal(t, uint64(0), i) 875 876 // If endIndex > count, IterateRange returns SliceOutOfBoundsError 877 err = array.IterateRange(0, count+1, func(v Value) (bool, error) { 878 i++ 879 return true, nil 880 }) 881 require.Equal(t, 1, errorCategorizationCount(err)) 882 require.ErrorAs(t, err, &userError) 883 require.ErrorAs(t, err, &sliceOutOfBoundsError) 884 require.ErrorAs(t, userError, &sliceOutOfBoundsError) 885 require.Equal(t, uint64(0), i) 886 887 // If startIndex > endIndex, IterateRange returns InvalidSliceIndexError 888 if count > 0 { 889 err = array.IterateRange(1, 0, func(v Value) (bool, error) { 890 i++ 891 return true, nil 892 }) 893 require.Equal(t, 1, errorCategorizationCount(err)) 894 require.ErrorAs(t, err, &userError) 895 require.ErrorAs(t, err, &invalidSliceIndexError) 896 require.ErrorAs(t, userError, &invalidSliceIndexError) 897 require.Equal(t, uint64(0), i) 898 } 899 900 // IterateRange returns no error and iteration function is called on sliced array 901 for startIndex := uint64(0); startIndex <= count; startIndex++ { 902 for endIndex := startIndex; endIndex <= count; endIndex++ { 903 i = uint64(0) 904 err = array.IterateRange(startIndex, endIndex, func(v Value) (bool, error) { 905 valueEqual(t, typeInfoComparator, v, values[int(startIndex+i)]) 906 i++ 907 return true, nil 908 }) 909 require.NoError(t, err) 910 require.Equal(t, endIndex-startIndex, i) 911 } 912 } 913 } 914 915 func TestArrayIterateRange(t *testing.T) { 916 typeInfo := testTypeInfo{42} 917 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 918 919 t.Run("empty", func(t *testing.T) { 920 storage := newTestPersistentStorage(t) 921 922 array, err := NewArray(storage, address, typeInfo) 923 require.NoError(t, err) 924 925 testArrayIterateRange(t, storage, array, []Value{}) 926 }) 927 928 t.Run("dataslab as root", func(t *testing.T) { 929 const arraySize = 10 930 931 storage := newTestPersistentStorage(t) 932 933 array, err := NewArray(storage, address, typeInfo) 934 require.NoError(t, err) 935 936 values := make([]Value, arraySize) 937 for i := uint64(0); i < arraySize; i++ { 938 value := Uint64Value(i) 939 values[i] = value 940 err := array.Append(value) 941 require.NoError(t, err) 942 } 943 944 testArrayIterateRange(t, storage, array, values) 945 }) 946 947 t.Run("metadataslab as root", func(t *testing.T) { 948 SetThreshold(256) 949 defer SetThreshold(1024) 950 951 const arraySize = 1024 952 953 storage := newTestPersistentStorage(t) 954 955 array, err := NewArray(storage, address, typeInfo) 956 require.NoError(t, err) 957 958 values := make([]Value, arraySize) 959 for i := uint64(0); i < arraySize; i++ { 960 value := Uint64Value(i) 961 values[i] = value 962 err := array.Append(value) 963 require.NoError(t, err) 964 } 965 966 testArrayIterateRange(t, storage, array, values) 967 }) 968 969 t.Run("stop", func(t *testing.T) { 970 const arraySize = 10 971 972 storage := newTestPersistentStorage(t) 973 974 array, err := NewArray(storage, address, typeInfo) 975 require.NoError(t, err) 976 977 for i := uint64(0); i < arraySize; i++ { 978 err := array.Append(Uint64Value(i)) 979 require.NoError(t, err) 980 } 981 982 i := uint64(0) 983 startIndex := uint64(1) 984 endIndex := uint64(5) 985 count := endIndex - startIndex 986 err = array.IterateRange(startIndex, endIndex, func(_ Value) (bool, error) { 987 if i == count/2 { 988 return false, nil 989 } 990 i++ 991 return true, nil 992 }) 993 require.NoError(t, err) 994 require.Equal(t, count/2, i) 995 }) 996 997 t.Run("error", func(t *testing.T) { 998 storage := newTestPersistentStorage(t) 999 1000 array, err := NewArray(storage, address, typeInfo) 1001 require.NoError(t, err) 1002 1003 const arraySize = 10 1004 for i := uint64(0); i < arraySize; i++ { 1005 err := array.Append(Uint64Value(i)) 1006 require.NoError(t, err) 1007 } 1008 1009 testErr := errors.New("test") 1010 1011 i := uint64(0) 1012 startIndex := uint64(1) 1013 endIndex := uint64(5) 1014 count := endIndex - startIndex 1015 err = array.IterateRange(startIndex, endIndex, func(_ Value) (bool, error) { 1016 if i == count/2 { 1017 return false, testErr 1018 } 1019 i++ 1020 return true, nil 1021 }) 1022 // err is testErr wrapped in ExternalError. 1023 require.Equal(t, 1, errorCategorizationCount(err)) 1024 var externalError *ExternalError 1025 require.ErrorAs(t, err, &externalError) 1026 require.Equal(t, testErr, externalError.Unwrap()) 1027 require.Equal(t, count/2, i) 1028 }) 1029 } 1030 1031 func TestArrayRootStorageID(t *testing.T) { 1032 SetThreshold(256) 1033 defer SetThreshold(1024) 1034 1035 const arraySize = 4096 1036 1037 typeInfo := testTypeInfo{42} 1038 storage := newTestPersistentStorage(t) 1039 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1040 1041 array, err := NewArray(storage, address, typeInfo) 1042 require.NoError(t, err) 1043 1044 savedRootID := array.StorageID() 1045 require.NotEqual(t, StorageIDUndefined, savedRootID) 1046 1047 // Append elements 1048 for i := uint64(0); i < arraySize; i++ { 1049 err := array.Append(Uint64Value(i)) 1050 require.NoError(t, err) 1051 require.Equal(t, savedRootID, array.StorageID()) 1052 } 1053 1054 require.True(t, typeInfoComparator(typeInfo, array.Type())) 1055 require.Equal(t, address, array.Address()) 1056 require.Equal(t, uint64(arraySize), array.Count()) 1057 1058 // Remove elements 1059 for i := uint64(0); i < arraySize; i++ { 1060 storable, err := array.Remove(0) 1061 require.NoError(t, err) 1062 require.Equal(t, Uint64Value(i), storable) 1063 require.Equal(t, savedRootID, array.StorageID()) 1064 } 1065 1066 require.True(t, typeInfoComparator(typeInfo, array.Type())) 1067 require.Equal(t, address, array.Address()) 1068 require.Equal(t, uint64(0), array.Count()) 1069 require.Equal(t, savedRootID, array.StorageID()) 1070 } 1071 1072 func TestArraySetRandomValues(t *testing.T) { 1073 1074 SetThreshold(256) 1075 defer SetThreshold(1024) 1076 1077 const arraySize = 4096 1078 1079 r := newRand(t) 1080 1081 typeInfo := testTypeInfo{42} 1082 storage := newTestPersistentStorage(t) 1083 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1084 1085 array, err := NewArray(storage, address, typeInfo) 1086 require.NoError(t, err) 1087 1088 values := make([]Value, arraySize) 1089 for i := uint64(0); i < arraySize; i++ { 1090 v := Uint64Value(i) 1091 values[i] = v 1092 err := array.Append(v) 1093 require.NoError(t, err) 1094 } 1095 1096 for i := uint64(0); i < arraySize; i++ { 1097 oldValue := values[i] 1098 newValue := randomValue(r, int(MaxInlineArrayElementSize)) 1099 values[i] = newValue 1100 1101 existingStorable, err := array.Set(i, newValue) 1102 require.NoError(t, err) 1103 1104 existingValue, err := existingStorable.StoredValue(storage) 1105 require.NoError(t, err) 1106 valueEqual(t, typeInfoComparator, oldValue, existingValue) 1107 } 1108 1109 verifyArray(t, storage, typeInfo, address, array, values, false) 1110 } 1111 1112 func TestArrayInsertRandomValues(t *testing.T) { 1113 1114 SetThreshold(256) 1115 defer SetThreshold(1024) 1116 1117 t.Run("insert-first", func(t *testing.T) { 1118 1119 const arraySize = 4096 1120 1121 r := newRand(t) 1122 1123 typeInfo := testTypeInfo{42} 1124 storage := newTestPersistentStorage(t) 1125 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1126 1127 array, err := NewArray(storage, address, typeInfo) 1128 require.NoError(t, err) 1129 1130 values := make([]Value, arraySize) 1131 for i := uint64(0); i < arraySize; i++ { 1132 v := randomValue(r, int(MaxInlineArrayElementSize)) 1133 values[arraySize-i-1] = v 1134 1135 err := array.Insert(0, v) 1136 require.NoError(t, err) 1137 } 1138 1139 verifyArray(t, storage, typeInfo, address, array, values, false) 1140 }) 1141 1142 t.Run("insert-last", func(t *testing.T) { 1143 1144 const arraySize = 4096 1145 1146 r := newRand(t) 1147 1148 typeInfo := testTypeInfo{42} 1149 storage := newTestPersistentStorage(t) 1150 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1151 1152 array, err := NewArray(storage, address, typeInfo) 1153 require.NoError(t, err) 1154 1155 values := make([]Value, arraySize) 1156 for i := uint64(0); i < arraySize; i++ { 1157 v := randomValue(r, int(MaxInlineArrayElementSize)) 1158 values[i] = v 1159 1160 err := array.Insert(i, v) 1161 require.NoError(t, err) 1162 } 1163 1164 verifyArray(t, storage, typeInfo, address, array, values, false) 1165 }) 1166 1167 t.Run("insert-random", func(t *testing.T) { 1168 1169 const arraySize = 4096 1170 1171 r := newRand(t) 1172 1173 typeInfo := testTypeInfo{42} 1174 storage := newTestPersistentStorage(t) 1175 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1176 1177 array, err := NewArray(storage, address, typeInfo) 1178 require.NoError(t, err) 1179 1180 values := make([]Value, arraySize) 1181 for i := uint64(0); i < arraySize; i++ { 1182 k := r.Intn(int(i) + 1) 1183 v := randomValue(r, int(MaxInlineArrayElementSize)) 1184 1185 copy(values[k+1:], values[k:]) 1186 values[k] = v 1187 1188 err := array.Insert(uint64(k), v) 1189 require.NoError(t, err) 1190 } 1191 1192 verifyArray(t, storage, typeInfo, address, array, values, false) 1193 }) 1194 } 1195 1196 func TestArrayRemoveRandomValues(t *testing.T) { 1197 1198 SetThreshold(256) 1199 defer SetThreshold(1024) 1200 1201 const arraySize = 4096 1202 1203 r := newRand(t) 1204 1205 typeInfo := testTypeInfo{42} 1206 storage := newTestPersistentStorage(t) 1207 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1208 1209 array, err := NewArray(storage, address, typeInfo) 1210 require.NoError(t, err) 1211 1212 values := make([]Value, arraySize) 1213 // Insert n random values into array 1214 for i := uint64(0); i < arraySize; i++ { 1215 v := randomValue(r, int(MaxInlineArrayElementSize)) 1216 values[i] = v 1217 1218 err := array.Insert(i, v) 1219 require.NoError(t, err) 1220 } 1221 1222 verifyArray(t, storage, typeInfo, address, array, values, false) 1223 1224 // Remove n elements at random index 1225 for i := uint64(0); i < arraySize; i++ { 1226 k := r.Intn(int(array.Count())) 1227 1228 existingStorable, err := array.Remove(uint64(k)) 1229 require.NoError(t, err) 1230 1231 existingValue, err := existingStorable.StoredValue(storage) 1232 require.NoError(t, err) 1233 valueEqual(t, typeInfoComparator, values[k], existingValue) 1234 1235 copy(values[k:], values[k+1:]) 1236 values = values[:len(values)-1] 1237 1238 if id, ok := existingStorable.(StorageIDStorable); ok { 1239 err = storage.Remove(StorageID(id)) 1240 require.NoError(t, err) 1241 } 1242 } 1243 1244 verifyEmptyArray(t, storage, typeInfo, address, array) 1245 } 1246 1247 func testArrayAppendSetInsertRemoveRandomValues( 1248 t *testing.T, 1249 r *rand.Rand, 1250 storage *PersistentSlabStorage, 1251 typeInfo TypeInfo, 1252 address Address, 1253 opCount int, 1254 ) (*Array, []Value) { 1255 const ( 1256 ArrayAppendOp = iota 1257 ArrayInsertOp 1258 ArraySetOp 1259 ArrayRemoveOp 1260 MaxArrayOp 1261 ) 1262 1263 array, err := NewArray(storage, address, typeInfo) 1264 require.NoError(t, err) 1265 1266 values := make([]Value, 0, opCount) 1267 for i := 0; i < opCount; i++ { 1268 1269 var nextOp int 1270 1271 for { 1272 nextOp = r.Intn(MaxArrayOp) 1273 1274 if array.Count() > 0 || (nextOp != ArrayRemoveOp && nextOp != ArraySetOp) { 1275 break 1276 } 1277 } 1278 1279 switch nextOp { 1280 1281 case ArrayAppendOp: 1282 v := randomValue(r, int(MaxInlineArrayElementSize)) 1283 values = append(values, v) 1284 1285 err := array.Append(v) 1286 require.NoError(t, err) 1287 1288 case ArraySetOp: 1289 k := r.Intn(int(array.Count())) 1290 v := randomValue(r, int(MaxInlineArrayElementSize)) 1291 1292 oldV := values[k] 1293 1294 values[k] = v 1295 1296 existingStorable, err := array.Set(uint64(k), v) 1297 require.NoError(t, err) 1298 1299 existingValue, err := existingStorable.StoredValue(storage) 1300 require.NoError(t, err) 1301 valueEqual(t, typeInfoComparator, oldV, existingValue) 1302 1303 if id, ok := existingStorable.(StorageIDStorable); ok { 1304 err = storage.Remove(StorageID(id)) 1305 require.NoError(t, err) 1306 } 1307 1308 case ArrayInsertOp: 1309 k := r.Intn(int(array.Count() + 1)) 1310 v := randomValue(r, int(MaxInlineArrayElementSize)) 1311 1312 if k == int(array.Count()) { 1313 values = append(values, v) 1314 } else { 1315 values = append(values, nil) 1316 copy(values[k+1:], values[k:]) 1317 values[k] = v 1318 } 1319 1320 err := array.Insert(uint64(k), v) 1321 require.NoError(t, err) 1322 1323 case ArrayRemoveOp: 1324 k := r.Intn(int(array.Count())) 1325 1326 existingStorable, err := array.Remove(uint64(k)) 1327 require.NoError(t, err) 1328 1329 existingValue, err := existingStorable.StoredValue(storage) 1330 require.NoError(t, err) 1331 valueEqual(t, typeInfoComparator, values[k], existingValue) 1332 1333 copy(values[k:], values[k+1:]) 1334 values = values[:len(values)-1] 1335 1336 if id, ok := existingStorable.(StorageIDStorable); ok { 1337 err = storage.Remove(StorageID(id)) 1338 require.NoError(t, err) 1339 } 1340 } 1341 1342 require.Equal(t, uint64(len(values)), array.Count()) 1343 require.True(t, typeInfoComparator(typeInfo, array.Type())) 1344 require.Equal(t, address, array.Address()) 1345 } 1346 1347 return array, values 1348 } 1349 1350 func TestArrayAppendSetInsertRemoveRandomValues(t *testing.T) { 1351 1352 SetThreshold(256) 1353 defer SetThreshold(1024) 1354 1355 const opCount = 4096 1356 1357 r := newRand(t) 1358 1359 typeInfo := testTypeInfo{42} 1360 storage := newTestPersistentStorage(t) 1361 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1362 1363 array, values := testArrayAppendSetInsertRemoveRandomValues(t, r, storage, typeInfo, address, opCount) 1364 verifyArray(t, storage, typeInfo, address, array, values, false) 1365 } 1366 1367 func TestArrayNestedArrayMap(t *testing.T) { 1368 1369 SetThreshold(256) 1370 defer SetThreshold(1024) 1371 1372 t.Run("small array", func(t *testing.T) { 1373 1374 const arraySize = 4096 1375 1376 nestedTypeInfo := testTypeInfo{43} 1377 storage := newTestPersistentStorage(t) 1378 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1379 1380 // Create a list of arrays with 2 elements. 1381 nestedArrays := make([]Value, arraySize) 1382 for i := uint64(0); i < arraySize; i++ { 1383 nested, err := NewArray(storage, address, nestedTypeInfo) 1384 require.NoError(t, err) 1385 1386 err = nested.Append(Uint64Value(i)) 1387 require.NoError(t, err) 1388 1389 require.True(t, nested.root.IsData()) 1390 1391 nestedArrays[i] = nested 1392 } 1393 1394 typeInfo := testTypeInfo{42} 1395 1396 array, err := NewArray(storage, address, typeInfo) 1397 require.NoError(t, err) 1398 1399 for _, a := range nestedArrays { 1400 err := array.Append(a) 1401 require.NoError(t, err) 1402 } 1403 1404 verifyArray(t, storage, typeInfo, address, array, nestedArrays, false) 1405 }) 1406 1407 t.Run("big array", func(t *testing.T) { 1408 1409 const arraySize = 4096 1410 1411 nestedTypeInfo := testTypeInfo{43} 1412 storage := newTestPersistentStorage(t) 1413 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1414 1415 values := make([]Value, arraySize) 1416 for i := uint64(0); i < arraySize; i++ { 1417 nested, err := NewArray(storage, address, nestedTypeInfo) 1418 require.NoError(t, err) 1419 1420 for i := uint64(0); i < 40; i++ { 1421 err := nested.Append(Uint64Value(math.MaxUint64)) 1422 require.NoError(t, err) 1423 } 1424 1425 require.False(t, nested.root.IsData()) 1426 1427 values[i] = nested 1428 } 1429 1430 typeInfo := testTypeInfo{42} 1431 1432 array, err := NewArray(storage, address, typeInfo) 1433 require.NoError(t, err) 1434 for _, a := range values { 1435 err := array.Append(a) 1436 require.NoError(t, err) 1437 } 1438 1439 verifyArray(t, storage, typeInfo, address, array, values, true) 1440 }) 1441 1442 t.Run("small map", func(t *testing.T) { 1443 1444 const arraySize = 4096 1445 1446 nestedTypeInfo := testTypeInfo{43} 1447 1448 storage := newTestPersistentStorage(t) 1449 1450 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1451 1452 nestedMaps := make([]Value, arraySize) 1453 for i := uint64(0); i < arraySize; i++ { 1454 nested, err := NewMap(storage, address, NewDefaultDigesterBuilder(), nestedTypeInfo) 1455 require.NoError(t, err) 1456 1457 storable, err := nested.Set(compare, hashInputProvider, Uint64Value(i), Uint64Value(i*2)) 1458 require.NoError(t, err) 1459 require.Nil(t, storable) 1460 1461 require.True(t, nested.root.IsData()) 1462 1463 nestedMaps[i] = nested 1464 } 1465 1466 typeInfo := testTypeInfo{42} 1467 1468 array, err := NewArray(storage, address, typeInfo) 1469 require.NoError(t, err) 1470 1471 for _, a := range nestedMaps { 1472 err := array.Append(a) 1473 require.NoError(t, err) 1474 } 1475 1476 verifyArray(t, storage, typeInfo, address, array, nestedMaps, false) 1477 }) 1478 1479 t.Run("big map", func(t *testing.T) { 1480 1481 const arraySize = 4096 1482 1483 nestedTypeInfo := testTypeInfo{43} 1484 storage := newTestPersistentStorage(t) 1485 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1486 1487 values := make([]Value, arraySize) 1488 for i := uint64(0); i < arraySize; i++ { 1489 nested, err := NewMap(storage, address, NewDefaultDigesterBuilder(), nestedTypeInfo) 1490 require.NoError(t, err) 1491 1492 for i := uint64(0); i < 25; i++ { 1493 storable, err := nested.Set(compare, hashInputProvider, Uint64Value(i), Uint64Value(i*2)) 1494 require.NoError(t, err) 1495 require.Nil(t, storable) 1496 } 1497 1498 require.False(t, nested.root.IsData()) 1499 1500 values[i] = nested 1501 } 1502 1503 typeInfo := testTypeInfo{42} 1504 1505 array, err := NewArray(storage, address, typeInfo) 1506 require.NoError(t, err) 1507 for _, a := range values { 1508 err := array.Append(a) 1509 require.NoError(t, err) 1510 } 1511 1512 verifyArray(t, storage, typeInfo, address, array, values, true) 1513 }) 1514 } 1515 1516 func TestArrayEncodeDecode(t *testing.T) { 1517 1518 SetThreshold(256) 1519 defer SetThreshold(1024) 1520 1521 t.Run("empty", func(t *testing.T) { 1522 typeInfo := testTypeInfo{42} 1523 storage := newTestBasicStorage(t) 1524 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1525 1526 array, err := NewArray(storage, address, typeInfo) 1527 require.NoError(t, err) 1528 1529 expectedData := []byte{ 1530 // extra data 1531 // version 1532 0x00, 1533 // extra data flag 1534 0x80, 1535 // array of extra data 1536 0x81, 1537 // type info 1538 0x18, 0x2a, 1539 1540 // version 1541 0x00, 1542 // array data slab flag 1543 0x80, 1544 // CBOR encoded array head (fixed size 3 byte) 1545 0x99, 0x00, 0x00, 1546 } 1547 1548 slabData, err := storage.Encode() 1549 require.NoError(t, err) 1550 require.Equal(t, 1, len(slabData)) 1551 require.Equal(t, expectedData, slabData[array.StorageID()]) 1552 1553 // Decode data to new storage 1554 storage2 := newTestPersistentStorageWithData(t, slabData) 1555 1556 // Test new array from storage2 1557 array2, err := NewArrayWithRootID(storage2, array.StorageID()) 1558 require.NoError(t, err) 1559 1560 verifyEmptyArray(t, storage2, typeInfo, address, array2) 1561 }) 1562 1563 t.Run("dataslab as root", func(t *testing.T) { 1564 typeInfo := testTypeInfo{42} 1565 storage := newTestBasicStorage(t) 1566 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1567 1568 array, err := NewArray(storage, address, typeInfo) 1569 require.NoError(t, err) 1570 1571 v := Uint64Value(0) 1572 values := []Value{v} 1573 err = array.Append(v) 1574 require.NoError(t, err) 1575 1576 expectedData := []byte{ 1577 // extra data 1578 // version 1579 0x00, 1580 // extra data flag 1581 0x80, 1582 // array of extra data 1583 0x81, 1584 // type info 1585 0x18, 0x2a, 1586 1587 // version 1588 0x00, 1589 // array data slab flag 1590 0x80, 1591 // CBOR encoded array head (fixed size 3 byte) 1592 0x99, 0x00, 0x01, 1593 // CBOR encoded array elements 1594 0xd8, 0xa4, 0x00, 1595 } 1596 1597 slabData, err := storage.Encode() 1598 require.NoError(t, err) 1599 require.Equal(t, 1, len(slabData)) 1600 require.Equal(t, expectedData, slabData[array.StorageID()]) 1601 1602 // Decode data to new storage 1603 storage2 := newTestPersistentStorageWithData(t, slabData) 1604 1605 // Test new array from storage2 1606 array2, err := NewArrayWithRootID(storage2, array.StorageID()) 1607 require.NoError(t, err) 1608 1609 verifyArray(t, storage2, typeInfo, address, array2, values, false) 1610 }) 1611 1612 t.Run("has pointers", func(t *testing.T) { 1613 typeInfo := testTypeInfo{42} 1614 storage := newTestBasicStorage(t) 1615 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1616 1617 array, err := NewArray(storage, address, typeInfo) 1618 require.NoError(t, err) 1619 1620 const arraySize = 20 1621 values := make([]Value, arraySize) 1622 for i := uint64(0); i < arraySize-1; i++ { 1623 v := NewStringValue(strings.Repeat("a", 22)) 1624 values[i] = v 1625 err := array.Append(v) 1626 require.NoError(t, err) 1627 } 1628 1629 typeInfo2 := testTypeInfo{43} 1630 1631 nestedArray, err := NewArray(storage, address, typeInfo2) 1632 require.NoError(t, err) 1633 1634 err = nestedArray.Append(Uint64Value(0)) 1635 require.NoError(t, err) 1636 1637 values[arraySize-1] = nestedArray 1638 1639 err = array.Append(nestedArray) 1640 require.NoError(t, err) 1641 1642 require.Equal(t, uint64(arraySize), array.Count()) 1643 require.Equal(t, uint64(1), nestedArray.Count()) 1644 1645 id1 := StorageID{Address: address, Index: StorageIndex{0, 0, 0, 0, 0, 0, 0, 1}} 1646 id2 := StorageID{Address: address, Index: StorageIndex{0, 0, 0, 0, 0, 0, 0, 2}} 1647 id3 := StorageID{Address: address, Index: StorageIndex{0, 0, 0, 0, 0, 0, 0, 3}} 1648 id4 := StorageID{Address: address, Index: StorageIndex{0, 0, 0, 0, 0, 0, 0, 4}} 1649 1650 // Expected serialized slab data with storage id 1651 expected := map[StorageID][]byte{ 1652 1653 // (metadata slab) headers: [{id:2 size:228 count:9} {id:3 size:270 count:11} ] 1654 id1: { 1655 // extra data 1656 // version 1657 0x00, 1658 // extra data flag 1659 0x81, 1660 // array of extra data 1661 0x81, 1662 // type info 1663 0x18, 0x2a, 1664 1665 // version 1666 0x00, 1667 // array meta data slab flag 1668 0x81, 1669 // child header count 1670 0x00, 0x02, 1671 // child header 1 (storage id, count, size) 1672 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 1673 0x00, 0x00, 0x00, 0x09, 1674 0x00, 0x00, 0x00, 0xe4, 1675 // child header 2 1676 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 1677 0x00, 0x00, 0x00, 0x0b, 1678 0x00, 0x00, 0x01, 0x0e, 1679 }, 1680 1681 // (data slab) next: 3, data: [aaaaaaaaaaaaaaaaaaaaaa ... aaaaaaaaaaaaaaaaaaaaaa] 1682 id2: { 1683 // version 1684 0x00, 1685 // array data slab flag 1686 0x00, 1687 // next storage id 1688 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 1689 // CBOR encoded array head (fixed size 3 byte) 1690 0x99, 0x00, 0x09, 1691 // CBOR encoded array elements 1692 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1693 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1694 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1695 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1696 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1697 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1698 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1699 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1700 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1701 }, 1702 1703 // (data slab) next: 0, data: [aaaaaaaaaaaaaaaaaaaaaa ... StorageID(...)] 1704 id3: { 1705 // version 1706 0x00, 1707 // array data slab flag 1708 0x40, 1709 // next storage id 1710 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1711 // CBOR encoded array head (fixed size 3 byte) 1712 0x99, 0x00, 0x0b, 1713 // CBOR encoded array elements 1714 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1715 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1716 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1717 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1718 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1719 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1720 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1721 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1722 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1723 0x76, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 1724 0xd8, 0xff, 0x50, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 1725 }, 1726 1727 // (data slab) next: 0, data: [0] 1728 id4: { 1729 // extra data 1730 // version 1731 0x00, 1732 // extra data flag 1733 0x80, 1734 // array of extra data 1735 0x81, 1736 // type info 1737 0x18, 0x2b, 1738 1739 // version 1740 0x00, 1741 // array data slab flag 1742 0x80, 1743 // CBOR encoded array head (fixed size 3 byte) 1744 0x99, 0x00, 0x01, 1745 // CBOR encoded array elements 1746 0xd8, 0xa4, 0x00, 1747 }, 1748 } 1749 1750 m, err := storage.Encode() 1751 require.NoError(t, err) 1752 require.Equal(t, len(expected), len(m)) 1753 require.Equal(t, expected[id1], m[id1]) 1754 require.Equal(t, expected[id2], m[id2]) 1755 require.Equal(t, expected[id3], m[id3]) 1756 require.Equal(t, expected[id4], m[id4]) 1757 1758 // Decode data to new storage 1759 storage2 := newTestPersistentStorageWithData(t, m) 1760 1761 // Test new array from storage2 1762 array2, err := NewArrayWithRootID(storage2, array.StorageID()) 1763 require.NoError(t, err) 1764 1765 verifyArray(t, storage2, typeInfo, address, array2, values, false) 1766 }) 1767 } 1768 1769 func TestArrayEncodeDecodeRandomValues(t *testing.T) { 1770 1771 SetThreshold(256) 1772 defer SetThreshold(1024) 1773 1774 const opCount = 8192 1775 1776 r := newRand(t) 1777 1778 typeInfo := testTypeInfo{42} 1779 storage := newTestPersistentStorage(t) 1780 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1781 1782 array, values := testArrayAppendSetInsertRemoveRandomValues(t, r, storage, typeInfo, address, opCount) 1783 1784 verifyArray(t, storage, typeInfo, address, array, values, false) 1785 1786 // Decode data to new storage 1787 storage2 := newTestPersistentStorageWithBaseStorage(t, storage.baseStorage) 1788 1789 // Test new array from storage2 1790 array2, err := NewArrayWithRootID(storage2, array.StorageID()) 1791 require.NoError(t, err) 1792 1793 verifyArray(t, storage2, typeInfo, address, array2, values, false) 1794 } 1795 1796 func TestEmptyArray(t *testing.T) { 1797 1798 t.Parallel() 1799 1800 typeInfo := testTypeInfo{42} 1801 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1802 storage := newTestBasicStorage(t) 1803 1804 array, err := NewArray(storage, address, typeInfo) 1805 require.NoError(t, err) 1806 1807 t.Run("get", func(t *testing.T) { 1808 s, err := array.Get(0) 1809 require.Equal(t, 1, errorCategorizationCount(err)) 1810 var userError *UserError 1811 var indexOutOfBoundsError *IndexOutOfBoundsError 1812 require.ErrorAs(t, err, &userError) 1813 require.ErrorAs(t, err, &indexOutOfBoundsError) 1814 require.ErrorAs(t, userError, &indexOutOfBoundsError) 1815 require.Nil(t, s) 1816 }) 1817 1818 t.Run("set", func(t *testing.T) { 1819 s, err := array.Set(0, Uint64Value(0)) 1820 require.Equal(t, 1, errorCategorizationCount(err)) 1821 var userError *UserError 1822 var indexOutOfBoundsError *IndexOutOfBoundsError 1823 require.ErrorAs(t, err, &userError) 1824 require.ErrorAs(t, err, &indexOutOfBoundsError) 1825 require.ErrorAs(t, userError, &indexOutOfBoundsError) 1826 require.Nil(t, s) 1827 }) 1828 1829 t.Run("insert", func(t *testing.T) { 1830 err := array.Insert(1, Uint64Value(0)) 1831 require.Equal(t, 1, errorCategorizationCount(err)) 1832 var userError *UserError 1833 var indexOutOfBoundsError *IndexOutOfBoundsError 1834 require.ErrorAs(t, err, &userError) 1835 require.ErrorAs(t, err, &indexOutOfBoundsError) 1836 require.ErrorAs(t, userError, &indexOutOfBoundsError) 1837 }) 1838 1839 t.Run("remove", func(t *testing.T) { 1840 s, err := array.Remove(0) 1841 require.Equal(t, 1, errorCategorizationCount(err)) 1842 var userError *UserError 1843 var indexOutOfBoundsError *IndexOutOfBoundsError 1844 require.ErrorAs(t, err, &userError) 1845 require.ErrorAs(t, err, &indexOutOfBoundsError) 1846 require.ErrorAs(t, userError, &indexOutOfBoundsError) 1847 require.Nil(t, s) 1848 }) 1849 1850 t.Run("iterate", func(t *testing.T) { 1851 i := uint64(0) 1852 err := array.Iterate(func(v Value) (bool, error) { 1853 i++ 1854 return true, nil 1855 }) 1856 require.NoError(t, err) 1857 require.Equal(t, uint64(0), i) 1858 }) 1859 1860 t.Run("count", func(t *testing.T) { 1861 count := array.Count() 1862 require.Equal(t, uint64(0), count) 1863 }) 1864 1865 t.Run("type", func(t *testing.T) { 1866 require.True(t, typeInfoComparator(typeInfo, array.Type())) 1867 }) 1868 1869 // TestArrayEncodeDecode/empty tests empty array encoding and decoding 1870 } 1871 1872 func TestArrayStringElement(t *testing.T) { 1873 1874 t.Parallel() 1875 1876 t.Run("inline", func(t *testing.T) { 1877 1878 const arraySize = 4096 1879 1880 r := newRand(t) 1881 1882 stringSize := int(MaxInlineArrayElementSize - 3) 1883 1884 values := make([]Value, arraySize) 1885 for i := uint64(0); i < arraySize; i++ { 1886 s := randStr(r, stringSize) 1887 values[i] = NewStringValue(s) 1888 } 1889 1890 storage := newTestPersistentStorage(t) 1891 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1892 typeInfo := testTypeInfo{42} 1893 1894 array, err := NewArray(storage, address, typeInfo) 1895 require.NoError(t, err) 1896 1897 for i := uint64(0); i < arraySize; i++ { 1898 err := array.Append(values[i]) 1899 require.NoError(t, err) 1900 } 1901 1902 verifyArray(t, storage, typeInfo, address, array, values, false) 1903 1904 stats, err := GetArrayStats(array) 1905 require.NoError(t, err) 1906 require.Equal(t, uint64(0), stats.StorableSlabCount) 1907 }) 1908 1909 t.Run("external slab", func(t *testing.T) { 1910 1911 const arraySize = 4096 1912 1913 r := newRand(t) 1914 1915 stringSize := int(MaxInlineArrayElementSize + 512) 1916 1917 values := make([]Value, arraySize) 1918 for i := uint64(0); i < arraySize; i++ { 1919 s := randStr(r, stringSize) 1920 values[i] = NewStringValue(s) 1921 } 1922 1923 storage := newTestPersistentStorage(t) 1924 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1925 typeInfo := testTypeInfo{42} 1926 1927 array, err := NewArray(storage, address, typeInfo) 1928 require.NoError(t, err) 1929 1930 for i := uint64(0); i < arraySize; i++ { 1931 err := array.Append(values[i]) 1932 require.NoError(t, err) 1933 } 1934 1935 verifyArray(t, storage, typeInfo, address, array, values, false) 1936 1937 stats, err := GetArrayStats(array) 1938 require.NoError(t, err) 1939 require.Equal(t, uint64(arraySize), stats.StorableSlabCount) 1940 }) 1941 } 1942 1943 func TestArrayStoredValue(t *testing.T) { 1944 1945 const arraySize = 4096 1946 1947 typeInfo := testTypeInfo{42} 1948 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 1949 storage := newTestPersistentStorage(t) 1950 1951 array, err := NewArray(storage, address, typeInfo) 1952 require.NoError(t, err) 1953 1954 values := make([]Value, arraySize) 1955 for i := uint64(0); i < arraySize; i++ { 1956 v := Uint64Value(i) 1957 values[i] = v 1958 err := array.Append(v) 1959 require.NoError(t, err) 1960 } 1961 1962 rootID := array.StorageID() 1963 1964 slabIterator, err := storage.SlabIterator() 1965 require.NoError(t, err) 1966 1967 for { 1968 id, slab := slabIterator() 1969 1970 if id == StorageIDUndefined { 1971 break 1972 } 1973 1974 value, err := slab.StoredValue(storage) 1975 1976 if id == rootID { 1977 require.NoError(t, err) 1978 1979 array2, ok := value.(*Array) 1980 require.True(t, ok) 1981 1982 verifyArray(t, storage, typeInfo, address, array2, values, false) 1983 } else { 1984 require.Equal(t, 1, errorCategorizationCount(err)) 1985 var fatalError *FatalError 1986 var notValueError *NotValueError 1987 require.ErrorAs(t, err, &fatalError) 1988 require.ErrorAs(t, err, ¬ValueError) 1989 require.ErrorAs(t, fatalError, ¬ValueError) 1990 require.Nil(t, value) 1991 } 1992 } 1993 } 1994 1995 func TestArrayPopIterate(t *testing.T) { 1996 1997 t.Run("empty", func(t *testing.T) { 1998 typeInfo := testTypeInfo{42} 1999 storage := newTestPersistentStorage(t) 2000 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2001 2002 array, err := NewArray(storage, address, typeInfo) 2003 require.NoError(t, err) 2004 2005 i := uint64(0) 2006 err = array.PopIterate(func(v Storable) { 2007 i++ 2008 }) 2009 require.NoError(t, err) 2010 require.Equal(t, uint64(0), i) 2011 2012 verifyEmptyArray(t, storage, typeInfo, address, array) 2013 }) 2014 2015 t.Run("root-dataslab", func(t *testing.T) { 2016 2017 const arraySize = 10 2018 2019 typeInfo := testTypeInfo{42} 2020 storage := newTestPersistentStorage(t) 2021 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2022 2023 array, err := NewArray(storage, address, typeInfo) 2024 require.NoError(t, err) 2025 2026 values := make([]Value, arraySize) 2027 for i := uint64(0); i < arraySize; i++ { 2028 v := Uint64Value(i) 2029 values[i] = v 2030 err := array.Append(v) 2031 require.NoError(t, err) 2032 } 2033 2034 i := 0 2035 err = array.PopIterate(func(v Storable) { 2036 vv, err := v.StoredValue(storage) 2037 require.NoError(t, err) 2038 valueEqual(t, typeInfoComparator, values[arraySize-i-1], vv) 2039 i++ 2040 }) 2041 require.NoError(t, err) 2042 require.Equal(t, arraySize, i) 2043 2044 verifyEmptyArray(t, storage, typeInfo, address, array) 2045 }) 2046 2047 t.Run("root-metaslab", func(t *testing.T) { 2048 SetThreshold(256) 2049 defer SetThreshold(1024) 2050 2051 const arraySize = 4096 2052 2053 typeInfo := testTypeInfo{42} 2054 storage := newTestPersistentStorage(t) 2055 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2056 2057 array, err := NewArray(storage, address, typeInfo) 2058 require.NoError(t, err) 2059 2060 values := make([]Value, arraySize) 2061 for i := uint64(0); i < arraySize; i++ { 2062 v := Uint64Value(i) 2063 values[i] = v 2064 err := array.Append(v) 2065 require.NoError(t, err) 2066 } 2067 2068 i := 0 2069 err = array.PopIterate(func(v Storable) { 2070 vv, err := v.StoredValue(storage) 2071 require.NoError(t, err) 2072 valueEqual(t, typeInfoComparator, values[arraySize-i-1], vv) 2073 i++ 2074 }) 2075 require.NoError(t, err) 2076 require.Equal(t, arraySize, i) 2077 2078 verifyEmptyArray(t, storage, typeInfo, address, array) 2079 }) 2080 } 2081 2082 func TestArrayFromBatchData(t *testing.T) { 2083 2084 t.Run("empty", func(t *testing.T) { 2085 typeInfo := testTypeInfo{42} 2086 2087 array, err := NewArray( 2088 newTestPersistentStorage(t), 2089 Address{1, 2, 3, 4, 5, 6, 7, 8}, 2090 typeInfo) 2091 require.NoError(t, err) 2092 require.Equal(t, uint64(0), array.Count()) 2093 2094 iter, err := array.Iterator() 2095 require.NoError(t, err) 2096 2097 // Create a new array with new storage, new address, and original array's elements. 2098 address := Address{2, 3, 4, 5, 6, 7, 8, 9} 2099 storage := newTestPersistentStorage(t) 2100 copied, err := NewArrayFromBatchData( 2101 storage, 2102 address, 2103 array.Type(), 2104 func() (Value, error) { 2105 return iter.Next() 2106 }) 2107 require.NoError(t, err) 2108 require.NotEqual(t, copied.StorageID(), array.StorageID()) 2109 2110 verifyEmptyArray(t, storage, typeInfo, address, copied) 2111 }) 2112 2113 t.Run("root-dataslab", func(t *testing.T) { 2114 2115 const arraySize = 10 2116 2117 typeInfo := testTypeInfo{42} 2118 array, err := NewArray( 2119 newTestPersistentStorage(t), 2120 Address{1, 2, 3, 4, 5, 6, 7, 8}, 2121 typeInfo) 2122 require.NoError(t, err) 2123 2124 values := make([]Value, arraySize) 2125 for i := uint64(0); i < arraySize; i++ { 2126 v := Uint64Value(i) 2127 values[i] = v 2128 err := array.Append(v) 2129 require.NoError(t, err) 2130 } 2131 2132 require.Equal(t, uint64(arraySize), array.Count()) 2133 2134 iter, err := array.Iterator() 2135 require.NoError(t, err) 2136 2137 // Create a new array with new storage, new address, and original array's elements. 2138 address := Address{2, 3, 4, 5, 6, 7, 8, 9} 2139 storage := newTestPersistentStorage(t) 2140 copied, err := NewArrayFromBatchData( 2141 storage, 2142 address, 2143 array.Type(), 2144 func() (Value, error) { 2145 return iter.Next() 2146 }) 2147 2148 require.NoError(t, err) 2149 require.NotEqual(t, copied.StorageID(), array.StorageID()) 2150 2151 verifyArray(t, storage, typeInfo, address, copied, values, false) 2152 }) 2153 2154 t.Run("root-metaslab", func(t *testing.T) { 2155 SetThreshold(256) 2156 defer SetThreshold(1024) 2157 2158 const arraySize = 4096 2159 2160 typeInfo := testTypeInfo{42} 2161 2162 array, err := NewArray( 2163 newTestPersistentStorage(t), 2164 Address{1, 2, 3, 4, 5, 6, 7, 8}, 2165 typeInfo) 2166 require.NoError(t, err) 2167 2168 values := make([]Value, arraySize) 2169 for i := uint64(0); i < arraySize; i++ { 2170 v := Uint64Value(i) 2171 values[i] = v 2172 err := array.Append(v) 2173 require.NoError(t, err) 2174 } 2175 2176 require.Equal(t, uint64(arraySize), array.Count()) 2177 2178 iter, err := array.Iterator() 2179 require.NoError(t, err) 2180 2181 address := Address{2, 3, 4, 5, 6, 7, 8, 9} 2182 storage := newTestPersistentStorage(t) 2183 copied, err := NewArrayFromBatchData( 2184 storage, 2185 address, 2186 array.Type(), 2187 func() (Value, error) { 2188 return iter.Next() 2189 }) 2190 2191 require.NoError(t, err) 2192 require.NotEqual(t, array.StorageID(), copied.StorageID()) 2193 2194 verifyArray(t, storage, typeInfo, address, copied, values, false) 2195 }) 2196 2197 t.Run("rebalance two data slabs", func(t *testing.T) { 2198 SetThreshold(256) 2199 defer SetThreshold(1024) 2200 2201 typeInfo := testTypeInfo{42} 2202 2203 array, err := NewArray( 2204 newTestPersistentStorage(t), 2205 Address{1, 2, 3, 4, 5, 6, 7, 8}, 2206 typeInfo) 2207 require.NoError(t, err) 2208 2209 var values []Value 2210 var v Value 2211 2212 v = NewStringValue(strings.Repeat("a", int(MaxInlineArrayElementSize-2))) 2213 values = append(values, v) 2214 2215 err = array.Insert(0, v) 2216 require.NoError(t, err) 2217 2218 for i := 0; i < 35; i++ { 2219 v = Uint64Value(i) 2220 values = append(values, v) 2221 2222 err = array.Append(v) 2223 require.NoError(t, err) 2224 } 2225 2226 require.Equal(t, uint64(36), array.Count()) 2227 2228 iter, err := array.Iterator() 2229 require.NoError(t, err) 2230 2231 storage := newTestPersistentStorage(t) 2232 address := Address{2, 3, 4, 5, 6, 7, 8, 9} 2233 copied, err := NewArrayFromBatchData( 2234 storage, 2235 address, 2236 array.Type(), 2237 func() (Value, error) { 2238 return iter.Next() 2239 }) 2240 2241 require.NoError(t, err) 2242 require.NotEqual(t, array.StorageID(), copied.StorageID()) 2243 2244 verifyArray(t, storage, typeInfo, address, copied, values, false) 2245 }) 2246 2247 t.Run("merge two data slabs", func(t *testing.T) { 2248 SetThreshold(256) 2249 defer SetThreshold(1024) 2250 2251 typeInfo := testTypeInfo{42} 2252 2253 array, err := NewArray( 2254 newTestPersistentStorage(t), 2255 Address{1, 2, 3, 4, 5, 6, 7, 8}, 2256 typeInfo) 2257 require.NoError(t, err) 2258 2259 var values []Value 2260 var v Value 2261 for i := 0; i < 35; i++ { 2262 v = Uint64Value(i) 2263 values = append(values, v) 2264 err = array.Append(v) 2265 require.NoError(t, err) 2266 } 2267 2268 v = NewStringValue(strings.Repeat("a", int(MaxInlineArrayElementSize-2))) 2269 values = append(values, nil) 2270 copy(values[25+1:], values[25:]) 2271 values[25] = v 2272 2273 err = array.Insert(25, v) 2274 require.NoError(t, err) 2275 2276 require.Equal(t, uint64(36), array.Count()) 2277 2278 iter, err := array.Iterator() 2279 require.NoError(t, err) 2280 2281 storage := newTestPersistentStorage(t) 2282 address := Address{2, 3, 4, 5, 6, 7, 8, 9} 2283 copied, err := NewArrayFromBatchData( 2284 storage, 2285 address, 2286 array.Type(), 2287 func() (Value, error) { 2288 return iter.Next() 2289 }) 2290 2291 require.NoError(t, err) 2292 require.NotEqual(t, array.StorageID(), copied.StorageID()) 2293 2294 verifyArray(t, storage, typeInfo, address, copied, values, false) 2295 }) 2296 2297 t.Run("random", func(t *testing.T) { 2298 SetThreshold(256) 2299 defer SetThreshold(1024) 2300 2301 const arraySize = 4096 2302 2303 r := newRand(t) 2304 2305 typeInfo := testTypeInfo{42} 2306 2307 array, err := NewArray( 2308 newTestPersistentStorage(t), 2309 Address{1, 2, 3, 4, 5, 6, 7, 8}, 2310 typeInfo) 2311 require.NoError(t, err) 2312 2313 values := make([]Value, arraySize) 2314 for i := uint64(0); i < arraySize; i++ { 2315 v := randomValue(r, int(MaxInlineArrayElementSize)) 2316 values[i] = v 2317 2318 err := array.Append(v) 2319 require.NoError(t, err) 2320 } 2321 2322 require.Equal(t, uint64(arraySize), array.Count()) 2323 2324 iter, err := array.Iterator() 2325 require.NoError(t, err) 2326 2327 storage := newTestPersistentStorage(t) 2328 2329 address := Address{2, 3, 4, 5, 6, 7, 8, 9} 2330 copied, err := NewArrayFromBatchData( 2331 storage, 2332 address, 2333 array.Type(), 2334 func() (Value, error) { 2335 return iter.Next() 2336 }) 2337 2338 require.NoError(t, err) 2339 require.NotEqual(t, array.StorageID(), copied.StorageID()) 2340 2341 verifyArray(t, storage, typeInfo, address, copied, values, false) 2342 }) 2343 2344 t.Run("data slab too large", func(t *testing.T) { 2345 // Slab size must not exceed maxThreshold. 2346 // We cannot make this problem happen after Atree Issue #193 2347 // was fixed by PR #194 & PR #197. This test is to catch regressions. 2348 2349 SetThreshold(256) 2350 defer SetThreshold(1024) 2351 2352 r := newRand(t) 2353 2354 typeInfo := testTypeInfo{42} 2355 array, err := NewArray( 2356 newTestPersistentStorage(t), 2357 Address{1, 2, 3, 4, 5, 6, 7, 8}, 2358 typeInfo) 2359 require.NoError(t, err) 2360 2361 var values []Value 2362 var v Value 2363 2364 v = NewStringValue(randStr(r, int(MaxInlineArrayElementSize-2))) 2365 values = append(values, v) 2366 err = array.Append(v) 2367 require.NoError(t, err) 2368 2369 v = NewStringValue(randStr(r, int(MaxInlineArrayElementSize-2))) 2370 values = append(values, v) 2371 err = array.Append(v) 2372 require.NoError(t, err) 2373 2374 v = NewStringValue(randStr(r, int(MaxInlineArrayElementSize-2))) 2375 values = append(values, v) 2376 err = array.Append(v) 2377 require.NoError(t, err) 2378 2379 iter, err := array.Iterator() 2380 require.NoError(t, err) 2381 2382 storage := newTestPersistentStorage(t) 2383 address := Address{2, 3, 4, 5, 6, 7, 8, 9} 2384 copied, err := NewArrayFromBatchData( 2385 storage, 2386 address, 2387 array.Type(), 2388 func() (Value, error) { 2389 return iter.Next() 2390 }) 2391 2392 require.NoError(t, err) 2393 require.NotEqual(t, array.StorageID(), copied.StorageID()) 2394 2395 verifyArray(t, storage, typeInfo, address, copied, values, false) 2396 }) 2397 } 2398 2399 func TestArrayNestedStorables(t *testing.T) { 2400 2401 t.Parallel() 2402 2403 typeInfo := testTypeInfo{42} 2404 2405 const arraySize = 1024 * 4 2406 2407 storage := newTestPersistentStorage(t) 2408 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2409 2410 array, err := NewArray(storage, address, typeInfo) 2411 require.NoError(t, err) 2412 2413 values := make([]Value, arraySize) 2414 for i := uint64(0); i < arraySize; i++ { 2415 s := strings.Repeat("a", int(i)) 2416 v := SomeValue{Value: NewStringValue(s)} 2417 values[i] = v 2418 2419 err := array.Append(v) 2420 require.NoError(t, err) 2421 } 2422 2423 verifyArray(t, storage, typeInfo, address, array, values, true) 2424 } 2425 2426 func TestArrayMaxInlineElement(t *testing.T) { 2427 t.Parallel() 2428 2429 r := newRand(t) 2430 2431 typeInfo := testTypeInfo{42} 2432 storage := newTestPersistentStorage(t) 2433 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2434 2435 array, err := NewArray(storage, address, typeInfo) 2436 require.NoError(t, err) 2437 2438 var values []Value 2439 for i := 0; i < 2; i++ { 2440 // String length is MaxInlineArrayElementSize - 3 to account for string encoding overhead. 2441 v := NewStringValue(randStr(r, int(MaxInlineArrayElementSize-3))) 2442 values = append(values, v) 2443 2444 err = array.Append(v) 2445 require.NoError(t, err) 2446 } 2447 2448 require.True(t, array.root.IsData()) 2449 2450 // Size of root data slab with two elements of max inlined size is target slab size minus 2451 // storage id size (next storage id is omitted in root slab), and minus 1 byte 2452 // (for rounding when computing max inline array element size). 2453 require.Equal(t, targetThreshold-storageIDSize-1, uint64(array.root.Header().size)) 2454 2455 verifyArray(t, storage, typeInfo, address, array, values, false) 2456 } 2457 2458 func TestArrayString(t *testing.T) { 2459 2460 SetThreshold(256) 2461 defer SetThreshold(1024) 2462 2463 t.Run("small", func(t *testing.T) { 2464 const arraySize = 6 2465 2466 typeInfo := testTypeInfo{42} 2467 storage := newTestPersistentStorage(t) 2468 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2469 2470 array, err := NewArray(storage, address, typeInfo) 2471 require.NoError(t, err) 2472 2473 for i := uint64(0); i < arraySize; i++ { 2474 err := array.Append(Uint64Value(i)) 2475 require.NoError(t, err) 2476 } 2477 2478 want := `[0 1 2 3 4 5]` 2479 require.Equal(t, want, array.String()) 2480 }) 2481 2482 t.Run("large", func(t *testing.T) { 2483 const arraySize = 120 2484 2485 typeInfo := testTypeInfo{42} 2486 storage := newTestPersistentStorage(t) 2487 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2488 2489 array, err := NewArray(storage, address, typeInfo) 2490 require.NoError(t, err) 2491 2492 for i := uint64(0); i < arraySize; i++ { 2493 err := array.Append(Uint64Value(i)) 2494 require.NoError(t, err) 2495 } 2496 2497 want := `[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119]` 2498 require.Equal(t, want, array.String()) 2499 }) 2500 } 2501 2502 func TestArraySlabDump(t *testing.T) { 2503 SetThreshold(256) 2504 defer SetThreshold(1024) 2505 2506 t.Run("small", func(t *testing.T) { 2507 const arraySize = 6 2508 2509 typeInfo := testTypeInfo{42} 2510 storage := newTestPersistentStorage(t) 2511 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2512 2513 array, err := NewArray(storage, address, typeInfo) 2514 require.NoError(t, err) 2515 2516 for i := uint64(0); i < arraySize; i++ { 2517 err := array.Append(Uint64Value(i)) 2518 require.NoError(t, err) 2519 } 2520 2521 want := []string{ 2522 "level 1, ArrayDataSlab id:0x102030405060708.1 size:23 count:6 elements: [0 1 2 3 4 5]", 2523 } 2524 dumps, err := DumpArraySlabs(array) 2525 require.NoError(t, err) 2526 require.Equal(t, want, dumps) 2527 }) 2528 2529 t.Run("large", func(t *testing.T) { 2530 const arraySize = 120 2531 2532 typeInfo := testTypeInfo{42} 2533 storage := newTestPersistentStorage(t) 2534 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2535 2536 array, err := NewArray(storage, address, typeInfo) 2537 require.NoError(t, err) 2538 2539 for i := uint64(0); i < arraySize; i++ { 2540 err := array.Append(Uint64Value(i)) 2541 require.NoError(t, err) 2542 } 2543 2544 want := []string{ 2545 "level 1, ArrayMetaDataSlab id:0x102030405060708.1 size:52 count:120 children: [{id:0x102030405060708.2 size:213 count:54} {id:0x102030405060708.3 size:285 count:66}]", 2546 "level 2, ArrayDataSlab id:0x102030405060708.2 size:213 count:54 elements: [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53]", 2547 "level 2, ArrayDataSlab id:0x102030405060708.3 size:285 count:66 elements: [54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119]", 2548 } 2549 2550 dumps, err := DumpArraySlabs(array) 2551 require.NoError(t, err) 2552 require.Equal(t, want, dumps) 2553 }) 2554 2555 t.Run("overflow", func(t *testing.T) { 2556 2557 typeInfo := testTypeInfo{42} 2558 storage := newTestPersistentStorage(t) 2559 address := Address{1, 2, 3, 4, 5, 6, 7, 8} 2560 2561 array, err := NewArray(storage, address, typeInfo) 2562 require.NoError(t, err) 2563 2564 err = array.Append(NewStringValue(strings.Repeat("a", int(MaxInlineArrayElementSize)))) 2565 require.NoError(t, err) 2566 2567 want := []string{ 2568 "level 1, ArrayDataSlab id:0x102030405060708.1 size:24 count:1 elements: [StorageIDStorable({[1 2 3 4 5 6 7 8] [0 0 0 0 0 0 0 2]})]", 2569 "overflow: &{0x102030405060708.2 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}", 2570 } 2571 2572 dumps, err := DumpArraySlabs(array) 2573 require.NoError(t, err) 2574 require.Equal(t, want, dumps) 2575 }) 2576 } 2577 2578 func errorCategorizationCount(err error) int { 2579 var fatalError *FatalError 2580 var userError *UserError 2581 var externalError *ExternalError 2582 2583 count := 0 2584 if errors.As(err, &fatalError) { 2585 count++ 2586 } 2587 if errors.As(err, &userError) { 2588 count++ 2589 } 2590 if errors.As(err, &externalError) { 2591 count++ 2592 } 2593 return count 2594 }