@@ -36,12 +36,13 @@ type diskLayer struct {
3636 db * Database // Path-based trie database
3737 cleans * fastcache.Cache // GC friendly memory cache of clean node RLPs
3838 buffer * nodebuffer // Node buffer to aggregate writes
39+ frozen * nodebuffer // Frozen node buffer waiting for flushing
3940 stale bool // Signals that the layer became stale (state progressed)
4041 lock sync.RWMutex // Lock used to protect stale flag
4142}
4243
4344// newDiskLayer creates a new disk layer based on the passing arguments.
44- func newDiskLayer (root common.Hash , id uint64 , db * Database , cleans * fastcache.Cache , buffer * nodebuffer ) * diskLayer {
45+ func newDiskLayer (root common.Hash , id uint64 , db * Database , cleans * fastcache.Cache , buffer * nodebuffer , frozen * nodebuffer ) * diskLayer {
4546 // Initialize a clean cache if the memory allowance is not zero
4647 // or reuse the provided cache if it is not nil (inherited from
4748 // the original disk layer).
@@ -54,6 +55,7 @@ func newDiskLayer(root common.Hash, id uint64, db *Database, cleans *fastcache.C
5455 db : db ,
5556 cleans : cleans ,
5657 buffer : buffer ,
58+ frozen : frozen ,
5759 }
5860}
5961
@@ -102,16 +104,19 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co
102104 if dl .stale {
103105 return nil , common.Hash {}, nil , errSnapshotStale
104106 }
105- // Try to retrieve the trie node from the not-yet-written
106- // node buffer first. Note the buffer is lock free since
107- // it's impossible to mutate the buffer before tagging the
108- // layer as stale.
109- n , found := dl .buffer .node (owner , path )
110- if found {
111- dirtyHitMeter .Mark (1 )
112- dirtyReadMeter .Mark (int64 (len (n .Blob )))
113- dirtyNodeHitDepthHist .Update (int64 (depth ))
114- return n .Blob , n .Hash , & nodeLoc {loc : locDirtyCache , depth : depth }, nil
107+ // Try to retrieve the trie node from the not-yet-written node buffer first
108+ // (both the live one and the frozen one). Note the buffer is lock free since
109+ // it's impossible to mutate the buffer before tagging the layer as stale.
110+ for _ , buffer := range []* nodebuffer {dl .buffer , dl .frozen } {
111+ if buffer != nil {
112+ n , found := buffer .node (owner , path )
113+ if found {
114+ dirtyHitMeter .Mark (1 )
115+ dirtyReadMeter .Mark (int64 (len (n .Blob )))
116+ dirtyNodeHitDepthHist .Update (int64 (depth ))
117+ return n .Blob , n .Hash , & nodeLoc {loc : locDirtyCache , depth : depth }, nil
118+ }
119+ }
115120 }
116121 dirtyMissMeter .Mark (1 )
117122
@@ -182,29 +187,51 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
182187 // Mark the diskLayer as stale before applying any mutations on top.
183188 dl .stale = true
184189
185- // Store the root->id lookup afterwards . All stored lookups are identified
190+ // Store the root->id lookup afterward . All stored lookups are identified
186191 // by the **unique** state root. It's impossible that in the same chain
187192 // blocks are not adjacent but have the same root.
188193 if dl .id == 0 {
189194 rawdb .WriteStateID (dl .db .diskdb , dl .root , 0 )
190195 }
191196 rawdb .WriteStateID (dl .db .diskdb , bottom .rootHash (), bottom .stateID ())
192197
193- // Construct a new disk layer by merging the nodes from the provided diff
194- // layer, and flush the content in disk layer if there are too many nodes
195- // cached. The clean cache is inherited from the original disk layer.
196- ndl := newDiskLayer (bottom .root , bottom .stateID (), dl .db , dl .cleans , dl .buffer .commit (bottom .nodes ))
197-
198198 // In a unique scenario where the ID of the oldest history object (after tail
199199 // truncation) surpasses the persisted state ID, we take the necessary action
200- // of forcibly committing the cached dirty nodes to ensure that the persisted
200+ // of forcibly committing the cached dirty states to ensure that the persisted
201201 // state ID remains higher.
202- if ! force && rawdb .ReadPersistentStateID (dl .db .diskdb ) < oldest {
202+ persistedID := rawdb .ReadPersistentStateID (dl .db .diskdb )
203+ if ! force && persistedID < oldest {
203204 force = true
204205 }
205- if err := ndl .buffer .flush (ndl .db .diskdb , ndl .cleans , ndl .id , force ); err != nil {
206- return nil , err
206+ // Merge the nodes of the bottom-most diff layer into the buffer as the combined one
207+ combined := dl .buffer .commit (bottom .nodes )
208+ if combined .full () || force {
209+ // Wait until the previous frozen buffer is fully flushed
210+ if dl .frozen != nil {
211+ if err := dl .frozen .flushed (); err != nil {
212+ return nil , err
213+ }
214+ }
215+ dl .frozen = nil
216+
217+ // Freeze the live buffer and schedule background flushing
218+ dl .frozen = combined
219+ dl .frozen .flush (dl .db .diskdb , dl .cleans , bottom .stateID ())
220+
221+ // Block until the frozen buffer is fully flushed out if the oldest history
222+ // surpasses the persisted state ID.
223+ if persistedID < oldest {
224+ if err := dl .frozen .flushed (); err != nil {
225+ return nil , err
226+ }
227+ }
228+ combined = newNodeBuffer (dl .db .bufferSize , nil , 0 )
207229 }
230+ // Construct a new disk layer by merging the nodes from the provided diff
231+ // layer, and flush the content in disk layer if there are too many nodes
232+ // cached. The clean cache is inherited from the original disk layer.
233+ ndl := newDiskLayer (bottom .root , bottom .stateID (), dl .db , dl .cleans , combined , dl .frozen )
234+
208235 // To remove outdated history objects from the end, we set the 'tail' parameter
209236 // to 'oldest-1' due to the offset between the freezer index and the history ID.
210237 if overflow {
@@ -249,25 +276,21 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) {
249276 return nil , err
250277 }
251278 } else {
279+ // Block until the frozen buffer is fully flushed
280+ if dl .frozen != nil {
281+ if err := dl .frozen .flushed (); err != nil {
282+ return nil , err
283+ }
284+ dl .frozen = nil // unset the frozen buffer
285+ }
252286 batch := dl .db .diskdb .NewBatch ()
253287 writeNodes (batch , nodes , dl .cleans )
254288 rawdb .WritePersistentStateID (batch , dl .id - 1 )
255289 if err := batch .Write (); err != nil {
256290 log .Crit ("Failed to write states" , "err" , err )
257291 }
258292 }
259- return newDiskLayer (h .meta .parent , dl .id - 1 , dl .db , dl .cleans , dl .buffer ), nil
260- }
261-
262- // setBufferSize sets the node buffer size to the provided value.
263- func (dl * diskLayer ) setBufferSize (size int ) error {
264- dl .lock .RLock ()
265- defer dl .lock .RUnlock ()
266-
267- if dl .stale {
268- return errSnapshotStale
269- }
270- return dl .buffer .setSize (size , dl .db .diskdb , dl .cleans , dl .id )
293+ return newDiskLayer (h .meta .parent , dl .id - 1 , dl .db , dl .cleans , dl .buffer , dl .frozen ), nil
271294}
272295
273296// size returns the approximate size of cached nodes in the disk layer.
0 commit comments