diff --git a/include/maxscale/hashtable.h b/include/maxscale/hashtable.h deleted file mode 100644 index 6061d7f78..000000000 --- a/include/maxscale/hashtable.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2018 MariaDB Corporation Ab - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file and at www.mariadb.com/bsl11. - * - * Change Date: 2022-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2 or later of the General - * Public License. - */ - #pragma once - -/** - * @file hashtable.h A general purpose hashtable mechanism for use within the - * gateway - */ -#include -#include -#include - -MXS_BEGIN_DECLS - -/** - * The entries within a hashtable. - * - * A NULL value for key indicates an empty entry. - * The next pointer is the overflow chain for this hashentry. - */ -typedef struct hashentry -{ - void *key; /**< The value of the key or NULL if empty entry */ - void *value; /**< The value associated with key */ - struct hashentry *next; /**< The overflow chain */ -} HASHENTRIES; - -/** - * HASHTABLE iterator - used to walk the hashtable in a thread safe - * way - */ -typedef struct hashiterator -{ - struct hashtable *table; /**< The hashtable the iterator refers to */ - int chain; /**< The current chain we are walking */ - int depth; /**< The current depth down the chain */ -} HASHITERATOR; - -/** - * The type definition for the hash function - */ -typedef int (*HASHHASHFN)(const void *); - -/** - * The type definition for the comparison function - */ -typedef int (*HASHCMPFN)(const void *, const void *); - -/** - * The type definition for the key/value copying functions - */ -typedef void *(*HASHCOPYFN)(const void *); - -/** - * The type definition for the key/value freeing functions - */ -typedef void (*HASHFREEFN)(void *); - -/** - * The general purpose hashtable struct. - */ -typedef struct hashtable -{ - int hashsize; /**< The number of HASHENTRIES */ - HASHENTRIES **entries; /**< The entries themselves */ - HASHHASHFN hashfn; /**< The hash function */ - HASHCMPFN cmpfn; /**< The key comparison function */ - HASHCOPYFN kcopyfn; /**< Optional key copy function */ - HASHCOPYFN vcopyfn; /**< Optional value copy function */ - HASHFREEFN kfreefn; /**< Optional key free function */ - HASHFREEFN vfreefn; /**< Optional value free function */ - SPINLOCK spin; /**< Internal spinlock for the hashtable */ - int n_readers; /**< Number of clients reading the table */ - int writelock; /**< The table is locked by a writer */ - bool ht_isflat; /**< Indicates whether hashtable is in stack or heap */ - int n_elements; /**< Number of added elements */ -} HASHTABLE; - -extern HASHTABLE *hashtable_alloc(int, HASHHASHFN hashfn, HASHCMPFN cmpfn); -HASHTABLE *hashtable_alloc_flat(HASHTABLE* target, - int size, - HASHHASHFN hashfn, - HASHCMPFN cmpfn); -/**< Allocate a hashtable */ -extern void hashtable_memory_fns(HASHTABLE *table, - HASHCOPYFN kcopyfn, - HASHCOPYFN vcopyfn, - HASHFREEFN kfreefn, - HASHFREEFN vfreefn); -/**< Provide an interface to control key/value memory - * manipulation - */ -extern void hashtable_free(HASHTABLE *); /**< Free a hashtable */ -extern int hashtable_add(HASHTABLE *, void *, void *); /**< Add an entry */ -extern int hashtable_delete(HASHTABLE *, void *); -/**< Delete an entry table */ -extern void *hashtable_fetch(HASHTABLE *, void *); -/**< Fetch the data for a given key */ -extern void hashtable_stats(HASHTABLE *); /**< Print statisitics */ -void hashtable_get_stats(void* hashtable, - int* hashsize, - int* nelems, - int* longest); -extern int hashtable_save(HASHTABLE *, - const char *filename, - int (*keywrite)(int, void*), - int (*valuewrite)(int, void*)); -extern int hashtable_load(HASHTABLE *, - const char *filename, - void *(*keyread)(int), - void *(*valueread)(int)); - -extern HASHITERATOR *hashtable_iterator(HASHTABLE *); -/**< Allocate an iterator on the hashtable */ -extern void *hashtable_next(HASHITERATOR *); -/**< Return the key of the hash table iterator */ -extern void hashtable_iterator_free(HASHITERATOR *); -extern int hashtable_size(HASHTABLE *table); - -extern void hashtable_item_free(void *data); -extern int hashtable_item_strcasecmp(const void* str1, const void* str2); -extern int hashtable_item_strcmp(const void* str1, const void* str2); -extern void* hashtable_item_strdup(const void *str); -extern int hashtable_item_strhash(const void *str); - -MXS_END_DECLS diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 630c42590..2d3f7ce9b 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -12,7 +12,6 @@ add_library(maxscale-common SHARED event.cc externcmd.cc filter.cc - hashtable.cc hint.cc housekeeper.cc httprequest.cc diff --git a/server/core/hashtable.cc b/server/core/hashtable.cc deleted file mode 100644 index ef0f39943..000000000 --- a/server/core/hashtable.cc +++ /dev/null @@ -1,921 +0,0 @@ -/* - * Copyright (c) 2016 MariaDB Corporation Ab - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file and at www.mariadb.com/bsl11. - * - * Change Date: 2022-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2 or later of the General - * Public License. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * @file hashtable.c General purpose hashtable routines - * - * The hashtable can be create with a custom number of hash buckets, - * a hash function and optional functions to call make copies of the key - * and value and to free them. - * - * The hashtable is arrange as a set of linked lists, the number of linked - * lists being the hashsize as requested by the user. Entries are hashed by - * calling the hash function that is passed in by the user, this is used as - * an index into the array of linked lists, usign modulo hashsize. - * - * The linked lists are searched using the key comparison function that is - * passed into the hash table creation routine. - * - * By default the hash table keeps the original pointers that are passed in - * for the keys and values, however two functions can be supplied to copy these - * a copy function and a free function. Please note the same function is used for - * the key and the value, if the actions required are different the called functions - * must understand how to differenate the key and value. - * - * The hash table implements a single write, multiple reader locking policy by - * using a pair of counters and a spinlock. The spinlock is used to protect the - * number of readers and writers counters when taking out locks. Releasing of - * locks uses pure atomic actions and thus does not require spinlock protection. - * - * @verbatim - * Revision History - * - * Date Who Description - * 23/06/2013 Mark Riddoch Initial implementation - * 23/07/2013 Mark Riddoch Addition of hashtable iterator - * 08/01/2014 Massimiliano Pinto Added copy and free funtion pointers for keys and values: - * it's possible to copy and free different data types via - * kcopyfn/kfreefn, vcopyfn/vfreefn - * 06/02/2015 Mark Riddoch Addition of hashtable_save and hashtable_load - * - * @endverbatim - */ - -static void hashtable_read_lock(HASHTABLE *table); -static void hashtable_read_unlock(HASHTABLE *table); -static void hashtable_write_lock(HASHTABLE *table); -static void hashtable_write_unlock(HASHTABLE *table); -static HASHTABLE *hashtable_alloc_real(HASHTABLE* target, - int size, - HASHHASHFN hashfn, - HASHCMPFN cmpfn); - -/** - * Special identity function used as default key/value copy function in the hashtable - * implementation. This avoids having to special case the code that manipulates - * the keys and values - * - * @param data The data pointer - * @return Return the value we were called with - */ -static void * -identityfn(const void *data) -{ - return (void*)data; -} - -/** - * Special null function used as default free function in the hashtable - * implementation. This avoids having to special case the code that manipulates - * the keys and values - * - * @param data The data pointer - */ -static void -nullfn(void *data) -{ -} - -/** - * Allocate a new hash table. - * - * The hashtable must have a size of at least one, however to be of any - * practical use a larger size sould be chosen as the size relates to the number - * of has buckets in the table. - * - * @param size The size of the hash table, msut be > 0 - * @param hashfn The user supplied hash function - * @param cmpfn The user supplied key comparison function - * @return The hashtable table - */ -HASHTABLE * -hashtable_alloc(int size, HASHHASHFN hashfn, HASHCMPFN cmpfn) -{ - return hashtable_alloc_real(NULL, size, hashfn, cmpfn); -} - -HASHTABLE* hashtable_alloc_flat(HASHTABLE* target, - int size, - HASHHASHFN hashfn, - HASHCMPFN cmpfn) -{ - return hashtable_alloc_real(target, size, hashfn, cmpfn); -} - -static HASHTABLE * -hashtable_alloc_real(HASHTABLE* target, - int size, - HASHHASHFN hashfn, - HASHCMPFN cmpfn) -{ - HASHTABLE *rval; - - if (target == NULL) - { - if ((rval = (HASHTABLE*)MXS_MALLOC(sizeof(HASHTABLE))) == NULL) - { - return NULL; - } - rval->ht_isflat = false; - } - else - { - rval = target; - rval->ht_isflat = true; - } - - rval->hashsize = size > 0 ? size : 1; - rval->hashfn = hashfn; - rval->cmpfn = cmpfn; - rval->kcopyfn = identityfn; - rval->vcopyfn = identityfn; - rval->kfreefn = nullfn; - rval->vfreefn = nullfn; - rval->n_readers = 0; - rval->writelock = 0; - rval->n_elements = 0; - spinlock_init(&rval->spin); - if ((rval->entries = (HASHENTRIES **)MXS_CALLOC(rval->hashsize, sizeof(HASHENTRIES *))) == NULL) - { - MXS_FREE(rval); - return NULL; - } - memset(rval->entries, 0, rval->hashsize * sizeof(HASHENTRIES *)); - - return rval; -} - -/** - * Delete an entire hash table - * - * @param table The hash table to delete - */ -void -hashtable_free(HASHTABLE *table) -{ - int i; - HASHENTRIES *entry, *ptr; - - if (table == NULL) - { - return; - } - - hashtable_write_lock(table); - for (i = 0; i < table->hashsize; i++) - { - entry = table->entries[i]; - while (entry) - { - ptr = entry->next; - table->kfreefn(entry->key); - table->vfreefn(entry->value); - MXS_FREE(entry); - entry = ptr; - } - } - MXS_FREE(table->entries); - - hashtable_write_unlock(table); - if (!table->ht_isflat) - { - MXS_FREE(table); - } -} - -/** - * Provide memory management functions to the hash table. This allows - * function pointers to be registered that can make copies of the - * key and value and free them as well. - * - * @param table The hash table - * @param kcopyfn The copy function for the key - * @param vcopyfn The copy function for the value - * @param kfreefn The free function for the key - * @param vfreefn The free function for the value - */ -void -hashtable_memory_fns(HASHTABLE *table, - HASHCOPYFN kcopyfn, - HASHCOPYFN vcopyfn, - HASHFREEFN kfreefn, - HASHFREEFN vfreefn) -{ - if (kcopyfn != NULL) - { - table->kcopyfn = kcopyfn; - } - if (vcopyfn != NULL) - { - table->vcopyfn = vcopyfn; - } - if (kfreefn != NULL) - { - table->kfreefn = kfreefn; - } - if (vfreefn != NULL) - { - table->vfreefn = vfreefn; - } -} - -/** - * Add an item to the hash table. - * - * @param table The hash table to which to add the item - * @param key The key of the item - * @param value The value for the item - * @return Return the number of items added - */ -int -hashtable_add(HASHTABLE *table, void *key, void *value) -{ - unsigned int hashkey; - HASHENTRIES *entry; - - if (table == NULL || key == NULL || value == NULL) - { - return 0; - } - - if (table->hashsize <= 0) - { - return 0; - } - else - { - hashkey = table->hashfn(key) % table->hashsize; - } - hashtable_write_lock(table); - entry = table->entries[hashkey % table->hashsize]; - while (entry && table->cmpfn(key, entry->key) != 0) - { - entry = entry->next; - } - if (entry && table->cmpfn(key, entry->key) == 0) - { - /* Duplicate key value */ - hashtable_write_unlock(table); - return 0; - } - else - { - HASHENTRIES *ptr = (HASHENTRIES *)MXS_MALLOC(sizeof(HASHENTRIES)); - if (ptr == NULL) - { - hashtable_write_unlock(table); - return 0; - } - - /* copy the key */ - ptr->key = table->kcopyfn(key); - - /* check succesfull key copy */ - if (ptr->key == NULL) - { - MXS_FREE(ptr); - hashtable_write_unlock(table); - - return 0; - } - - /* copy the value */ - ptr->value = table->vcopyfn(value); - - /* check succesfull value copy */ - if (ptr->value == NULL) - { - /* remove the key ! */ - table->kfreefn(ptr->key); - MXS_FREE(ptr); - - /* value not copied, return */ - hashtable_write_unlock(table); - - return 0; - } - - ptr->next = table->entries[hashkey % table->hashsize]; - table->entries[hashkey % table->hashsize] = ptr; - } - table->n_elements++; - hashtable_write_unlock(table); - - return 1; -} - -/** - * Delete an item from the hash table that has a given key - * - * @param table The hash table to delete from - * @param key The key value of the item to remove - * @return Return the number of items deleted - */ -int -hashtable_delete(HASHTABLE *table, void *key) -{ - unsigned int hashkey; - HASHENTRIES *entry, *ptr; - - if (table == NULL || key == NULL) - { - return 0; - } - - hashkey = table->hashfn(key) % table->hashsize; - hashtable_write_lock(table); - entry = table->entries[hashkey % table->hashsize]; - while (entry && entry->key && table->cmpfn(key, entry->key) != 0) - { - entry = entry->next; - } - if (entry == NULL) - { - /* Not found */ - hashtable_write_unlock(table); - return 0; - } - - if (entry == table->entries[hashkey % table->hashsize]) - { - /* We are removing from the first entry */ - table->entries[hashkey % table->hashsize] = entry->next; - table->kfreefn(entry->key); - table->vfreefn(entry->value); - - if (entry->next != NULL) - { - entry->key = entry->next->key; - entry->value = entry->next->value; - } - else - { - entry->key = NULL; - entry->value = NULL; - } - MXS_FREE(entry); - } - else - { - ptr = table->entries[hashkey % table->hashsize]; - while (ptr && ptr->next != entry) - { - ptr = ptr->next; - } - if (ptr == NULL) - { - hashtable_write_unlock(table); - return 0; /* This should never happen */ - } - ptr->next = entry->next; - table->kfreefn(entry->key); - table->vfreefn(entry->value); - MXS_FREE(entry); - } - table->n_elements--; - assert(table->n_elements >= 0); - hashtable_write_unlock(table); - return 1; -} - -/** - * Fetch an item with a given key value from the hash table - * - * @param table The hash table - * @param key The key value - * @return The item or NULL if the item was not found - */ -void * -hashtable_fetch(HASHTABLE *table, void *key) -{ - unsigned int hashkey; - HASHENTRIES *entry; - - if (table == NULL || key == NULL || 0 == table->hashsize) - { - return NULL; - } - - hashkey = table->hashfn(key) % table->hashsize; - hashtable_read_lock(table); - entry = table->entries[hashkey % table->hashsize]; - while (entry && entry->key && table->cmpfn(key, entry->key) != 0) - { - entry = entry->next; - } - if (entry == NULL) - { - hashtable_read_unlock(table); - return NULL; - } - else - { - hashtable_read_unlock(table); - return entry->value; - } -} - -/** - * Print hash table statistics to the standard output - * - * @param table The hash table - */ -void -hashtable_stats(HASHTABLE *table) -{ - int total, longest, i, j; - HASHENTRIES *entries; - - if (table == NULL) - { - return; - } - - printf("Hashtable: %p, size %d\n", table, table->hashsize); - total = 0; - longest = 0; - hashtable_read_lock(table); - for (i = 0; i < table->hashsize; i++) - { - j = 0; - entries = table->entries[i]; - while (entries) - { - j++; - entries = entries->next; - } - total += j; - if (j > longest) - { - longest = j; - } - } - hashtable_read_unlock(table); - printf("\tNo. of entries: %d\n", total); - printf("\tAverage chain length: %.1f\n", (float)total / table->hashsize); - printf("\tLongest chain length: %d\n", longest); -} - -/** - * Produces stat output about hashtable - * - * Parameters: - * @param table - - * - * - * @param hashsize - - * - * - * @param nelems - - * - * - * @param longest - - * - * - * @return void - * - * - */ -void hashtable_get_stats(void* table, - int* hashsize, - int* nelems, - int* longest) -{ - HASHTABLE* ht; - HASHENTRIES* entries; - int i; - int j; - - *nelems = 0; - *longest = 0; - *hashsize = 0; - - if (table != NULL) - { - ht = (HASHTABLE *)table; - hashtable_read_lock(ht); - - for (i = 0; i < ht->hashsize; i++) - { - j = 0; - entries = ht->entries[i]; - while (entries) - { - j++; - entries = entries->next; - } - *nelems += j; - if (j > *longest) - { - *longest = j; - } - } - *hashsize = ht->hashsize; - hashtable_read_unlock(ht); - } -} - - -/** - * Take a read lock on the hashtable. - * - * The hashtable support multiple readers and a single writer, - * we have a spinlock to protect the two counts, n_readers and - * writelock. - * - * We take the hashtable spinlock and then check that writelock - * is set to zero. If not we release the spinlock and do dirty - * reads of writelock until it goes to 0. Once it is zero we - * acquire the spinlock again and test that writelock is still - * 0. - * - * With writelock set to zero we increment n_readers with the - * spinlock still held. - * - * @param table The hashtable to lock. - */ -static void -hashtable_read_lock(HASHTABLE *table) -{ - spinlock_acquire(&table->spin); - while (table->writelock) - { - spinlock_release(&table->spin); - while (atomic_add(&table->writelock, 1) != 0) - { - atomic_add(&table->writelock, -1); - } - atomic_add(&table->writelock, -1); - spinlock_acquire(&table->spin); - } - atomic_add(&table->n_readers, 1); - spinlock_release(&table->spin); -} - -/** - * Release a previously obtained readlock. - * - * Simply decrement the n_readers value for the hash table - * - * @param table The hash table to unlock - */ -static void -hashtable_read_unlock(HASHTABLE *table) -{ - atomic_add(&table->n_readers, -1); -} - -/** - * Obtain an exclusive write lock for the hash table. - * - * We acquire the hashtable spinlock, check for the number of - * readers beign zero. If it is not we hold the spinlock and - * loop waiting for the n_readers to reach zero. This will prevent - * any new readers beign granted access but will not prevent current - * readers releasing the read lock. - * - * Once we have no readers we increment writelock and test if we are - * the only writelock holder, if not we repeat the process. We hold - * the spinlock throughout the process since both read and write - * locks do not require the spinlock to be acquired. - * - * @param table The table to lock for updates - */ -static void -hashtable_write_lock(HASHTABLE *table) -{ - int available; - - spinlock_acquire(&table->spin); - do - { - while (atomic_add(&table->n_readers, 1) != 0) - { - atomic_add(&table->n_readers, -1); - } - atomic_add(&table->n_readers, -1); - available = atomic_add(&table->writelock, 1); - if (available != 0) - { - atomic_add(&table->writelock, -1); - } - } - while (available != 0); - spinlock_release(&table->spin); -} - -/** - * Release the write lock on the hash table. - * - * @param table The hash table to unlock - */ -static void -hashtable_write_unlock(HASHTABLE *table) -{ - atomic_add(&table->writelock, -1); -} - -/** - * Create an iterator on a hash table - * - * @param table The table to ceate an iterator on - * @return An iterator to use in future calls - */ -HASHITERATOR * -hashtable_iterator(HASHTABLE *table) -{ - HASHITERATOR *rval = (HASHITERATOR *)MXS_MALLOC(sizeof(HASHITERATOR)); - - if (rval) - { - rval->table = table; - rval->chain = 0; - rval->depth = -1; - } - return rval; -} - -/** - * Return the next key for a hashtable iterator - * - * @param iter The hashtable iterator - * @return The next key value or NULL - */ -void * -hashtable_next(HASHITERATOR *iter) -{ - int i; - HASHENTRIES *entries; - - if (iter == NULL) - { - return NULL; - } - - iter->depth++; - while (iter->chain < iter->table->hashsize) - { - hashtable_read_lock(iter->table); - if ((entries = iter->table->entries[iter->chain]) != NULL) - { - i = 0; - while (entries && i < iter->depth) - { - entries = entries->next; - i++; - } - hashtable_read_unlock(iter->table); - if (entries) - { - return entries->key; - } - } - else - { - hashtable_read_unlock(iter->table); - } - iter->depth = 0; - iter->chain++; - } - return NULL; -} - -/** - * Free a hashtable iterator - * - * @param iter The iterator to free - */ -void -hashtable_iterator_free(HASHITERATOR *iter) -{ - MXS_FREE(iter); -} - -/** - * Save a hashtable to disk - * - * @param table Hashtable to save - * @param filename Filename to write hashtable into - * @param keywrite Pointer to function that writes a single key - * @param valuewrite Pointer to function that writes a single value - * @return Number of entries written or -1 on error - */ -int -hashtable_save(HASHTABLE *table, const char *filename, - int (*keywrite)(int, void*), - int (*valuewrite)(int, void*)) -{ - int fd, rval = 0; - HASHITERATOR *iter; - void *key, *value; - - if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) - { - return -1; - } - if (write(fd, "HASHTABLE", 7) != 7) // Magic number - { - close(fd); - return -1; - } - if (write(fd, &rval, sizeof(rval)) == -1) // Write zero counter, will be overrwriten at end - { - MXS_ERROR("Failed to write hashtable item count: %d, %s", errno, - mxs_strerror(errno)); - } - if ((iter = hashtable_iterator(table)) != NULL) - { - while ((key = hashtable_next(iter)) != NULL) - { - if (!(*keywrite)(fd, key)) - { - close(fd); - hashtable_iterator_free(iter); - return -1; - } - if ((value = hashtable_fetch(table, key)) == NULL || - (*valuewrite)(fd, value) == 0) - { - close(fd); - hashtable_iterator_free(iter); - return -1; - } - rval++; - } - } - - /* Now go back and write the count of entries */ - if (lseek(fd, 7L, SEEK_SET) != -1) - { - if (write(fd, &rval, sizeof(rval)) == -1) - { - MXS_ERROR("Failed to write hashtable item count: %d, %s", errno, - mxs_strerror(errno)); - } - } - - close(fd); - hashtable_iterator_free(iter); - return rval; -} - -/** - * Load a hashtable from disk - * - * @param table Hashtable to load - * @param filename Filename to read hashtable from - * @param keyread Pointer to function that reads a single key - * @param valueread Pointer to function that reads a single value - * @return Number of entries read or -1 on error - */ -int -hashtable_load(HASHTABLE *table, const char *filename, - void *(*keyread)(int), - void *(*valueread)(int)) -{ - int fd, count, rval = 0; - void *key, *value; - char buf[40]; - - if ((fd = open(filename, O_RDONLY)) == -1) - { - return -1; - } - if (read(fd, buf, 7) != 7) - { - close(fd); - return -1; - } - if (strncmp(buf, "HASHTABLE", 7) != 0) - { - close(fd); - return -1; - } - if (read(fd, &count, sizeof(count)) != sizeof(count)) - { - close(fd); - return -1; - } - while (count--) - { - key = keyread(fd); - value = valueread(fd); - if (key == NULL || value == NULL) - { - break; - } - hashtable_add(table, key, value); - rval++; - } - - close(fd); - return rval; -} - -/** - * Return the number of elements added to the hashtable - * @param table Hashtable to measure - * @return Number of inserted elements or 0 if table is NULL - */ -int hashtable_size(HASHTABLE *table) -{ - assert(table); - spinlock_acquire(&table->spin); - int rval = table->n_elements; - spinlock_release(&table->spin); - return rval; -} - -/** - * Frees memory assumed to have been allocated using one of the MaxScale - * allocation functions. Intended to be used together with a hashtable - * copy function that merely makes a straight memory copy of the key/value, - * e.g. hashtable_item_strdup. - * @param data The memory to be freed. - */ -void hashtable_item_free(void *data) -{ - MXS_FREE(data); -} - -/** - * Convenience function intended for use as the comparison function of a hashtable, - * when the key is a NULL terminated string. Behaves as strcasecmp. - * @param str1 Pointer to string. - * @param str2 Pointer to string. - * @return Same as strcasecmp. - */ -int hashtable_item_strcasecmp(const void *str1, const void *str2) -{ - return strcasecmp((const char*)str1, (const char*)str2); -} - -/** - * Convenience function intended for use as the comparison function of a hashtable, - * when the key is a NULL terminated string. Behaves as strcmp. - * @param str1 Pointer to string. - * @param str2 Pointer to string. - * @return Same as strcmp. - */ -int hashtable_item_strcmp(const void *str1, const void *str2) -{ - return strcmp((const char*)str1, (const char*)str2); -} - -/** - * Convenience function intended for use as the copy function of a hashtable, - * when the key/value is a NULL terminated string. - * @param data A pointer to a NULL terminated string. - * @return A copy of the provided string or NULL if memory - * allocation fails. - */ -void* hashtable_item_strdup(const void* data) -{ - return MXS_STRDUP((const char*)data); -} - -/** - * Convenience function intended for use as the hash function of a hashtable, - * when the key is a NULL terminated string. - * @param data A pointer to a NULL terminated string. - * @return A hash of the string. - */ -int hashtable_item_strhash(const void* data) -{ - int hash = 0; - - if (data) - { - const char* key = (const char*)data; - - int c; - - while ((c = *key++)) - { - hash = c + (hash << 6) + (hash << 16) - hash; - } - } - - return hash; -} diff --git a/server/core/test/CMakeLists.txt b/server/core/test/CMakeLists.txt index 542afab1d..022d1602e 100644 --- a/server/core/test/CMakeLists.txt +++ b/server/core/test/CMakeLists.txt @@ -6,7 +6,6 @@ add_executable(test_config test_config.cc) add_executable(test_dcb test_dcb.cc) add_executable(test_event test_event.cc) add_executable(test_filter test_filter.cc) -add_executable(test_hash test_hash.cc) add_executable(test_hint test_hint.cc) add_executable(test_http test_http.cc) add_executable(test_json test_json.cc) @@ -35,7 +34,6 @@ target_link_libraries(test_config maxscale-common) target_link_libraries(test_dcb maxscale-common) target_link_libraries(test_event maxscale-common) target_link_libraries(test_filter maxscale-common) -target_link_libraries(test_hash maxscale-common) target_link_libraries(test_hint maxscale-common) target_link_libraries(test_http maxscale-common) target_link_libraries(test_json maxscale-common) @@ -63,7 +61,6 @@ add_test(test_config test_config) add_test(test_dcb test_dcb) add_test(test_event test_event) add_test(test_filter test_filter) -add_test(test_hash test_hash) add_test(test_hint test_hint) add_test(test_http test_http) add_test(test_json test_json) diff --git a/server/core/test/test_hash.cc b/server/core/test/test_hash.cc deleted file mode 100644 index e95d484c8..000000000 --- a/server/core/test/test_hash.cc +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (c) 2016 MariaDB Corporation Ab - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file and at www.mariadb.com/bsl11. - * - * Change Date: 2022-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2 or later of the General - * Public License. - */ - -/** - * - * @verbatim - * Revision History - * - * Date Who Description - * 18/08-2014 Mark Riddoch Initial implementation - * - * @endverbatim - */ - -// To ensure that ss_info_assert asserts also when builing in non-debug mode. -#if !defined(SS_DEBUG) -#define SS_DEBUG -#endif -#if defined(NDEBUG) -#undef NDEBUG -#endif -#include -#include -#include -#include -#include - -#include -#include -#include - -static void -read_lock(HASHTABLE *table) -{ - spinlock_acquire(&table->spin); - while (table->writelock) - { - spinlock_release(&table->spin); - while (table->writelock) - ; - spinlock_acquire(&table->spin); - } - table->n_readers++; - spinlock_release(&table->spin); -} - -static void -read_unlock(HASHTABLE *table) -{ - atomic_add(&table->n_readers, -1); -} - -static int hfun(const void* key); -static int cmpfun(const void *, const void *); - -static int hfun(const void* key) -{ - const int *i = (const int *)key; - int j = (*i * 23) + 41; - return j; - /* return *(int *)key; */ -} - -static int cmpfun(const void* v1, const void* v2) -{ - int i1; - int i2; - - i1 = *(const int *)v1; - i2 = *(const int *)v2; - - return (i1 < i2 ? -1 : (i1 > i2 ? 1 : 0)); -} - -static double start; - -/** - * test1 spinlock_acquire_nowait tests - * - * Test that spinlock_acquire_nowait returns false if the spinlock - * is already taken. - * - * Test that spinlock_acquire_nowait returns true if the spinlock - * is not taken. - * - * Test that spinlock_acquire_nowait does hold the spinlock. - */ -static bool do_hashtest( - int argelems, - int argsize) -{ - bool succp = true; - HASHTABLE* h; - int nelems; - int i; - int* val_arr; - int hsize; - int longest; - int* iter; - - fprintf(stderr, - "testhash : creating hash table of size %d, including %d " - "elements in total, at time %g.", - argsize, - argelems, - (double)clock() - start); - - val_arr = (int *)MXS_MALLOC(sizeof(void *)*argelems); - MXS_ABORT_IF_NULL(val_arr); - - h = hashtable_alloc(argsize, hfun, cmpfun); - - fprintf(stderr, "\t..done\nAdd %d elements to hash table.", argelems); - - for (i = 0; i < argelems; i++) - { - val_arr[i] = i; - hashtable_add(h, (void *)&val_arr[i], (void *)&val_arr[i]); - } - if (argelems > 1000) - { - fprintf(stderr, "\t..done\nOperation took %g", (double)clock() - start); - } - - fprintf(stderr, "\t..done\nRead hash table statistics."); - - hashtable_get_stats((void *)h, &hsize, &nelems, &longest); - - fprintf(stderr, "\t..done\nValidate read values."); - - ss_info_dassert(hsize == (argsize > 0 ? argsize : 1), "Invalid hash size"); - ss_info_dassert((nelems == argelems) || (nelems == 0 && argsize == 0), - "Invalid element count"); - ss_info_dassert(longest <= nelems, "Too large longest list value"); - if (argelems > 1000) - { - fprintf(stderr, "\t..done\nOperation took %g", (double)clock() - start); - } - - fprintf(stderr, "\t..done\nValidate iterator."); - - HASHITERATOR *iterator = hashtable_iterator(h); - read_lock(h); - for (i = 0; i < (argelems + 1); i++) - { - iter = (int *)hashtable_next(iterator); - if (iter == NULL) - { - break; - } - if (argelems < 100) - { - fprintf(stderr, "\nNext item, iter = %d, i = %d", *iter, i); - } - } - read_unlock(h); - ss_info_dassert((i == argelems) || (i == 0 && argsize == 0), "\nIncorrect number of elements from iterator"); - hashtable_iterator_free(iterator); - if (argelems > 1000) - { - fprintf(stderr, "\t..done\nOperation took %g", (double)clock() - start); - } - - fprintf(stderr, "\t\t..done\n\nTest completed successfully.\n\n"); - - hashtable_free(h); - - - MXS_FREE(val_arr); - return succp; -} - -/** - * @node Simple test which creates hashtable and frees it. Size and number of entries - * sre specified by user and passed as arguments. - * - * - * @return 0 if succeed, 1 if failed. - * - * - * @details (write detailed description here) - * - */ -int main(void) -{ - int rc = 1; - start = (double) clock(); - - if (!do_hashtest(0, 1)) - { - goto return_rc; - } - if (!do_hashtest(10, 1)) - { - goto return_rc; - } - if (!do_hashtest(1000, 10)) - { - goto return_rc; - } - if (!do_hashtest(10, 0)) - { - goto return_rc; - } - if (!do_hashtest(10, -5)) - { - goto return_rc; - } - if (!do_hashtest(1500, 17)) - { - goto return_rc; - } - if (!do_hashtest(1, 1)) - { - goto return_rc; - } - if (!do_hashtest(10000, 133)) - { - goto return_rc; - } - if (!do_hashtest(1000, 1000)) - { - goto return_rc; - } - if (!do_hashtest(1000, 100000)) - { - goto return_rc; - } - - rc = 0; -return_rc: - return rc; -}