@@ -23,16 +23,37 @@ export interface DumperOptions {
2323 writeBatchSize : number
2424 topDirSize : number
2525 metrics ?: number
26+ maxCacheSize ?: number
2627}
2728
2829
2930export abstract class Dumper < B extends { hash : string , height : number } , O extends DumperOptions = DumperOptions > {
31+
32+ private timestampCache = new Map < number , number > ( ) ;
33+
34+ private addToCache ( block : B ) : void {
35+ const maxCacheSize = this . options ( ) . maxCacheSize ?? this . getDefaultCacheSize ( ) ;
36+ if ( this . timestampCache . size >= maxCacheSize ) {
37+ const heights = Array . from ( this . timestampCache . keys ( ) ) . sort ( ( a , b ) => a - b ) ;
38+ const removeCount = Math . ceil ( maxCacheSize * 0.2 ) ;
39+ const keysToRemove = heights . slice ( 0 , removeCount ) ;
40+ for ( const key of keysToRemove ) {
41+ this . timestampCache . delete ( key ) ;
42+ }
43+ this . log ( ) . debug ( `Cache cleanup: removed ${ keysToRemove . length } oldest block timestamps` ) ;
44+ }
45+
46+ this . timestampCache . set ( block . height , this . getBlockTimestamp ( block ) ) ;
47+ }
48+
3049 protected abstract getBlocks ( range : Range ) : AsyncIterable < B [ ] >
3150
3251 protected abstract getFinalizedHeight ( ) : Promise < number >
3352
3453 protected abstract getPrevBlockHash ( block : B ) : string
3554
55+ protected abstract getBlockTimestamp ( block : B ) : number
56+
3657 protected setUpProgram ( program : Command ) : void { }
3758
3859 protected getDefaultChunkSize ( ) : number {
@@ -43,6 +64,10 @@ export abstract class Dumper<B extends {hash: string, height: number}, O extends
4364 return 1024
4465 }
4566
67+ protected getDefaultCacheSize ( ) : number {
68+ return 10
69+ }
70+
4671 protected getLoggingNamespace ( ) : string {
4772 return 'sqd:dump'
4873 }
@@ -61,6 +86,7 @@ export abstract class Dumper<B extends {hash: string, height: number}, O extends
6186 program . option ( '--chunk-size <MB>' , 'Data chunk size in megabytes' , positiveInt , this . getDefaultChunkSize ( ) )
6287 program . option ( '--write-batch-size <number>' , 'Number of blocks to write at a time' , positiveInt , 10 )
6388 program . option ( '--top-dir-size <number>' , 'Number of items in a top level dir' , positiveInt , this . getDefaultTopDirSize ( ) )
89+ program . option ( '--max-cache-size <number>' , 'Maximum number of blocks to keep in memory cache' , positiveInt , this . getDefaultCacheSize ( ) )
6490 program . option ( '--metrics <port>' , 'Enable prometheus metrics server' , nat )
6591 return program
6692 }
@@ -176,6 +202,17 @@ export abstract class Dumper<B extends {hash: string, height: number}, O extends
176202 }
177203 }
178204
205+ const lastBlock = last ( blocks )
206+ const mintedTimestamp = this . getBlockTimestamp ( lastBlock )
207+
208+ for ( const block of blocks ) {
209+ this . addToCache ( block ) ;
210+ }
211+
212+ this . prometheus ( ) . setLatestBlockMetrics ( lastBlock . height , mintedTimestamp )
213+ this . log ( ) . debug ( `Received block ${ lastBlock . height } with minted timestamp ${ mintedTimestamp } ` )
214+ this . log ( ) . debug ( `Cache size: ${ this . timestampCache . size } ` )
215+
179216 yield blocks
180217
181218 progress . setCurrentValue ( last ( blocks ) . height )
@@ -206,7 +243,11 @@ export abstract class Dumper<B extends {hash: string, height: number}, O extends
206243 for ( let block of bb ) {
207244 process . stdout . write ( JSON . stringify ( block ) + '\n' )
208245 }
209- prometheus . setLastWrittenBlock ( last ( bb ) . height )
246+ const lastBlockHeight = last ( bb ) . height ;
247+ prometheus . setLastWrittenBlock ( lastBlockHeight ) ;
248+ const processedTimestamp = this . getBlockTimestamp ( last ( bb ) ) ;
249+ prometheus . setProcessedBlockMetrics ( processedTimestamp ) ;
250+ this . log ( ) . debug ( `Processed block ${ lastBlockHeight } at ${ processedTimestamp } ` ) ;
210251 }
211252 } else {
212253 let archive = new ArchiveLayout ( this . destination ( ) , {
@@ -217,7 +258,18 @@ export abstract class Dumper<B extends {hash: string, height: number}, O extends
217258 range : this . range ( ) ,
218259 chunkSize : chunkSize * 1024 * 1024 ,
219260 writeBatchSize : this . options ( ) . writeBatchSize ,
220- onSuccessWrite : ctx => prometheus . setLastWrittenBlock ( ctx . blockRange . to . height )
261+ onSuccessWrite : ctx => {
262+ const blockHeight = ctx . blockRange . to . height ;
263+ prometheus . setLastWrittenBlock ( blockHeight ) ;
264+
265+ const cachedTimestamp = this . timestampCache . get ( blockHeight ) ;
266+ if ( cachedTimestamp ) {
267+ prometheus . setProcessedBlockMetrics ( cachedTimestamp ) ;
268+ this . log ( ) . debug ( `Processed block ${ blockHeight } at ${ cachedTimestamp } ` ) ;
269+ } else {
270+ this . log ( ) . warn ( `No cached timestamp available for height ${ blockHeight } ` ) ;
271+ }
272+ }
221273 } )
222274 }
223275 } , err => {
0 commit comments