41
41
42
42
const
43
43
BaseDistance = 128 'u64
44
- PersistBatchSize = 32 'u64
45
- MaxQueueSize = 12
44
+ PersistBatchSize = 4 'u64
45
+ MaxQueueSize = 128
46
46
47
47
# ------------------------------------------------------------------------------
48
48
# Private functions
@@ -292,8 +292,7 @@ proc updateFinalized(c: ForkedChainRef, finalized: BlockRef, fcuHead: BlockRef)
292
292
doAssert(candidate.isNil.not )
293
293
c.latest = candidate
294
294
295
- proc updateBase(c: ForkedChainRef, base: BlockRef):
296
- Future[void ] {.async: (raises: [CancelledError]) , gcsafe.} =
295
+ proc updateBase(c: ForkedChainRef, base: BlockRef): uint =
297
296
# #
298
297
# # A1 - A2 - A3 D5 - D6
299
298
# # / /
@@ -312,53 +311,110 @@ proc updateBase(c: ForkedChainRef, base: BlockRef):
312
311
# No update, return
313
312
return
314
313
315
- # Persist the new base block - this replaces the base tx in coredb!
316
- for x in base.everyNthBlock(4 ):
317
- const
318
- # We cap waiting for an idle slot in case there's a lot of network traffic
319
- # taking up all CPU - we don't want to _completely_ stop processing blocks
320
- # in this case - doing so also allows us to benefit from more batching /
321
- # larger network reads when under load.
322
- idleTimeout = 10 .milliseconds
323
-
324
- discard await idleAsync().withTimeout(idleTimeout)
325
- c.com.db.persist(x.txFrame, Opt.some(x.stateRoot))
314
+ c.com.db.persist(base.txFrame, Opt.some(base.stateRoot))
326
315
327
- # Update baseTxFrame when we about to yield to the event loop
328
- # and prevent other modules accessing expired baseTxFrame.
329
- c.baseTxFrame = x .txFrame
316
+ # Update baseTxFrame when we about to yield to the event loop
317
+ # and prevent other modules accessing expired baseTxFrame.
318
+ c.baseTxFrame = base .txFrame
330
319
331
320
# Cleanup in-memory blocks starting from base backward
332
321
# e.g. B2 backward.
333
- var count = 0
334
- loopIt(base.parent):
322
+ var
323
+ count = 0 'u
324
+ it = base.parent
325
+
326
+ while it.isOk:
335
327
c.removeBlockFromCache(it)
336
328
inc count
329
+ let b = it
330
+ it = it.parent
331
+ b.parent = nil
337
332
338
333
# Update base branch
339
334
c.base = base
340
335
c.base.parent = nil
341
336
342
- # Log only if more than one block persisted
343
- # This is to avoid log spamming, during normal operation
344
- # of the client following the chain
345
- # When multiple blocks are persisted together, it's mainly
346
- # during `beacon sync` or `nrpc sync`
347
- if count > 1 :
348
- notice " Finalized blocks persisted" ,
349
- nBlocks = count,
350
- base = c.base.number,
351
- baseHash = c.base.hash.short,
352
- pendingFCU = c.pendingFCU.short,
353
- resolvedFin= c.latestFinalizedBlockNumber
337
+ count
338
+
339
+ proc processUpdateBase(c: ForkedChainRef) {.async: (raises: [CancelledError]) .} =
340
+ if c.baseQueue.len > 0 :
341
+ let base = c.baseQueue.popFirst()
342
+ c.persistedCount += c.updateBase(base)
343
+
344
+ const
345
+ minLogInterval = 5
346
+
347
+ if c.baseQueue.len == 0 :
348
+ let time = EthTime.now()
349
+ if time - c.lastBaseLogTime > minLogInterval:
350
+ # Log only if more than one block persisted
351
+ # This is to avoid log spamming, during normal operation
352
+ # of the client following the chain
353
+ # When multiple blocks are persisted together, it's mainly
354
+ # during `beacon sync` or `nrpc sync`
355
+ if c.persistedCount > 1 :
356
+ notice " Finalized blocks persisted" ,
357
+ nBlocks = c.persistedCount,
358
+ base = c.base.number,
359
+ baseHash = c.base.hash.short,
360
+ pendingFCU = c.pendingFCU.short,
361
+ resolvedFin= c.latestFinalizedBlockNumber
362
+ else :
363
+ debug " Finalized blocks persisted" ,
364
+ nBlocks = c.persistedCount,
365
+ target = c.base.hash.short,
366
+ base = c.base.number,
367
+ baseHash = c.base.hash.short,
368
+ pendingFCU = c.pendingFCU.short,
369
+ resolvedFin= c.latestFinalizedBlockNumber
370
+ c.lastBaseLogTime = time
371
+ c.persistedCount = 0
372
+ return
373
+
374
+ if c.queue.isNil:
375
+ # This recursive mode only used in test env with small set of blocks
376
+ await c.processUpdateBase()
354
377
else :
355
- debug " Finalized blocks persisted" ,
356
- nBlocks = count,
357
- target = base.hash.short,
358
- base = c.base.number,
359
- baseHash = c.base.hash.short,
360
- pendingFCU = c.pendingFCU.short,
361
- resolvedFin= c.latestFinalizedBlockNumber
378
+ proc asyncHandler(): Future[Result[void , string ]] {.async: (raises: [CancelledError]) .} =
379
+ await c.processUpdateBase()
380
+ ok()
381
+ await c.queue.addLast(QueueItem(handler: asyncHandler))
382
+
383
+ proc queueUpdateBase(c: ForkedChainRef, base: BlockRef)
384
+ {.async: (raises: [CancelledError]) .} =
385
+ let
386
+ prevQueuedBase = if c.baseQueue.len > 0 :
387
+ c.baseQueue.peekLast()
388
+ else :
389
+ c.base
390
+
391
+ if prevQueuedBase.number == base.number:
392
+ return
393
+
394
+ var
395
+ number = base.number - min(base.number, PersistBatchSize)
396
+ steps = newSeqOfCap[BlockRef]((base.number-c.base.number) div PersistBatchSize + 1)
397
+ it = prevQueuedBase
398
+
399
+ steps.add base
400
+
401
+ while it.number > prevQueuedBase.number:
402
+ if it.number == number:
403
+ steps.add it
404
+ number -= min(number, PersistBatchSize)
405
+ it = it.parent
406
+
407
+ for i in countdown(steps.len-1, 0):
408
+ c.baseQueue.addLast(steps[i])
409
+
410
+ if c.queue.isNil:
411
+ # This recursive mode only used in test env with small set of blocks
412
+ await c.processUpdateBase()
413
+ else:
414
+ proc asyncHandler(): Future[Result[void , string ]] {.async: (raises: [CancelledError]) .} =
415
+ await c.processUpdateBase()
416
+ ok()
417
+ await c.queue.addLast(QueueItem(handler: asyncHandler))
362
418
363
419
proc validateBlock(c: ForkedChainRef,
364
420
parent: BlockRef,
@@ -426,7 +482,7 @@ proc validateBlock(c: ForkedChainRef,
426
482
prevBase = c.base.number
427
483
428
484
c.updateFinalized(base, base)
429
- await c.updateBase (base)
485
+ await c.queueUpdateBase (base)
430
486
431
487
# If on disk head behind base, move it to base too.
432
488
if c.base.number > prevBase:
@@ -437,7 +493,7 @@ proc validateBlock(c: ForkedChainRef,
437
493
438
494
template queueOrphan(c: ForkedChainRef, parent: BlockRef, finalized = false ): auto =
439
495
if c.queue.isNil:
440
- # This recursive mode only used in test env with finite set of blocks
496
+ # This recursive mode only used in test env with small set of blocks
441
497
c.processOrphan(parent, finalized)
442
498
else :
443
499
proc asyncHandler(): Future[Result[void , string ]] {.async: (raises: [CancelledError]) .} =
@@ -533,6 +589,8 @@ proc init*(
533
589
quarantine: Quarantine.init(),
534
590
fcuHead: fcuHead,
535
591
fcuSafe: fcuSafe,
592
+ baseQueue: initDeque[BlockRef](),
593
+ lastBaseLogTime: EthTime.now(),
536
594
)
537
595
538
596
# updateFinalized will stop ancestor lineage
@@ -630,7 +688,7 @@ proc forkChoice*(c: ForkedChainRef,
630
688
# and possibly switched to other chain beside the one with head.
631
689
doAssert(finalized.number <= head.number)
632
690
doAssert(base.number <= finalized.number)
633
- await c.updateBase (base)
691
+ await c.queueUpdateBase (base)
634
692
635
693
ok()
636
694
0 commit comments