@@ -127,14 +127,30 @@ func (indexer *txIndexer) loop(chain *BlockChain) {
127127
128128 // Listening to chain events and manipulate the transaction indexes.
129129 var (
130- stop chan struct {} // Non-nil if background routine is active.
131- done chan struct {} // Non-nil if background routine is active.
132- lastHead uint64 // The latest announced chain head (whose tx indexes are assumed created)
133- lastTail = rawdb .ReadTxIndexTail (indexer .db ) // The oldest indexed block, nil means nothing indexed
134-
135- headCh = make (chan ChainHeadEvent )
136- sub = chain .SubscribeChainHeadEvent (headCh )
130+ stop chan struct {} // Non-nil if background routine is active.
131+ done chan struct {} // Non-nil if background routine is active.
132+ lastHead uint64 // The latest announced chain head (whose tx indexes are assumed created)
133+ headCh = make (chan ChainHeadEvent )
134+ sub = chain .SubscribeChainHeadEvent (headCh )
137135 )
136+
137+ lastTail := rawdb .ReadTxIndexTail (indexer .db )
138+ if lastTail != nil {
139+ // NOTE: The "TransactionIndexTail" key may exist only in cold SST files.
140+ // Without a recent write, the key won't be in the memtable or block cache,
141+ // causing every Get to trigger expensive readBlock + CRC checks.
142+ //
143+ // This dummy write forces the key into the memtable (and later SST),
144+ // ensuring future reads are fast (from memory or block cache).
145+ batch := indexer .db .NewBatch ()
146+ rawdb .WriteTxIndexTail (batch , * lastTail )
147+
148+ if err := batch .Write (); err != nil {
149+ log .Crit ("Failed to write TransactionIndexTail warm-up" , "error" , err )
150+ return
151+ }
152+ }
153+
138154 defer sub .Unsubscribe ()
139155
140156 // Launch the initial processing if chain is not empty (head != genesis).
0 commit comments