From 97fec4179bb923bc09fae8348ab27b74c45a150e Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 30 May 2015 17:41:28 +0200 Subject: [PATCH] clean-up: remove cockoo hash (unused and unmaintained) Cockoo hashing is a thrilling algorithm. We investigated it during the time or our first draft towards a confirugation system in 2008. This usage turned up some problems -- not sure if based on the implementation or the algorithm itself; at that time, we just switched to the probabilistic splay tree. The whole configuration system effort stalled afterwards; so the cuckoo implementation remained in tree as a zombie. --- src/common/config-lookup.h | 2 +- src/lib/cuckoo.c | 528 ------------------------------ src/lib/cuckoo.h | 197 ----------- tests/library/c-lib/test-psplay.c | 12 +- 4 files changed, 2 insertions(+), 737 deletions(-) delete mode 100644 src/lib/cuckoo.c delete mode 100644 src/lib/cuckoo.h diff --git a/src/common/config-lookup.h b/src/common/config-lookup.h index a6816813c..ad512b354 100644 --- a/src/common/config-lookup.h +++ b/src/common/config-lookup.h @@ -142,7 +142,7 @@ lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key) -/* Lookup hash entries for the cuckoo hash */ +/* == lookup hash entries using the PSplay tree */ /** @internal Structure defining single hash table entries.*/ diff --git a/src/lib/cuckoo.c b/src/lib/cuckoo.c deleted file mode 100644 index 4b3a2cbee..000000000 --- a/src/lib/cuckoo.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - A cuckoo hash implementation - - Copyright (C) - 2008, Christian Thaeter - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "cuckoo.h" - -#include - -#define CUCKOO_GRANULARITY int - -enum compact_state - { - COMPACTING_OFF, - COMPACTING_AUTO, - COMPACTED - }; - -struct cuckoo_struct -{ - size_t size; /* t1 = 4*size; t2 = 2*size; t3 = size */ - size_t itemsize; - - struct cuckoo_vtable vtable; - - uint32_t r1; /* random, reset for each rehash */ - uint32_t r2; - uint32_t r3; - - void* t1; - void* t2; - void* t3; - - unsigned maxloops; /* sqrt (4 * size) */ - - enum compact_state autocompact; - size_t elements; -}; - - -static inline uint32_t cuckoo_fast_prng () -{ - static uint32_t rnd = 0xbabeface; - return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1); -} - -static inline int -iszero (void* mem, size_t size) -{ - while (size && !*(CUCKOO_GRANULARITY*)mem) - { - size -= sizeof (CUCKOO_GRANULARITY); - mem += sizeof (CUCKOO_GRANULARITY); - } - return !size; -} - -static inline void -xmemmov (void* dst, void* src, size_t size) -{ - while (size) - { - size -= sizeof (CUCKOO_GRANULARITY); - *(CUCKOO_GRANULARITY*)(dst + size) = *(CUCKOO_GRANULARITY*)(src + size); - } -} - - -Cuckoo -cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable) -{ - if (!self) - return NULL; - - self->size = 16; - self->itemsize = (itemsize * sizeof (CUCKOO_GRANULARITY) - + sizeof (CUCKOO_GRANULARITY) - 1) / sizeof (CUCKOO_GRANULARITY); /* round up to next CUCKOO_GRANULARITY boundary */ - self->r1 = cuckoo_fast_prng (); - self->r2 = cuckoo_fast_prng (); - self->r3 = cuckoo_fast_prng (); - - if (!vtable->h1 || !vtable->h2 || !vtable->h3) - return NULL; - - self->vtable.h1 = vtable->h1; - self->vtable.h2 = vtable->h2; - self->vtable.h3 = vtable->h3; - - if (!vtable->cmp) - return NULL; - - self->vtable.cmp = vtable->cmp; - - self->vtable.dtor = vtable->dtor; - - if (vtable->mov) - self->vtable.mov = vtable->mov; - else - self->vtable.mov = xmemmov; - - self->t1 = calloc (self->size * 4, itemsize); - self->t2 = calloc (self->size * 2, itemsize); - self->t3 = calloc (self->size, itemsize); - if (!self->t1 || !self->t2 || !self->t3) - { - free (self->t1); - free (self->t2); - free (self->t3); - return NULL; - } - - self->maxloops = 1; - while (self->maxloops * self->maxloops < self->size * 4) - ++self->maxloops; - - self->autocompact = COMPACTING_AUTO; - self->elements = 0; - - return self; -} - -Cuckoo -cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable) -{ - Cuckoo self = malloc (sizeof (struct cuckoo_struct)); - if (!cuckoo_init (self, itemsize, vtable)) - { - free (self); - return NULL; - } - return self; -} - -Cuckoo -cuckoo_destroy (Cuckoo self) -{ - if (self) - { - - if (self->vtable.dtor) - { - void* elem; - for (elem = self->t1; elem < self->t1 + self->size * 4; elem += self->size) - self->vtable.dtor (elem); - for (elem = self->t2; elem < self->t1 + self->size * 2; elem += self->size) - self->vtable.dtor (elem); - for (elem = self->t3; elem < self->t1 + self->size; elem += self->size) - self->vtable.dtor (elem); - } - - free (self->t1); - free (self->t2); - free (self->t3); - } - return self; -} - - -void -cuckoo_delete (Cuckoo self) -{ - free (cuckoo_destroy (self)); -} - - -static void* -cuckoo_insert_internal_ (Cuckoo self, void* item) -{ - void* pos; - CUCKOO_GRANULARITY tmp[self->itemsize / sizeof(CUCKOO_GRANULARITY)]; - - for (unsigned n = 0; n < self->maxloops; ++n) - { - /* find nest */ - pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size)); - /* kick old egg out */ - if (iszero (pos, self->itemsize)) - memset (tmp, 0, self->itemsize); - else - self->vtable.mov (tmp, pos, self->itemsize); - /* lay egg */ - self->vtable.mov (pos, item, self->itemsize); - - if (iszero (tmp, self->itemsize)) - return pos; - - /* find nest */ - pos = self->t2 + self->itemsize * (self->vtable.h2 (tmp, self->r2) % (2*self->size)); - /* kick old egg out */ - self->vtable.mov (item, pos, self->itemsize); - /* lay egg */ - self->vtable.mov (pos, tmp, self->itemsize); - - if (iszero (item, self->itemsize)) - return pos; - - /* find nest */ - pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size); - /* kick old egg out */ - self->vtable.mov (tmp, pos, self->itemsize); - /* lay egg */ - self->vtable.mov (pos, item, self->itemsize); - - if (iszero (tmp, self->itemsize)) - return pos; - - /* copy tmp to item, which will be reinserted on next interation / after rehashing */ - self->vtable.mov (item, tmp, self->itemsize); - } - return NULL; -} - - -size_t -cuckoo_nelements (Cuckoo self) -{ - return self->elements; -} - - -static void -cuckoo_rehash (Cuckoo self) -{ - retry1: - - self->r1 = cuckoo_fast_prng (); - - for (size_t i = 0; i < 4*self->size; ++i) - { - unsigned n; - void* pos = self->t1 + self->itemsize * i; - if (!iszero (pos, self->itemsize)) - { - for (n = 0; n < self->maxloops; ++n) - { - unsigned hash = self->vtable.h1 (pos, self->r1) % (4*self->size); - if (hash != i) - { - char t[self->itemsize]; - void* hpos = self->t1 + self->itemsize * hash; - self->vtable.mov (t, hpos, self->itemsize); - self->vtable.mov (hpos, pos, self->itemsize); - self->vtable.mov (pos, t, self->itemsize); - if (iszero (t, self->itemsize)) - break; - } - else - break; - } - if (n == self->maxloops) - goto retry1; - } - } - - retry2: - self->r2 = cuckoo_fast_prng (); - - for (size_t i = 0; i < 2*self->size; ++i) - { - unsigned n; - void* pos = self->t2 + self->itemsize * i; - if (!iszero (pos, self->itemsize)) - { - for (n = 0; n < self->maxloops; ++n) - { - unsigned hash = self->vtable.h2 (pos, self->r2) % (2*self->size); - if (hash != i) - { - char t[self->itemsize]; - void* hpos = self->t2 + self->itemsize * hash; - self->vtable.mov (t, hpos, self->itemsize); - self->vtable.mov (hpos, pos, self->itemsize); - self->vtable.mov (pos, t, self->itemsize); - if (iszero (t, self->itemsize)) - break; - } - else - break; - } - if (n == self->maxloops) - goto retry2; - } - } - - retry3: - self->r3 = cuckoo_fast_prng (); - - for (size_t i = 0; i < self->size; ++i) - { - unsigned n; - void* pos = self->t3 + self->itemsize * i; - if (!iszero (pos, self->itemsize)) - { - for (n = 0; n < self->maxloops; ++n) - { - unsigned hash = self->vtable.h3 (pos, self->r3) % self->size; - if (hash != i) - { - char t[self->itemsize]; - void* hpos = self->t3 + self->itemsize * hash; - self->vtable.mov (t, hpos, self->itemsize); - self->vtable.mov (hpos, pos, self->itemsize); - self->vtable.mov (pos, t, self->itemsize); - if (iszero (t, self->itemsize)) - break; - } - else - break; - } - if (n == self->maxloops) - goto retry3; - } - } -} - -static int -cuckoo_grow (Cuckoo self) -{ - /* rotate hashfuncs, tables, randoms */ - cuckoo_hashfunc th = self->vtable.h3; - self->vtable.h3 = self->vtable.h2; - self->vtable.h2 = self->vtable.h1; - self->vtable.h1 = th; - - uint32_t tr = self->r3; - self->r3 = self->r2; - self->r2 = self->r1; - self->r1 = tr; - - void* tt = self->t3; - self->t3 = self->t2; - self->t2 = self->t1; - - /* double new base size */ - self->size *= 2; - while (self->maxloops * self->maxloops < self->size * 4) - ++self->maxloops; - - /* alloc new t1 */ - self->t1 = calloc (self->size * 4, self->itemsize); - if (!self->t1) - { - self->t1 = tt; - return 0; - } - - /* reinsert tt */ - size_t ttsize = self->size / 2; - for (size_t i = 0; i < ttsize; ++i) - { - void* pos = tt + i * self->itemsize; - if (!iszero (pos, self->itemsize)) - { - while (!cuckoo_insert_internal_ (self, pos)) - cuckoo_rehash (self); - } - } - free (tt); - - self->autocompact = COMPACTING_AUTO; - return 1; -} - - -int -cuckoo_reserve (Cuckoo self, size_t more) -{ - int ret = 1; - if (more) - while (self->elements+self->maxloops+more >= 6*self->size) - ret = cuckoo_grow (self); - - self->autocompact = COMPACTING_OFF; - return ret; -} - - -int -cuckoo_compact (Cuckoo self) -{ - if (self->autocompact == COMPACTED) - return 1; - - if (self->size > 2 && self->elements < self->size * 3) - { - cuckoo_hashfunc th = self->vtable.h1; - self->vtable.h1 = self->vtable.h2; - self->vtable.h2 = self->vtable.h3; - self->vtable.h3 = th; - - uint32_t tr = self->r1; - self->r1 = self->r2; - self->r2 = self->r3; - self->r3 = tr; - - void* tt = self->t1; - self->t1 = self->t2; - self->t2 = self->t3; - - /* halve base size */ - self->size /= 2; - while (self->maxloops * self->maxloops >= self->size * 4) - --self->maxloops; - - /* alloc new t3 */ - self->t3 = calloc (self->size, self->itemsize); - if (!self->t3) - { - self->t3 = tt; - return 0; - } - - /* reinsert tt */ - size_t ttsize = self->size * 8; - for (size_t i = 0; i < ttsize; ++i) - { - void* pos = tt + i * self->itemsize; - if (!iszero (pos, self->itemsize)) - { - --self->elements; - cuckoo_insert (self, pos); - } - } - free (tt); - self->autocompact = COMPACTED; - } - return 1; -} - - -void* -cuckoo_insert (Cuckoo self, void* item) -{ - char tmp[self->itemsize]; - - void* found; - if ((found = cuckoo_find (self, item))) - { - if (self->vtable.dtor) - self->vtable.dtor (found); - self->vtable.mov (found, item, self->itemsize); - return found; - } - - self->vtable.mov (tmp, item, self->itemsize); - - for (unsigned n = 6; n; --n) /* rehash/grow loop */ - { - if ((found = cuckoo_insert_internal_ (self, tmp))) - { - ++self->elements; - return found; - } - - if (self->elements > n*self->size) - { - n = 6; - if (!cuckoo_grow (self)) - return NULL; - } - else - cuckoo_rehash (self); - } - return NULL; -} - - -void* -cuckoo_find (Cuckoo self, void* item) -{ - void* pos; - - pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size)); - if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos)) - return pos; - - pos = self->t2 + self->itemsize * (self->vtable.h2 (item, self->r2) % (2*self->size)); - if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos)) - return pos; - - pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size); - if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos)) - return pos; - - return NULL; -} - - -void -cuckoo_remove (Cuckoo self, void* item) -{ - if (item) - { - if (self->vtable.dtor) - self->vtable.dtor (item); - - memset (item, 0, self->itemsize); - --self->elements; - - if (self->autocompact == COMPACTING_AUTO && self->size > 2 && self->elements <= self->size*2) - cuckoo_compact (self); - } -} - - -/* -// Local Variables: -// mode: C -// c-file-style: "gnu" -// indent-tabs-mode: nil -// End: -*/ diff --git a/src/lib/cuckoo.h b/src/lib/cuckoo.h deleted file mode 100644 index cb7abf371..000000000 --- a/src/lib/cuckoo.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - A cuckoo hash implementation - - Copyright (C) - 2008, Christian Thaeter - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -#ifndef CUCKOO_H -#define CUCKOO_H - -/** - * @file - * Cuckoo hashing - * This hashing gives guaranteed O(1) lookup complexity and amortized O(1) insert and remove complexity. - * Hash tables by default grow and shrink automatically. It is posible to preallocate entries and turn - * automatic shrinking off taking out the memory management factors for insert and remove operations. - * This implementation uses 3 Tables which exponential growing sizes. - */ - -#include -#include - -struct cuckoo_struct; -typedef struct cuckoo_struct * Cuckoo; - -/** - * Hash function. - * User supplied universal hash function - * @param item address of the item to be hashed - * @param r pseudo random number, 31 significant bits, regenerated on each rehash - * @return hash value - */ -typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r); - -/** - * Compare function. - * User supplied compare function - * @param item1 address of the first item - * @param item2 address of the second item - * @return 1 when the items are identical, 0 otherwise - */ -typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2); - -/** - * Item destructor function. - * User supplied destructor function. This function is called when items are removed - * from the hash or at hash detroy/delete time. Must be safe to be called on a zeroed element. - * @param item address of the item to be destroyed - */ -typedef void (*cuckoo_dtorfunc)(void* item); - -/** - * Move function. - * User supplied item move function - * @param dest target address for the move operation - * @param src source for the move operation - * @param size size of a item (requested size rounded up to the next CUCKOO_GRANULARITY) - * It might be necessary to invalidate the source in some case, cuckoo will zero it out - * after moving. - */ -typedef void (*cuckoo_movfunc)(void* dest, void* src, size_t size); - - -/** - * Function table used to specialise various functions used by the hash. - * TODO some elements might be NULL, then defaults are used - */ -struct cuckoo_vtable -{ - cuckoo_hashfunc h1; - cuckoo_hashfunc h2; - cuckoo_hashfunc h3; - cuckoo_cmpfunc cmp; - cuckoo_dtorfunc dtor; - cuckoo_movfunc mov; -}; - - -/** - * Initialise a cuckoo hash. - * @param self pointer to a uninitialised cuckoo datastructure - * @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY - * @param vtable initialised vtable - * @return The initialised hashtable or NULL at allocation failure - */ -Cuckoo -cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable); - -/** - * Allocate a new cuckoo hash. - * @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY - * @param startsize initial size of table t3, as 2's exponent - * @param vtable initialised vtable - * @return The initialised hashtable or NULL at allocation failure - */ -Cuckoo -cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable); - - -/** - * Destroy a cuckoo hash. - * Frees internal used resources. - * @param self cuckoo hash to destroy - * @return The now uninitialised hashtable - */ -Cuckoo -cuckoo_destroy (Cuckoo self); - -/** - * Deallocate a cuckoo hash. - * @param self handle of the hash table to be freed - */ -void -cuckoo_delete (Cuckoo self); - -/** - * Get the number of elements stored in a hash. - * @return number of elements, 0 when empty - */ -size_t -cuckoo_nelements (Cuckoo self); - -/** - * Insert an element into a hash. - * amortized O(1) complexity because it may rarely rehash the tables or even grow them. - * see cuckoo_reserve() about how to preallocate entries to prevent the growing costs. - * Inserting an element already in the hash calls the dtor for the old entry and places - * the new one into the hash. - * @param self handle to the hash table - * @param item pointer to a item to be inserted - * @return pointer to inserted element on successful insert, NULL on allocation failure - * Note: at failure there is one arbitary hash cell lost! - */ -void* -cuckoo_insert (Cuckoo self, void* item); - -/** - * Find a value by key in a hash. - * @param self handle to the hash table - * @param item pointer to an item to be looked up - * @return found object or NULL if not present - */ -void* -cuckoo_find (Cuckoo self, void* item); - -/** - * Remove a item from a hash. - * amortized O(1) complexity when it automatically shrink its tables. - * guaranteed O(1) complexity when automatic shrinking is turned off. - * see cuckoo_reserve() about how turn automatic shrinking off. - * @param self handle to the hash table - * @param item pointer to the item to be removed - */ -void -cuckoo_remove (Cuckoo self, void* item); - -/** - * Shrink the hash sizes when possible and turn autocompacting on. - * only useful when autmatic shrinking is turned off. - * see cuckoo_reserve() about how turn shrinking off. - * @param self handle to the hash table - */ -int -cuckoo_compact (Cuckoo self); - -/** - * Prereserve hash entries and turn autocompacting off. - * @param self handle to the hash table - * @param more number of entries to be additionally reserved - * In rare circumstances inserting into a hash which has reserved some entries - * it may still need to rehash (or even rarer) to grow the table. - * While autocompacting is turned off, removing is completely O(1). - */ -int -cuckoo_reserve (Cuckoo self, size_t more); - -#endif -/* -// Local Variables: -// mode: C -// c-file-style: "gnu" -// indent-tabs-mode: nil -// End: -*/ diff --git a/tests/library/c-lib/test-psplay.c b/tests/library/c-lib/test-psplay.c index dd652d5bb..dc50bb548 100644 --- a/tests/library/c-lib/test-psplay.c +++ b/tests/library/c-lib/test-psplay.c @@ -402,9 +402,7 @@ TESTS_END -/* - cuckoo support functions -*/ +/* === PSplay support functions === */ static int cmp_fn (const void* a, const void* b) @@ -431,10 +429,6 @@ delete_fn (PSplaynode node) } -//static psplay_delete_fn -//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data) -//{ -//} static int @@ -455,10 +449,6 @@ fdelete_fn (PSplaynode node) testitem_delete ((TestItem) node); } -//static psplay_delete_fn -//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data) -//{ -//}