use std::hash::Hash;
use std::io;
use std::net::IpAddr;
use std::ops::RangeBounds;
use std::sync::Arc;
use std::time::Duration;
use ipnet::IpNet;
use crate::bounds::Key;
use crate::clock::{NodeId, Timestamp};
use crate::entry::Entry;
use crate::persistence::Persistence;
use crate::replicated_map::Config;
use crate::{Discovery, ReplicatedMap};
use rsos::Fingerprint;
pub struct ReplicatedSet<K>(ReplicatedMap<K, ()>)
where
K: Clone + Hash + Eq + Send + Sync;
impl<K: Clone + Hash + Eq + Send + Sync> Clone for ReplicatedSet<K> {
fn clone(&self) -> Self {
ReplicatedSet(self.0.clone())
}
}
impl<K: Key + Hash> ReplicatedSet<K> {
pub async fn new(config: Config) -> io::Result<Self> {
ReplicatedMap::new(config).await.map(ReplicatedSet)
}
#[must_use]
pub fn node_id(&self) -> NodeId {
self.0.node_id()
}
#[must_use]
pub fn with_persistence(self, backend: Arc<dyn Persistence<K, ()>>) -> Self {
ReplicatedSet(self.0.with_persistence(backend))
}
#[must_use]
pub fn with_seed(self, peer: IpAddr) -> Self {
ReplicatedSet(self.0.with_seed(peer))
}
pub fn seed_peer(&self, peer: IpAddr) {
self.0.seed_peer(peer);
}
#[must_use]
pub fn with_discovery(self, discovery: Arc<dyn Discovery>) -> Self {
ReplicatedSet(self.0.with_discovery(discovery))
}
#[must_use]
pub fn with_dns_discovery(self, name: impl Into<String>, port: u16) -> Self {
ReplicatedSet(self.0.with_dns_discovery(name, port))
}
#[must_use]
pub fn with_discovery_interval(self, interval: Duration) -> Self {
ReplicatedSet(self.0.with_discovery_interval(interval))
}
#[must_use]
pub fn with_discovery_miss_threshold(self, threshold: u32) -> Self {
ReplicatedSet(self.0.with_discovery_miss_threshold(threshold))
}
#[must_use]
pub fn with_discovery_decommission_floor(self, floor: Duration) -> Self {
ReplicatedSet(self.0.with_discovery_decommission_floor(floor))
}
#[must_use]
pub fn with_tombstone_timeout(self, tombstone_timeout: Duration) -> Self {
ReplicatedSet(self.0.with_tombstone_timeout(tombstone_timeout))
}
pub fn set_pre_insert<F: Send + Sync + Fn(&K, &Entry<Timestamp, ()>) + 'static>(
&self,
pre_insert: F,
) {
self.0.set_pre_insert(pre_insert);
}
#[must_use]
pub fn fingerprint<R: RangeBounds<K>>(&self, range: R) -> Fingerprint {
self.0.fingerprint(range)
}
#[must_use]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[must_use]
pub fn insert(&self, key: K) -> bool {
self.0.insert(key, ()).is_some()
}
pub fn insert_bulk(&self, keys: &[K]) {
let pairs: Vec<(K, ())> = keys.iter().cloned().map(|k| (k, ())).collect();
self.0.insert_bulk(&pairs);
}
pub fn load_bulk(&self, keys: &[K]) {
let pairs: Vec<(K, ())> = keys.iter().cloned().map(|k| (k, ())).collect();
self.0.load_bulk(&pairs);
}
#[must_use]
pub fn remove(&self, key: &K) -> bool {
self.0.remove(key).is_some()
}
pub fn remove_bulk(&self, keys: &[K]) {
self.0.remove_bulk(keys);
}
#[must_use]
pub fn contains(&self, key: &K) -> bool {
self.0.contains_key(key)
}
pub fn clear(&self) {
self.0.clear();
}
pub fn retain<P: FnMut(&K) -> bool>(&self, mut keep: P) {
self.0.retain(|k, ()| keep(k));
}
pub fn delete_range<R: RangeBounds<K>>(&self, range: R) {
self.0.delete_range(range);
}
#[must_use]
pub fn keys(&self) -> Vec<K> {
self.0.keys()
}
pub async fn start_reconciliation(&self) {
self.0.start_reconciliation().await;
}
pub fn forget_peer(&self, peer: IpAddr) {
self.0.forget_peer(peer);
}
pub fn set_nets(&self, nets: &[IpNet]) {
self.0.set_nets(nets);
}
#[must_use]
pub fn add_net(&self, net: IpNet) -> bool {
self.0.add_net(net)
}
#[must_use]
pub fn remove_net(&self, net: IpNet) -> bool {
self.0.remove_net(net)
}
#[must_use]
pub fn nets(&self) -> Vec<IpNet> {
self.0.nets()
}
#[must_use]
pub fn local_net(&self) -> IpNet {
self.0.local_net()
}
pub fn set_remote_interval(&self, interval: u32) {
self.0.set_remote_interval(interval);
}
pub fn set_remote_fanout(&self, fanout: usize) {
self.0.set_remote_fanout(fanout);
}
pub fn set_tombstone_timeout(&self, timeout: Duration) {
self.0.set_tombstone_timeout(timeout);
}
pub fn set_reconcile_interval(&self, interval: Duration) {
self.0.set_reconcile_interval(interval);
}
pub async fn run(self) {
self.0.run().await;
}
}
#[cfg(test)]
mod replicated_set_tests {
use std::time::Duration;
use crate::replicated_map::{Config, MAX_NETS};
use crate::ReplicatedSet;
fn ephemeral_config() -> Config {
Config {
port: 0,
listen_addr: "127.0.0.1".parse().unwrap(),
nets: [None; MAX_NETS],
remote_interval: 6,
remote_fanout: 2,
cluster_key: None,
insecure_no_key: true,
node_id: None,
encrypt: false,
reconcile_interval: Duration::from_secs(1),
bulk_send_rate: Some(32 * 1024 * 1024),
recv_buffer_size: Some(8 * 1024 * 1024),
send_buffer_size: Some(8 * 1024 * 1024),
freshness_window: gossip::replay::FRESHNESS_WINDOW_DEFAULT,
max_peers: 1024,
max_concurrent_bulk_dumps: 4,
}
}
#[tokio::test]
async fn insert_remove_contains_and_bulk_agree_on_membership() {
let set = ReplicatedSet::<i32>::new(ephemeral_config()).await.unwrap();
assert!(set.is_empty());
assert!(!set.contains(&1));
assert!(!set.insert(1)); assert!(set.contains(&1));
assert!(set.insert(1)); assert_eq!(set.len(), 1);
set.insert_bulk(&[2, 3]);
assert_eq!(set.len(), 3);
assert!(set.contains(&2) && set.contains(&3));
assert!(set.remove(&1)); assert!(!set.contains(&1));
assert!(!set.remove(&1));
set.remove_bulk(&[2, 3]);
assert!(set.is_empty());
}
}