diff --git a/triedb/pathdb/history_index.go b/triedb/pathdb/history_index.go index 0c5eb8db21..eee4c10273 100644 --- a/triedb/pathdb/history_index.go +++ b/triedb/pathdb/history_index.go @@ -42,7 +42,7 @@ func parseIndex(blob []byte, bitmapSize int) ([]*indexBlockDesc, error) { } var ( lastID uint32 - descList []*indexBlockDesc + descList = make([]*indexBlockDesc, 0, len(blob)/size) ) for i := 0; i < len(blob)/size; i++ { var desc indexBlockDesc diff --git a/triedb/pathdb/history_index_block.go b/triedb/pathdb/history_index_block.go index fd43d81b78..bb823bb13f 100644 --- a/triedb/pathdb/history_index_block.go +++ b/triedb/pathdb/history_index_block.go @@ -65,13 +65,13 @@ func (d *indexBlockDesc) encode() []byte { return buf[:] } -// decode unpacks index block descriptor from byte stream. It's safe to mutate +// decode unpacks index block descriptor from byte stream. It's unsafe to mutate // the provided byte stream after the function call. func (d *indexBlockDesc) decode(blob []byte) { d.max = binary.BigEndian.Uint64(blob[:8]) d.entries = binary.BigEndian.Uint16(blob[8:10]) d.id = binary.BigEndian.Uint32(blob[10:14]) - d.extBitmap = bytes.Clone(blob[indexBlockDescSize:]) + d.extBitmap = blob[indexBlockDescSize:] // no-deep copy! } // copy returns a deep-copied object. diff --git a/triedb/pathdb/history_reader.go b/triedb/pathdb/history_reader.go index 8b45f9ffbb..4ae1fb36cb 100644 --- a/triedb/pathdb/history_reader.go +++ b/triedb/pathdb/history_reader.go @@ -285,10 +285,7 @@ func newTrienodeReader(disk ethdb.KeyValueReader, freezer ethdb.AncientReader, r // readTrienode retrieves the trienode data from the specified trienode history. func (r *trienodeReader) readTrienode(addrHash common.Hash, path string, historyID uint64) ([]byte, bool, error) { - tr, err := newTrienodeHistoryReader(historyID, r.freezer) - if err != nil { - return nil, false, err - } + tr := newTrienodeHistoryReader(historyID, r.freezer) return tr.read(addrHash, path) } diff --git a/triedb/pathdb/history_trienode.go b/triedb/pathdb/history_trienode.go index ded7e2f854..6e4bec36a2 100644 --- a/triedb/pathdb/history_trienode.go +++ b/triedb/pathdb/history_trienode.go @@ -719,80 +719,60 @@ func (sr *singleTrienodeHistoryReader) read(key []byte) ([]byte, bool, error) { // It resolves data from the underlying ancient store only when needed, minimizing // I/O overhead. type trienodeHistoryReader struct { - id uint64 // ID of the associated trienode history - reader ethdb.AncientReader // Database reader of ancient store - keyRanges map[common.Hash]iRange // Key ranges identifying trie chunks - valRanges map[common.Hash]iRange // Value ranges identifying trie chunks - iReaders map[common.Hash]*singleTrienodeHistoryReader // readers for each individual trie chunk + id uint64 // ID of the associated trienode history + reader ethdb.AncientReader // Database reader of ancient store } // newTrienodeHistoryReader constructs the reader for specific trienode history. -func newTrienodeHistoryReader(id uint64, reader ethdb.AncientReader) (*trienodeHistoryReader, error) { - r := &trienodeHistoryReader{ - id: id, - reader: reader, - iReaders: make(map[common.Hash]*singleTrienodeHistoryReader), +func newTrienodeHistoryReader(id uint64, reader ethdb.AncientReader) *trienodeHistoryReader { + return &trienodeHistoryReader{ + id: id, + reader: reader, } - if err := r.decodeHeader(); err != nil { - return nil, err - } - return r, nil } // decodeHeader decodes the header section of trienode history. -func (r *trienodeHistoryReader) decodeHeader() error { +func (r *trienodeHistoryReader) decodeHeader(owner common.Hash) (iRange, iRange, bool, error) { header, err := rawdb.ReadTrienodeHistoryHeader(r.reader, r.id) if err != nil { - return err + return iRange{}, iRange{}, false, err } _, owners, keyOffsets, valOffsets, err := decodeHeader(header) if err != nil { - return err + return iRange{}, iRange{}, false, err } - r.keyRanges = make(map[common.Hash]iRange, len(owners)) - r.valRanges = make(map[common.Hash]iRange, len(owners)) + pos := sort.Search(len(owners), func(i int) bool { + return owner.Cmp(owners[i]) <= 0 + }) + if pos == len(owners) || owners[pos] != owner { + return iRange{}, iRange{}, false, nil + } + var keyRange iRange + if pos != 0 { + keyRange.start = keyOffsets[pos-1] + } + keyRange.limit = keyOffsets[pos] - for i, owner := range owners { - // Decode the key range for this trie chunk - var keyStart uint32 - if i != 0 { - keyStart = keyOffsets[i-1] - } - r.keyRanges[owner] = iRange{ - start: keyStart, - limit: keyOffsets[i], - } - // Decode the value range for this trie chunk - var valStart uint32 - if i != 0 { - valStart = valOffsets[i-1] - } - r.valRanges[owner] = iRange{ - start: valStart, - limit: valOffsets[i], - } + var valRange iRange + if pos != 0 { + valRange.start = valOffsets[pos-1] } - return nil + valRange.limit = valOffsets[pos] + return keyRange, valRange, true, nil } // read retrieves the trie node data with the provided TrieID and node path. func (r *trienodeHistoryReader) read(owner common.Hash, path string) ([]byte, bool, error) { - ir, ok := r.iReaders[owner] - if !ok { - keyRange, exists := r.keyRanges[owner] - if !exists { - return nil, false, nil // not found - } - valRange, exists := r.valRanges[owner] - if !exists { - return nil, false, nil // not found - } - var err error - ir, err = newSingleTrienodeHistoryReader(r.id, r.reader, keyRange, valRange) - if err != nil { - return nil, false, err - } - r.iReaders[owner] = ir + keyRange, valRange, found, err := r.decodeHeader(owner) + if err != nil { + return nil, false, err + } + if !found { + return nil, false, nil + } + ir, err := newSingleTrienodeHistoryReader(r.id, r.reader, keyRange, valRange) + if err != nil { + return nil, false, err } return ir.read([]byte(path)) } diff --git a/triedb/pathdb/history_trienode_test.go b/triedb/pathdb/history_trienode_test.go index 531b749c31..05278c30b1 100644 --- a/triedb/pathdb/history_trienode_test.go +++ b/triedb/pathdb/history_trienode_test.go @@ -138,10 +138,7 @@ func TestTrienodeHistoryReader(t *testing.T) { } } for i, h := range hs { - tr, err := newTrienodeHistoryReader(uint64(i+1), freezer) - if err != nil { - t.Fatalf("Failed to construct the history reader: %v", err) - } + tr := newTrienodeHistoryReader(uint64(i+1), freezer) for _, owner := range h.owners { nodes := h.nodes[owner] for key, value := range nodes { @@ -418,14 +415,13 @@ func TestTrienodeHistoryReaderNonExistentPath(t *testing.T) { if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil { t.Fatalf("Failed to write trienode history: %v", err) } - - tr, err := newTrienodeHistoryReader(1, freezer) - if err != nil { - t.Fatalf("Failed to construct history reader: %v", err) - } + tr := newTrienodeHistoryReader(1, freezer) // Try to read a non-existent path - var found bool + var ( + err error + found bool + ) _, found, err = tr.read(testrand.Hash(), "nonexistent") if found || err != nil { t.Fatal("Expected not found for non-existent trie owner") @@ -459,11 +455,7 @@ func TestTrienodeHistoryReaderNilValues(t *testing.T) { if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil { t.Fatalf("Failed to write trienode history: %v", err) } - - tr, err := newTrienodeHistoryReader(1, freezer) - if err != nil { - t.Fatalf("Failed to construct history reader: %v", err) - } + tr := newTrienodeHistoryReader(1, freezer) // Test reading nil values data1, found, err := tr.read(owner, "nil1") @@ -511,11 +503,7 @@ func TestTrienodeHistoryReaderNilKey(t *testing.T) { if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil { t.Fatalf("Failed to write trienode history: %v", err) } - - tr, err := newTrienodeHistoryReader(1, freezer) - if err != nil { - t.Fatalf("Failed to construct history reader: %v", err) - } + tr := newTrienodeHistoryReader(1, freezer) // Test reading nil values data1, _, err := tr.read(owner, "") @@ -713,11 +701,7 @@ func TestSearchSingle(t *testing.T) { if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil { t.Fatalf("Failed to write trienode history: %v", err) } - - tr, err := newTrienodeHistoryReader(1, freezer) - if err != nil { - t.Fatalf("Failed to construct history reader: %v", err) - } + tr := newTrienodeHistoryReader(1, freezer) // Test reading non-existent entry keys := []string{