Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,37 @@ impl<
self.shards.iter().map(|s| s.read().hits()).sum()
}

#[inline]
fn compute_shard_index(&self, hash: u64) -> u64 {
// Give preference to the bits in the middle of the hash. When choosing the
// shard, rotate the hash by usize::BITS / 2 so we avoid the lower bits and
// the highest 7 bits that hashbrown uses internally for probing, improving
// the real entropy available to each hashbrown shard.
hash.rotate_right(usize::BITS / 2) & self.shards_mask
}

/// Returns the shard index for the given key.
///
/// The returned index is guaranteed to be in `[0, num_shards())`.
///
/// # Use cases
///
/// - **Batching**: group keys by shard index before acquiring shard locks, so
/// each lock is taken only once per batch instead of once per key.
///
/// # Notes
///
/// The mapping from key to shard index depends on the [`BuildHasher`] supplied
/// at construction time. If two `Cache` instances are built with different
/// hashers, the same key may map to different shard indices.
///
/// [`BuildHasher`]: std::hash::BuildHasher
#[inline]
pub fn shard_index<Q: Hash + Equivalent<Key> + ?Sized>(&self, key: &Q) -> usize {
let hash = self.hash_builder.hash_one(key);
self.compute_shard_index(hash) as usize
}

#[inline]
fn shard_for<Q>(
&self,
Expand All @@ -220,11 +251,7 @@ impl<
Q: Hash + Equivalent<Key> + ?Sized,
{
let hash = self.hash_builder.hash_one(key);
// When choosing the shard, rotate the hash bits usize::BITS / 2 so that we
// give preference to the bits in the middle of the hash.
// Internally hashbrown uses the lower bits for start of probing + the 7 highest,
// so by picking something else we improve the real entropy available to each hashbrown shard.
let shard_idx = (hash.rotate_right(usize::BITS / 2) & self.shards_mask) as usize;
let shard_idx = self.compute_shard_index(hash) as usize;
self.shards.get(shard_idx).map(|s| (s, hash))
}

Expand Down