core: cache chain head

This commit is contained in:
Gary Rong 2025-05-04 22:58:38 +08:00
parent 8777ba0b6a
commit 13bb575af5

View file

@ -47,6 +47,10 @@ type txIndexer struct {
// and all others shouldn't. // and all others shouldn't.
limit uint64 limit uint64
// The current head of blockchain for transaction indexing. This field
// is accessed by both the indexer and the indexing progress queries.
head atomic.Uint64
// The current tail of the indexed transactions, null indicates // The current tail of the indexed transactions, null indicates
// that no transactions have been indexed yet. // that no transactions have been indexed yet.
// //
@ -74,6 +78,7 @@ func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer {
term: make(chan chan struct{}), term: make(chan chan struct{}),
closed: make(chan struct{}), closed: make(chan struct{}),
} }
indexer.head.Store(indexer.resolveHead())
indexer.tail.Store(rawdb.ReadTxIndexTail(chain.db)) indexer.tail.Store(rawdb.ReadTxIndexTail(chain.db))
go indexer.loop(chain) go indexer.loop(chain)
@ -228,16 +233,15 @@ func (indexer *txIndexer) loop(chain *BlockChain) {
// Listening to chain events and manipulate the transaction indexes. // Listening to chain events and manipulate the transaction indexes.
var ( var (
stop chan struct{} // Non-nil if background routine is active stop chan struct{} // Non-nil if background routine is active
done chan struct{} // Non-nil if background routine is active done chan struct{} // Non-nil if background routine is active
head = indexer.resolveHead() // The latest announced chain head
headCh = make(chan ChainHeadEvent) headCh = make(chan ChainHeadEvent)
sub = chain.SubscribeChainHeadEvent(headCh) sub = chain.SubscribeChainHeadEvent(headCh)
) )
defer sub.Unsubscribe() defer sub.Unsubscribe()
// Validate the transaction indexes and repair if necessary // Validate the transaction indexes and repair if necessary
head := indexer.head.Load()
indexer.repair(head) indexer.repair(head)
// Launch the initial processing if chain is not empty (head != genesis). // Launch the initial processing if chain is not empty (head != genesis).
@ -250,15 +254,18 @@ func (indexer *txIndexer) loop(chain *BlockChain) {
for { for {
select { select {
case h := <-headCh: case h := <-headCh:
indexer.head.Store(h.Header.Number.Uint64())
if done == nil { if done == nil {
stop = make(chan struct{}) stop = make(chan struct{})
done = make(chan struct{}) done = make(chan struct{})
go indexer.run(h.Header.Number.Uint64(), stop, done) go indexer.run(h.Header.Number.Uint64(), stop, done)
} }
case <-done: case <-done:
stop = nil stop = nil
done = nil done = nil
indexer.tail.Store(rawdb.ReadTxIndexTail(indexer.db)) indexer.tail.Store(rawdb.ReadTxIndexTail(indexer.db))
case ch := <-indexer.term: case ch := <-indexer.term:
if stop != nil { if stop != nil {
close(stop) close(stop)
@ -314,7 +321,7 @@ func (indexer *txIndexer) report(head uint64, tail *uint64) TxIndexProgress {
// only updated at the end of each indexing operation. However, this delay is // only updated at the end of each indexing operation. However, this delay is
// considered acceptable. // considered acceptable.
func (indexer *txIndexer) txIndexProgress() TxIndexProgress { func (indexer *txIndexer) txIndexProgress() TxIndexProgress {
return indexer.report(indexer.resolveHead(), indexer.tail.Load()) return indexer.report(indexer.head.Load(), indexer.tail.Load())
} }
// close shutdown the indexer. Safe to be called for multiple times. // close shutdown the indexer. Safe to be called for multiple times.