mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-20 11:46:44 +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 (
|
var (
|
||||||
lastID uint32
|
lastID uint32
|
||||||
descList []*indexBlockDesc
|
descList = make([]*indexBlockDesc, 0, len(blob)/size)
|
||||||
)
|
)
|
||||||
for i := 0; i < len(blob)/size; i++ {
|
for i := 0; i < len(blob)/size; i++ {
|
||||||
var desc indexBlockDesc
|
var desc indexBlockDesc
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,13 @@ func (d *indexBlockDesc) encode() []byte {
|
||||||
return buf[:]
|
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.
|
// the provided byte stream after the function call.
|
||||||
func (d *indexBlockDesc) decode(blob []byte) {
|
func (d *indexBlockDesc) decode(blob []byte) {
|
||||||
d.max = binary.BigEndian.Uint64(blob[:8])
|
d.max = binary.BigEndian.Uint64(blob[:8])
|
||||||
d.entries = binary.BigEndian.Uint16(blob[8:10])
|
d.entries = binary.BigEndian.Uint16(blob[8:10])
|
||||||
d.id = binary.BigEndian.Uint32(blob[10:14])
|
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.
|
// 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.
|
// readTrienode retrieves the trienode data from the specified trienode history.
|
||||||
func (r *trienodeReader) readTrienode(addrHash common.Hash, path string, historyID uint64) ([]byte, bool, error) {
|
func (r *trienodeReader) readTrienode(addrHash common.Hash, path string, historyID uint64) ([]byte, bool, error) {
|
||||||
tr, err := newTrienodeHistoryReader(historyID, r.freezer)
|
tr := newTrienodeHistoryReader(historyID, r.freezer)
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
return tr.read(addrHash, path)
|
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
|
// It resolves data from the underlying ancient store only when needed, minimizing
|
||||||
// I/O overhead.
|
// I/O overhead.
|
||||||
type trienodeHistoryReader struct {
|
type trienodeHistoryReader struct {
|
||||||
id uint64 // ID of the associated trienode history
|
id uint64 // ID of the associated trienode history
|
||||||
reader ethdb.AncientReader // Database reader of ancient store
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTrienodeHistoryReader constructs the reader for specific trienode history.
|
// newTrienodeHistoryReader constructs the reader for specific trienode history.
|
||||||
func newTrienodeHistoryReader(id uint64, reader ethdb.AncientReader) (*trienodeHistoryReader, error) {
|
func newTrienodeHistoryReader(id uint64, reader ethdb.AncientReader) *trienodeHistoryReader {
|
||||||
r := &trienodeHistoryReader{
|
return &trienodeHistoryReader{
|
||||||
id: id,
|
id: id,
|
||||||
reader: reader,
|
reader: reader,
|
||||||
iReaders: make(map[common.Hash]*singleTrienodeHistoryReader),
|
|
||||||
}
|
}
|
||||||
if err := r.decodeHeader(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeHeader decodes the header section of trienode history.
|
// 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)
|
header, err := rawdb.ReadTrienodeHistoryHeader(r.reader, r.id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return iRange{}, iRange{}, false, err
|
||||||
}
|
}
|
||||||
_, owners, keyOffsets, valOffsets, err := decodeHeader(header)
|
_, owners, keyOffsets, valOffsets, err := decodeHeader(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return iRange{}, iRange{}, false, err
|
||||||
}
|
}
|
||||||
r.keyRanges = make(map[common.Hash]iRange, len(owners))
|
pos := sort.Search(len(owners), func(i int) bool {
|
||||||
r.valRanges = make(map[common.Hash]iRange, len(owners))
|
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 {
|
var valRange iRange
|
||||||
// Decode the key range for this trie chunk
|
if pos != 0 {
|
||||||
var keyStart uint32
|
valRange.start = valOffsets[pos-1]
|
||||||
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],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
valRange.limit = valOffsets[pos]
|
||||||
|
return keyRange, valRange, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// read retrieves the trie node data with the provided TrieID and node path.
|
// 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) {
|
func (r *trienodeHistoryReader) read(owner common.Hash, path string) ([]byte, bool, error) {
|
||||||
ir, ok := r.iReaders[owner]
|
keyRange, valRange, found, err := r.decodeHeader(owner)
|
||||||
if !ok {
|
if err != nil {
|
||||||
keyRange, exists := r.keyRanges[owner]
|
return nil, false, err
|
||||||
if !exists {
|
}
|
||||||
return nil, false, nil // not found
|
if !found {
|
||||||
}
|
return nil, false, nil
|
||||||
valRange, exists := r.valRanges[owner]
|
}
|
||||||
if !exists {
|
ir, err := newSingleTrienodeHistoryReader(r.id, r.reader, keyRange, valRange)
|
||||||
return nil, false, nil // not found
|
if err != nil {
|
||||||
}
|
return nil, false, err
|
||||||
var err error
|
|
||||||
ir, err = newSingleTrienodeHistoryReader(r.id, r.reader, keyRange, valRange)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
r.iReaders[owner] = ir
|
|
||||||
}
|
}
|
||||||
return ir.read([]byte(path))
|
return ir.read([]byte(path))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -138,10 +138,7 @@ func TestTrienodeHistoryReader(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i, h := range hs {
|
for i, h := range hs {
|
||||||
tr, err := newTrienodeHistoryReader(uint64(i+1), freezer)
|
tr := newTrienodeHistoryReader(uint64(i+1), freezer)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to construct the history reader: %v", err)
|
|
||||||
}
|
|
||||||
for _, owner := range h.owners {
|
for _, owner := range h.owners {
|
||||||
nodes := h.nodes[owner]
|
nodes := h.nodes[owner]
|
||||||
for key, value := range nodes {
|
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 {
|
if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil {
|
||||||
t.Fatalf("Failed to write trienode history: %v", err)
|
t.Fatalf("Failed to write trienode history: %v", err)
|
||||||
}
|
}
|
||||||
|
tr := newTrienodeHistoryReader(1, freezer)
|
||||||
tr, err := newTrienodeHistoryReader(1, freezer)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to construct history reader: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to read a non-existent path
|
// Try to read a non-existent path
|
||||||
var found bool
|
var (
|
||||||
|
err error
|
||||||
|
found bool
|
||||||
|
)
|
||||||
_, found, err = tr.read(testrand.Hash(), "nonexistent")
|
_, found, err = tr.read(testrand.Hash(), "nonexistent")
|
||||||
if found || err != nil {
|
if found || err != nil {
|
||||||
t.Fatal("Expected not found for non-existent trie owner")
|
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 {
|
if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil {
|
||||||
t.Fatalf("Failed to write trienode history: %v", err)
|
t.Fatalf("Failed to write trienode history: %v", err)
|
||||||
}
|
}
|
||||||
|
tr := newTrienodeHistoryReader(1, freezer)
|
||||||
tr, err := newTrienodeHistoryReader(1, freezer)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to construct history reader: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test reading nil values
|
// Test reading nil values
|
||||||
data1, found, err := tr.read(owner, "nil1")
|
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 {
|
if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil {
|
||||||
t.Fatalf("Failed to write trienode history: %v", err)
|
t.Fatalf("Failed to write trienode history: %v", err)
|
||||||
}
|
}
|
||||||
|
tr := newTrienodeHistoryReader(1, freezer)
|
||||||
tr, err := newTrienodeHistoryReader(1, freezer)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to construct history reader: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test reading nil values
|
// Test reading nil values
|
||||||
data1, _, err := tr.read(owner, "")
|
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 {
|
if err := rawdb.WriteTrienodeHistory(freezer, 1, header, keySection, valueSection); err != nil {
|
||||||
t.Fatalf("Failed to write trienode history: %v", err)
|
t.Fatalf("Failed to write trienode history: %v", err)
|
||||||
}
|
}
|
||||||
|
tr := newTrienodeHistoryReader(1, freezer)
|
||||||
tr, err := newTrienodeHistoryReader(1, freezer)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to construct history reader: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test reading non-existent entry
|
// Test reading non-existent entry
|
||||||
keys := []string{
|
keys := []string{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue