|
| 1 | +//! MDBX storage connector. |
| 2 | +//! |
| 3 | +//! Unified connector that can open both hot and cold MDBX databases. |
| 4 | +
|
| 5 | +use crate::{MdbxColdBackend, MdbxColdError}; |
| 6 | +use signet_cold::ColdConnect; |
| 7 | +use signet_hot::HotConnect; |
| 8 | +use signet_hot_mdbx::{DatabaseArguments, DatabaseEnv, MdbxError}; |
| 9 | +use std::path::PathBuf; |
| 10 | + |
| 11 | +/// Errors that can occur when initializing MDBX connectors. |
| 12 | +#[derive(Debug, thiserror::Error)] |
| 13 | +pub enum MdbxConnectorError { |
| 14 | + /// Missing environment variable. |
| 15 | + #[error("missing environment variable: {0}")] |
| 16 | + MissingEnvVar(&'static str), |
| 17 | + |
| 18 | + /// Hot storage initialization failed. |
| 19 | + #[error("hot storage initialization failed: {0}")] |
| 20 | + HotInit(#[from] MdbxError), |
| 21 | + |
| 22 | + /// Cold storage initialization failed. |
| 23 | + #[error("cold storage initialization failed: {0}")] |
| 24 | + ColdInit(#[from] MdbxColdError), |
| 25 | +} |
| 26 | + |
| 27 | +/// Connector for MDBX storage (both hot and cold). |
| 28 | +/// |
| 29 | +/// This unified connector can open MDBX databases for both hot and cold storage. |
| 30 | +/// It holds the path and database arguments, which can include custom geometry, |
| 31 | +/// sync mode, max readers, and other MDBX-specific configuration. |
| 32 | +/// |
| 33 | +/// # Example |
| 34 | +/// |
| 35 | +/// ```ignore |
| 36 | +/// use signet_hot_mdbx::{MdbxConnector, DatabaseArguments}; |
| 37 | +/// |
| 38 | +/// // Hot storage with custom args |
| 39 | +/// let hot = MdbxConnector::new("/tmp/hot") |
| 40 | +/// .with_db_args(DatabaseArguments::new().with_max_readers(1000)); |
| 41 | +/// |
| 42 | +/// // Cold storage with default args |
| 43 | +/// let cold = MdbxConnector::new("/tmp/cold"); |
| 44 | +/// ``` |
| 45 | +#[derive(Debug, Clone)] |
| 46 | +pub struct MdbxConnector { |
| 47 | + path: PathBuf, |
| 48 | + db_args: DatabaseArguments, |
| 49 | +} |
| 50 | + |
| 51 | +impl MdbxConnector { |
| 52 | + /// Create a new MDBX connector with default database arguments. |
| 53 | + pub fn new(path: impl Into<PathBuf>) -> Self { |
| 54 | + Self { path: path.into(), db_args: DatabaseArguments::new() } |
| 55 | + } |
| 56 | + |
| 57 | + /// Set custom database arguments. |
| 58 | + /// |
| 59 | + /// This allows configuring MDBX-specific settings like geometry, sync mode, |
| 60 | + /// max readers, and exclusive mode. |
| 61 | + #[must_use] |
| 62 | + pub const fn with_db_args(mut self, db_args: DatabaseArguments) -> Self { |
| 63 | + self.db_args = db_args; |
| 64 | + self |
| 65 | + } |
| 66 | + |
| 67 | + /// Get a reference to the path. |
| 68 | + pub fn path(&self) -> &std::path::Path { |
| 69 | + &self.path |
| 70 | + } |
| 71 | + |
| 72 | + /// Get a reference to the database arguments. |
| 73 | + pub const fn db_args(&self) -> &DatabaseArguments { |
| 74 | + &self.db_args |
| 75 | + } |
| 76 | + |
| 77 | + /// Create a connector from environment variables. |
| 78 | + /// |
| 79 | + /// Reads the path from the specified environment variable. |
| 80 | + /// |
| 81 | + /// # Example |
| 82 | + /// |
| 83 | + /// ```ignore |
| 84 | + /// use signet_cold_mdbx::MdbxConnector; |
| 85 | + /// |
| 86 | + /// let hot = MdbxConnector::from_env("SIGNET_HOT_PATH")?; |
| 87 | + /// let cold = MdbxConnector::from_env("SIGNET_COLD_PATH")?; |
| 88 | + /// ``` |
| 89 | + pub fn from_env(env_var: &'static str) -> Result<Self, MdbxConnectorError> { |
| 90 | + let path: PathBuf = |
| 91 | + std::env::var(env_var).map_err(|_| MdbxConnectorError::MissingEnvVar(env_var))?.into(); |
| 92 | + Ok(Self::new(path)) |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +impl HotConnect for MdbxConnector { |
| 97 | + type Hot = DatabaseEnv; |
| 98 | + type Error = MdbxError; |
| 99 | + |
| 100 | + fn connect(&self) -> Result<Self::Hot, Self::Error> { |
| 101 | + self.db_args.clone().open_rw(&self.path) |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +impl ColdConnect for MdbxConnector { |
| 106 | + type Cold = MdbxColdBackend; |
| 107 | + type Error = MdbxColdError; |
| 108 | + |
| 109 | + #[allow(clippy::manual_async_fn)] |
| 110 | + fn connect(&self) -> impl std::future::Future<Output = Result<Self::Cold, Self::Error>> + Send { |
| 111 | + // MDBX open is sync, but wrapped in async for trait consistency |
| 112 | + // Opens read-write and creates tables |
| 113 | + let path = self.path.clone(); |
| 114 | + async move { MdbxColdBackend::open_rw(&path) } |
| 115 | + } |
| 116 | +} |
0 commit comments