mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 11:20:45 +00:00
triedb/pathdb: optimize allocation
This commit is contained in:
parent
5df5020f0d
commit
990a71c952
5 changed files with 48 additions and 87 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
Loading…
Reference in a new issue