@@ -54,6 +54,7 @@ use crate::event::EventQueue;
5454use crate :: fee_estimator:: OnchainFeeEstimator ;
5555use crate :: gossip:: GossipSource ;
5656use crate :: io:: sqlite_store:: SqliteStore ;
57+ use crate :: io:: tier_store:: TierStore ;
5758use crate :: io:: utils:: {
5859 read_event_queue, read_external_pathfinding_scores_from_cache, read_network_graph,
5960 read_node_metrics, read_output_sweeper, read_payments, read_peer_info, read_pending_payments,
@@ -151,6 +152,21 @@ impl std::fmt::Debug for LogWriterConfig {
151152 }
152153}
153154
155+ #[ derive( Default ) ]
156+ struct TierStoreConfig {
157+ ephemeral : Option < Arc < DynStore > > ,
158+ backup : Option < Arc < DynStore > > ,
159+ }
160+
161+ impl std:: fmt:: Debug for TierStoreConfig {
162+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
163+ f. debug_struct ( "TierStoreConfig" )
164+ . field ( "ephemeral" , & self . ephemeral . as_ref ( ) . map ( |_| "Arc<DynStore>" ) )
165+ . field ( "backup" , & self . backup . as_ref ( ) . map ( |_| "Arc<DynStore>" ) )
166+ . finish ( )
167+ }
168+ }
169+
154170/// An error encountered during building a [`Node`].
155171///
156172/// [`Node`]: crate::Node
@@ -278,6 +294,7 @@ pub struct NodeBuilder {
278294 liquidity_source_config : Option < LiquiditySourceConfig > ,
279295 log_writer_config : Option < LogWriterConfig > ,
280296 async_payments_role : Option < AsyncPaymentsRole > ,
297+ tier_store_config : Option < TierStoreConfig > ,
281298 runtime_handle : Option < tokio:: runtime:: Handle > ,
282299 pathfinding_scores_sync_config : Option < PathfindingScoresSyncConfig > ,
283300 recovery_mode : bool ,
@@ -296,6 +313,7 @@ impl NodeBuilder {
296313 let gossip_source_config = None ;
297314 let liquidity_source_config = None ;
298315 let log_writer_config = None ;
316+ let tier_store_config = None ;
299317 let runtime_handle = None ;
300318 let pathfinding_scores_sync_config = None ;
301319 let recovery_mode = false ;
@@ -305,6 +323,7 @@ impl NodeBuilder {
305323 gossip_source_config,
306324 liquidity_source_config,
307325 log_writer_config,
326+ tier_store_config,
308327 runtime_handle,
309328 async_payments_role : None ,
310329 pathfinding_scores_sync_config,
@@ -614,6 +633,36 @@ impl NodeBuilder {
614633 self
615634 }
616635
636+ /// Configures the backup store for local disaster recovery.
637+ ///
638+ /// When building with tiered storage, this store receives a second durable
639+ /// copy of data written to the primary store.
640+ ///
641+ /// Writes and removals for primary-backed data only succeed once both the
642+ /// primary and backup stores complete successfully.
643+ ///
644+ /// If not set, durable data will be stored only in the primary store.
645+ #[ allow( dead_code) ] // Used by subsequent FFI/test integration commits.
646+ pub fn set_backup_store ( & mut self , backup_store : Arc < DynStore > ) -> & mut Self {
647+ let tier_store_config = self . tier_store_config . get_or_insert ( TierStoreConfig :: default ( ) ) ;
648+ tier_store_config. backup = Some ( backup_store) ;
649+ self
650+ }
651+
652+ /// Configures the ephemeral store for non-critical, frequently-accessed data.
653+ ///
654+ /// When building with tiered storage, this store is used for ephemeral data like
655+ /// the network graph and scorer data to reduce latency for reads. Data stored here
656+ /// can be rebuilt if lost.
657+ ///
658+ /// If not set, non-critical data will be stored in the primary store.
659+ #[ allow( dead_code) ] // Used by subsequent FFI/test integration commits.
660+ pub fn set_ephemeral_store ( & mut self , ephemeral_store : Arc < DynStore > ) -> & mut Self {
661+ let tier_store_config = self . tier_store_config . get_or_insert ( TierStoreConfig :: default ( ) ) ;
662+ tier_store_config. ephemeral = Some ( ephemeral_store) ;
663+ self
664+ }
665+
617666 /// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
618667 /// previously configured.
619668 pub fn build ( & self , node_entropy : NodeEntropy ) -> Result < Node , BuildError > {
@@ -762,8 +811,23 @@ impl NodeBuilder {
762811 }
763812
764813 /// Builds a [`Node`] instance according to the options previously configured.
814+ ///
815+ /// The provided `kv_store` will be used as the primary storage backend. Optionally,
816+ /// an ephemeral store for frequently-accessed non-critical data (e.g., network graph, scorer)
817+ /// and a backup store for local disaster recovery can be configured via
818+ /// [`set_ephemeral_store`] and [`set_backup_store`].
819+ ///
820+ /// [`set_ephemeral_store`]: Self::set_ephemeral_store
821+ /// [`set_backup_store`]: Self::set_backup_store
765822 pub fn build_with_store < S : SyncAndAsyncKVStore + Send + Sync + ' static > (
766823 & self , node_entropy : NodeEntropy , kv_store : S ,
824+ ) -> Result < Node , BuildError > {
825+ let primary_store: Arc < DynStore > = Arc :: new ( DynStoreWrapper ( kv_store) ) ;
826+ self . build_with_dynstore ( node_entropy, primary_store)
827+ }
828+
829+ fn build_with_dynstore (
830+ & self , node_entropy : NodeEntropy , primary_store : Arc < DynStore > ,
767831 ) -> Result < Node , BuildError > {
768832 let logger = setup_logger ( & self . log_writer_config , & self . config ) ?;
769833
@@ -776,6 +840,13 @@ impl NodeBuilder {
776840 } ) ?)
777841 } ;
778842
843+ let ts_config = self . tier_store_config . as_ref ( ) ;
844+ let mut tier_store = TierStore :: new ( primary_store, Arc :: clone ( & logger) ) ;
845+ if let Some ( config) = ts_config {
846+ config. ephemeral . as_ref ( ) . map ( |s| tier_store. set_ephemeral_store ( Arc :: clone ( s) ) ) ;
847+ config. backup . as_ref ( ) . map ( |s| tier_store. set_backup_store ( Arc :: clone ( s) ) ) ;
848+ }
849+
779850 let seed_bytes = node_entropy. to_seed_bytes ( ) ;
780851 let config = Arc :: new ( self . config . clone ( ) ) ;
781852
@@ -790,7 +861,7 @@ impl NodeBuilder {
790861 seed_bytes,
791862 runtime,
792863 logger,
793- Arc :: new ( DynStoreWrapper ( kv_store ) ) ,
864+ Arc :: new ( DynStoreWrapper ( tier_store ) ) ,
794865 )
795866 }
796867}
0 commit comments