use crate::object_store::Result;
use crate::transfer_timeouts::TransferTimeoutConnector;
use crate::ObjectStoreError;
use std::fmt;
use std::sync::Arc;
#[derive(Clone)]
pub(crate) struct StoreIoRuntime {
inner: Arc<OwnedRuntime>,
}
struct OwnedRuntime {
runtime: Option<tokio::runtime::Runtime>,
}
impl StoreIoRuntime {
pub(crate) fn new() -> Result<Self> {
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(1)
.thread_name("loonfs-store-io")
.enable_all()
.build()
.map_err(|error| {
ObjectStoreError::Configuration(format!(
"failed to start store io runtime: {error}"
))
})?;
Ok(Self {
inner: Arc::new(OwnedRuntime {
runtime: Some(runtime),
}),
})
}
pub(crate) fn connector(&self) -> TransferTimeoutConnector {
let handle = self
.inner
.runtime
.as_ref()
.expect("store io runtime should live until the last store clone drops")
.handle()
.clone();
TransferTimeoutConnector::new(handle)
}
}
impl fmt::Debug for StoreIoRuntime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StoreIoRuntime").finish_non_exhaustive()
}
}
impl Drop for OwnedRuntime {
fn drop(&mut self) {
if let Some(runtime) = self.runtime.take() {
runtime.shutdown_background();
}
}
}
#[cfg(test)]
mod tests {
use super::StoreIoRuntime;
#[tokio::test]
async fn store_io_runtime_drops_safely_inside_an_async_context() {
let runtime = StoreIoRuntime::new().expect("start io runtime");
let clone = runtime.clone();
drop(runtime);
drop(clone);
}
#[tokio::test]
async fn connector_construction_does_not_touch_the_caller_runtime() {
let runtime = StoreIoRuntime::new().expect("start io runtime");
let _connector = runtime.connector();
}
}