diff --git a/core/parallel_state_processor.go b/core/parallel_state_processor.go index 1e9f75717c..e6a0d97167 100644 --- a/core/parallel_state_processor.go +++ b/core/parallel_state_processor.go @@ -144,7 +144,7 @@ func (p *ParallelStateProcessor) init() { p.parallelDBManager = state.NewParallelDBManager(20000, state.NewEmptySlotDB) - quickMergeNum := 2 // p.parallelNum / 2 + quickMergeNum := 0 // p.parallelNum / 2 for i := 0; i < p.parallelNum-quickMergeNum; i++ { p.slotState[i] = &SlotState{ primaryWakeUpChan: make(chan struct{}, 1), diff --git a/core/state/parallel_statedb.go b/core/state/parallel_statedb.go index 478ddf2f87..bd6a687799 100644 --- a/core/state/parallel_statedb.go +++ b/core/state/parallel_statedb.go @@ -1726,10 +1726,10 @@ func (s *ParallelStateDB) FinaliseForParallel(deleteEmptyObjects bool, mainDB *S // obj.finalise(true) will clear its dirtyStorage, will make prefetch broken. if !s.isParallel || !s.parallel.isSlotDB { obj.finalise(true) // Prefetch slots in the background - } else { + } /* else { // don't do finalise() here as to keep dirtyObjects unchanged in dirtyStorages, which avoid contention issue. - obj.fixUpOriginAndResetPendingStorage() - } + // obj.fixUpOriginAndResetPendingStorage() + }*/ } if obj.created { diff --git a/core/state/state_object.go b/core/state/state_object.go index 6d21a66dfb..cf89d774cd 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -798,6 +798,15 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject { return object } +// rebase is similar with deepCopy, instead of do copy, it just rebase the db of the Object. +// it is used for the case that the original state object in the mainDB is obsoleted or does not exist, +// so that we can reuse the one generated in slot execution. +func (object *stateObject) rebase(db *StateDB) *stateObject { + object.db = db.getBaseStateDB() + object.dbItf = db + return object +} + func (s *stateObject) MergeSlotObject(db Database, dirtyObjs *stateObject, keys StateKeys) { for key := range keys { // In parallel mode, always GetState by StateDB, not by StateObject directly, @@ -810,10 +819,12 @@ func (s *stateObject) MergeSlotObject(db Database, dirtyObjs *stateObject, keys dirtyObjs.originStorage.Range(func(keyItf, valueItf interface{}) bool { key := keyItf.(common.Hash) value := valueItf.(common.Hash) + s.storageRecordsLock.Lock() // Skip noop changes, persist actual changes if _, ok := s.originStorage.GetValue(key); !ok { s.originStorage.StoreValue(key, value) } + s.storageRecordsLock.Unlock() return true }) } diff --git a/core/state/statedb.go b/core/state/statedb.go index ac888ec415..076f062955 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -2512,7 +2512,12 @@ func (s *StateDB) MergeSlotDB(slotDb *ParallelStateDB, slotReceipt *types.Receip mainObj, exist := s.loadStateObj(addr) if !exist || mainObj.deleted { // addr not exist on main DB, the object is created in the merging tx. - mainObj = dirtyObj.deepCopy(s) + if slotDb.parallel.useDAG { + // if use DAG, unconfirmed DB is not touched, so the dirtyObj can be used directly + mainObj = dirtyObj.rebase(s) + } else { + mainObj = dirtyObj.deepCopy(s) + } if !dirtyObj.deleted { mainObj.finalise(true) } @@ -2554,7 +2559,12 @@ func (s *StateDB) MergeSlotDB(slotDb *ParallelStateDB, slotReceipt *types.Receip // may not empty until block validation. so the pendingStorage filled by the execution of previous txs // in same block may get overwritten by deepCopy here, which causes issue in root calculation. if _, created := s.parallel.createdObjectRecord[addr]; created { - newMainObj = dirtyObj.deepCopy(s) + if slotDb.parallel.useDAG { + // if use DAG, unconfirmed DB is not touched, so the dirtyObj can be used directly + newMainObj = dirtyObj.rebase(s) + } else { + newMainObj = dirtyObj.deepCopy(s) + } } else { // Merge the dirtyObject with mainObject if _, balanced := slotDb.parallel.balanceChangesInSlot[addr]; balanced { @@ -2579,7 +2589,12 @@ func (s *StateDB) MergeSlotDB(slotDb *ParallelStateDB, slotReceipt *types.Receip } } else { // The object is deleted in the TX. - newMainObj = dirtyObj.deepCopy(s) + if slotDb.parallel.useDAG { + // if use DAG, unconfirmed DB is not touched, so the dirtyObj can be used directly + newMainObj = dirtyObj.rebase(s) + } else { + newMainObj = dirtyObj.deepCopy(s) + } } // All cases with addrStateChange set to true/false can be deleted. so handle it here.