@@ -31,29 +31,50 @@ import (
31
31
// thread-safe to use. However, callers need to ensure the thread-safety
32
32
// of the referenced layer by themselves.
33
33
type layerTree struct {
34
- lock sync. RWMutex
34
+ base * diskLayer
35
35
layers map [common.Hash ]layer
36
+
37
+ // descendants is a two-dimensional map where the keys represent
38
+ // an ancestor state root, and the values are the state roots of
39
+ // all its descendants.
40
+ //
41
+ // For example: r -> [c1, c2, ..., cn], where c1 through cn are
42
+ // the descendants of state r.
43
+ //
44
+ // This map includes all the existing diff layers and the disk layer.
45
+ descendants map [common.Hash ]map [common.Hash ]struct {}
46
+ lookup * lookup
47
+ lock sync.RWMutex
36
48
}
37
49
38
50
// newLayerTree constructs the layerTree with the given head layer.
39
51
func newLayerTree (head layer ) * layerTree {
40
52
tree := new (layerTree )
41
- tree .reset (head )
53
+ tree .init (head )
42
54
return tree
43
55
}
44
56
45
- // reset initializes the layerTree by the given head layer.
46
- // All the ancestors will be iterated out and linked in the tree.
47
- func (tree * layerTree ) reset (head layer ) {
57
+ // init initializes the layerTree by the given head layer.
58
+ func (tree * layerTree ) init (head layer ) {
48
59
tree .lock .Lock ()
49
60
defer tree .lock .Unlock ()
50
61
51
- var layers = make (map [common.Hash ]layer )
52
- for head != nil {
53
- layers [head .rootHash ()] = head
54
- head = head .parentLayer ()
62
+ current := head
63
+ tree .layers = make (map [common.Hash ]layer )
64
+ tree .descendants = make (map [common.Hash ]map [common.Hash ]struct {})
65
+
66
+ for {
67
+ tree .layers [current .rootHash ()] = current
68
+ tree .fillAncestors (current )
69
+
70
+ parent := current .parentLayer ()
71
+ if parent == nil {
72
+ break
73
+ }
74
+ current = parent
55
75
}
56
- tree .layers = layers
76
+ tree .base = current .(* diskLayer ) // panic if it's not a disk layer
77
+ tree .lookup = newLookup (head , tree .isDescendant )
57
78
}
58
79
59
80
// get retrieves a layer belonging to the given state root.
@@ -64,6 +85,43 @@ func (tree *layerTree) get(root common.Hash) layer {
64
85
return tree .layers [root ]
65
86
}
66
87
88
+ // isDescendant returns whether the specified layer with given root is a
89
+ // descendant of a specific ancestor.
90
+ //
91
+ // This function assumes the read lock has been held.
92
+ func (tree * layerTree ) isDescendant (root common.Hash , ancestor common.Hash ) bool {
93
+ subset := tree .descendants [ancestor ]
94
+ if subset == nil {
95
+ return false
96
+ }
97
+ _ , ok := subset [root ]
98
+ return ok
99
+ }
100
+
101
+ // fillAncestors identifies the ancestors of the given layer and populates the
102
+ // descendants set. The ancestors include the diff layers below the supplied
103
+ // layer and also the disk layer.
104
+ //
105
+ // This function assumes the write lock has been held.
106
+ func (tree * layerTree ) fillAncestors (layer layer ) {
107
+ hash := layer .rootHash ()
108
+ for {
109
+ parent := layer .parentLayer ()
110
+ if parent == nil {
111
+ break
112
+ }
113
+ layer = parent
114
+
115
+ phash := parent .rootHash ()
116
+ subset := tree .descendants [phash ]
117
+ if subset == nil {
118
+ subset = make (map [common.Hash ]struct {})
119
+ tree .descendants [phash ] = subset
120
+ }
121
+ subset [hash ] = struct {}{}
122
+ }
123
+ }
124
+
67
125
// forEach iterates the stored layers inside and applies the
68
126
// given callback on them.
69
127
func (tree * layerTree ) forEach (onLayer func (layer )) {
@@ -101,8 +159,16 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6
101
159
l := parent .update (root , parent .stateID ()+ 1 , block , newNodeSet (nodes .Flatten ()), states )
102
160
103
161
tree .lock .Lock ()
162
+ defer tree .lock .Unlock ()
163
+
164
+ // Link the given layer into the layer set
104
165
tree .layers [l .rootHash ()] = l
105
- tree .lock .Unlock ()
166
+
167
+ // Link the given layer into its ancestors (up to the current disk layer)
168
+ tree .fillAncestors (l )
169
+
170
+ // Link the given layer into the state mutation history
171
+ tree .lookup .addLayer (l )
106
172
return nil
107
173
}
108
174
@@ -127,8 +193,16 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
127
193
if err != nil {
128
194
return err
129
195
}
130
- // Replace the entire layer tree with the flat base
131
- tree .layers = map [common.Hash ]layer {base .rootHash (): base }
196
+ tree .base = base
197
+
198
+ // Reset the layer tree with the single new disk layer
199
+ tree .layers = map [common.Hash ]layer {
200
+ base .rootHash (): base ,
201
+ }
202
+ // Resets the descendants map, since there's only a single disk layer
203
+ // with no descendants.
204
+ tree .descendants = make (map [common.Hash ]map [common.Hash ]struct {})
205
+ tree .lookup = newLookup (base , tree .isDescendant )
132
206
return nil
133
207
}
134
208
// Dive until we run out of layers or reach the persistent database
@@ -143,6 +217,11 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
143
217
}
144
218
// We're out of layers, flatten anything below, stopping if it's the disk or if
145
219
// the memory limit is not yet exceeded.
220
+ var (
221
+ err error
222
+ replaced layer
223
+ newBase * diskLayer
224
+ )
146
225
switch parent := diff .parentLayer ().(type ) {
147
226
case * diskLayer :
148
227
return nil
@@ -152,14 +231,33 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
152
231
// parent is linked correctly.
153
232
diff .lock .Lock ()
154
233
155
- base , err := parent .persist (false )
234
+ // Hold the reference of the original layer being replaced
235
+ replaced = parent
236
+
237
+ // Replace the original parent layer with new disk layer. The procedure
238
+ // can be illustrated as below:
239
+ //
240
+ // Before change:
241
+ // Chain:
242
+ // C1->C2->C3->C4 (HEAD)
243
+ // ->C2'->C3'->C4'
244
+ //
245
+ // After change:
246
+ // Chain:
247
+ // (a) C3->C4 (HEAD)
248
+ // (b) C1->C2
249
+ // ->C2'->C3'->C4'
250
+ // The original C3 is replaced by the new base (with root C3)
251
+ // Dangling layers in (b) will be removed later
252
+ newBase , err = parent .persist (false )
156
253
if err != nil {
157
254
diff .lock .Unlock ()
158
255
return err
159
256
}
160
- tree .layers [base .rootHash ()] = base
161
- diff .parent = base
257
+ tree .layers [newBase .rootHash ()] = newBase
162
258
259
+ // Link the new parent and release the lock
260
+ diff .parent = newBase
163
261
diff .lock .Unlock ()
164
262
165
263
default :
@@ -173,19 +271,28 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
173
271
children [parent ] = append (children [parent ], root )
174
272
}
175
273
}
274
+ clearDiff := func (layer layer ) {
275
+ diff , ok := layer .(* diffLayer )
276
+ if ! ok {
277
+ return
278
+ }
279
+ tree .lookup .removeLayer (diff )
280
+ }
176
281
var remove func (root common.Hash )
177
282
remove = func (root common.Hash ) {
283
+ clearDiff (tree .layers [root ])
284
+
285
+ // Unlink the layer from the layer tree and cascade to its children
286
+ delete (tree .descendants , root )
178
287
delete (tree .layers , root )
179
288
for _ , child := range children [root ] {
180
289
remove (child )
181
290
}
182
291
delete (children , root )
183
292
}
184
- for root , layer := range tree .layers {
185
- if dl , ok := layer .(* diskLayer ); ok && dl .isStale () {
186
- remove (root )
187
- }
188
- }
293
+ remove (tree .base .rootHash ()) // remove the old/stale disk layer
294
+ clearDiff (replaced ) // remove the lookup data of the stale parent being replaced
295
+ tree .base = newBase // update the base layer with newly constructed one
189
296
return nil
190
297
}
191
298
@@ -194,17 +301,41 @@ func (tree *layerTree) bottom() *diskLayer {
194
301
tree .lock .RLock ()
195
302
defer tree .lock .RUnlock ()
196
303
197
- if len (tree .layers ) == 0 {
198
- return nil // Shouldn't happen, empty tree
304
+ return tree .base
305
+ }
306
+
307
+ // lookupAccount returns the layer that is guaranteed to contain the account data
308
+ // corresponding to the specified state root being queried.
309
+ func (tree * layerTree ) lookupAccount (accountHash common.Hash , state common.Hash ) (layer , error ) {
310
+ // Hold the read lock to prevent the unexpected layer changes
311
+ tree .lock .RLock ()
312
+ defer tree .lock .RUnlock ()
313
+
314
+ tip := tree .lookup .accountTip (accountHash , state , tree .base .root )
315
+ if tip == (common.Hash {}) {
316
+ return nil , fmt .Errorf ("[%#x] %w" , state , errSnapshotStale )
199
317
}
200
- // pick a random one as the entry point
201
- var current layer
202
- for _ , layer := range tree .layers {
203
- current = layer
204
- break
318
+ l := tree .layers [tip ]
319
+ if l == nil {
320
+ return nil , fmt .Errorf ("triedb layer [%#x] missing" , tip )
205
321
}
206
- for current .parentLayer () != nil {
207
- current = current .parentLayer ()
322
+ return l , nil
323
+ }
324
+
325
+ // lookupStorage returns the layer that is guaranteed to contain the storage slot
326
+ // data corresponding to the specified state root being queried.
327
+ func (tree * layerTree ) lookupStorage (accountHash common.Hash , slotHash common.Hash , state common.Hash ) (layer , error ) {
328
+ // Hold the read lock to prevent the unexpected layer changes
329
+ tree .lock .RLock ()
330
+ defer tree .lock .RUnlock ()
331
+
332
+ tip := tree .lookup .storageTip (accountHash , slotHash , state , tree .base .root )
333
+ if tip == (common.Hash {}) {
334
+ return nil , fmt .Errorf ("[%#x] %w" , state , errSnapshotStale )
335
+ }
336
+ l := tree .layers [tip ]
337
+ if l == nil {
338
+ return nil , fmt .Errorf ("triedb layer [%#x] missing" , tip )
208
339
}
209
- return current .( * diskLayer )
340
+ return l , nil
210
341
}
0 commit comments