pub struct HashRing<T, S = DefaultHashBuilder> { /* private fields */ }Expand description
HashRing represents a set of nodes (cluster) that shall use consistent hashing HashRing provides methods to add and remove nodes to the cluster HashRing can calculate for each node which hashranges they are responsible for HashRing can calculate replication instructions if a cluster changes or if the cluster if replaced completely to find target nodes and source nodes with affected hashranges
Implementations§
Source§impl<T> HashRing<T>
impl<T> HashRing<T>
pub fn get_hash_ranges(&self) -> Vec<Replicas<T>>
Sourcepub fn find_sources(
&self,
target: &T,
source: &HashRing<T>,
available_nodes: &[T],
) -> Vec<Replicas<T>>
pub fn find_sources( &self, target: &T, source: &HashRing<T>, available_nodes: &[T], ) -> Vec<Replicas<T>>
for given node: Node calculate all available source Nodes that can provide keys which need to be stored on the given node (after a change of the given cluster) for general replication instructions within the cluster, use fn get_hash_ranges() available nodes provides all nodes that can be used to replicate keys from this covers different scenarios:
self(this HashRing) andsourcecover the same deployment of one cluster, containing nodes that left or joined the ringself(this HashRing) andsourcecover the same deployment of one cluster, containing some nodes that are terminating currently (available to sync from, but should not receive new keys)sourcerefering to the original deployment andself(this HashRing) refering to the replacement deployment, therefor available_nodes refering to the original deployment
§Arguments
target- return replication sources for this node. target needs to be member of the current HashRingsource- find replication nodes within this HashRingavailable_nodes- define all nodes that can be used for replication in source HashRing
§Examples
use std::hash::{Hash, Hasher};
use std::net::Ipv4Addr;
use std::str::FromStr;
use hashring_coordinator::HashRing;
#[derive(Debug, Copy, Clone, PartialEq)]
struct Node {
addr: Ipv4Addr,
}
impl Node {
fn new(ip: &str) -> Self {
let addr = Ipv4Addr::from_str(ip).unwrap();
Node { addr }
}
}
impl Hash for Node {
fn hash<H: Hasher>(&self, s: &mut H) {
(self.addr).hash(s)
}
}
let node1 = Node::new("127.0.0.1"); // hash @1093046220658055553
let node2 = Node::new("127.0.0.2"); // hash @7508079630756128442
let node3 = Node::new("127.0.0.3"); // hash @12322253174093194230
let nodes_original = vec![node1, node2];
let mut ring_original = HashRing::new(0, 1);
ring_original.batch_add(nodes_original.clone());
let mut ring_new = ring_original.clone();
ring_new.add(node3.clone());
// sources contains a list with hashranges and target nodes that can be synchronized to node3
// sources = [Replicas { hash_range: 7508079630756128443..=12322253174093194230, nodes: [Node { addr: 127.0.0.1 }] }]
// node3 was added, thus the hashrange between node2 and node3 which was located on node1 so far can be moved over to node3
let sources = ring_new.find_sources(&node3, &ring_original, &nodes_original);
Sourcepub fn merge_replicas(&self, replicas: Vec<Replicas<T>>) -> Vec<Replicas<T>>
pub fn merge_replicas(&self, replicas: Vec<Replicas<T>>) -> Vec<Replicas<T>>
merge hashranges together, if the hashrange touch and all affected nodes are identical
pub fn hash_nodes(&self, nodes: &Vec<T>) -> u64
Source§impl<T, S> HashRing<T, S>
impl<T, S> HashRing<T, S>
pub fn batch_add(&mut self, nodes: Vec<T>)
Sourcepub fn get<U: Hash>(&self, key: &U) -> Vec<T>
pub fn get<U: Hash>(&self, key: &U) -> Vec<T>
returns all real nodes responsible for key
Returns an empty array if the ring is empty
Sourcepub fn get_hash<U>(&self, input: &U) -> u64where
U: Hash,
pub fn get_hash<U>(&self, input: &U) -> u64where
U: Hash,
returns the hash for a given key or node (as used in this HashRing)
pub fn nodes(&self) -> Vec<T>
Source§impl<T> HashRing<T>
Hash Ring
impl<T> HashRing<T>
Hash Ring
A hash ring that provides consistent hashing for nodes that are added to it.
Sourcepub fn new(replicas: usize, vnodes: usize) -> HashRing<T>
pub fn new(replicas: usize, vnodes: usize) -> HashRing<T>
Create a new HashRing.
§Arguments
replicas- number of nodes to store copies of each key (set replicas to 0, to store each key only once)vnodes- number of virtual nodes per real node in the cluster (higher number means more even distribution of keys across all nodes, but higher processing effort)
Source§impl<T, S> HashRing<T, S>
impl<T, S> HashRing<T, S>
Sourcepub fn with_hasher(
replicas: usize,
vnodes: usize,
hash_builder: S,
) -> HashRing<T, S>
pub fn with_hasher( replicas: usize, vnodes: usize, hash_builder: S, ) -> HashRing<T, S>
Creates an empty HashRing which will use the given hash builder.
§Arguments
replicas- number of nodes to store copies of each key (set replicas to 0, to store each key only once)vnodes- number of virtual nodes per real node in the cluster (higher number means more even distribution of keys across all nodes, but higher processing effort)hash_builder- implementation of BuildHasher to provider a Hasher for the HashRing
§Examples
use hashring_coordinator::HashRing;
use siphasher::sip::SipHasher;
use std::hash::{BuildHasher, Hash, Hasher};
#[derive(Clone, PartialEq, Debug)]
pub struct DefaultHashBuilder;
impl BuildHasher for DefaultHashBuilder {
type Hasher = SipHasher;
fn build_hasher(&self) -> Self::Hasher {
SipHasher::new()
}
}
struct Node {}
impl Hash for Node {
fn hash<H: Hasher>(&self, s: &mut H) {
todo!()
}
}
let hash_builder = DefaultHashBuilder {};
let mut ring: HashRing<Node, DefaultHashBuilder> = HashRing::with_hasher(2, 100, hash_builder);