Skip to content

Commit

Permalink
Heading toward consistent hash implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
rbtcollins committed Aug 21, 2017
1 parent 216c8ce commit 9dcfb1b
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ authors = ["Robert Collins <[email protected]>"]
[dependencies]
libc="*"
pnetlink= { version="*", git = "https://github.com/rbtcollins/pnetlink" }
siphasher = "~0.1"

[dependencies.netmap]
git = "https://github.com/rbtcollins/netmap-rs"
Expand Down
44 changes: 44 additions & 0 deletions src/consistenthash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) 2017 Robert Collins. Licensed under the Apache-2.0 license.
//
// Consistent hashing for selecting backends.

use std::hash::{Hash, Hasher};

use siphasher::sip::{SipHasher};

use super::primes;

/// Generate permutations for a given offset, skip, pool
///
/// ```
/// use rusty_rail::consistenthash::permutations;
///
/// assert_eq!(permutations(3, 4, 7), vec![3, 0, 4, 1, 5, 2, 6]);
/// assert_eq!(permutations(0, 2, 7), vec![0, 2, 4, 6, 1, 3, 5]);
/// assert_eq!(permutations(3, 1, 7), vec![3, 4, 5, 6, 0, 1, 2]);
/// ```
pub fn permutations(offset: u32, skip: u32, pool_size: u32) -> Vec<u32> {
let mut res: Vec<u32> = Vec::with_capacity(pool_size as usize);
for pos in 0..pool_size {
res.push((offset + pos * skip) % pool_size)
}
res
}

/// Generate permutations for a given name and pool size.
///
/// ```
/// use rusty_rail::consistenthash::permute_backend;
///
/// assert_eq!(permute_backend("fred".to_string(), 7), vec![1, 0, 6, 5, 4, 3, 2]);
/// assert_eq!(permute_backend("ralph".to_string(), 7), vec![3, 2, 1, 0, 6, 5, 4]);
/// assert_eq!(permute_backend("larry".to_string(), 7), vec![4, 0, 3, 6, 2, 5, 1]);
/// ```
pub fn permute_backend(name: String, pool_size: u32) -> Vec<u32> {
let mut s = SipHasher::new();
name.hash(&mut s);
let offset = (s.finish() % pool_size as u64) as u32;
"differenthash".hash(&mut s);
let skip = (s.finish() % (pool_size as u64 - 1) + 1) as u32;
permutations(offset, skip, pool_size)
}
6 changes: 5 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
extern crate netmap;
extern crate pnet;
extern crate pnetlink;
extern crate siphasher;

use std::hash::{Hash, SipHasher, Hasher};
use std::hash::{Hash, Hasher};
use std::net::Ipv4Addr;

use netmap::{NetmapSlot, NetmapRing};
Expand All @@ -14,10 +15,13 @@ use pnet::packet::{MutablePacket, Packet};
use pnet::packet::ip::IpNextHeaderProtocols::Gre;
use pnet::packet::gre;
use pnet::util::MacAddr;
use siphasher::sip::{SipHasher};

pub mod arpcache;
pub mod configuration;
pub mod error;
pub mod primes;
pub mod consistenthash;

enum Direction {
Destination,
Expand Down
36 changes: 36 additions & 0 deletions src/primes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2017 Robert Collins. Licensed under the Apache-2.0 license.
//
// Used in implementing the maglev consistent hash.
extern crate netmap;

#[test]
fn examples() {
assert_eq!(primes(0), vec![]);
assert_eq!(primes(1), vec![]);
assert_eq!(primes(2), vec![2]);
assert_eq!(primes(3), vec![2, 3]);
assert_eq!(primes(4), vec![2, 3]);
assert_eq!(primes(5), vec![2, 3, 5]);
}

/// Returns all primes less than or equal to limit in a vector
fn primes(limit: usize) -> Vec<u32> {
let sqrt = (limit as f64).sqrt().ceil() as usize;
let mut res: Vec<u32> = Vec::with_capacity(sqrt);
let mut sieve = vec![false; limit+1];
if limit < 2 {
return res;
}
for candidate in 2..limit + 1 {
if sieve[candidate] {
continue;
}
res.push(candidate as u32);
let mut composite = 2 * candidate;
while composite <= limit {
sieve[composite] = true;
composite += candidate
}
}
res
}

0 comments on commit 9dcfb1b

Please sign in to comment.