mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
core/filtermaps: check cutoff during checkpoint sync; revert to unindexed mode if init fails
This commit is contained in:
parent
91a85de0d4
commit
3033e81e10
3 changed files with 33 additions and 14 deletions
|
|
@ -54,6 +54,7 @@ type FilterMaps struct {
|
||||||
// We chose to implement disabling this way because it requires less special
|
// We chose to implement disabling this way because it requires less special
|
||||||
// case logic in eth/filters.
|
// case logic in eth/filters.
|
||||||
disabled bool
|
disabled bool
|
||||||
|
disabledCh chan struct{} // closed by indexer if disabled
|
||||||
|
|
||||||
closeCh chan struct{}
|
closeCh chan struct{}
|
||||||
closeWg sync.WaitGroup
|
closeWg sync.WaitGroup
|
||||||
|
|
@ -196,6 +197,7 @@ func NewFilterMaps(db ethdb.KeyValueStore, initView *ChainView, historyCutoff, f
|
||||||
blockProcessingCh: make(chan bool, 1),
|
blockProcessingCh: make(chan bool, 1),
|
||||||
history: config.History,
|
history: config.History,
|
||||||
disabled: config.Disabled,
|
disabled: config.Disabled,
|
||||||
|
disabledCh: make(chan struct{}),
|
||||||
exportFileName: config.ExportFileName,
|
exportFileName: config.ExportFileName,
|
||||||
Params: params,
|
Params: params,
|
||||||
indexedRange: filterMapsRange{
|
indexedRange: filterMapsRange{
|
||||||
|
|
@ -278,8 +280,13 @@ func (f *FilterMaps) initChainView(chainView *ChainView) *ChainView {
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset un-initializes the FilterMaps structure and removes all related data from
|
// reset un-initializes the FilterMaps structure and removes all related data from
|
||||||
// the database. The function returns true if everything was successfully removed.
|
// the database.
|
||||||
func (f *FilterMaps) reset() bool {
|
// Note that in case of leveldb database the fallback implementation of DeleteRange
|
||||||
|
// might take a long time to finish and deleting the entire database may be
|
||||||
|
// interrupted by a shutdown. Deleting the filterMapsRange entry first does
|
||||||
|
// guarantee though that the next init() will not return successfully until the
|
||||||
|
// entire database has been cleaned.
|
||||||
|
func (f *FilterMaps) reset() {
|
||||||
f.indexLock.Lock()
|
f.indexLock.Lock()
|
||||||
f.indexedRange = filterMapsRange{}
|
f.indexedRange = filterMapsRange{}
|
||||||
f.indexedView = nil
|
f.indexedView = nil
|
||||||
|
|
@ -292,11 +299,16 @@ func (f *FilterMaps) reset() bool {
|
||||||
// deleting the range first ensures that resetDb will be called again at next
|
// deleting the range first ensures that resetDb will be called again at next
|
||||||
// startup and any leftover data will be removed even if it cannot finish now.
|
// startup and any leftover data will be removed even if it cannot finish now.
|
||||||
rawdb.DeleteFilterMapsRange(f.db)
|
rawdb.DeleteFilterMapsRange(f.db)
|
||||||
return f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database")
|
f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database")
|
||||||
}
|
}
|
||||||
|
|
||||||
// init initializes an empty log index according to the current targetView.
|
// init initializes an empty log index according to the current targetView.
|
||||||
func (f *FilterMaps) init() error {
|
func (f *FilterMaps) init() error {
|
||||||
|
// ensure that there is no remaining data in the filter maps key range
|
||||||
|
if !f.safeDeleteRange(rawdb.DeleteFilterMapsDb, "Resetting log index database") {
|
||||||
|
return errors.New("could not reset log index database")
|
||||||
|
}
|
||||||
|
|
||||||
f.indexLock.Lock()
|
f.indexLock.Lock()
|
||||||
defer f.indexLock.Unlock()
|
defer f.indexLock.Unlock()
|
||||||
|
|
||||||
|
|
@ -317,6 +329,13 @@ func (f *FilterMaps) init() error {
|
||||||
bestIdx, bestLen = idx, max
|
bestIdx, bestLen = idx, max
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var initBlockNumber uint64
|
||||||
|
if bestLen > 0 {
|
||||||
|
initBlockNumber = checkpoints[bestIdx][bestLen-1].BlockNumber
|
||||||
|
}
|
||||||
|
if initBlockNumber < f.historyCutoff {
|
||||||
|
return errors.New("cannot start indexing before history cutoff point")
|
||||||
|
}
|
||||||
batch := f.db.NewBatch()
|
batch := f.db.NewBatch()
|
||||||
for epoch := range bestLen {
|
for epoch := range bestLen {
|
||||||
cp := checkpoints[bestIdx][epoch]
|
cp := checkpoints[bestIdx][epoch]
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ func (f *FilterMaps) indexerLoop() {
|
||||||
|
|
||||||
if f.disabled {
|
if f.disabled {
|
||||||
f.reset()
|
f.reset()
|
||||||
|
close(f.disabledCh)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Info("Started log indexer")
|
log.Info("Started log indexer")
|
||||||
|
|
@ -48,12 +49,11 @@ func (f *FilterMaps) indexerLoop() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := f.init(); err != nil {
|
if err := f.init(); err != nil {
|
||||||
log.Error("Error initializing log index", "error", err)
|
log.Error("Error initializing log index; reverting to unindexed mode", "error", err)
|
||||||
// unexpected error; there is not a lot we can do here, maybe it
|
f.reset()
|
||||||
// recovers, maybe not. Calling event processing here ensures
|
f.disabled = true
|
||||||
// that we can still properly shutdown in case of an infinite loop.
|
close(f.disabledCh)
|
||||||
f.processSingleEvent(true)
|
return
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !f.targetHeadIndexed() {
|
if !f.targetHeadIndexed() {
|
||||||
|
|
|
||||||
|
|
@ -141,10 +141,6 @@ func (fm *FilterMapsMatcherBackend) synced() {
|
||||||
// range that has not been changed and has been consistent with all states of the
|
// range that has not been changed and has been consistent with all states of the
|
||||||
// chain since the previous SyncLogIndex or the creation of the matcher backend.
|
// chain since the previous SyncLogIndex or the creation of the matcher backend.
|
||||||
func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange, error) {
|
func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange, error) {
|
||||||
if fm.f.disabled {
|
|
||||||
return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
syncCh := make(chan SyncRange, 1)
|
syncCh := make(chan SyncRange, 1)
|
||||||
fm.f.matchersLock.Lock()
|
fm.f.matchersLock.Lock()
|
||||||
fm.syncCh = syncCh
|
fm.syncCh = syncCh
|
||||||
|
|
@ -154,12 +150,16 @@ func (fm *FilterMapsMatcherBackend) SyncLogIndex(ctx context.Context) (SyncRange
|
||||||
case fm.f.matcherSyncCh <- fm:
|
case fm.f.matcherSyncCh <- fm:
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return SyncRange{}, ctx.Err()
|
return SyncRange{}, ctx.Err()
|
||||||
|
case <-fm.f.disabledCh:
|
||||||
|
return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case vr := <-syncCh:
|
case vr := <-syncCh:
|
||||||
return vr, nil
|
return vr, nil
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return SyncRange{}, ctx.Err()
|
return SyncRange{}, ctx.Err()
|
||||||
|
case <-fm.f.disabledCh:
|
||||||
|
return SyncRange{HeadNumber: fm.f.targetView.headNumber}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue