Skip to content

Commit

Permalink
use spawn_blocking to run zebra_state::init from start cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
arya2 committed Sep 21, 2022
1 parent 2b4f7ec commit ded6a8b
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 2 deletions.
2 changes: 1 addition & 1 deletion zebra-state/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down
16 changes: 16 additions & 0 deletions zebra-state/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Request, Response, BoxError>,
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.
Expand Down
5 changes: 4 additions & 1 deletion zebrad/src/commands/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions zebrad/tests/acceptance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit ded6a8b

Please sign in to comment.