Skip to content

Commit 5d52237

Browse files
committed
remove second vector
1 parent 23f3080 commit 5d52237

File tree

2 files changed

+45
-22
lines changed

2 files changed

+45
-22
lines changed

crates/consistent-hashing/benchmarks/performance.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::{
2-
hash::{DefaultHasher, Hash},
2+
hash::{DefaultHasher, Hash, Hasher},
33
hint::black_box,
44
time::Duration,
55
};
66

77
use consistent_hashing::{ConsistentChooseKHasher, ConsistentHasher};
88
use criterion::{
9-
criterion_group, criterion_main, AxisScale, Bencher, BenchmarkId, Criterion, PlotConfiguration,
9+
criterion_group, criterion_main, AxisScale, BenchmarkId, Criterion, PlotConfiguration,
1010
Throughput,
1111
};
1212
use rand::{rng, Rng};
@@ -23,7 +23,7 @@ fn throughput_benchmark(c: &mut Criterion) {
2323
|| &keys,
2424
|keys| {
2525
for key in keys {
26-
let mut h = DefaultHasher::new();
26+
let mut h = DefaultHasher::default();
2727
key.hash(&mut h);
2828
black_box(ConsistentHasher::new(h).prev(*n + 1));
2929
}
@@ -38,9 +38,9 @@ fn throughput_benchmark(c: &mut Criterion) {
3838
|keys| {
3939
let mut res = Vec::with_capacity(k);
4040
for key in keys {
41-
let mut h = DefaultHasher::new();
41+
let mut h = DefaultHasher::default();
4242
key.hash(&mut h);
43-
black_box(ConsistentChooseKHasher::new(h, k).prev(*n + k, &mut res));
43+
black_box(ConsistentChooseKHasher::new(h, k).prev_with_vec(*n + k, &mut res));
4444
}
4545
},
4646
criterion::BatchSize::SmallInput,

crates/consistent-hashing/src/lib.rs

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub trait HashSequence {
1212
pub trait HashSeqBuilder {
1313
type Seq: HashSequence;
1414

15+
/// Returns a bit mask indicating which buckets have at least one hash.
1516
fn bit_mask(&self) -> u64;
1617
/// Return a HashSequence instance which is seeded with the given bit position
1718
/// and the seed of this builder.
@@ -66,7 +67,7 @@ struct BucketIterator<H: HashSequence> {
6667
hasher: H,
6768
n: usize,
6869
is_first: bool,
69-
bit: u64, // A bitmask with a single bit set.
70+
bit: u64, // A bitmask with a single bit set.
7071
}
7172

7273
impl<H: HashSequence> BucketIterator<H> {
@@ -199,20 +200,30 @@ pub struct ConsistentHasher<H: HashSeqBuilder> {
199200
builder: H,
200201
}
201202

202-
impl<H: HashSeqBuilder + Clone> ConsistentHasher<H> {
203+
impl<H: HashSeqBuilder> ConsistentHasher<H> {
203204
pub fn new(builder: H) -> Self {
204205
Self { builder }
205206
}
206207

207-
pub fn prev(&self, n: usize) -> Option<usize> {
208+
pub fn prev(&self, n: usize) -> Option<usize>
209+
where
210+
H: Clone,
211+
{
208212
let mut sampler = ConsistentHashRevIterator::new(n, self.builder.clone());
209213
sampler.next()
210214
}
211215

212-
pub fn next(&self, n: usize) -> Option<usize> {
216+
pub fn next(&self, n: usize) -> Option<usize>
217+
where
218+
H: Clone,
219+
{
213220
let mut sampler = ConsistentHashIterator::new(n, self.builder.clone());
214221
sampler.next()
215222
}
223+
224+
pub fn into_prev(self, n: usize) -> Option<usize> {
225+
ConsistentHashRevIterator::new(n, self.builder).next()
226+
}
216227
}
217228

218229
/// Implementation of a consistent choose k hashing algorithm.
@@ -231,27 +242,38 @@ impl<H: ManySeqBuilder> ConsistentChooseKHasher<H> {
231242
Self { builder, k }
232243
}
233244

234-
// TODO: Implement this as an iterator!
235-
pub fn prev(&self, mut n: usize, samples: &mut Vec<usize>) {
236-
let mut samplers: Vec<_> = (0..self.k)
237-
.map(|i| ConsistentHashRevIterator::new(n - i, self.builder.seq_builder(i)).peekable())
238-
.collect();
245+
pub fn prev(&self, n: usize) -> Vec<usize> {
246+
let mut res = Vec::with_capacity(self.k);
247+
self.prev_with_vec(n, &mut res);
248+
res
249+
}
250+
251+
pub fn prev_with_vec(&self, mut n: usize, samples: &mut Vec<usize>) {
252+
assert!(n >= self.k, "n must be at least k");
239253
samples.clear();
254+
for i in 0..self.k {
255+
samples.push(
256+
ConsistentHasher::new(self.builder.seq_builder(i))
257+
.into_prev(n - i)
258+
.expect("must not fail")
259+
+ i,
260+
);
261+
}
240262
for i in (0..self.k).rev() {
241-
let mut max = 0;
242-
for k in 0..=i {
243-
while samplers[k].peek() >= Some(&(n - k)) && n - k > 0 {
244-
samplers[k].next();
263+
n = samples[0..=i].iter().copied().max().expect("");
264+
samples[i] = n;
265+
for j in 0..i {
266+
if samples[j] == n {
267+
samples[j] = ConsistentHasher::new(self.builder.seq_builder(j))
268+
.into_prev(n - j)
269+
.expect("must not fail")
270+
+ j;
245271
}
246-
max = max.max(samplers[k].peek().unwrap() + k);
247272
}
248-
samples.push(max);
249-
n = max;
250273
}
251274
}
252275
}
253276

254-
255277
#[cfg(test)]
256278
mod tests {
257279
use std::hash::DefaultHasher;
@@ -327,6 +349,7 @@ mod tests {
327349
}
328350
}
329351
println!("{stats:?}");
352+
assert_eq!(stats, vec![10, 12, 6, 6, 6, 5, 9, 10]);
330353
// Test consistency when increasing k!
331354
for k in 1..10 {
332355
for n in k + 1..20 {

0 commit comments

Comments
 (0)