Skip to content

Instantly share code, notes, and snippets.

@mkmik
Created April 21, 2021 14:18
Show Gist options
  • Save mkmik/e9569fb9ad9873171f2685758086182c to your computer and use it in GitHub Desktop.
Save mkmik/e9569fb9ad9873171f2685758086182c to your computer and use it in GitHub Desktop.
#![allow(dead_code)]
use rendezvous_hash::RendezvousNodes;
use rendezvous_hash::{Capacity, WeightedNode};
use std::collections::hash_map::DefaultHasher;
use std::collections::{HashMap, HashSet};
use std::hash::BuildHasherDefault;
type MyBuildHasher = BuildHasherDefault<DefaultHasher>;
fn main() {
//hrw();
anchor();
}
fn hrw() {
let mut nodes = RendezvousNodes::default();
nodes.insert(WeightedNode::new("foo", Capacity::new(1.0).unwrap()));
nodes.insert(WeightedNode::new("bar", Capacity::new(1.0).unwrap()));
nodes.insert(WeightedNode::new("baz", Capacity::new(1.0).unwrap()));
nodes.insert(WeightedNode::new("qux", Capacity::new(1.0).unwrap()));
let mut foos = HashSet::new();
let mut counts = HashMap::new();
for item in 0..100000 {
let node = nodes.calc_candidates(&item).nth(0).unwrap();
*counts.entry(node.node.to_string()).or_insert(0) += 1;
if node.node == "foo" {
foos.insert(item);
}
}
println!("{}", ((counts["foo"] as f64) / 100.0).round());
println!("{}", ((counts["bar"] as f64) / 100.0).round());
println!("{}", ((counts["baz"] as f64) / 100.0).round());
println!("{}", ((counts["qux"] as f64) / 100.0).round());
let mut nodes = RendezvousNodes::default();
nodes.insert(WeightedNode::new("foo", Capacity::new(1.0).unwrap()));
nodes.insert(WeightedNode::new("bar", Capacity::new(1.0).unwrap()));
nodes.insert(WeightedNode::new("baz", Capacity::new(1.0).unwrap()));
nodes.insert(WeightedNode::new("qux", Capacity::new(1.0).unwrap()));
nodes.insert(WeightedNode::new("qux2", Capacity::new(1.0).unwrap())); // or just bump capacity of qux to 2.0, same effect on remapping
let mut foos_2 = HashSet::new();
let mut counts = HashMap::new();
for item in 0..100000 {
let node = nodes.calc_candidates(&item).nth(0).unwrap();
*counts.entry(node.node.to_string()).or_insert(0) += 1;
if node.node == "foo" {
foos_2.insert(item);
}
}
println!(
"remapped in foo {}%",
foos.difference(&foos_2).collect::<Vec<_>>().len() as f64 / (counts["foo"] as f64) * 100.0
);
}
fn anchor() {
// The capacity has to stay the same otherwise it will reshard everything
// Empirically, some values of capacity produce better effects on rebalancing spread
// than others. In any case anchorhash seems worse than HRW
let capacity = 1024 * 32;
let anchor = anchorhash::Builder::with_hasher(MyBuildHasher::default())
.with_resources(vec!["foo", "bar", "baz", "qux"])
.build(capacity);
let mut foos = HashSet::new();
let mut counts = HashMap::new();
for item in 0..100000 {
let node = anchor.get_resource(item).unwrap();
*counts.entry(node.to_string()).or_insert(0) += 1;
if node == &"foo" {
foos.insert(item);
}
}
println!("{}", ((counts["foo"] as f64) / 100.0).round());
println!("{}", ((counts["bar"] as f64) / 100.0).round());
println!("{}", ((counts["baz"] as f64) / 100.0).round());
println!("{}", ((counts["qux"] as f64) / 100.0).round());
let anchor = anchorhash::Builder::with_hasher(MyBuildHasher::default())
.with_resources(vec!["foo", "bar", "baz", "qux", "quz2"])
.build(capacity);
let mut foos_2 = HashSet::new();
let mut counts = HashMap::new();
for item in 0..100000 {
let node = anchor.get_resource(item).unwrap();
*counts.entry(node.to_string()).or_insert(0) += 1;
if node == &"foo" {
foos_2.insert(item);
}
}
println!(
"remapped in foo {}%",
foos.difference(&foos_2).collect::<Vec<_>>().len() as f64 / (counts["foo"] as f64) * 100.0
);
}
fn anchor_ordering() {
println!("ordering A");
{
let mut anchor = anchorhash::Builder::with_hasher(MyBuildHasher::default())
.with_resources(vec![1, 2, 3])
.build(20);
println!("{}", anchor.get_resource("key1").unwrap());
anchor.add_resource(4).unwrap();
println!("{}", anchor.get_resource("key1").unwrap());
anchor.add_resource(5).unwrap();
println!("{}", anchor.get_resource("key1").unwrap());
anchor.remove_resource(&4).unwrap();
anchor.remove_resource(&5).unwrap();
println!("final: {}", anchor.get_resource("key1").unwrap());
}
println!("ordering B:");
{
let mut anchor = anchorhash::Builder::with_hasher(MyBuildHasher::default())
.with_resources(vec![1, 2, 3])
.build(20);
println!("{}", anchor.get_resource("key1").unwrap());
anchor.add_resource(5).unwrap();
println!("{}", anchor.get_resource("key1").unwrap());
anchor.add_resource(4).unwrap();
println!("{}", anchor.get_resource("key1").unwrap());
anchor.remove_resource(&4).unwrap();
anchor.remove_resource(&5).unwrap();
println!("final: {}", anchor.get_resource("key1").unwrap());
}
println!("direct A");
{
let anchor = anchorhash::Builder::with_hasher(MyBuildHasher::default())
.with_resources(vec![1, 2, 3, 4, 5])
.build(20);
println!("{}", anchor.get_resource("key1").unwrap());
}
println!("direct A");
{
let anchor = anchorhash::Builder::with_hasher(MyBuildHasher::default())
.with_resources(vec![1, 2, 3, 5, 4])
.build(20);
println!("{}", anchor.get_resource("key1").unwrap());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment