@@ -55,6 +55,7 @@ class ChainState:
5555 flush_time = attr .ib () # Time of flush
5656 first_sync = attr .ib ()
5757 db_version = attr .ib ()
58+ utxo_count = attr .ib ()
5859
5960 def copy (self ):
6061 return copy .copy (self )
@@ -189,6 +190,18 @@ def assert_flushed(self, flush_data):
189190 assert not flush_data .undo_infos
190191 self .history .assert_flushed ()
191192
193+ def log_flush_stats (self , prefix , flush_data , elapsed ):
194+ tx_delta = flush_data .state .tx_count - self .last_flush_state .tx_count
195+ size_delta = flush_data .state .chain_size - self .last_flush_state .chain_size
196+ utxo_count_delta = flush_data .state .utxo_count - self .last_flush_state .utxo_count
197+
198+ self .logger .info (f'{ prefix } #{ self .history .flush_count :,d} took { elapsed :.1f} s. '
199+ f'Height { flush_data .state .height :,d} '
200+ f'txs: { flush_data .state .tx_count :,d} ({ tx_delta :+,d} ) '
201+ f'utxos: { flush_data .state .utxo_count :,d} ({ utxo_count_delta :+,d} ) '
202+ f'size: { flush_data .state .chain_size :,d} ({ size_delta :+,d} )' )
203+ return size_delta
204+
192205 def flush_dbs (self , flush_data , flush_utxos , size_remaining ):
193206 '''Flush out cached state. History is always flushed; UTXOs are
194207 flushed if flush_utxos.'''
@@ -220,13 +233,7 @@ def flush_dbs(self, flush_data, flush_utxos, size_remaining):
220233 self .state = flush_data .state .copy ()
221234 self .write_utxo_state (self .utxo_db )
222235
223- tx_delta = flush_data .state .tx_count - self .last_flush_state .tx_count
224- size_delta = flush_data .state .chain_size - self .last_flush_state .chain_size
225-
226- self .logger .info (f'flush #{ self .history .flush_count :,d} took { elapsed :.1f} s. '
227- f'Height { flush_data .state .height :,d} '
228- f'txs: { flush_data .state .tx_count :,d} ({ tx_delta :+,d} ) '
229- f'size: { flush_data .state .chain_size :,d} ({ size_delta :+,d} )' )
236+ size_delta = self .log_flush_stats ('flush' , flush_data , elapsed )
230237
231238 # Catch-up stats
232239 if self .utxo_db .for_sync :
@@ -332,14 +339,7 @@ def flush_backup(self, flush_data, touched):
332339 self .history .backup (touched , flush_data .state .tx_count )
333340 self .flush_utxo_db (flush_data )
334341
335- elapsed = time .time () - start_time
336- tx_delta = flush_data .state .tx_count - self .last_flush_state .tx_count
337- size_delta = flush_data .state .chain_size - self .last_flush_state .chain_size
338-
339- self .logger .info (f'backup flush #{ self .history .flush_count :,d} took '
340- f'{ elapsed :.1f} s. Height { flush_data .state .height :,d} '
341- f'txs: { flush_data .state .tx_count :,d} ({ tx_delta :+,d} ) '
342- f'size: { flush_data .state .chain_size :,d} ({ size_delta :+,d} )' )
342+ self .log_flush_stats ('backup flush' , flush_data , time .time () - start_time )
343343
344344 self .last_flush_state = flush_data .state .copy ()
345345
@@ -482,12 +482,19 @@ def clear_excess_undo_info(self):
482482 # -- UTXO database
483483
484484 def read_utxo_state (self ):
485+ def count_utxos ():
486+ count = 0
487+ for db_key , db_value in self .utxo_db .iterator (prefix = b'u' ):
488+ count += 1
489+ return count
490+
485491 now = time .time ()
486492 state = self .utxo_db .get (b'state' )
487493 if not state :
488494 state = ChainState (height = - 1 , tx_count = 0 , chain_size = 0 , tip = bytes (32 ),
489495 flush_count = 0 , sync_time = 0 , flush_time = now ,
490- first_sync = True , db_version = max (self .DB_VERSIONS ))
496+ first_sync = True , db_version = max (self .DB_VERSIONS ),
497+ utxo_count = 0 )
491498 else :
492499 state = ast .literal_eval (state .decode ())
493500 if not isinstance (state , dict ):
@@ -506,14 +513,20 @@ def read_utxo_state(self):
506513 flush_time = now ,
507514 first_sync = state ['first_sync' ],
508515 db_version = state ['db_version' ],
516+ utxo_count = state .get ('utxo_count' , - 1 ),
509517 )
510518
511519 self .state = state
512- self .last_flush_state = state .copy ()
513520 if state .db_version not in self .DB_VERSIONS :
514521 raise self .DBError (f'your UTXO DB version is { state .db_version } but this '
515522 f'software only handles versions { self .DB_VERSIONS } ' )
516523
524+ if self .state .utxo_count == - 1 :
525+ self .logger .info ('counting UTXOs, please wait...' )
526+ self .state .utxo_count = count_utxos ()
527+
528+ self .last_flush_state = state .copy ()
529+
517530 # These are as we flush data to disk ahead of DB state
518531 self .fs_height = state .height
519532 self .fs_tx_count = state .tx_count
@@ -525,6 +538,7 @@ def read_utxo_state(self):
525538 self .logger .info (f'height: { state .height :,d} ' )
526539 self .logger .info (f'tip: { hash_to_hex_str (state .tip )} ' )
527540 self .logger .info (f'tx count: { state .tx_count :,d} ' )
541+ self .logger .info (f'utxo count: { state .utxo_count :,d} ' )
528542 self .logger .info (f'chain size: { state .chain_size // 1_000_000_000 } GB '
529543 f'({ state .chain_size :,d} bytes)' )
530544 if self .utxo_db .for_sync :
@@ -544,6 +558,7 @@ def write_utxo_state(self, batch):
544558 'wall_time' : self .state .sync_time ,
545559 'first_sync' : self .state .first_sync ,
546560 'db_version' : self .state .db_version ,
561+ 'utxo_count' : self .state .utxo_count ,
547562 }
548563 batch .put (b'state' , repr (state ).encode ())
549564
0 commit comments