@@ -31,29 +31,41 @@ 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
35
- layers map [common.Hash ]layer
34
+ base * diskLayer
35
+ layers map [common.Hash ]layer
36
+ descendants map [common.Hash ]map [common.Hash ]struct {}
37
+ lookup * lookup
38
+ lock sync.RWMutex
36
39
}
37
40
38
41
// newLayerTree constructs the layerTree with the given head layer.
39
42
func newLayerTree (head layer ) * layerTree {
40
43
tree := new (layerTree )
41
- tree .reset (head )
44
+ tree .init (head )
42
45
return tree
43
46
}
44
47
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 ) {
48
+ // init initializes the layerTree by the given head layer.
49
+ func (tree * layerTree ) init (head layer ) {
48
50
tree .lock .Lock ()
49
51
defer tree .lock .Unlock ()
50
52
51
- var layers = make (map [common.Hash ]layer )
52
- for head != nil {
53
- layers [head .rootHash ()] = head
54
- head = head .parentLayer ()
53
+ current := head
54
+ tree .layers = make (map [common.Hash ]layer )
55
+ tree .descendants = make (map [common.Hash ]map [common.Hash ]struct {})
56
+
57
+ for {
58
+ tree .layers [current .rootHash ()] = current
59
+ tree .fillAncestors (current )
60
+
61
+ parent := current .parentLayer ()
62
+ if parent == nil {
63
+ break
64
+ }
65
+ current = parent
55
66
}
56
- tree .layers = layers
67
+ tree .base = current .(* diskLayer ) // panic if it's not a disk layer
68
+ tree .lookup = newLookup (head , tree .isDescendant )
57
69
}
58
70
59
71
// get retrieves a layer belonging to the given state root.
@@ -64,6 +76,43 @@ func (tree *layerTree) get(root common.Hash) layer {
64
76
return tree .layers [root ]
65
77
}
66
78
79
+ // isDescendant returns whether the specified layer with given root is a
80
+ // descendant of a specific ancestor.
81
+ //
82
+ // This function assumes the read lock has been held.
83
+ func (tree * layerTree ) isDescendant (root common.Hash , ancestor common.Hash ) bool {
84
+ subset := tree .descendants [ancestor ]
85
+ if subset == nil {
86
+ return false
87
+ }
88
+ _ , ok := subset [root ]
89
+ return ok
90
+ }
91
+
92
+ // fillAncestors identifies the ancestors of the given layer and populates the
93
+ // descendants set. The ancestors include the diff layers below the supplied
94
+ // layer and also the disk layer.
95
+ //
96
+ // This function assumes the write lock has been held.
97
+ func (tree * layerTree ) fillAncestors (layer layer ) {
98
+ hash := layer .rootHash ()
99
+ for {
100
+ parent := layer .parentLayer ()
101
+ if parent == nil {
102
+ break
103
+ }
104
+ layer = parent
105
+
106
+ phash := parent .rootHash ()
107
+ subset := tree .descendants [phash ]
108
+ if subset == nil {
109
+ subset = make (map [common.Hash ]struct {})
110
+ tree .descendants [phash ] = subset
111
+ }
112
+ subset [hash ] = struct {}{}
113
+ }
114
+ }
115
+
67
116
// forEach iterates the stored layers inside and applies the
68
117
// given callback on them.
69
118
func (tree * layerTree ) forEach (onLayer func (layer )) {
@@ -101,8 +150,11 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6
101
150
l := parent .update (root , parent .stateID ()+ 1 , block , newNodeSet (nodes .Flatten ()), states )
102
151
103
152
tree .lock .Lock ()
153
+ defer tree .lock .Unlock ()
154
+
104
155
tree .layers [l .rootHash ()] = l
105
- tree .lock .Unlock ()
156
+ tree .fillAncestors (l )
157
+ tree .lookup .addLayer (l )
106
158
return nil
107
159
}
108
160
@@ -127,8 +179,14 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
127
179
if err != nil {
128
180
return err
129
181
}
130
- // Replace the entire layer tree with the flat base
131
- tree .layers = map [common.Hash ]layer {base .rootHash (): base }
182
+ tree .base = base
183
+
184
+ // Reset the layer tree with the single new disk layer
185
+ tree .layers = map [common.Hash ]layer {
186
+ base .rootHash (): base ,
187
+ }
188
+ tree .descendants = make (map [common.Hash ]map [common.Hash ]struct {})
189
+ tree .lookup = newLookup (base , tree .isDescendant )
132
190
return nil
133
191
}
134
192
// Dive until we run out of layers or reach the persistent database
@@ -143,6 +201,11 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
143
201
}
144
202
// We're out of layers, flatten anything below, stopping if it's the disk or if
145
203
// the memory limit is not yet exceeded.
204
+ var (
205
+ err error
206
+ replaced layer
207
+ newBase * diskLayer
208
+ )
146
209
switch parent := diff .parentLayer ().(type ) {
147
210
case * diskLayer :
148
211
return nil
@@ -152,14 +215,33 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
152
215
// parent is linked correctly.
153
216
diff .lock .Lock ()
154
217
155
- base , err := parent .persist (false )
218
+ // Hold the reference of the original layer being replaced
219
+ replaced = parent
220
+
221
+ // Replace the original parent layer with new disk layer. The procedure
222
+ // can be illustrated as below:
223
+ //
224
+ // Before change:
225
+ // Chain:
226
+ // C1->C2->C3->C4 (HEAD)
227
+ // ->C2'->C3'->C4'
228
+ //
229
+ // After change:
230
+ // Chain:
231
+ // (a) C3->C4 (HEAD)
232
+ // (b) C1->C2
233
+ // ->C2'->C3'->C4'
234
+ // The original C3 is replaced by the new base (with root C3)
235
+ // Dangling layers in (b) will be removed later
236
+ newBase , err = parent .persist (false )
156
237
if err != nil {
157
238
diff .lock .Unlock ()
158
239
return err
159
240
}
160
- tree .layers [base .rootHash ()] = base
161
- diff .parent = base
241
+ tree .layers [newBase .rootHash ()] = newBase
162
242
243
+ // Link the new parent and release the lock
244
+ diff .parent = newBase
163
245
diff .lock .Unlock ()
164
246
165
247
default :
@@ -173,19 +255,28 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
173
255
children [parent ] = append (children [parent ], root )
174
256
}
175
257
}
258
+ clearDiff := func (layer layer ) {
259
+ diff , ok := layer .(* diffLayer )
260
+ if ! ok {
261
+ return
262
+ }
263
+ tree .lookup .removeLayer (diff )
264
+ }
176
265
var remove func (root common.Hash )
177
266
remove = func (root common.Hash ) {
267
+ clearDiff (tree .layers [root ])
268
+
269
+ // Unlink the layer from the layer tree and cascade to its children
270
+ delete (tree .descendants , root )
178
271
delete (tree .layers , root )
179
272
for _ , child := range children [root ] {
180
273
remove (child )
181
274
}
182
275
delete (children , root )
183
276
}
184
- for root , layer := range tree .layers {
185
- if dl , ok := layer .(* diskLayer ); ok && dl .isStale () {
186
- remove (root )
187
- }
188
- }
277
+ remove (tree .base .rootHash ()) // remove the old/stale disk layer
278
+ clearDiff (replaced ) // remove the lookup data of the stale parent being replaced
279
+ tree .base = newBase // update the base layer with newly constructed one
189
280
return nil
190
281
}
191
282
@@ -194,17 +285,39 @@ func (tree *layerTree) bottom() *diskLayer {
194
285
tree .lock .RLock ()
195
286
defer tree .lock .RUnlock ()
196
287
197
- if len (tree .layers ) == 0 {
198
- return nil // Shouldn't happen, empty tree
288
+ return tree .base
289
+ }
290
+
291
+ // lookupAccount returns the layer that is confirmed to contain the account data
292
+ // being searched for.
293
+ func (tree * layerTree ) lookupAccount (accountHash common.Hash , state common.Hash ) (layer , error ) {
294
+ tree .lock .RLock ()
295
+ defer tree .lock .RUnlock ()
296
+
297
+ tip := tree .lookup .accountTip (accountHash , state , tree .base .root )
298
+ if tip == (common.Hash {}) {
299
+ return nil , fmt .Errorf ("[%#x] %w" , state , errSnapshotStale )
199
300
}
200
- // pick a random one as the entry point
201
- var current layer
202
- for _ , layer := range tree .layers {
203
- current = layer
204
- break
301
+ l := tree .layers [tip ]
302
+ if l == nil {
303
+ return nil , fmt .Errorf ("triedb layer [%#x] missing" , tip )
205
304
}
206
- for current .parentLayer () != nil {
207
- current = current .parentLayer ()
305
+ return l , nil
306
+ }
307
+
308
+ // lookupStorage returns the layer that is confirmed to contain the storage slot
309
+ // data being searched for.
310
+ func (tree * layerTree ) lookupStorage (accountHash common.Hash , slotHash common.Hash , state common.Hash ) (layer , error ) {
311
+ tree .lock .RLock ()
312
+ defer tree .lock .RUnlock ()
313
+
314
+ tip := tree .lookup .storageTip (accountHash , slotHash , state , tree .base .root )
315
+ if tip == (common.Hash {}) {
316
+ return nil , fmt .Errorf ("[%#x] %w" , state , errSnapshotStale )
317
+ }
318
+ l := tree .layers [tip ]
319
+ if l == nil {
320
+ return nil , fmt .Errorf ("triedb layer [%#x] missing" , tip )
208
321
}
209
- return current .( * diskLayer )
322
+ return l , nil
210
323
}
0 commit comments