core: remove old storage items asynchronously

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgeniy Stratonikov 2021-11-09 15:13:53 +03:00
parent 582d489c90
commit fac595bbdf
4 changed files with 41 additions and 21 deletions

View file

@ -67,9 +67,6 @@ const (
// stateJumpStarted means that state jump was just initiated, but outdated storage items
// were not yet removed.
stateJumpStarted
// oldStorageItemsRemoved means that outdated contract storage items were removed, but
// new storage items were not yet saved.
oldStorageItemsRemoved
// newStorageItemsAdded means that contract storage items are up-to-date with the current
// state.
newStorageItemsAdded
@ -354,6 +351,9 @@ func (bc *Blockchain) init() error {
bc.dao.Version = ver
bc.persistent.Version = ver
// Always try to remove garbage. If there is nothing to do, it will exit quickly.
go bc.removeOldStorageItems()
// At this point there was no version found in the storage which
// implies a creating fresh storage with the version specified
// and the genesis block as first block.
@ -478,6 +478,26 @@ func (bc *Blockchain) init() error {
return bc.updateExtensibleWhitelist(bHeight)
}
func (bc *Blockchain) removeOldStorageItems() {
_, err := bc.dao.Store.Get(storage.SYSCleanStorage.Bytes())
if err != nil {
return
}
b := bc.dao.Store.Batch()
prefix := statesync.TemporaryPrefix(bc.dao.Version.StoragePrefix)
bc.dao.Store.Seek([]byte{byte(prefix)}, func(k, _ []byte) {
// #1468, but don't need to copy here, because it is done by Store.
b.Delete(k)
})
b.Delete(storage.SYSCleanStorage.Bytes())
err = bc.dao.Store.PutBatch(b)
if err != nil {
bc.log.Error("failed to remove old storage items", zap.Error(err))
}
}
// jumpToState is an atomic operation that changes Blockchain state to the one
// specified by the state sync point p. All the data needed for the jump must be
// collected by the state sync module.
@ -509,20 +529,6 @@ func (bc *Blockchain) jumpToStateInternal(p uint32, stage stateJumpStage) error
}
fallthrough
case stateJumpStarted:
// Replace old storage items by new ones, it should be done step-by step.
// Firstly, remove all old genesis-related items.
b := bc.dao.Store.Batch()
bc.dao.Store.Seek([]byte{byte(bc.dao.Version.StoragePrefix)}, func(k, _ []byte) {
// #1468, but don't need to copy here, because it is done by Store.
b.Delete(k)
})
b.Put(jumpStageKey, []byte{byte(oldStorageItemsRemoved)})
err := bc.dao.Store.PutBatch(b)
if err != nil {
return fmt.Errorf("failed to store state jump stage: %w", err)
}
fallthrough
case oldStorageItemsRemoved:
newPrefix := statesync.TemporaryPrefix(bc.dao.Version.StoragePrefix)
v, err := bc.dao.GetVersion()
if err != nil {
@ -538,6 +544,14 @@ func (bc *Blockchain) jumpToStateInternal(p uint32, stage stateJumpStage) error
if err != nil {
return fmt.Errorf("failed to store state jump stage: %w", err)
}
err = bc.dao.Store.Put(storage.SYSCleanStorage.Bytes(), []byte{})
if err != nil {
return fmt.Errorf("failed to store clean storage flag: %w", err)
}
go bc.removeOldStorageItems()
fallthrough
case newStorageItemsAdded:
// After current state is updated, we need to remove outdated state-related data if so.