Skip to content

Commit 66f2059

Browse files
rjl493456442fjl
authored andcommitted
triedb/pathdb: implement iterator of history index (ethereum#32981)
This change introduces an iterator for the history index in the pathdb. It provides sequential access to historical entries, enabling efficient scanning and future features built on top of historical state traversal.
1 parent b8908e3 commit 66f2059

File tree

4 files changed

+684
-69
lines changed

4 files changed

+684
-69
lines changed

triedb/pathdb/history_index.go

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"errors"
2121
"fmt"
2222
"math"
23-
"sort"
2423

2524
"github.com/ethereum/go-ethereum/core/rawdb"
2625
"github.com/ethereum/go-ethereum/ethdb"
@@ -119,30 +118,34 @@ func (r *indexReader) refresh() error {
119118
return nil
120119
}
121120

121+
// newIterator creates an iterator for traversing the index entries.
122+
func (r *indexReader) newIterator() *indexIterator {
123+
return newIndexIterator(r.descList, func(id uint32) (*blockReader, error) {
124+
br, ok := r.readers[id]
125+
if !ok {
126+
var err error
127+
br, err = newBlockReader(readStateIndexBlock(r.state, r.db, id))
128+
if err != nil {
129+
return nil, err
130+
}
131+
r.readers[id] = br
132+
}
133+
return br, nil
134+
})
135+
}
136+
122137
// readGreaterThan locates the first element that is greater than the specified
123138
// id. If no such element is found, MaxUint64 is returned.
124139
func (r *indexReader) readGreaterThan(id uint64) (uint64, error) {
125-
index := sort.Search(len(r.descList), func(i int) bool {
126-
return id < r.descList[i].max
127-
})
128-
if index == len(r.descList) {
129-
return math.MaxUint64, nil
140+
it := r.newIterator()
141+
found := it.SeekGT(id)
142+
if err := it.Error(); err != nil {
143+
return 0, err
130144
}
131-
desc := r.descList[index]
132-
133-
br, ok := r.readers[desc.id]
134-
if !ok {
135-
var err error
136-
blob := readStateIndexBlock(r.state, r.db, desc.id)
137-
br, err = newBlockReader(blob)
138-
if err != nil {
139-
return 0, err
140-
}
141-
r.readers[desc.id] = br
145+
if !found {
146+
return math.MaxUint64, nil
142147
}
143-
// The supplied ID is not greater than block.max, ensuring that an element
144-
// satisfying the condition can be found.
145-
return br.readGreaterThan(id)
148+
return it.ID(), nil
146149
}
147150

148151
// indexWriter is responsible for writing index data for a specific state (either

triedb/pathdb/history_index_block.go

Lines changed: 5 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"errors"
2222
"fmt"
2323
"math"
24-
"sort"
2524
)
2625

2726
const (
@@ -164,58 +163,15 @@ func newBlockReader(blob []byte) (*blockReader, error) {
164163
// readGreaterThan locates the first element in the block that is greater than
165164
// the specified value. If no such element is found, MaxUint64 is returned.
166165
func (br *blockReader) readGreaterThan(id uint64) (uint64, error) {
167-
var err error
168-
index := sort.Search(len(br.restarts), func(i int) bool {
169-
item, n := binary.Uvarint(br.data[br.restarts[i]:])
170-
if n <= 0 {
171-
err = fmt.Errorf("failed to decode item at restart %d", br.restarts[i])
172-
}
173-
return item > id
174-
})
175-
if err != nil {
166+
it := newBlockIterator(br.data, br.restarts)
167+
found := it.SeekGT(id)
168+
if err := it.Error(); err != nil {
176169
return 0, err
177170
}
178-
if index == 0 {
179-
item, _ := binary.Uvarint(br.data[br.restarts[0]:])
180-
return item, nil
181-
}
182-
var (
183-
start int
184-
limit int
185-
result uint64
186-
)
187-
if index == len(br.restarts) {
188-
// The element being searched falls within the last restart section,
189-
// there is no guarantee such element can be found.
190-
start = int(br.restarts[len(br.restarts)-1])
191-
limit = len(br.data)
192-
} else {
193-
// The element being searched falls within the non-last restart section,
194-
// such element can be found for sure.
195-
start = int(br.restarts[index-1])
196-
limit = int(br.restarts[index])
197-
}
198-
pos := start
199-
for pos < limit {
200-
x, n := binary.Uvarint(br.data[pos:])
201-
if pos == start {
202-
result = x
203-
} else {
204-
result += x
205-
}
206-
if result > id {
207-
return result, nil
208-
}
209-
pos += n
210-
}
211-
// The element which is greater than specified id is not found.
212-
if index == len(br.restarts) {
171+
if !found {
213172
return math.MaxUint64, nil
214173
}
215-
// The element which is the first one greater than the specified id
216-
// is exactly the one located at the restart point.
217-
item, _ := binary.Uvarint(br.data[br.restarts[index]:])
218-
return item, nil
174+
return it.ID(), nil
219175
}
220176

221177
type blockWriter struct {

0 commit comments

Comments
 (0)