Skip to content

Commit f20fc18

Browse files
committed
Integrate TierStore into NodeBuilder
Adds TierStoreConfig and two configuration methods to NodeBuilder: - set_backup_store: Configure backup store for disaster recovery - set_ephemeral_store: Configure ephemeral store for non-critical data Modifies build_with_store to wrap the provided store in a TierStore, as the primary store, applying any configured ephemeral and backup stores. Note: Temporal dead code allowance will be removed in test commit.
1 parent 3e23b2d commit f20fc18

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

src/builder.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ use crate::event::EventQueue;
5454
use crate::fee_estimator::OnchainFeeEstimator;
5555
use crate::gossip::GossipSource;
5656
use crate::io::sqlite_store::SqliteStore;
57+
use crate::io::tier_store::TierStore;
5758
use 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,33 @@ 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 asynchronous copies
639+
/// of all critical data written to the primary store.
640+
///
641+
/// Backup writes are non-blocking and do not affect primary store operation performance.
642+
#[allow(dead_code)]
643+
pub fn set_backup_store(&mut self, backup_store: Arc<DynStore>) -> &mut Self {
644+
let tier_store_config = self.tier_store_config.get_or_insert(TierStoreConfig::default());
645+
tier_store_config.backup = Some(backup_store);
646+
self
647+
}
648+
649+
/// Configures the ephemeral store for non-critical, frequently-accessed data.
650+
///
651+
/// When building with tiered storage, this store is used for ephemeral data like
652+
/// the network graph and scorer data to reduce latency for reads. Data stored here
653+
/// can be rebuilt if lost.
654+
///
655+
/// If not set, non-critical data will be stored in the primary store.
656+
#[allow(dead_code)]
657+
pub fn set_ephemeral_store(&mut self, ephemeral_store: Arc<DynStore>) -> &mut Self {
658+
let tier_store_config = self.tier_store_config.get_or_insert(TierStoreConfig::default());
659+
tier_store_config.ephemeral = Some(ephemeral_store);
660+
self
661+
}
662+
617663
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
618664
/// previously configured.
619665
pub fn build(&self, node_entropy: NodeEntropy) -> Result<Node, BuildError> {
@@ -762,6 +808,14 @@ impl NodeBuilder {
762808
}
763809

764810
/// Builds a [`Node`] instance according to the options previously configured.
811+
///
812+
/// The provided `kv_store` will be used as the primary storage backend. Optionally,
813+
/// an ephemeral store for frequently-accessed non-critical data (e.g., network graph, scorer)
814+
/// and a backup store for local disaster recovery can be configured via
815+
/// [`set_ephemeral_store`] and [`set_backup_store`].
816+
///
817+
/// [`set_ephemeral_store`]: Self::set_ephemeral_store
818+
/// [`set_backup_store`]: Self::set_backup_store
765819
pub fn build_with_store<S: SyncAndAsyncKVStore + Send + Sync + 'static>(
766820
&self, node_entropy: NodeEntropy, kv_store: S,
767821
) -> Result<Node, BuildError> {
@@ -776,6 +830,15 @@ impl NodeBuilder {
776830
})?)
777831
};
778832

833+
let ts_config = self.tier_store_config.as_ref();
834+
let primary_store: Arc<DynStore> = Arc::new(DynStoreWrapper(kv_store));
835+
let mut tier_store =
836+
TierStore::new(primary_store, Arc::clone(&runtime), Arc::clone(&logger));
837+
if let Some(config) = ts_config {
838+
config.ephemeral.as_ref().map(|s| tier_store.set_ephemeral_store(Arc::clone(s)));
839+
config.backup.as_ref().map(|s| tier_store.set_backup_store(Arc::clone(s)));
840+
}
841+
779842
let seed_bytes = node_entropy.to_seed_bytes();
780843
let config = Arc::new(self.config.clone());
781844

@@ -790,7 +853,7 @@ impl NodeBuilder {
790853
seed_bytes,
791854
runtime,
792855
logger,
793-
Arc::new(DynStoreWrapper(kv_store)),
856+
Arc::new(DynStoreWrapper(tier_store)),
794857
)
795858
}
796859
}

0 commit comments

Comments
 (0)