Skip to content

Commit 3a31dce

Browse files
committed
Remove account leaf cache
With static vid lookup we can find cached accounts in `O(1)` in the regular caches - no need to waste time and effort on maintaining a separate path-based cache for it. 5% speed bump from just the removal - more to be had by reallocating the memory to other causes.
1 parent 2aaafe1 commit 3a31dce

File tree

9 files changed

+17
-105
lines changed

9 files changed

+17
-105
lines changed

execution_chain/db/aristo/aristo_constants.nim

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ const
4141
v += 1'u64 shl (i * 4)
4242
v
4343

44-
ACC_LRU_SIZE* = 1024 * 1024
45-
## LRU cache size for accounts that have storage, see `.accLeaves` and
46-
## `.stoLeaves` fields of the main descriptor.
44+
STO_LRU_SIZE* = 1024 * 1024
45+
## LRU cache size for the storage leaf cache (see AristoDbRef.stoLeaves)
4746

4847
# End

execution_chain/db/aristo/aristo_delete.nim

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,7 @@ proc deleteAccountRecord*(
147147
if stoID.isValid:
148148
?db.delStoTreeImpl(stoID.vid, accPath)
149149

150-
let otherLeaf = ?db.deleteImpl(accHike)
151-
152-
db.layersPutAccLeaf(accPath, nil)
153-
154-
if otherLeaf.isValid:
155-
db.layersPutAccLeaf(
156-
Hash32(getBytes(NibblesBuf.fromBytes(accPath.data).replaceSuffix(otherLeaf.pfx))),
157-
AccLeafRef(otherLeaf),
158-
)
150+
discard ?db.deleteImpl(accHike)
159151

160152
ok()
161153

@@ -214,7 +206,6 @@ proc deleteStorageData*(
214206
# De-register the deleted storage tree from the account record
215207
let leaf = AccLeafRef(wpAcc.vtx).dup # Dup on modify
216208
leaf.stoID.isValid = false
217-
db.layersPutAccLeaf(accPath, leaf)
218209
db.layersPutVtx((accHike.root, wpAcc.vid), leaf)
219210

220211
ok()
@@ -248,7 +239,6 @@ proc deleteStorageTree*(
248239
# De-register the deleted storage tree from the accounts record
249240
let leaf = accVtx.dup # Dup on modify
250241
leaf.stoID.isValid = false
251-
db.layersPutAccLeaf(accPath, leaf)
252242
db.layersPutVtx((accHike.root, wpAcc.vid), leaf)
253243
ok()
254244

execution_chain/db/aristo/aristo_desc.nim

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ type
6868
kMap*: Table[RootedVertexID,HashKey] ## Merkle hash key mapping
6969
vTop*: VertexID ## Last used vertex ID
7070

71-
accLeaves*: Table[Hash32, AccLeafRef] ## Account path -> VertexRef
7271
stoLeaves*: Table[Hash32, StoLeafRef] ## Storage path -> VertexRef
7372

7473
blockNumber*: Opt[uint64] ## Block number set when checkpointing the frame
@@ -85,7 +84,6 @@ type
8584

8685
Snapshot* = object
8786
vtx*: Table[RootedVertexID, VtxSnapshot]
88-
acc*: Table[Hash32, (AccLeafRef, int)]
8987
sto*: Table[Hash32, (StoLeafRef, int)]
9088
level*: Opt[int] # when this snapshot was taken
9189

@@ -110,14 +108,6 @@ type
110108

111109
txRef*: AristoTxRef ## Bottom-most in-memory frame
112110

113-
accLeaves*: LruCache[Hash32, AccLeafRef]
114-
## Account path to payload cache - accounts are frequently accessed by
115-
## account path when contracts interact with them - this cache ensures
116-
## that we don't have to re-traverse the storage trie for every such
117-
## interaction
118-
## TODO a better solution would probably be to cache this in a type
119-
## exposed to the high-level API
120-
121111
stoLeaves*: LruCache[Hash32, StoLeafRef]
122112
## Mixed account/storage path to payload cache - same as above but caches
123113
## the full lookup of storage slots

execution_chain/db/aristo/aristo_fetch.nim

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,6 @@ proc retrieveLeaf(
4040

4141
return err(FetchPathNotFound)
4242

43-
proc cachedAccLeaf*(db: AristoTxRef; accPath: Hash32): Opt[AccLeafRef] =
44-
# Return vertex from layers or cache, `nil` if it's known to not exist and
45-
# none otherwise
46-
db.layersGetAccLeaf(accPath) or
47-
db.db.accLeaves.get(accPath) or
48-
Opt.none(AccLeafRef)
49-
5043
proc cachedStoLeaf*(db: AristoTxRef; mixPath: Hash32): Opt[StoLeafRef] =
5144
# Return vertex from layers or cache, `nil` if it's known to not exist and
5245
# none otherwise
@@ -132,18 +125,9 @@ proc retrieveAccLeaf(
132125
db: AristoTxRef;
133126
accPath: Hash32;
134127
): Result[AccLeafRef,AristoError] =
135-
if (let leafVtx = db.cachedAccLeaf(accPath); leafVtx.isSome()):
136-
if not leafVtx[].isValid():
137-
return err(FetchPathNotFound)
138-
return ok leafVtx[]
139-
140-
let (staticVtx, path, next) = db.retrieveAccStatic(accPath).valueOr:
141-
if error == FetchPathNotFound:
142-
db.db.accLeaves.put(accPath, nil)
143-
return err(error)
128+
let (staticVtx, path, next) = ? db.retrieveAccStatic(accPath)
144129

145130
if staticVtx.isValid():
146-
db.db.accLeaves.put(accPath, staticVtx)
147131
return ok staticVtx
148132

149133
# Updated payloads are stored in the layers so if we didn't find them there,
@@ -155,13 +139,10 @@ proc retrieveAccLeaf(
155139
# meaning that it was a hit - else searches for non-existing paths would
156140
# skew the results towards more depth than exists in the MPT
157141
db.db.lookups.hits += 1
158-
db.db.accLeaves.put(accPath, nil)
159142
return err(error)
160143

161144
db.db.lookups.higher += 1
162145

163-
db.db.accLeaves.put(accPath, AccLeafRef(leafVtx))
164-
165146
ok AccLeafRef(leafVtx)
166147

167148
proc retrieveMerkleHash(
@@ -215,11 +196,16 @@ proc fetchAccountHike*(
215196
): Result[void,AristoError] =
216197
## Expand account path to account leaf or return failure
217198

218-
# Prefer the leaf cache so as not to burden the lower layers
219-
let leaf = db.cachedAccLeaf(accPath)
220-
if leaf == Opt.some(AccLeafRef(nil)):
199+
# Pre-lookup in case the account does not exist
200+
let (staticVtx, path, next) = db.retrieveAccStatic(accPath).valueOr:
221201
return err(FetchAccInaccessible)
222202

203+
let leaf =
204+
if staticVtx.isValid():
205+
Opt.some(staticVtx)
206+
else:
207+
Opt.none(AccLeafRef)
208+
223209
accPath.hikeUp(STATE_ROOT_VID, db, leaf, accHike).isOkOr:
224210
return err(FetchAccInaccessible)
225211

execution_chain/db/aristo/aristo_init/init_common.nim

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,7 @@ proc finishSession*(hdl: TypedPutHdlRef; db: TypedBackendRef) =
8484
proc initInstance*(db: AristoDbRef): Result[void, AristoError] =
8585
let vTop = ?db.getTuvFn()
8686
db.txRef = AristoTxRef(db: db, vTop: vTop, snapshot: Snapshot(level: Opt.some(0)))
87-
db.accLeaves = LruCache[Hash32, AccLeafRef].init(ACC_LRU_SIZE)
88-
db.stoLeaves = LruCache[Hash32, StoLeafRef].init(ACC_LRU_SIZE)
87+
db.stoLeaves = LruCache[Hash32, StoLeafRef].init(STO_LRU_SIZE)
8988
ok()
9089

9190
proc finish*(db: AristoDbRef; eradicate = false) =

execution_chain/db/aristo/aristo_layers.nim

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,6 @@ func layersGetKeyOrVoid*(db: AristoTxRef; rvid: RootedVertexID): HashKey =
5858
## Simplified version of `layersGetKey()`
5959
(db.layersGetKey(rvid).valueOr (VOID_HASH_KEY, 0))[0]
6060

61-
func layersGetAccLeaf*(db: AristoTxRef; accPath: Hash32): Opt[AccLeafRef] =
62-
for w in db.rstack(stopAtSnapshot = true):
63-
if w.snapshot.level.isSome():
64-
w.snapshot.acc.withValue(accPath, item):
65-
return Opt.some(item[][0])
66-
break
67-
68-
w.accLeaves.withValue(accPath, item):
69-
return Opt.some(item[])
70-
71-
Opt.none(AccLeafRef)
72-
7361
func layersGetStoLeaf*(db: AristoTxRef; mixPath: Hash32): Opt[StoLeafRef] =
7462
for w in db.rstack(stopAtSnapshot = true):
7563
if w.snapshot.level.isSome():
@@ -129,12 +117,6 @@ func layersResKeys*(db: AristoTxRef; hike: Hike, skip: int) =
129117
for i in (skip + 1)..hike.legs.len:
130118
db.layersResKey((hike.root, hike.legs[^i].wp.vid), hike.legs[^i].wp.vtx)
131119

132-
func layersPutAccLeaf*(db: AristoTxRef; accPath: Hash32; leafVtx: AccLeafRef) =
133-
db.accLeaves[accPath] = leafVtx
134-
135-
if db.snapshot.level.isSome():
136-
db.snapshot.acc[accPath] = (leafVtx, db.level)
137-
138120
func layersPutStoLeaf*(db: AristoTxRef; mixPath: Hash32; leafVtx: StoLeafRef) =
139121
db.stoLeaves[mixPath] = leafVtx
140122

@@ -149,11 +131,9 @@ func isEmpty*(ly: AristoTxRef): bool =
149131
## Returns `true` if the layer does not contain any changes, i.e. all the
150132
## tables are empty.
151133
ly.snapshot.vtx.len == 0 and
152-
ly.snapshot.acc.len == 0 and
153134
ly.snapshot.sto.len == 0 and
154135
ly.sTab.len == 0 and
155136
ly.kMap.len == 0 and
156-
ly.accLeaves.len == 0 and
157137
ly.stoLeaves.len == 0
158138

159139
proc copyFrom*(snapshot: var Snapshot, tx: AristoTxRef) =
@@ -163,8 +143,6 @@ proc copyFrom*(snapshot: var Snapshot, tx: AristoTxRef) =
163143
do:
164144
snapshot.vtx[rvid] = (vtx, VOID_HASH_KEY, tx.level)
165145

166-
for k, v in tx.accLeaves:
167-
snapshot.acc[k] = (v, tx.level)
168146
for k, v in tx.stoLeaves:
169147
snapshot.sto[k] = (v, tx.level)
170148

@@ -195,7 +173,6 @@ proc mergeAndReset*(trg, src: AristoTxRef) =
195173
mergeAndReset(trg.sTab, src.sTab)
196174
mergeAndReset(trg.kMap, src.kMap)
197175

198-
mergeAndReset(trg.accLeaves, src.accLeaves)
199176
mergeAndReset(trg.stoLeaves, src.stoLeaves)
200177

201178
# ------------------------------------------------------------------------------

execution_chain/db/aristo/aristo_merge.nim

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -216,21 +216,11 @@ proc mergeAccountRecord*(
216216
## not on the database already or different from `accRec`, and `false`
217217
## otherwise.
218218
##
219-
let updated = db.mergePayloadImpl(
220-
STATE_ROOT_VID, accPath, db.cachedAccLeaf(accPath), accRec
221-
).valueOr:
219+
discard db.mergePayloadImpl(STATE_ROOT_VID, accPath, Opt.none(AccLeafRef), accRec).valueOr:
222220
if error == MergeNoAction:
223221
return ok false
224222
return err(error)
225223

226-
# Update leaf cache both of the merged value and potentially the displaced
227-
# leaf resulting from splitting a leaf into a branch with two leaves
228-
db.layersPutAccLeaf(accPath, updated[0])
229-
if updated[1].isValid:
230-
let otherPath =
231-
Hash32(getBytes(NibblesBuf.fromBytes(accPath.data).replaceSuffix(updated[1].pfx)))
232-
db.layersPutAccLeaf(otherPath, updated[2])
233-
234224
ok true
235225

236226
proc mergeStorageData*(
@@ -282,7 +272,6 @@ proc mergeStorageData*(
282272
# Make sure that there is an account that refers to that storage trie
283273
let leaf = AccLeafRef(accHike.legs[^1].wp.vtx).dup # Dup on modify
284274
leaf.stoID = useID
285-
db.layersPutAccLeaf(accPath, leaf)
286275
db.layersPutVtx((STATE_ROOT_VID, accHike.legs[^1].wp.vid), leaf)
287276

288277
ok()

execution_chain/db/aristo/aristo_tx_frame.nim

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,13 @@ proc buildSnapshot(txFrame: AristoTxRef, minLevel: int) =
5757
tbl.del(k)
5858
5959
txFrame.snapshot.vtx.delIfIt(it[2] < minLevel)
60-
txFrame.snapshot.acc.delIfIt(it[1] < minLevel)
6160
txFrame.snapshot.sto.delIfIt(it[1] < minLevel)
6261

6362
if frame.snapshot.level.isSome() and isKeyframe:
6463
txFrame.snapshot.vtx = initTable[RootedVertexID, VtxSnapshot](
6564
max(1024, max(frame.sTab.len, frame.snapshot.vtx.len))
6665
)
6766
68-
txFrame.snapshot.acc = initTable[Hash32, (AccLeafRef, int)](
69-
max(1024, max(frame.accLeaves.len, frame.snapshot.acc.len))
70-
)
71-
7267
txFrame.snapshot.sto = initTable[Hash32, (StoLeafRef, int)](
7368
max(1024, max(frame.stoLeaves.len, frame.snapshot.sto.len))
7469
)
@@ -77,10 +72,6 @@ proc buildSnapshot(txFrame: AristoTxRef, minLevel: int) =
7772
if v[2] >= minLevel:
7873
txFrame.snapshot.vtx[k] = v
7974

80-
for k, v in frame.snapshot.acc:
81-
if v[1] >= minLevel:
82-
txFrame.snapshot.acc[k] = v
83-
8475
for k, v in frame.snapshot.sto:
8576
if v[1] >= minLevel:
8677
txFrame.snapshot.sto[k] = v
@@ -141,8 +132,7 @@ proc persist*(
141132
# which caters to the scenario where changes from multiple blocks
142133
# have already been written to sTab and the changes can moved into
143134
# the bottom.
144-
if (bottom.snapshot.vtx.len + bottom.snapshot.acc.len + bottom.snapshot.sto.len) ==
145-
0:
135+
if (bottom.snapshot.vtx.len + bottom.snapshot.sto.len) == 0:
146136
bottom.snapshot.level.reset()
147137
else:
148138
# Incoming snapshots already have sTab baked in - make sure we don't
@@ -212,27 +202,19 @@ with --debug-eager-state-root."""
212202
# in-memory and on-disk state)
213203

214204
# Copy back updated payloads
215-
for accPath, vtx in txFrame.accLeaves:
216-
if vtx == nil:
217-
db.accLeaves.del(accPath)
218-
else:
219-
discard db.accLeaves.update(accPath, vtx)
220-
221205
for mixPath, vtx in txFrame.stoLeaves:
222206
if vtx == nil:
223207
db.stoLeaves.del(mixPath)
224208
else:
225209
discard db.stoLeaves.update(mixPath, vtx)
226210

227211
txFrame.snapshot.vtx.clear()
228-
txFrame.snapshot.acc.clear()
229212
txFrame.snapshot.sto.clear()
230213
# Since txFrame is now the base, it contains all changes and therefore acts
231214
# as a snapshot
232215
txFrame.snapshot.level = Opt.some(txFrame.level)
233216
txFrame.sTab.clear()
234217
txFrame.kMap.clear()
235-
txFrame.accLeaves.clear()
236218
txFrame.stoLeaves.clear()
237219
txFrame.blockNumber.reset()
238220

execution_chain/db/opts.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ const
3333
## re-reads from file.
3434
##
3535
## A bit of space on top of the filter is left for data block caching
36-
defaultRdbVtxCacheSize* = 512 * 1024 * 1024
36+
defaultRdbVtxCacheSize* = 768 * 1024 * 1024
3737
## Cache of branches and leaves in the state MPTs (world and account)
3838
defaultRdbKeyCacheSize* = 1280 * 1024 * 1024
3939
## Hashes of the above
40-
defaultRdbBranchCacheSize* = 1024 * 1024 * 1024
40+
defaultRdbBranchCacheSize* = 1280 * 1024 * 1024
4141
## Cache of branches and leaves in the state MPTs (world and account)
4242

4343

0 commit comments

Comments
 (0)