Skip to content

Commit ca8bd29

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. Without the account leaf cache, the number of queries for non-existing vids spikes because of all the path-based guesses, which we compensate with a simpler "empty" cache in the database layer. We put the memory savings towards the branch/vtx caches instead.
1 parent af07a53 commit ca8bd29

File tree

13 files changed

+38
-105
lines changed

13 files changed

+38
-105
lines changed

execution_chain/db/aristo/aristo_constants.nim

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ const
4444
v += 1'u64 shl (i * 4)
4545
v
4646

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

5150
# 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_init/rocks_db/rdb_desc.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ type
6262
rdBranchLru*: LruCache[VertexID, (VertexID, uint16)]
6363
rdBranchSize*: int
6464

65+
rdEmptyLru*: LruCache[VertexID,tuple[]] ## Read cache
66+
6567
AristoCFs* = enum
6668
## Column family symbols/handles and names used on the database
6769
AdmCF = "AriAdm" ## Admin column family name

execution_chain/db/aristo/aristo_init/rocks_db/rdb_get.nim

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,16 @@ proc getVtx*(
203203
)
204204
return ok(move(rc.value))
205205

206+
block:
207+
var rc =
208+
if GetVtxFlag.PeekCache in flags:
209+
rdb.rdEmptyLru.peek(rvid.vid)
210+
else:
211+
rdb.rdEmptyLru.get(rvid.vid)
212+
if rc.isOk():
213+
rdbVtxLruStats[rvid.to(RdbStateType)][RdbVertexType.Empty].inc(true)
214+
return ok(VertexRef(nil))
215+
206216
# Otherwise fetch from backend database
207217
# A threadvar is used to avoid allocating an environment for onData
208218
var res {.threadvar.}: Result[VertexRef, AristoError]
@@ -217,6 +227,9 @@ proc getVtx*(
217227

218228
if not gotData:
219229
rdbVtxLruStats[rvid.to(RdbStateType)][RdbVertexType.Empty].inc(false)
230+
if GetVtxFlag.PeekCache notin flags:
231+
rdb.rdEmptyLru.put(rvid.vid, default(tuple[]))
232+
220233
return ok(VertexRef(nil))
221234

222235
if res.isErr():

execution_chain/db/aristo/aristo_init/rocks_db/rdb_init.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ proc init*(rdb: var RdbInst, opts: DbOptions, baseDb: RocksDbInstanceRef) =
9999
rdb.rdKeyLru = typeof(rdb.rdKeyLru).init(rdb.rdKeySize)
100100
rdb.rdVtxLru = typeof(rdb.rdVtxLru).init(rdb.rdVtxSize)
101101
rdb.rdBranchLru = typeof(rdb.rdBranchLru).init(rdb.rdBranchSize)
102+
rdb.rdEmptyLru = typeof(rdb.rdEmptyLru).init(rdb.rdVtxSize) # reuse vtx cache size
102103

103104
if opts.rdbPrintStats:
104105
let

execution_chain/db/aristo/aristo_init/rocks_db/rdb_put.nim

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ proc putVtx*(
105105
else:
106106
discard rdb.rdVtxLru.update(rvid.vid, vtx)
107107

108+
rdb.rdEmptyLru.del(rvid.vid)
109+
108110
if key.isValid:
109111
if rdb.rdKeyLru.len < rdb.rdKeyLru.capacity:
110112
rdb.rdKeyLru.put(rvid.vid, key)
@@ -126,6 +128,9 @@ proc putVtx*(
126128
rdb.rdVtxLru.del rvid.vid
127129
rdb.rdKeyLru.del rvid.vid
128130

131+
if rdb.rdEmptyLru.len < rdb.rdEmptyLru.capacity:
132+
rdb.rdEmptyLru.put(rvid.vid, default(tuple[]))
133+
129134
ok()
130135

131136
# ------------------------------------------------------------------------------

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
# ------------------------------------------------------------------------------

0 commit comments

Comments
 (0)