Skip to content

Commit 3c55545

Browse files
authored
txFrame HashKeys (kMap) memory optimization (#3606)
* Move kMap HashKeys in ForkedChain. * Only move hashkeys when batchsize is greater than 1. * Add a test. * Add more tests.
1 parent 69cc793 commit 3c55545

File tree

4 files changed

+113
-6
lines changed

4 files changed

+113
-6
lines changed

execution_chain/core/chain/forked_chain.nim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,13 @@ proc validateBlock(c: ForkedChainRef,
437437
c.latestFinalizedBlockNumber)
438438

439439
let
440+
# As a memory optimization we move the HashKeys (kMap) stored in the
441+
# parent txFrame to the new txFrame unless the block number is one
442+
# greater than a block which is expected to be persisted based on the
443+
# persistBatchSize
444+
moveParentHashKeys = c.persistBatchSize > 1 and (blk.header.number mod c.persistBatchSize) != 1
440445
parentFrame = parent.txFrame
441-
txFrame = parentFrame.txFrameBegin
446+
txFrame = parentFrame.txFrameBegin(moveParentHashKeys)
442447

443448
# TODO shortLog-equivalent for eth types
444449
debug "Validating block",

execution_chain/db/aristo/aristo_tx_frame.nim

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,15 @@ proc buildSnapshot(txFrame: AristoTxRef, minLevel: int) =
9191

9292
txFrame.snapshot.level = Opt.some(minLevel)
9393

94-
proc txFrameBegin*(db: AristoDbRef, parent: AristoTxRef): AristoTxRef =
94+
proc txFrameBegin*(db: AristoDbRef, parent: AristoTxRef, moveParentHashKeys = false): AristoTxRef =
9595
let parent = if parent == nil: db.txRef else: parent
96-
AristoTxRef(db: db, parent: parent, vTop: parent.vTop, level: parent.level + 1)
96+
97+
AristoTxRef(
98+
db: db,
99+
parent: parent,
100+
kMap: if moveParentHashKeys: move(parent.kMap) else: default(parent.kMap.type),
101+
vTop: parent.vTop,
102+
level: parent.level + 1)
97103

98104
proc dispose*(tx: AristoTxRef) =
99105
tx[].reset()

execution_chain/db/core_db/base.nim

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,16 +455,19 @@ proc txFrameBegin*(db: CoreDbRef): CoreDbTxRef =
455455
##
456456
let
457457
kTx = db.kvt.txFrameBegin(nil)
458-
aTx = db.mpt.txFrameBegin(nil)
458+
aTx = db.mpt.txFrameBegin(nil, false)
459459

460460
CoreDbTxRef(kTx: kTx, aTx: aTx)
461461

462-
proc txFrameBegin*(parent: CoreDbTxRef): CoreDbTxRef =
462+
proc txFrameBegin*(
463+
parent: CoreDbTxRef,
464+
moveParentHashKeys = false
465+
): CoreDbTxRef =
463466
## Constructor
464467
##
465468
let
466469
kTx = parent.kTx.db.txFrameBegin(parent.kTx)
467-
aTx = parent.aTx.db.txFrameBegin(parent.aTx)
470+
aTx = parent.aTx.db.txFrameBegin(parent.aTx, moveParentHashKeys)
468471

469472
CoreDbTxRef(kTx: kTx, aTx: aTx)
470473

tests/test_aristo/test_tx_frame.nim

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,96 @@ suite "Aristo TxFrame":
108108
check:
109109
tx.fetchAccountRecord(acc1[0]).isOk()
110110
tx.fetchAccountRecord(acc2[0]).isErr() # Doesn't exist in tx2
111+
112+
test "Frames using moveParentHashKeys parameter":
113+
let
114+
tx0 = db.txFrameBegin(db.baseTxFrame())
115+
tx1 = db.txFrameBegin(tx0)
116+
117+
check:
118+
tx0.mergeAccountRecord(acc1[0], acc1[1]).isOk()
119+
tx1.mergeAccountRecord(acc2[0], acc2[1]).isOk()
120+
tx0.fetchStateRoot() != tx1.fetchStateRoot()
121+
tx0.kMap.len() == 0
122+
tx1.kMap.len() == 1
123+
124+
# Check that the kMap hashkeys are moved correctly
125+
# and that the stateroot is correct before and after each move.
126+
let tx2 = db.txFrameBegin(tx1, moveParentHashKeys = true)
127+
check:
128+
tx1.kMap.len() == 0
129+
tx2.kMap.len() == 1
130+
tx1.fetchStateRoot() == tx2.fetchStateRoot()
131+
# keys are recomputed when fetching state root even after moving
132+
tx1.kMap.len() == 1
133+
tx2.kMap.len() == 1
134+
135+
let tx3 = db.txFrameBegin(tx2, moveParentHashKeys = false)
136+
check:
137+
tx2.kMap.len() == 1
138+
tx3.kMap.len() == 0
139+
tx2.fetchStateRoot() == tx3.fetchStateRoot()
140+
141+
test "Frames using moveParentHashKeys parameter - moved from persist":
142+
let
143+
tx0 = db.txFrameBegin(db.baseTxFrame())
144+
tx1 = db.txFrameBegin(tx0)
145+
146+
check:
147+
tx0.mergeAccountRecord(acc1[0], acc1[1]).isOk()
148+
tx1.mergeAccountRecord(acc2[0], acc2[1]).isOk()
149+
tx0.fetchStateRoot() != tx1.fetchStateRoot()
150+
tx0.kMap.len() == 0
151+
tx1.kMap.len() == 1
152+
153+
let
154+
tx2 = db.txFrameBegin(tx1, moveParentHashKeys = true)
155+
stateRoot = tx1.fetchStateRoot().get()
156+
157+
# Check that we can still persist the moved from txFrame
158+
tx1.checkpoint(1, skipSnapshot = true)
159+
let batch = db.putBegFn().expect("working batch")
160+
db.persist(batch, tx1, Opt.some(stateRoot))
161+
check:
162+
db.putEndFn(batch).isOk()
163+
164+
db.finish()
165+
166+
# Load the data
167+
db.initInstance().expect("working backend")
168+
let tx = db.baseTxFrame()
169+
check:
170+
tx.fetchAccountRecord(acc1[0]).isOk()
171+
tx.fetchAccountRecord(acc2[0]).isOk()
172+
173+
test "Frames using moveParentHashKeys parameter - moved to persist":
174+
let
175+
tx0 = db.txFrameBegin(db.baseTxFrame())
176+
tx1 = db.txFrameBegin(tx0)
177+
178+
check:
179+
tx0.mergeAccountRecord(acc1[0], acc1[1]).isOk()
180+
tx1.mergeAccountRecord(acc2[0], acc2[1]).isOk()
181+
tx0.fetchStateRoot() != tx1.fetchStateRoot()
182+
tx0.kMap.len() == 0
183+
tx1.kMap.len() == 1
184+
185+
let
186+
tx2 = db.txFrameBegin(tx1, moveParentHashKeys = true)
187+
stateRoot = tx1.fetchStateRoot().get()
188+
189+
# Check that we can still persist the moved to txFrame
190+
tx2.checkpoint(2, skipSnapshot = true)
191+
let batch = db.putBegFn().expect("working batch")
192+
db.persist(batch, tx2, Opt.some(stateRoot))
193+
check:
194+
db.putEndFn(batch).isOk()
195+
196+
db.finish()
197+
198+
# Load the data
199+
db.initInstance().expect("working backend")
200+
let tx = db.baseTxFrame()
201+
check:
202+
tx.fetchAccountRecord(acc1[0]).isOk()
203+
tx.fetchAccountRecord(acc2[0]).isOk()

0 commit comments

Comments
 (0)