|
86 | 86 | // range of accounts covered. |
87 | 87 | ErrNotCoveredYet = errors.New("not covered yet") |
88 | 88 |
|
| 89 | + // ErrNotConstructed is returned if the callers want to iterate the snapshot |
| 90 | + // while the generation is not finished yet. |
| 91 | + ErrNotConstructed = errors.New("snapshot is not constructed") |
| 92 | + |
89 | 93 | // errSnapshotCycle is returned if a snapshot is attempted to be inserted |
90 | 94 | // that forms a cycle in the snapshot tree. |
91 | 95 | errSnapshotCycle = errors.New("snapshot cycle") |
@@ -609,11 +613,61 @@ func (t *Tree) Rebuild(root common.Hash) { |
609 | 613 | // AccountIterator creates a new account iterator for the specified root hash and |
610 | 614 | // seeks to a starting account hash. |
611 | 615 | func (t *Tree) AccountIterator(root common.Hash, seek common.Hash) (AccountIterator, error) { |
| 616 | + ok, err := t.generating() |
| 617 | + if err != nil { |
| 618 | + return nil, err |
| 619 | + } |
| 620 | + if ok { |
| 621 | + return nil, ErrNotConstructed |
| 622 | + } |
612 | 623 | return newFastAccountIterator(t, root, seek) |
613 | 624 | } |
614 | 625 |
|
615 | 626 | // StorageIterator creates a new storage iterator for the specified root hash and |
616 | 627 | // account. The iterator will be move to the specific start position. |
617 | 628 | func (t *Tree) StorageIterator(root common.Hash, account common.Hash, seek common.Hash) (StorageIterator, error) { |
| 629 | + ok, err := t.generating() |
| 630 | + if err != nil { |
| 631 | + return nil, err |
| 632 | + } |
| 633 | + if ok { |
| 634 | + return nil, ErrNotConstructed |
| 635 | + } |
618 | 636 | return newFastStorageIterator(t, root, account, seek) |
619 | 637 | } |
| 638 | + |
| 639 | +// disklayer is an internal helper function to return the disk layer. |
| 640 | +// The lock of snapTree is assumed to be held already. |
| 641 | +func (t *Tree) disklayer() *diskLayer { |
| 642 | + var snap snapshot |
| 643 | + for _, s := range t.layers { |
| 644 | + snap = s |
| 645 | + break |
| 646 | + } |
| 647 | + if snap == nil { |
| 648 | + return nil |
| 649 | + } |
| 650 | + switch layer := snap.(type) { |
| 651 | + case *diskLayer: |
| 652 | + return layer |
| 653 | + case *diffLayer: |
| 654 | + return layer.origin |
| 655 | + default: |
| 656 | + panic(fmt.Sprintf("%T: undefined layer", snap)) |
| 657 | + } |
| 658 | +} |
| 659 | + |
| 660 | +// generating is an internal helper function which reports whether the snapshot |
| 661 | +// is still under the construction. |
| 662 | +func (t *Tree) generating() (bool, error) { |
| 663 | + t.lock.Lock() |
| 664 | + defer t.lock.Unlock() |
| 665 | + |
| 666 | + layer := t.disklayer() |
| 667 | + if layer == nil { |
| 668 | + return false, errors.New("disk layer is missing") |
| 669 | + } |
| 670 | + layer.lock.RLock() |
| 671 | + defer layer.lock.RUnlock() |
| 672 | + return layer.genMarker != nil, nil |
| 673 | +} |
0 commit comments