@@ -27,42 +27,42 @@ use crate::db::rocksdb::RocksDb;
27
27
use std:: {
28
28
io:: { Cursor , Read , Write } , ops:: Deref ,
29
29
sync:: { Arc , atomic:: { AtomicU8 , AtomicU32 , Ordering } } ,
30
- time:: { Duration , Instant , SystemTime , UNIX_EPOCH }
30
+ time:: { Duration , Instant , SystemTime , UNIX_EPOCH } ,
31
31
} ;
32
32
use ton_block:: BlockIdExt ;
33
33
use ton_types:: { ByteOrderRead , Cell , Result , fail} ;
34
34
35
35
pub ( crate ) struct DbEntry {
36
36
pub cell_id : CellId , // TODO: remove this id
37
- pub block_id_ext : BlockIdExt ,
37
+ pub block_id : BlockIdExt ,
38
38
pub db_index : u32 ,
39
- pub saved_at : u64 ,
39
+ pub save_utime : u64 ,
40
40
}
41
41
42
42
impl DbEntry {
43
- pub fn with_params ( cell_id : CellId , block_id_ext : BlockIdExt , db_index : u32 , saved_at : u64 ) -> Self {
44
- Self { cell_id, block_id_ext , db_index, saved_at }
43
+ pub fn with_params ( cell_id : CellId , block_id : BlockIdExt , db_index : u32 , save_utime : u64 ) -> Self {
44
+ Self { cell_id, block_id , db_index, save_utime }
45
45
}
46
46
}
47
47
48
48
impl Serializable for DbEntry {
49
49
fn serialize < T : Write > ( & self , writer : & mut T ) -> Result < ( ) > {
50
50
writer. write_all ( self . cell_id . key ( ) ) ?;
51
- self . block_id_ext . serialize ( writer) ?;
51
+ self . block_id . serialize ( writer) ?;
52
52
writer. write_all ( & self . db_index . to_le_bytes ( ) ) ?;
53
- writer. write_all ( & self . saved_at . to_le_bytes ( ) ) ?;
53
+ writer. write_all ( & self . save_utime . to_le_bytes ( ) ) ?;
54
54
Ok ( ( ) )
55
55
}
56
56
57
57
fn deserialize < T : Read > ( reader : & mut T ) -> Result < Self > {
58
58
let mut buf = [ 0 ; 32 ] ;
59
59
reader. read_exact ( & mut buf) ?;
60
60
let cell_id = CellId :: new ( buf. into ( ) ) ;
61
- let block_id_ext = BlockIdExt :: deserialize ( reader) ?;
61
+ let block_id = BlockIdExt :: deserialize ( reader) ?;
62
62
let db_index = reader. read_le_u32 ( ) . unwrap_or ( 0 ) ; // use 0 db by default
63
- let saved_at = reader. read_le_u64 ( ) . unwrap_or ( 0 ) ;
63
+ let save_utime = reader. read_le_u64 ( ) . unwrap_or ( 0 ) ;
64
64
65
- Ok ( Self { cell_id, block_id_ext , db_index, saved_at } )
65
+ Ok ( Self { cell_id, block_id , db_index, save_utime } )
66
66
}
67
67
}
68
68
@@ -76,6 +76,8 @@ pub struct ShardStateDb {
76
76
stop : AtomicU8
77
77
}
78
78
79
+ const SHARDSTATES_GC_LAG_SEC : u64 = 300 ;
80
+
79
81
impl ShardStateDb {
80
82
81
83
const MASK_GC_STARTED : u8 = 0x01 ;
@@ -305,8 +307,8 @@ impl ShardStateDb {
305
307
306
308
let c = boc_db. save_as_dynamic_boc ( state_root. deref ( ) ) ?;
307
309
308
- let saved_at = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) ?. as_secs ( ) ;
309
- let db_entry = DbEntry :: with_params ( cell_id. clone ( ) , id. clone ( ) , boc_db. db_index ( ) , saved_at ) ;
310
+ let save_utime = SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) ?. as_secs ( ) ;
311
+ let db_entry = DbEntry :: with_params ( cell_id. clone ( ) , id. clone ( ) , boc_db. db_index ( ) , save_utime ) ;
310
312
let mut buf = Vec :: new ( ) ;
311
313
db_entry. serialize ( & mut Cursor :: new ( & mut buf) ) ?;
312
314
@@ -341,7 +343,7 @@ impl ShardStateDb {
341
343
}
342
344
343
345
pub trait AllowStateGcResolver : Send + Sync {
344
- fn allow_state_gc ( & self , block_id : & BlockIdExt , saved_at : u64 , gc_utime : u64 ) -> Result < bool > ;
346
+ fn allow_state_gc ( & self , block_id : & BlockIdExt , save_utime : u64 , gc_utime : u64 ) -> Result < bool > ;
345
347
}
346
348
347
349
#[ derive( Default ) ]
@@ -416,26 +418,51 @@ fn mark(
416
418
gc_resolver : & dyn AllowStateGcResolver ,
417
419
gc_time : u64
418
420
) -> MarkResult {
419
- let mut to_mark = Vec :: new ( ) ;
420
- let mut to_sweep = Vec :: new ( ) ;
421
+ // We should leave last states in DB to avoid full state saving when DB will active.
422
+ // 1) enumerate all roots with their save-time
423
+ // 2) remember max time and max masterchain root
424
+ // 3) do not sweep last masterchain root and shardchains roots
425
+ // for last SHARDSTATES_GC_LAG_SEC seconds
426
+
427
+ let mut last_mc_seqno = 0 ;
428
+ let mut roots = Vec :: new ( ) ;
429
+ let mut max_shard_utime = 0 ;
430
+
421
431
shardstate_db. for_each ( & mut |_key, value| {
422
432
let db_entry = DbEntry :: from_slice ( value) ?;
423
- let cell_id = db_entry. cell_id ;
424
- let block_id_ext = db_entry. block_id_ext ;
425
433
if db_entry. db_index == dynamic_boc_db. db_index ( ) {
426
- if gc_resolver . allow_state_gc ( & block_id_ext , db_entry . saved_at , gc_time ) ? {
427
- log :: trace! ( target : TARGET , "mark to_sweep block_id {} cell_id {} db_index {} " ,
428
- block_id_ext , cell_id , dynamic_boc_db . db_index ( ) ) ;
429
- to_sweep . push ( ( block_id_ext , cell_id ) ) ;
434
+ if db_entry . block_id . shard ( ) . is_masterchain ( ) {
435
+ if db_entry . block_id . seq_no ( ) > last_mc_seqno {
436
+ last_mc_seqno = db_entry . block_id . seq_no ( ) ;
437
+ }
430
438
} else {
431
- log :: trace! ( target : TARGET , "mark to_mark block_id {} cell_id {} db_index {} " ,
432
- block_id_ext , cell_id , dynamic_boc_db . db_index ( ) ) ;
433
- to_mark . push ( cell_id ) ;
439
+ if db_entry . save_utime > max_shard_utime {
440
+ max_shard_utime = db_entry . save_utime ;
441
+ }
434
442
}
443
+ roots. push ( db_entry) ;
435
444
}
436
445
Ok ( true )
437
446
} ) ?;
438
447
448
+ let mut to_mark = Vec :: new ( ) ;
449
+ let mut to_sweep = Vec :: new ( ) ;
450
+ for root in roots {
451
+ let is_mc = root. block_id . shard ( ) . is_masterchain ( ) ;
452
+ if gc_resolver. allow_state_gc ( & root. block_id , root. save_utime , gc_time) ?
453
+ && ( !is_mc || root. block_id . seq_no ( ) < last_mc_seqno)
454
+ && ( is_mc || root. save_utime + SHARDSTATES_GC_LAG_SEC < max_shard_utime)
455
+ {
456
+ log:: trace!( target: TARGET , "mark to_sweep block_id {} cell_id {} db_index {} utime {}" ,
457
+ root. block_id, root. cell_id, dynamic_boc_db. db_index( ) , root. save_utime) ;
458
+ to_sweep. push ( ( root. block_id , root. cell_id ) ) ;
459
+ } else {
460
+ log:: trace!( target: TARGET , "mark to_mark block_id {} cell_id {} db_index {} utime {}" ,
461
+ root. block_id, root. cell_id, dynamic_boc_db. db_index( ) , root. save_utime) ;
462
+ to_mark. push ( root. cell_id ) ;
463
+ }
464
+ }
465
+
439
466
let marked_roots = to_mark. len ( ) ;
440
467
let mut marked = FnvHashSet :: default ( ) ;
441
468
if !to_sweep. is_empty ( ) {
0 commit comments