@@ -21,7 +21,8 @@ use crate::daemon::db_util::{
2121} ;
2222use crate :: db:: SettingsStore ;
2323use crate :: db:: car:: ManyCar ;
24- use crate :: db:: { MarkAndSweep , MemoryDB , SettingsExt , ttl:: EthMappingCollector } ;
24+ use crate :: db:: gc:: { MarkAndSweep , SnapshotGarbageCollector } ;
25+ use crate :: db:: { MemoryDB , SettingsExt , ttl:: EthMappingCollector } ;
2526use crate :: libp2p:: { Libp2pService , PeerManager } ;
2627use crate :: message_pool:: { MessagePool , MpoolConfig , MpoolRpcProvider } ;
2728use crate :: networks:: { self , ChainConfig } ;
@@ -44,6 +45,7 @@ use once_cell::sync::Lazy;
4445use raw_sync_2:: events:: { Event , EventInit as _, EventState } ;
4546use shared_memory:: ShmemConf ;
4647use std:: path:: Path ;
48+ use std:: sync:: OnceLock ;
4749use std:: time:: Duration ;
4850use std:: { cmp, sync:: Arc } ;
4951use tempfile:: { Builder , TempPath } ;
@@ -66,6 +68,8 @@ static IPC_PATH: Lazy<TempPath> = Lazy::new(|| {
6668 . into_temp_path ( )
6769} ) ;
6870
71+ pub static GLOBAL_SNAPSHOT_GC : OnceLock < Arc < SnapshotGarbageCollector < DbType > > > = OnceLock :: new ( ) ;
72+
6973// The parent process and the daemonized child communicate through an Event in
7074// shared memory. The identity of the shared memory object is written to a
7175// temporary file. The parent process is responsible for cleaning up the file
@@ -467,12 +471,12 @@ fn maybe_start_rpc_service(
467471 Ok ( ( ) )
468472}
469473
470- fn maybe_start_f3_service (
471- services : & mut JoinSet < anyhow :: Result < ( ) > > ,
472- opts : & CliOpts ,
473- config : & Config ,
474- ctx : & AppContext ,
475- ) {
474+ fn maybe_start_f3_service ( opts : & CliOpts , config : & Config , ctx : & AppContext ) {
475+ // already running
476+ if crate :: rpc :: f3 :: F3_LEASE_MANAGER . get ( ) . is_some ( ) {
477+ return ;
478+ }
479+
476480 if !config. client . enable_rpc {
477481 if crate :: f3:: is_sidecar_ffi_enabled ( ctx. state_manager . chain_config ( ) ) {
478482 tracing:: warn!( "F3 sidecar is enabled but not run because RPC is disabled. " )
@@ -485,7 +489,7 @@ fn maybe_start_f3_service(
485489 let state_manager = & ctx. state_manager ;
486490 let p2p_peer_id = ctx. p2p_peer_id ;
487491 let admin_jwt = ctx. admin_jwt . clone ( ) ;
488- services . spawn_blocking ( {
492+ tokio :: task :: spawn_blocking ( {
489493 crate :: rpc:: f3:: F3_LEASE_MANAGER
490494 . set ( crate :: rpc:: f3:: F3LeaseManager :: new (
491495 state_manager. chain_config ( ) . network . clone ( ) ,
@@ -516,7 +520,6 @@ fn maybe_start_f3_service(
516520 std:: env:: var ( "FOREST_F3_ROOT" )
517521 . unwrap_or ( default_f3_root. display ( ) . to_string ( ) ) ,
518522 ) ;
519- Ok ( ( ) )
520523 }
521524 } ) ;
522525 }
@@ -595,13 +598,41 @@ fn maybe_start_indexer_service(
595598pub ( super ) async fn start (
596599 start_time : chrono:: DateTime < chrono:: Utc > ,
597600 opts : CliOpts ,
598- mut config : Config ,
601+ config : Config ,
599602 shutdown_send : mpsc:: Sender < ( ) > ,
600603) -> anyhow:: Result < ( ) > {
601604 startup_init ( & opts, & config) ?;
605+ let ( snap_gc, snap_gc_reboot_rx) = SnapshotGarbageCollector :: new ( & config) ?;
606+ let snap_gc = Arc :: new ( snap_gc) ;
607+ GLOBAL_SNAPSHOT_GC
608+ . set ( snap_gc. clone ( ) )
609+ . ok ( )
610+ . context ( "failed to set GLOBAL_SNAPSHOT_GC" ) ?;
611+ loop {
612+ tokio:: select! {
613+ _ = snap_gc_reboot_rx. recv_async( ) => {
614+ snap_gc. cleanup_before_reboot( ) . await ;
615+ }
616+ result = start_services( start_time, & opts, config. clone( ) , shutdown_send. clone( ) , |ctx| {
617+ snap_gc. set_db( ctx. db. clone( ) ) ;
618+ } ) => {
619+ break result
620+ }
621+ }
622+ }
623+ }
624+
625+ pub ( super ) async fn start_services (
626+ start_time : chrono:: DateTime < chrono:: Utc > ,
627+ opts : & CliOpts ,
628+ mut config : Config ,
629+ shutdown_send : mpsc:: Sender < ( ) > ,
630+ on_app_context_initialized : impl Fn ( & AppContext ) ,
631+ ) -> anyhow:: Result < ( ) > {
602632 let mut services = JoinSet :: new ( ) ;
603- maybe_start_track_peak_rss_service ( & mut services, & opts) ;
604- let ctx = AppContext :: init ( & opts, & config) . await ?;
633+ maybe_start_track_peak_rss_service ( & mut services, opts) ;
634+ let ctx = AppContext :: init ( opts, & config) . await ?;
635+ on_app_context_initialized ( & ctx) ;
605636 info ! (
606637 "Using network :: {}" ,
607638 get_actual_chain_name( & ctx. network_name)
@@ -611,10 +642,8 @@ pub(super) async fn start(
611642 return Ok ( ( ) ) ;
612643 }
613644 let p2p_service = create_p2p_service ( & mut services, & mut config, & ctx) . await ?;
614-
615645 let mpool = create_mpool ( & mut services, & p2p_service, & ctx) ?;
616-
617- let chain_follower = create_chain_follower ( & opts, & p2p_service, mpool. clone ( ) , & ctx) ?;
646+ let chain_follower = create_chain_follower ( opts, & p2p_service, mpool. clone ( ) , & ctx) ?;
618647
619648 info ! (
620649 "Starting network:: {}" ,
@@ -631,20 +660,20 @@ pub(super) async fn start(
631660 & ctx,
632661 ) ?;
633662
634- maybe_import_snapshot ( & opts, & mut config, & ctx) . await ?;
663+ maybe_import_snapshot ( opts, & mut config, & ctx) . await ?;
635664 if opts. halt_after_import {
636665 // Cancel all async services
637666 services. shutdown ( ) . await ;
638667 return Ok ( ( ) ) ;
639668 }
640669 ctx. state_manager . populate_cache ( ) ;
641670 maybe_start_metrics_service ( & mut services, & config, & ctx) . await ?;
642- maybe_start_gc_service ( & mut services, & opts, & config, & ctx) ;
643- maybe_start_f3_service ( & mut services , & opts, & config, & ctx) ;
671+ maybe_start_gc_service ( & mut services, opts, & config, & ctx) ;
672+ maybe_start_f3_service ( opts, & config, & ctx) ;
644673 maybe_start_health_check_service ( & mut services, & config, & p2p_service, & chain_follower, & ctx)
645674 . await ?;
646- maybe_populate_eth_mappings_in_background ( & mut services, & opts, config. clone ( ) , & ctx) ;
647- maybe_start_indexer_service ( & mut services, & opts, & config, & ctx) ;
675+ maybe_populate_eth_mappings_in_background ( & mut services, opts, config. clone ( ) , & ctx) ;
676+ maybe_start_indexer_service ( & mut services, opts, & config, & ctx) ;
648677 if !opts. stateless {
649678 ensure_proof_params_downloaded ( ) . await ?;
650679 }
0 commit comments