use std::path::PathBuf;
use ts_mooncake::store::StoreSetup;
use crate::{
executor::{monotonic_clock, Executor, ExecutorConfig, Namespace},
layout::HostLayout,
mooncake::MooncakeStore,
store::{process_memory_store, HostBuffer, Store},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StoreSettings {
Memory,
Mooncake {
library: PathBuf,
setup: StoreSetup,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Settings {
pub config: ExecutorConfig,
pub namespace: Namespace,
pub weight_version: String,
pub host: HostBuffer,
pub layout: HostLayout,
pub store: StoreSettings,
}
impl Settings {
pub fn start(&self) -> Result<Executor, ts_mooncake::Error> {
let store: Box<dyn Store> = match &self.store {
StoreSettings::Memory => Box::new(process_memory_store()),
StoreSettings::Mooncake { library, setup } => {
Box::new(MooncakeStore::connect(library, setup, self.host)?)
}
};
Ok(Executor::start(
store,
self.host,
self.layout.clone(),
self.namespace.clone(),
&self.weight_version,
self.config,
monotonic_clock(),
))
}
}
#[cfg(feature = "python")]
impl Settings {
pub fn from_python(settings: &pyo3::Bound<'_, pyo3::PyAny>) -> pyo3::PyResult<Self> {
use std::time::Duration;
use pyo3::prelude::*;
let runtime = settings.getattr("runtime")?;
let scheduler = runtime.getattr("scheduler")?;
let config = ExecutorConfig {
max_operations: scheduler.getattr("max_operations")?.extract()?,
max_keys_per_operation: scheduler.getattr("max_keys_per_operation")?.extract()?,
query_workers: runtime.getattr("query_workers")?.extract()?,
read_workers: runtime.getattr("read_workers")?.extract()?,
write_workers: runtime.getattr("write_workers")?.extract()?,
failure_threshold: runtime.getattr("failure_threshold")?.extract()?,
recovery_interval: Duration::from_millis(
runtime.getattr("recovery_interval_ms")?.extract()?,
),
};
let groups: Vec<(usize, usize, usize)> = settings.getattr("groups")?.extract()?;
let layout = HostLayout {
groups: groups
.into_iter()
.map(
|(packing, block_bytes, shard_count)| crate::layout::GroupLayout {
packing,
block_bytes,
shard_count,
},
)
.collect(),
lcm_block_bytes: settings.getattr("lcm_block_bytes")?.extract()?,
num_lcm_blocks: settings.getattr("num_lcm_blocks")?.extract()?,
owner_rank: settings.getattr("owner_rank")?.extract()?,
tp_rank: settings.getattr("tp_rank")?.extract()?,
};
let host = HostBuffer {
base: settings.getattr("host_buffer")?.extract()?,
len: settings.getattr("host_buffer_bytes")?.extract()?,
};
if host.len != layout.bytes() {
return Err(pyo3::exceptions::PyValueError::new_err(format!(
"the {}-byte Host pool does not match its layout ({} bytes)",
host.len,
layout.bytes()
)));
}
let backend: String = settings.getattr("backend")?.extract()?;
let store = match backend.as_str() {
"memory" => StoreSettings::Memory,
"mooncake" => {
let mooncake = settings.getattr("mooncake")?;
StoreSettings::Mooncake {
library: PathBuf::from(mooncake.getattr("library")?.extract::<String>()?),
setup: StoreSetup {
local_hostname: mooncake.getattr("local_hostname")?.extract()?,
metadata_server: mooncake.getattr("metadata_server")?.extract()?,
global_segment_size: mooncake.getattr("global_segment_size")?.extract()?,
local_buffer_size: mooncake.getattr("local_buffer_size")?.extract()?,
protocol: mooncake.getattr("protocol")?.extract()?,
device_name: mooncake.getattr("device_name")?.extract()?,
master_server_address: mooncake
.getattr("master_server_address")?
.extract()?,
tenant_id: mooncake.getattr("tenant_id")?.extract()?,
},
}
}
other => {
return Err(pyo3::exceptions::PyValueError::new_err(format!(
"unsupported L3 store {other:?}"
)))
}
};
Ok(Self {
config,
namespace: Namespace {
deployment_id: settings.getattr("deployment_id")?.extract()?,
has_draft: settings.getattr("has_draft")?.extract()?,
},
weight_version: settings.getattr("weight_version")?.extract()?,
host,
layout,
store,
})
}
}