use std::fmt;
use display_more::DisplayOptionExt;
use openraft_macros::since;
use crate::StoredMembership;
use crate::log_id::LogId;
use crate::node::Node;
use crate::node::NodeId;
use crate::storage::SnapshotSignature;
use crate::vote::RaftCommittedLeaderId;
#[since(version = "0.10.0", change = "removed `snapshot_id`")]
#[since(
version = "0.10.0",
change = "from `SnapshotMeta<C>` to `SnapshotMeta<CLID, NID, N>`"
)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize),
serde(bound = "", from = "SnapshotMetaWire<CLID, NID, N>")
)]
pub struct SnapshotMeta<CLID, NID, N>
where
CLID: RaftCommittedLeaderId,
NID: NodeId,
N: Node,
{
pub last_log_id: Option<LogId<CLID>>,
pub last_membership: StoredMembership<CLID, NID, N>,
}
#[cfg(feature = "serde")]
#[derive(serde::Deserialize)]
#[serde(bound = "")]
struct SnapshotMetaWire<CLID, NID, N>
where
CLID: RaftCommittedLeaderId,
NID: NodeId,
N: Node,
{
last_log_id: Option<LogId<CLID>>,
last_membership: StoredMembership<CLID, NID, N>,
#[serde(default)]
#[allow(dead_code)]
snapshot_id: crate::SnapshotId,
}
#[cfg(feature = "serde")]
impl<CLID, NID, N> From<SnapshotMetaWire<CLID, NID, N>> for SnapshotMeta<CLID, NID, N>
where
CLID: RaftCommittedLeaderId,
NID: NodeId,
N: Node,
{
fn from(wire: SnapshotMetaWire<CLID, NID, N>) -> Self {
SnapshotMeta {
last_log_id: wire.last_log_id,
last_membership: wire.last_membership,
}
}
}
#[cfg(feature = "serde")]
impl<CLID, NID, N> serde::Serialize for SnapshotMeta<CLID, NID, N>
where
CLID: RaftCommittedLeaderId,
NID: NodeId,
N: Node,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
use serde::ser::SerializeStruct;
let mut s = serializer.serialize_struct("SnapshotMeta", 3)?;
s.serialize_field("last_log_id", &self.last_log_id)?;
s.serialize_field("last_membership", &self.last_membership)?;
s.serialize_field("snapshot_id", "")?;
s.end()
}
}
impl<CLID, NID, N> Default for SnapshotMeta<CLID, NID, N>
where
CLID: RaftCommittedLeaderId,
NID: NodeId,
N: Node,
{
fn default() -> Self {
Self {
last_log_id: None,
last_membership: StoredMembership::default(),
}
}
}
impl<CLID, NID, N> fmt::Display for SnapshotMeta<CLID, NID, N>
where
CLID: RaftCommittedLeaderId,
NID: NodeId,
N: Node,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{{last_log:{}, last_membership: {}}}",
self.last_log_id.display(),
self.last_membership
)
}
}
impl<CLID, NID, N> SnapshotMeta<CLID, NID, N>
where
CLID: RaftCommittedLeaderId,
NID: NodeId,
N: Node,
{
pub fn signature(&self) -> SnapshotSignature<CLID> {
SnapshotSignature {
last_log_id: self.last_log_id.clone(),
last_membership_log_id: self.last_membership.log_id().as_ref().map(|x| Box::new(x.clone())),
}
}
pub fn last_log_id(&self) -> Option<&LogId<CLID>> {
self.last_log_id.as_ref()
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "serde")]
#[test]
fn test_snapshot_meta_serde() {
use maplit::btreeset;
use crate::Membership;
use crate::StoredMembership;
use crate::engine::testing::UTConfig;
use crate::engine::testing::log_id;
use crate::type_config::alias::SnapshotMetaOf;
let meta = SnapshotMetaOf::<UTConfig> {
last_log_id: Some(log_id(1, 2, 3)),
last_membership: StoredMembership::new(
Some(log_id(4, 5, 6)),
Membership::new_with_defaults(vec![btreeset! {1,2}], []),
),
};
let want = r#"{"last_log_id":{"leader_id":{"term":1,"node_id":2},"index":3},"last_membership":{"log_id":{"leader_id":{"term":4,"node_id":5},"index":6},"membership":{"configs":[[1,2]],"nodes":{"1":null,"2":null}}},"snapshot_id":""}"#;
assert_eq!(want, serde_json::to_string(&meta).unwrap());
assert_eq!(meta, serde_json::from_str::<SnapshotMetaOf<UTConfig>>(want).unwrap());
let v09 = r#"{"last_log_id":{"leader_id":{"term":1,"node_id":2},"index":3},"last_membership":{"log_id":{"leader_id":{"term":4,"node_id":5},"index":6},"membership":{"configs":[[1,2]],"nodes":{"1":null,"2":null}}},"snapshot_id":"1-2-3-4"}"#;
assert_eq!(meta, serde_json::from_str::<SnapshotMetaOf<UTConfig>>(v09).unwrap());
}
}