summaryrefslogtreecommitdiffstats
path: root/src/api/peers.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-19 23:56:33 +0200
committertv <tv@krebsco.de>2026-10-19 23:56:33 +0200
commit2dd4712902c63bfe393933ed165bb7481aa932ec (patch)
tree8b66447844e643a82bd8d5df62442610d469a67b /src/api/peers.rs
parentd3a9d5d3ebff98e342dff1df0ebad86f346719f5 (diff)
add epochs
Diffstat (limited to 'src/api/peers.rs')
-rw-r--r--src/api/peers.rs31
1 files changed, 30 insertions, 1 deletions
diff --git a/src/api/peers.rs b/src/api/peers.rs
index b2658a5..b12e3bf 100644
--- a/src/api/peers.rs
+++ b/src/api/peers.rs
@@ -15,6 +15,7 @@ use utoipa::ToSchema;
use super::store_status;
use crate::peer::forgotten_path;
+use crate::replica::Epoch;
use crate::state::{unix_millis, AppState, HelloState, Liveness, PeerMembership, PeerState};
use crate::store;
@@ -27,6 +28,23 @@ pub(crate) enum PeerLivenessStatus {
#[derive(Debug, Serialize, ToSchema)]
#[serde(rename_all = "camelCase")]
+pub(crate) struct EpochInfo {
+ generation: u64,
+ /// Hex-encoded snapshot hash; all zeros for the genesis epoch.
+ id: String,
+}
+
+impl From<Epoch> for EpochInfo {
+ fn from(epoch: Epoch) -> Self {
+ Self {
+ generation: epoch.generation,
+ id: epoch.id_hex(),
+ }
+ }
+}
+
+#[derive(Debug, Serialize, ToSchema)]
+#[serde(rename_all = "camelCase")]
pub(crate) struct PeerStatus {
public_key: String,
validated_cluster: Option<String>,
@@ -35,11 +53,16 @@ pub(crate) struct PeerStatus {
last_seen_secs_ago: Option<u64>,
dormant_for_secs: Option<u64>,
has_pending_delivery: bool,
+ /// Epoch the peer last advertised; absent until it has sent a message.
+ epoch: Option<EpochInfo>,
+ /// Whether that epoch equals ours, i.e. whether we sync with this peer.
+ same_epoch: Option<bool>,
}
#[derive(Debug, Serialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub(crate) struct PeerListResponse {
+ local_epoch: EpochInfo,
peers: Vec<PeerStatus>,
}
@@ -73,6 +96,7 @@ pub(crate) async fn list_peers(
.collect();
let now = Instant::now();
+ let local_epoch = state.local_epoch();
let mut peers = Vec::with_capacity(snapshot.len());
for (public_key, peer_state_mutex) in snapshot {
@@ -99,11 +123,16 @@ pub(crate) async fn list_peers(
.map(|t| now.saturating_duration_since(t).as_secs()),
dormant_for_secs,
has_pending_delivery: ps.pending_outbound_sync.is_some(),
+ epoch: ps.epoch.map(EpochInfo::from),
+ same_epoch: ps.epoch.map(|epoch| epoch == local_epoch),
});
}
peers.sort_by(|a, b| a.public_key.cmp(&b.public_key));
- Ok(Json(PeerListResponse { peers }))
+ Ok(Json(PeerListResponse {
+ local_epoch: local_epoch.into(),
+ peers,
+ }))
}
#[utoipa::path(