@@ -31,29 +31,41 @@ import (
3131// thread-safe to use. However, callers need to ensure the thread-safety
3232// of the referenced layer by themselves.
3333type 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
3639}
3740
3841// newLayerTree constructs the layerTree with the given head layer.
3942func newLayerTree (head layer ) * layerTree {
4043 tree := new (layerTree )
41- tree .reset (head )
44+ tree .init (head )
4245 return tree
4346}
4447
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 ) {
4850 tree .lock .Lock ()
4951 defer tree .lock .Unlock ()
5052
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
5566 }
56- tree .layers = layers
67+ tree .base = current .(* diskLayer ) // panic if it's not a disk layer
68+ tree .lookup = newLookup (head , tree .isDescendant )
5769}
5870
5971// get retrieves a layer belonging to the given state root.
@@ -64,6 +76,43 @@ func (tree *layerTree) get(root common.Hash) layer {
6476 return tree .layers [root ]
6577}
6678
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+
67116// forEach iterates the stored layers inside and applies the
68117// given callback on them.
69118func (tree * layerTree ) forEach (onLayer func (layer )) {
@@ -101,8 +150,11 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6
101150 l := parent .update (root , parent .stateID ()+ 1 , block , newNodeSet (nodes .Flatten ()), states )
102151
103152 tree .lock .Lock ()
153+ defer tree .lock .Unlock ()
154+
104155 tree .layers [l .rootHash ()] = l
105- tree .lock .Unlock ()
156+ tree .fillAncestors (l )
157+ tree .lookup .addLayer (l )
106158 return nil
107159}
108160
@@ -127,8 +179,14 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
127179 if err != nil {
128180 return err
129181 }
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 )
132190 return nil
133191 }
134192 // 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 {
143201 }
144202 // We're out of layers, flatten anything below, stopping if it's the disk or if
145203 // the memory limit is not yet exceeded.
204+ var (
205+ err error
206+ replaced layer
207+ newBase * diskLayer
208+ )
146209 switch parent := diff .parentLayer ().(type ) {
147210 case * diskLayer :
148211 return nil
@@ -152,14 +215,33 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
152215 // parent is linked correctly.
153216 diff .lock .Lock ()
154217
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 )
156237 if err != nil {
157238 diff .lock .Unlock ()
158239 return err
159240 }
160- tree .layers [base .rootHash ()] = base
161- diff .parent = base
241+ tree .layers [newBase .rootHash ()] = newBase
162242
243+ // Link the new parent and release the lock
244+ diff .parent = newBase
163245 diff .lock .Unlock ()
164246
165247 default :
@@ -173,19 +255,28 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
173255 children [parent ] = append (children [parent ], root )
174256 }
175257 }
258+ clearDiff := func (layer layer ) {
259+ diff , ok := layer .(* diffLayer )
260+ if ! ok {
261+ return
262+ }
263+ tree .lookup .removeLayer (diff )
264+ }
176265 var remove func (root common.Hash )
177266 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 )
178271 delete (tree .layers , root )
179272 for _ , child := range children [root ] {
180273 remove (child )
181274 }
182275 delete (children , root )
183276 }
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
189280 return nil
190281}
191282
@@ -194,17 +285,39 @@ func (tree *layerTree) bottom() *diskLayer {
194285 tree .lock .RLock ()
195286 defer tree .lock .RUnlock ()
196287
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 )
199300 }
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 )
205304 }
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 )
208321 }
209- return current .( * diskLayer )
322+ return l , nil
210323}
0 commit comments