diff --git a/examples/raft-kv-memstore/src/lib.rs b/examples/raft-kv-memstore/src/lib.rs index 328a52ad6..035bd4e30 100644 --- a/examples/raft-kv-memstore/src/lib.rs +++ b/examples/raft-kv-memstore/src/lib.rs @@ -11,6 +11,7 @@ use actix_web::HttpServer; use openraft::storage::Adaptor; use openraft::BasicNode; use openraft::Config; +use openraft::StorageTypeConfig; use openraft::TokioRuntime; use crate::app::App; @@ -37,7 +38,17 @@ openraft::declare_raft_types!( pub type LogStore = Adaptor>; pub type StateMachineStore = Adaptor>; -pub type Raft = openraft::Raft; + +/// Storage types configuration for `openraft`. +pub struct StorageConfig; + +impl StorageTypeConfig for StorageConfig { + type NetworkFactory = Network; + type LogStorage = LogStore; + type StateMachine = StateMachineStore; +} + +pub type Raft = openraft::Raft; pub mod typ { use openraft::BasicNode; diff --git a/examples/raft-kv-rocksdb/Cargo.toml b/examples/raft-kv-rocksdb/Cargo.toml index 94f442466..bc355cfd3 100644 --- a/examples/raft-kv-rocksdb/Cargo.toml +++ b/examples/raft-kv-rocksdb/Cargo.toml @@ -21,7 +21,7 @@ name = "raft-key-value-rocks" path = "src/bin/main.rs" [dependencies] -openraft = { path = "../../openraft", features = ["serde"] } +openraft = { path = "../../openraft", features = ["serde", "compat-08"] } async-std = { version = "1.12.0", features = ["attributes", "tokio1"] } async-trait = "0.1.36" diff --git a/openraft/Cargo.toml b/openraft/Cargo.toml index bc281a3fb..f55a258d4 100644 --- a/openraft/Cargo.toml +++ b/openraft/Cargo.toml @@ -76,9 +76,12 @@ single-term-leader = [] compat = [] # Turn on to let openraft provide additional data types to build v0.7 compatible RaftStorage. -compat-07 = ["compat", "serde", "dep:or07", "compat-07-testing"] +compat-07 = ["compat", "serde", "dep:or07", "compat-07-testing", "compat-08"] compat-07-testing = ["dep:tempfile", "anyhow", "dep:serde_json"] +# Turn on compatibility with original `Raft` API with individual types for network/log/state machine. +compat-08 = [] + # Allows an application to implement a custom the v2 storage API. # See `openraft::storage::v2` for more details. # V2 API are unstable and may change in the future. diff --git a/openraft/src/lib.rs b/openraft/src/lib.rs index 5fe24843b..c6ad8e9f2 100644 --- a/openraft/src/lib.rs +++ b/openraft/src/lib.rs @@ -61,6 +61,7 @@ pub mod log_id; pub mod metrics; pub mod network; pub mod raft; +pub mod raft_compat; pub mod storage; pub mod testing; pub mod timer; @@ -90,6 +91,7 @@ pub use network::RPCTypes; pub use network::RaftNetwork; pub use network::RaftNetworkFactory; pub use type_config::RaftTypeConfig; +pub use type_config::StorageTypeConfig; pub use crate::async_runtime::AsyncRuntime; pub use crate::async_runtime::TokioRuntime; @@ -114,7 +116,6 @@ pub use crate::node::BasicNode; pub use crate::node::EmptyNode; pub use crate::node::Node; pub use crate::node::NodeId; -pub use crate::raft::Raft; pub use crate::raft_state::MembershipState; pub use crate::raft_state::RaftState; pub use crate::raft_types::SnapshotId; @@ -139,6 +140,11 @@ pub use crate::vote::CommittedLeaderId; pub use crate::vote::LeaderId; pub use crate::vote::Vote; +#[cfg(not(feature = "compat-08"))] +pub use crate::raft::Raft; +#[cfg(feature = "compat-08")] +pub use crate::raft_compat::Raft; + #[cfg(feature = "serde")] #[doc(hidden)] pub trait OptionalSerde: serde::Serialize + for<'a> serde::Deserialize<'a> {} diff --git a/openraft/src/raft/mod.rs b/openraft/src/raft/mod.rs index 6203f2150..ba0016f6d 100644 --- a/openraft/src/raft/mod.rs +++ b/openraft/src/raft/mod.rs @@ -48,12 +48,9 @@ use crate::error::RaftError; use crate::membership::IntoNodes; use crate::metrics::RaftMetrics; use crate::metrics::Wait; -use crate::network::RaftNetworkFactory; use crate::raft::raft_inner::RaftInner; use crate::raft::runtime_config_handle::RuntimeConfigHandle; use crate::raft::trigger::Trigger; -use crate::storage::RaftLogStorage; -use crate::storage::RaftStateMachine; use crate::AsyncRuntime; use crate::ChangeMembers; use crate::LogId; @@ -63,6 +60,7 @@ use crate::OptionalSend; use crate::RaftState; pub use crate::RaftTypeConfig; use crate::StorageHelper; +pub use crate::StorageTypeConfig; /// Define types for a Raft type configuration. /// @@ -124,28 +122,22 @@ macro_rules! declare_raft_types { /// `shutdown` method should be called on this type to await the shutdown of the node. If the parent /// application needs to shutdown the Raft node for any reason, calling `shutdown` will do the /// trick. -pub struct Raft +pub struct Raft where C: RaftTypeConfig, - N: RaftNetworkFactory, - LS: RaftLogStorage, - SM: RaftStateMachine, + S: StorageTypeConfig, { - inner: Arc>, - _phantom: PhantomData, + inner: Arc>, } -impl Clone for Raft +impl Clone for Raft where C: RaftTypeConfig, - N: RaftNetworkFactory, - LS: RaftLogStorage, - SM: RaftStateMachine, + S: StorageTypeConfig, { fn clone(&self) -> Self { Self { inner: self.inner.clone(), - _phantom: PhantomData, } } } @@ -159,7 +151,7 @@ where // // Notably, the state machine, log storage and network factory DO NOT have to be `Send`, those // are only used within Raft task(s) on a single thread. -unsafe impl Send for Raft +unsafe impl Send for Raft where C: RaftTypeConfig, N: RaftNetworkFactory, @@ -177,7 +169,7 @@ where // SAFETY: Even for a single-threaded Raft, the API object is MT-capable. // // See above for details. -unsafe impl Sync for Raft +unsafe impl Sync for Raft where C: RaftTypeConfig + Send, N: RaftNetworkFactory, @@ -191,12 +183,10 @@ where { } -impl Raft +impl Raft where C: RaftTypeConfig, - N: RaftNetworkFactory, - LS: RaftLogStorage, - SM: RaftStateMachine, + S: StorageTypeConfig, { /// Create and spawn a new Raft task. /// @@ -221,9 +211,9 @@ where pub async fn new( id: C::NodeId, config: Arc, - network: N, - mut log_store: LS, - mut state_machine: SM, + network: S::NetworkFactory, + mut log_store: S::LogStorage, + mut state_machine: S::StateMachine, ) -> Result> { let (tx_api, rx_api) = mpsc::unbounded_channel(); let (tx_notify, rx_notify) = mpsc::unbounded_channel(); @@ -257,7 +247,7 @@ where let sm_handle = sm::Worker::spawn(state_machine, tx_notify.clone()); - let core: RaftCore = RaftCore { + let core: RaftCore = RaftCore { id, config: config.clone(), runtime_config: runtime_config.clone(), @@ -295,10 +285,7 @@ where core_state: Mutex::new(CoreState::Running(core_handle)), }; - Ok(Self { - inner: Arc::new(inner), - _phantom: Default::default(), - }) + Ok(Self { inner: Arc::new(inner) }) } /// Return a handle to update runtime config. @@ -310,7 +297,7 @@ where /// let raft = Raft::new(...).await?; /// raft.runtime_config().heartbeat(true); /// ``` - pub fn runtime_config(&self) -> RuntimeConfigHandle { + pub fn runtime_config(&self) -> RuntimeConfigHandle { RuntimeConfigHandle::new(self.inner.as_ref()) } @@ -337,7 +324,7 @@ where /// let raft = Raft::new(...).await?; /// raft.trigger().elect().await?; /// ``` - pub fn trigger(&self) -> Trigger { + pub fn trigger(&self) -> Trigger { Trigger::new(self.inner.as_ref()) } @@ -694,7 +681,7 @@ where #[tracing::instrument(level = "debug", skip(self, mes, rx))] pub(crate) async fn call_core( &self, - mes: RaftMsg, + mes: RaftMsg, rx: oneshot::Receiver>, ) -> Result> where @@ -739,8 +726,11 @@ where /// If the API channel is already closed (Raft is in shutdown), then the request functor is /// destroyed right away and not called at all. pub fn external_request< - F: FnOnce(&RaftState::Instant>, &mut LS, &mut N) - + OptionalSend + F: FnOnce( + &RaftState::Instant>, + &mut S::LogStorage, + &mut S::NetworkFactory, + ) + OptionalSend + 'static, >( &self, diff --git a/openraft/src/raft_compat.rs b/openraft/src/raft_compat.rs new file mode 100644 index 000000000..8c48940e0 --- /dev/null +++ b/openraft/src/raft_compat.rs @@ -0,0 +1,37 @@ +//! Compatibility layer for `Raft` with old type parameters. + +use crate::storage::RaftLogStorage; +use crate::storage::RaftStateMachine; +use crate::RaftNetworkFactory; +use crate::RaftTypeConfig; +use crate::StorageTypeConfig; +use std::marker::PhantomData; + +/// Default type for storage configuration for compatibility. +/// +/// This type implements [`StorageTypeConfig`] with the supplied types for network, +/// log storage and state machine. +pub struct DefaultStorageConfig +where + C: RaftTypeConfig, + N: RaftNetworkFactory, + LS: RaftLogStorage, + SM: RaftStateMachine, +{ + _phantom: PhantomData<(C, N, LS, SM)>, +} + +impl StorageTypeConfig for DefaultStorageConfig +where + C: RaftTypeConfig, + N: RaftNetworkFactory, + LS: RaftLogStorage, + SM: RaftStateMachine, +{ + type NetworkFactory = N; + type LogStorage = LS; + type StateMachine = SM; +} + +/// Type alias to forward to the new `Raft` implementation. +pub type Raft = crate::raft::Raft>; diff --git a/openraft/src/type_config.rs b/openraft/src/type_config.rs index 9436a9ae4..faa6fe9af 100644 --- a/openraft/src/type_config.rs +++ b/openraft/src/type_config.rs @@ -6,6 +6,8 @@ use tokio::io::AsyncWrite; use crate::entry::FromAppData; use crate::entry::RaftEntry; +use crate::storage::RaftLogStorage; +use crate::storage::RaftStateMachine; use crate::AppData; use crate::AppDataResponse; use crate::AsyncRuntime; @@ -13,6 +15,7 @@ use crate::Node; use crate::NodeId; use crate::OptionalSend; use crate::OptionalSync; +use crate::RaftNetworkFactory; /// Configuration of types used by the [`Raft`] core engine. /// @@ -41,7 +44,7 @@ use crate::OptionalSync; /// ``` /// [`Raft`]: crate::Raft pub trait RaftTypeConfig: - Sized + OptionalSend + OptionalSync + Debug + Clone + Copy + Default + Eq + PartialEq + Ord + PartialOrd + 'static + Sized + Send + Sync + Debug + Clone + Copy + Default + Eq + PartialEq + Ord + PartialOrd + 'static { /// Application-specific request data passed to the state machine. type D: AppData; @@ -67,3 +70,22 @@ pub trait RaftTypeConfig: /// Asynchronous runtime type. type AsyncRuntime: AsyncRuntime; } + +/// Configuration of types used by the [`Raft`] core engine for the storage. +/// +/// The (empty) implementation of this structure defines network factory, log storage and +/// state machine types. Refer to the documentation of associated types for more information. +/// +/// [`Raft`]: crate::Raft +// : Sized + Send + Sync + Debug + Clone + Copy + Default + Eq + PartialEq + Ord + PartialOrd + +// 'static +pub trait StorageTypeConfig { + /// Network factory to use to create new connections. + type NetworkFactory: RaftNetworkFactory; + + /// Log storage storing the deltas. + type LogStorage: RaftLogStorage; + + /// State machine processing requests and storing the snapshot of the data. + type StateMachine: RaftStateMachine; +} diff --git a/rocksstore/Cargo.toml b/rocksstore/Cargo.toml index 22790d7cc..6215bd48f 100644 --- a/rocksstore/Cargo.toml +++ b/rocksstore/Cargo.toml @@ -16,7 +16,7 @@ repository = { workspace = true } # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -openraft = { path= "../openraft", version = "0.8.4", features=["serde"] } +openraft = { path= "../openraft", version = "0.8.4", features=["serde", "compat-08"] } rocksdb = "0.20.1" byteorder = "1.4.3" diff --git a/sledstore/Cargo.toml b/sledstore/Cargo.toml index cf9d6c899..bd607be68 100644 --- a/sledstore/Cargo.toml +++ b/sledstore/Cargo.toml @@ -14,7 +14,7 @@ license = { workspace = true } repository = { workspace = true } [dependencies] -openraft = { path= "../openraft", version = "0.8.4", features=["serde"] } +openraft = { path= "../openraft", version = "0.8.4", features=["serde", "compat-08"] } sled = "0.34.7" byteorder = "1.4.3" diff --git a/stores/rocksstore-v2/Cargo.toml b/stores/rocksstore-v2/Cargo.toml index 64ceccecb..7ff60b9a8 100644 --- a/stores/rocksstore-v2/Cargo.toml +++ b/stores/rocksstore-v2/Cargo.toml @@ -18,7 +18,7 @@ repository = "https://github.com/datafuselabs/openraft" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -openraft = { path= "../../openraft", version = "0.8.4", features=["serde", "storage-v2"] } +openraft = { path= "../../openraft", version = "0.8.4", features=["serde", "storage-v2", "compat-08"] } rocksdb = "0.20.1" rand = "*" diff --git a/tests/tests/fixtures/mod.rs b/tests/tests/fixtures/mod.rs index b54b6452b..1b302773a 100644 --- a/tests/tests/fixtures/mod.rs +++ b/tests/tests/fixtures/mod.rs @@ -51,6 +51,7 @@ use openraft::RaftLogId; use openraft::RaftMetrics; use openraft::RaftState; use openraft::ServerState; +use openraft::StorageTypeConfig; use openraft::TokioInstant; use openraft::TokioRuntime; use openraft::Vote; @@ -71,8 +72,17 @@ pub mod logging; pub type MemLogStore = Adaptor>; pub type MemStateMachine = Adaptor>; +/// Storage types configuration for `openraft` tests. +pub struct StorageConfig; + +impl StorageTypeConfig for StorageConfig { + type NetworkFactory = TypedRaftRouter; + type LogStorage = MemLogStore; + type StateMachine = MemStateMachine; +} + /// A concrete Raft type used during testing. -pub type MemRaft = Raft; +pub type MemRaft = Raft; pub fn init_default_ut_tracing() { static START: Once = Once::new();