5 #ifndef CVMFS_SMALLHASH_H_
6 #define CVMFS_SMALLHASH_H_
8 #ifndef __STDC_FORMAT_MACROS
10 #define __STDC_FORMAT_MACROS
13 #include <gtest/gtest_prod.h>
33 template<
class Key,
class Value,
class Derived>
60 void Init(uint32_t expected_size, Key empty,
61 uint32_t (*hasher)(
const Key &key))
66 static_cast<uint32_t
>(
static_cast<double>(expected_size)/
kLoadFactor);
73 bool Lookup(
const Key &key, Value *value)
const {
76 const bool found =
DoLookup(key, &bucket, &collisions);
92 if (
keys_[bucket] == *key) {
105 const bool found =
DoLookup(key, &bucket, &collisions);
109 void Insert(
const Key &key,
const Value &value) {
110 static_cast<Derived *
>(
this)->
Grow();
111 const bool overwritten =
DoInsert(key, value,
true);
112 size_ += !overwritten;
118 const bool found =
DoLookup(key, &bucket, &collisions);
124 Key rehash =
keys_[bucket];
129 static_cast<Derived *
>(
this)->
Shrink();
140 const double unit =
sizeof(Key) +
sizeof(Value);
145 uint32_t *max_collisions)
const
166 static_cast<double>(
static_cast<uint32_t
>(-1)));
167 return static_cast<uint32_t
>(bucket) %
capacity_;
173 for (uint32_t i = 0; i <
capacity_; ++i) {
174 new (
keys_ + i) Key();
176 for (uint32_t i = 0; i <
capacity_; ++i) {
183 for (uint32_t i = 0; i < c; ++i) {
186 for (uint32_t i = 0; i < c; ++i) {
199 const bool count_collisions)
203 const bool overwritten =
DoLookup(key, &bucket, &collisions);
204 if (count_collisions) {
213 bool DoLookup(
const Key &key, uint32_t *bucket, uint32_t *collisions)
const {
217 if (
keys_[*bucket] == key)
253 template<
class Key,
class Value>
255 public SmallHashBase< Key, Value, SmallHashFixed<Key, Value> >
267 template<
class Key,
class Value>
269 public SmallHashBase< Key, Value, SmallHashDynamic<Key, Value> >
320 uint32_t target_capacity =
capacity() / 2;
338 static_cast<uint32_t *
>(smmap(N *
sizeof(uint32_t)));
340 for (
unsigned i = 0; i < N; ++i)
343 for (
unsigned i = 0; i < N-1; ++i) {
344 const uint32_t swap_idx = i +
g_prng.
Next(N - i);
345 uint32_t tmp = shuffled[i];
346 shuffled[i] = shuffled[swap_idx];
347 shuffled[swap_idx] = tmp;
356 uint32_t old_size =
size();
362 if (new_capacity < old_capacity) {
364 for (uint32_t i = 0; i < old_capacity; ++i) {
367 old_values[shuffled_indices[i]]);
370 smunmap(shuffled_indices);
372 for (uint32_t i = 0; i < old_capacity; ++i) {
385 for (uint32_t i = 0; i < other.
capacity_; ++i) {
388 other.
values_[shuffled_indices[i]]);
391 smunmap(shuffled_indices);
405 template<
class Key,
class Value>
415 uint32_t (*hasher)(
const Key &key))
422 static_cast<pthread_mutex_t *
>(smalloc(N *
sizeof(pthread_mutex_t)));
423 for (uint8_t i = 0; i < N; ++i) {
424 int retval = pthread_mutex_init(&locks_[i], NULL);
426 hashmaps_[i].Init(128, empty_key, hasher);
432 pthread_mutex_destroy(&
locks_[i]);
438 bool Lookup(
const Key &key, Value *value) {
441 const bool result =
hashmaps_[target].Lookup(key, value);
446 void Insert(
const Key &key,
const Value &value) {
482 hashmaps_[i].GetCollisionStats(&num_collisions[i], &max_collisions[i]);
489 uint32_t hash =
MurmurHash2(&key,
sizeof(key), 0x37);
491 static_cast<double>(hash) * static_cast<double>(
num_hashmaps_) /
492 static_cast<double>(
static_cast<uint32_t
>(-1));
496 inline void Lock(
const uint8_t target) {
497 int retval = pthread_mutex_lock(&
locks_[target]);
501 inline void Unlock(
const uint8_t target) {
502 int retval = pthread_mutex_unlock(&
locks_[target]);
513 template<
class Key,
class Value>
516 template<
class Key,
class Value,
class Derived>
519 template<
class Key,
class Value>
522 template<
class Key,
class Value>
525 #endif // CVMFS_SMALLHASH_H_
uint32_t capacity() const
SmallHashDynamic< Key, Value > * hashmaps_
void GetCollisionStats(uint64_t *num_collisions, uint32_t *max_collisions) const
uint32_t(* hasher_)(const Key &key)
void Unlock(const uint8_t target)
void Init(const uint8_t num_hashmaps, const Key &empty_key, uint32_t(*hasher)(const Key &key))
void Insert(const Key &key, const Value &value)
void GetSizes(uint32_t *sizes)
uint64_t bytes_allocated() const
uint32_t ScaleHash(const Key &key) const
assert((mem||(size==0))&&"Out Of Memory")
uint32_t * ShuffleIndices(const uint32_t N)
void CopyFrom(const SmallHashDynamic< Key, Value > &other)
static const double kThresholdGrow
bool Lookup(const Key &key, Value *value)
uint8_t SelectHashmap(const Key &key)
void Lock(const uint8_t target)
SmallHashDynamic(const SmallHashDynamic< Key, Value > &other)
uint32_t threshold_shrink_
bool LookupEx(Key *key, Value *value) const
static double GetEntrySize()
uint32_t capacity() const
void Insert(const Key &key, const Value &value)
static const double kThresholdGrow
uint64_t bytes_allocated_
void Erase(const Key &key)
static const double kLoadFactor
bool Contains(const Key &key) const
bool DoInsert(const Key &key, const Value &value, const bool count_collisions)
void DoClear(const bool reset_capacity)
void GetCollisionStats(uint64_t *num_collisions, uint32_t *max_collisions)
void SetHasher(uint32_t(*hasher)(const Key &key))
uint32_t num_migrates() const
bool Erase(const Key &key)
uint8_t num_hashmaps() const
FRIEND_TEST(T_Smallhash, InsertAndCopyMd5Slow)
SmallHashBase< Key, Value, SmallHashDynamic< Key, Value > > Base
uint32_t initial_capacity_
static const double kThresholdShrink
bool Lookup(const Key &key, Value *value) const
void DeallocMemory(Key *k, Value *v, uint32_t c)
void Init(uint32_t expected_size, Key empty, uint32_t(*hasher)(const Key &key))
bool DoLookup(const Key &key, uint32_t *bucket, uint32_t *collisions) const
void Migrate(const uint32_t new_capacity)
uint32_t MurmurHash2(const void *key, int len, uint32_t seed)
static const double kThresholdShrink
SmallHashDynamic< Key, Value > & operator=(const SmallHashDynamic< Key, Value > &other)
uint32_t Next(const uint64_t boundary)