From ded6a8bfd446ccc322daf2b5ceb6f82d7be8d66c Mon Sep 17 00:00:00 2001 From: arya2 Date: Wed, 21 Sep 2022 18:09:53 -0400 Subject: [PATCH 1/2] use spawn_blocking to run zebra_state::init from start cmd --- zebra-state/src/lib.rs | 2 +- zebra-state/src/service.rs | 16 ++++++++++++++++ zebrad/src/commands/start.rs | 5 ++++- zebrad/tests/acceptance.rs | 25 +++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/zebra-state/src/lib.rs b/zebra-state/src/lib.rs index 7b81d554f33..89505af7acf 100644 --- a/zebra-state/src/lib.rs +++ b/zebra-state/src/lib.rs @@ -34,7 +34,7 @@ pub use request::{FinalizedBlock, HashOrHeight, PreparedBlock, ReadRequest, Requ pub use response::{ReadResponse, Response}; pub use service::{ chain_tip::{ChainTipChange, LatestChainTip, TipAction}, - init, OutputIndex, OutputLocation, TransactionLocation, + init, spawn_init, OutputIndex, OutputLocation, TransactionLocation, }; #[cfg(any(test, feature = "proptest-impl"))] diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 5e7859bdb22..77853984bf7 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -1292,6 +1292,22 @@ pub fn init( ) } +/// Calls [`init`] with the provided [`Config`] and [`Network`] from a blocking task. +/// +/// Returns a [`tokio::task::JoinHandle`] with a boxed state service, +/// a read state service, and receivers for state chain tip updates. +pub fn spawn_init( + config: Config, + network: Network, +) -> tokio::task::JoinHandle<( + BoxService, + ReadStateService, + LatestChainTip, + ChainTipChange, +)> { + tokio::task::spawn_blocking(move || init(config, network)) +} + /// Returns a [`StateService`] with an ephemeral [`Config`] and a buffer with a single slot. /// /// This can be used to create a state service for testing. diff --git a/zebrad/src/commands/start.rs b/zebrad/src/commands/start.rs index b22a82df7ce..455397598c8 100644 --- a/zebrad/src/commands/start.rs +++ b/zebrad/src/commands/start.rs @@ -103,8 +103,11 @@ impl StartCmd { info!(?config); info!("initializing node state"); + info!("opening database, this may take a couple minutes"); + let (state_service, read_only_state_service, latest_chain_tip, chain_tip_change) = - zebra_state::init(config.state.clone(), config.network.network); + zebra_state::spawn_init(config.state.clone(), config.network.network).await?; + let state = ServiceBuilder::new() .buffer(Self::state_buffer_bound()) .service(state_service); diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index 11793002628..cc99d535658 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -313,6 +313,31 @@ fn start_args() -> Result<()> { Ok(()) } +#[tokio::test] +async fn db_init_outside_future_executor() -> Result<()> { + use std::time::{Duration, Instant}; + + let _init_guard = zebra_test::init(); + let config = default_test_config()?; + + let start = Instant::now(); + + let db_init_handle = zebra_state::spawn_init(config.state.clone(), config.network.network); + + // it's faster to panic if it takes longer than expected, since the executor + // will wait indefinitely for blocking operation to finish once started + let block_duration = start.elapsed(); + assert!( + block_duration < Duration::from_millis(5), + "futures executor was blocked longer than expected ({:?})", + block_duration, + ); + + db_init_handle.await?; + + Ok(()) +} + #[test] fn persistent_mode() -> Result<()> { let _init_guard = zebra_test::init(); From 84be95432a327af7a7faa367206173793c5695e3 Mon Sep 17 00:00:00 2001 From: arya2 Date: Wed, 21 Sep 2022 19:12:09 -0400 Subject: [PATCH 2/2] uses zebra_state::spawn_init in copy-state command --- zebra-state/src/service.rs | 1 - zebrad/src/commands/copy_state.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 77853984bf7..f69017728db 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -1293,7 +1293,6 @@ pub fn init( } /// Calls [`init`] with the provided [`Config`] and [`Network`] from a blocking task. -/// /// Returns a [`tokio::task::JoinHandle`] with a boxed state service, /// a read state service, and receivers for state chain tip updates. pub fn spawn_init( diff --git a/zebrad/src/commands/copy_state.rs b/zebrad/src/commands/copy_state.rs index 36e71d97588..ee87c68c46a 100644 --- a/zebrad/src/commands/copy_state.rs +++ b/zebrad/src/commands/copy_state.rs @@ -117,7 +117,7 @@ impl CopyStateCmd { _source_read_only_state_service, _source_latest_chain_tip, _source_chain_tip_change, - ) = old_zs::init(source_config.clone(), network); + ) = old_zs::spawn_init(source_config.clone(), network).await?; let elapsed = source_start_time.elapsed(); info!(?elapsed, "finished initializing source state service"); @@ -136,7 +136,7 @@ impl CopyStateCmd { _target_read_only_state_service, _target_latest_chain_tip, _target_chain_tip_change, - ) = new_zs::init(target_config.clone(), network); + ) = new_zs::spawn_init(target_config.clone(), network).await?; let elapsed = target_start_time.elapsed(); info!(?elapsed, "finished initializing target state service");