dbms: development [#CONV-2944].

This commit is contained in:
Alexey Milovidov 2011-12-19 07:00:15 +00:00
parent d7aa5b5fa6
commit 9e273e4d24
3 changed files with 59 additions and 18 deletions

View File

@ -39,7 +39,8 @@ struct UInt128
struct UInt128Hash struct UInt128Hash
{ {
size_t operator()(UInt128 x) const { return x.first ^ x.second; } default_hash<UInt64> hash64;
size_t operator()(UInt128 x) const { return hash64(x.first ^ 0xB15652B8790A0D36ULL) ^ hash64(x.second); }
}; };
struct UInt128ZeroTraits struct UInt128ZeroTraits

View File

@ -27,12 +27,31 @@ namespace DB
* - проитерироваться по имеющимся в ней значениям. * - проитерироваться по имеющимся в ней значениям.
* *
* Open addressing. * Open addressing.
* Quadratic probing (пока ещё не уверен, что оно не может зациклиться). * Linear probing (подходит, если хэш функция хорошая!).
* Значение с нулевым ключём хранится отдельно. * Значение с нулевым ключём хранится отдельно.
* Удаления элементов нет. * Удаления элементов нет.
*/ */
/** Хэш функции, которые лучше чем тривиальная функция std::tr1::hash.
*/
template <typename T> struct default_hash;
template <> struct default_hash<UInt64>
{
size_t operator() (UInt64 key) const
{
key = (~key) + (key << 18);
key = key ^ ((key >> 31) | (key << 33));
key = key * 21;
key = key ^ ((key >> 11) | (key << 53));
key = key + (key << 6);
key = key ^ ((key >> 22) | (key << 42));
return key;
}
};
/** Способ проверить, что ключ нулевой, /** Способ проверить, что ключ нулевой,
* а также способ установить значение ключа в ноль. * а также способ установить значение ключа в ноль.
*/ */
@ -47,7 +66,7 @@ template
< <
typename Key, typename Key,
typename Mapped, typename Mapped,
typename Hash = std::tr1::hash<Key>, typename Hash = default_hash<Key>,
typename ZeroTraits = default_zero_traits<Key>, typename ZeroTraits = default_zero_traits<Key>,
int INITIAL_SIZE_DEGREE = 16, /** Изначально выделить кусок памяти для 64K элементов. int INITIAL_SIZE_DEGREE = 16, /** Изначально выделить кусок памяти для 64K элементов.
* Уменьшите значение для лучшей кэш-локальности в случае маленького количества уникальных ключей. * Уменьшите значение для лучшей кэш-локальности в случае маленького количества уникальных ключей.
@ -72,6 +91,9 @@ private:
Hash hash; Hash hash;
#ifdef DBMS_HASH_MAP_COUNT_COLLISIONS
mutable size_t collisions;
#endif
inline size_t buf_size() const { return 1 << size_degree; } inline size_t buf_size() const { return 1 << size_degree; }
inline size_t max_fill() const { return 1 << (size_degree - 1); } inline size_t max_fill() const { return 1 << (size_degree - 1); }
@ -105,12 +127,13 @@ private:
void reinsert(const Value & x) void reinsert(const Value & x)
{ {
size_t place_value = place(hash(x.first)); size_t place_value = place(hash(x.first));
unsigned increment = 1;
while (!ZeroTraits::check(buf[place_value].first)) while (!ZeroTraits::check(buf[place_value].first))
{ {
place_value += increment; ++place_value;
++increment;
place_value &= mask(); place_value &= mask();
#ifdef DBMS_HASH_MAP_COUNT_COLLISIONS
++collisions;
#endif
} }
memcpy(&buf[place_value], &x, sizeof(x)); memcpy(&buf[place_value], &x, sizeof(x));
} }
@ -129,6 +152,9 @@ public:
{ {
ZeroTraits::set(zero_value()->first); ZeroTraits::set(zero_value()->first);
buf = reinterpret_cast<Value*>(calloc(buf_size(), sizeof(Value))); buf = reinterpret_cast<Value*>(calloc(buf_size(), sizeof(Value)));
#ifdef DBMS_HASH_MAP_COUNT_COLLISIONS
collisions = 0;
#endif
} }
~HashMap() ~HashMap()
@ -250,12 +276,13 @@ public:
} }
size_t place_value = place(hash(x.first)); size_t place_value = place(hash(x.first));
unsigned increment = 1;
while (!ZeroTraits::check(buf[place_value].first) && buf[place_value].first != x.first) while (!ZeroTraits::check(buf[place_value].first) && buf[place_value].first != x.first)
{ {
place_value += increment; ++place_value;
++increment;
place_value &= mask(); place_value &= mask();
#ifdef DBMS_HASH_MAP_COUNT_COLLISIONS
++collisions;
#endif
} }
iterator res(this, &buf[place_value]); iterator res(this, &buf[place_value]);
@ -309,12 +336,13 @@ public:
} }
size_t place_value = place(hash(x)); size_t place_value = place(hash(x));
unsigned increment = 1;
while (!ZeroTraits::check(buf[place_value].first) && buf[place_value].first != x) while (!ZeroTraits::check(buf[place_value].first) && buf[place_value].first != x)
{ {
place_value += increment; ++place_value;
++increment;
place_value &= mask(); place_value &= mask();
#ifdef DBMS_HASH_MAP_COUNT_COLLISIONS
++collisions;
#endif
} }
it = iterator(this, &buf[place_value]); it = iterator(this, &buf[place_value]);
@ -343,12 +371,13 @@ public:
return has_zero ? begin() : end(); return has_zero ? begin() : end();
size_t place_value = place(hash(x)); size_t place_value = place(hash(x));
unsigned increment = 1;
while (!ZeroTraits::check(buf[place_value].first) && buf[place_value].first != x) while (!ZeroTraits::check(buf[place_value].first) && buf[place_value].first != x)
{ {
place_value += increment; ++place_value;
++increment;
place_value &= mask(); place_value &= mask();
#ifdef DBMS_HASH_MAP_COUNT_COLLISIONS
++collisions;
#endif
} }
return !ZeroTraits::check(buf[place_value].first) ? iterator(this, &buf[place_value]) : end(); return !ZeroTraits::check(buf[place_value].first) ? iterator(this, &buf[place_value]) : end();
@ -361,12 +390,13 @@ public:
return has_zero ? begin() : end(); return has_zero ? begin() : end();
size_t place_value = place(hash(x.first)); size_t place_value = place(hash(x.first));
unsigned increment = 1;
while (!ZeroTraits::check(buf[place_value].first) && buf[place_value].first != x) while (!ZeroTraits::check(buf[place_value].first) && buf[place_value].first != x)
{ {
place_value += increment; ++place_value;
++increment;
place_value &= mask(); place_value &= mask();
#ifdef DBMS_HASH_MAP_COUNT_COLLISIONS
++collisions;
#endif
} }
return !ZeroTraits::check(buf[place_value].first) ? const_iterator(this, &buf[place_value]) : end(); return !ZeroTraits::check(buf[place_value].first) ? const_iterator(this, &buf[place_value]) : end();
@ -382,6 +412,13 @@ public:
{ {
return 0 == m_size; return 0 == m_size;
} }
#ifdef DBMS_HASH_MAP_COUNT_COLLISIONS
size_t getCollisions() const
{
return collisions;
}
#endif
}; };
} }

View File

@ -9,6 +9,8 @@
#include <statdaemons/Stopwatch.h> #include <statdaemons/Stopwatch.h>
#define DBMS_HASH_MAP_COUNT_COLLISIONS
#include <DB/Core/Types.h> #include <DB/Core/Types.h>
#include <DB/IO/ReadBufferFromFile.h> #include <DB/IO/ReadBufferFromFile.h>
#include <DB/IO/CompressedReadBuffer.h> #include <DB/IO/CompressedReadBuffer.h>
@ -80,6 +82,7 @@ int main(int argc, char ** argv)
<< "DB::HashMap. Size: " << map.size() << "DB::HashMap. Size: " << map.size()
<< ", elapsed: " << watch.elapsedSeconds() << ", elapsed: " << watch.elapsedSeconds()
<< " (" << n / watch.elapsedSeconds() << " elem/sec.)" << " (" << n / watch.elapsedSeconds() << " elem/sec.)"
<< ", collisions: " << map.getCollisions()
<< std::endl; << std::endl;
} }