Implementing a KVS - Hash table implementations (4-2)
2- A deep dive into the hash function implementations in pre-existing Key-Value stores:Ā
GCC offers a hash table library called unordered_map in TR1, and It basically is very similar to Javaās implementation of a hashtable, in the sense that every (key, value) pair
The next attribute here helps with the collision handling: just like Java, if two keys have the same hashcode, we have a linked list structure where we store the pairs with the same hashcode for their keys.Ā
(PS: we store both the key and the value, donāt bother me with the wholeĀ āhow would i know which value corresponds to my key).
I found this figure in Emmanuelās blog which describes how the hash table is stored in the heap, and as you can see there are memory spaces calledĀ āNodeā which means we have space where we store a pointer to the actual (key,value) pair.Ā
Google offers a hash table library called dense_hash_map in SparseHash v2.0.2. This hash table structure is more interesting than the latter since, first of all, we donāt lose a bunch of space just writing addresses. We also donāt use linked list to handle collisions, we use quadratic internal probing in case of collisions, and in terms of locality, itās better than the linked list structure since in every cache line we have 64 bytes and every pair is 16 bytes long, so we can very likely find the pair weāre looking for on the same line (see quadratic internal probing formula here).
Both of the previous hash table implementations are in-memory, which isnāt what weāre going to be implementing ourselves. But It was still interesting to see how It works.
Now on to something similar to what weāll be doing, HashDb from Kyoto Cabinet.
So HashDB is one of the data structures KC developed, itās persistent on-disk and it uses separate chaining through a BST for every bucket. AND, the bucket array has a fixed size, so no matter how bad the load factor is, you can never change that and youāre just going to suffer.
Itās not impossible, but itās costly, since everything is stored on disk and re-hashing the keys after resizing the bucket array will require access to the disk for all the keys, and once you have so many entries, basically, trying to do this is a death wish. You can store the hashed keys, but that comes down to a space/time compromise, so Kyoto Cabinet just thoughtĀ āfk allā and fixed the bucket arrayās size.
Of course, the BST needs a comparable type to classify the nodes, so they use a function called fold_hash which helps with that (honest to God, I didnāt get it; itās meant to make these keys ācomparableā, but the function seems to apply operations on the same hash so itās kinda like...not doing anything? Anyways, letās hope Emmanuel answers my question on his blog post about this.
An extra cool thing about HashDB, even though It can be a total pain when we have collisions and weāll have to find the correct pair..., is that memory management should be handled by KC and not the OS, like Itās the case for dense_hash_map and unordered_map. So, we actually store everything in a file and we also have as to where the free blocks of space are (we have the offset, the size of this space).Ā
These free blocks are allocated using std::setās upper_bound method, which will return the closest free space possible.