@@ -36,12 +36,13 @@ type diskLayer struct {
36
36
db * Database // Path-based trie database
37
37
cleans * fastcache.Cache // GC friendly memory cache of clean node RLPs
38
38
buffer * nodebuffer // Node buffer to aggregate writes
39
+ frozen * nodebuffer // Frozen node buffer waiting for flushing
39
40
stale bool // Signals that the layer became stale (state progressed)
40
41
lock sync.RWMutex // Lock used to protect stale flag
41
42
}
42
43
43
44
// 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 {
45
46
// Initialize a clean cache if the memory allowance is not zero
46
47
// or reuse the provided cache if it is not nil (inherited from
47
48
// the original disk layer).
@@ -54,6 +55,7 @@ func newDiskLayer(root common.Hash, id uint64, db *Database, cleans *fastcache.C
54
55
db : db ,
55
56
cleans : cleans ,
56
57
buffer : buffer ,
58
+ frozen : frozen ,
57
59
}
58
60
}
59
61
@@ -102,16 +104,19 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co
102
104
if dl .stale {
103
105
return nil , common.Hash {}, nil , errSnapshotStale
104
106
}
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
+ }
115
120
}
116
121
dirtyMissMeter .Mark (1 )
117
122
@@ -182,29 +187,51 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
182
187
// Mark the diskLayer as stale before applying any mutations on top.
183
188
dl .stale = true
184
189
185
- // Store the root->id lookup afterwards . All stored lookups are identified
190
+ // Store the root->id lookup afterward . All stored lookups are identified
186
191
// by the **unique** state root. It's impossible that in the same chain
187
192
// blocks are not adjacent but have the same root.
188
193
if dl .id == 0 {
189
194
rawdb .WriteStateID (dl .db .diskdb , dl .root , 0 )
190
195
}
191
196
rawdb .WriteStateID (dl .db .diskdb , bottom .rootHash (), bottom .stateID ())
192
197
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
-
198
198
// In a unique scenario where the ID of the oldest history object (after tail
199
199
// 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
201
201
// 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 {
203
204
force = true
204
205
}
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 )
207
229
}
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
+
208
235
// To remove outdated history objects from the end, we set the 'tail' parameter
209
236
// to 'oldest-1' due to the offset between the freezer index and the history ID.
210
237
if overflow {
@@ -249,25 +276,21 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) {
249
276
return nil , err
250
277
}
251
278
} 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
+ }
252
286
batch := dl .db .diskdb .NewBatch ()
253
287
writeNodes (batch , nodes , dl .cleans )
254
288
rawdb .WritePersistentStateID (batch , dl .id - 1 )
255
289
if err := batch .Write (); err != nil {
256
290
log .Crit ("Failed to write states" , "err" , err )
257
291
}
258
292
}
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
271
294
}
272
295
273
296
// size returns the approximate size of cached nodes in the disk layer.
0 commit comments