fix: avoid rewriting peer list file when unchanged (#1488)

save_peer_list() ran unconditionally every 60s from the discovery
loop, writing the same data to disk even when the peer set hadn't
changed. Compare the newly encoded peer list against the bytes
already on disk and skip the write when they match.

Fixes #1457

Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1488
Reviewed-by: Alex <lx@deuxfleurs.fr>
This commit is contained in:
Andreas Schneider
2026-07-14 10:54:33 +00:00
committed by Alex
parent 936e53fe2f
commit 7e246b20e9
+23 -5
View File
@@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet};
use std::io::{Read, Write};
use std::net::{IpAddr, SocketAddr};
use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock, RwLockReadGuard};
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard};
use std::time::{Duration, Instant};
use arc_swap::ArcSwapOption;
@@ -24,6 +24,7 @@ use garage_util::config::KubernetesDiscoveryConfig;
use garage_util::config::{Config, DataDirEnum};
use garage_util::data::*;
use garage_util::error::*;
use garage_util::migrate::Migrate;
use garage_util::persister::Persister;
use garage_util::time::*;
@@ -89,6 +90,9 @@ pub struct System {
pub id: Uuid,
persist_peer_list: Persister<PeerList>,
// Cache of the bytes last read from / written to the peer list file,
// to avoid waking up the disk with a read on every save_peer_list() call.
cached_peer_list_bytes: Mutex<Option<Vec<u8>>>,
pub(crate) local_status: RwLock<NodeStatus>,
node_status: RwLock<HashMap<Uuid, (u64, NodeStatus)>>,
@@ -311,6 +315,7 @@ impl System {
let sys = Arc::new(System {
id: netapp.id.into(),
persist_peer_list,
cached_peer_list_bytes: Mutex::new(None),
local_status: RwLock::new(local_status),
node_status: RwLock::new(HashMap::new()),
netapp: netapp.clone(),
@@ -779,10 +784,23 @@ impl System {
peer_list.extend(prev_peer_list.0);
}
// Save new peer list to file
self.persist_peer_list
.save_async(&PeerList(peer_list))
.await
// Sort for a deterministic encoding, so that we can detect below
// whether the peer list actually changed since last time.
peer_list.sort_by_key(|(id, _)| *id);
let new_peer_list = PeerList(peer_list);
let new_peer_list_bytes = new_peer_list.encode()?;
// Skip writing to disk if nothing changed since the last save,
// but still cache the bytes so we don't have to read the file again.
let cached_peer_list_bytes = self.cached_peer_list_bytes.lock().unwrap().clone();
if cached_peer_list_bytes.as_deref() == Some(&new_peer_list_bytes[..]) {
return Ok(());
}
self.persist_peer_list.save_async(&new_peer_list).await?;
*self.cached_peer_list_bytes.lock().unwrap() = Some(new_peer_list_bytes);
Ok(())
}
}