diff --git a/server/core/hashtable.c b/server/core/hashtable.c index b945f3631..4e1a2f4e1 100644 --- a/server/core/hashtable.c +++ b/server/core/hashtable.c @@ -102,7 +102,7 @@ HASHTABLE *rval; rval->ht_chk_top = CHK_NUM_HASHTABLE; rval->ht_chk_tail = CHK_NUM_HASHTABLE; #endif - rval->hashsize = size; + rval->hashsize = size > 0 ? size : 1; rval->hashfn = hashfn; rval->cmpfn = cmpfn; rval->kcopyfn = nullfn; @@ -112,12 +112,12 @@ HASHTABLE *rval; rval->n_readers = 0; rval->writelock = 0; spinlock_init(&rval->spin); - if ((rval->entries = (HASHENTRIES **)calloc(size, sizeof(HASHENTRIES *))) == NULL) + if ((rval->entries = (HASHENTRIES **)calloc(rval->hashsize, sizeof(HASHENTRIES *))) == NULL) { free(rval); return NULL; } - memset(rval->entries, 0, size * sizeof(HASHENTRIES *)); + memset(rval->entries, 0, rval->hashsize * sizeof(HASHENTRIES *)); return rval; } diff --git a/server/core/test/testhash.c b/server/core/test/testhash.c index 6aac2d016..3fa9d7f0d 100644 --- a/server/core/test/testhash.c +++ b/server/core/test/testhash.c @@ -1,19 +1,73 @@ +/* + * This file is distributed as part of MaxScale. It 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, + * version 2. + * + * 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., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright SkySQL Ab 2014 + */ + +/** + * + * @verbatim + * Revision History + * + * Date Who Description + * 18/08-2014 Mark Riddoch Initial implementation + * + * @endverbatim + */ + #include #include #include +#include +#include #include "../../include/hashtable.h" +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(void* key); static int cmpfun (void *, void *); static int hfun( void* key) { - return *(int *)key; + int *i = (int *)key; + int j = (*i * 23) + 41; + return j; + /* return *(int *)key; */ } - static int cmpfun( void* v1, void* v2) @@ -27,7 +81,19 @@ static int cmpfun( 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) @@ -39,12 +105,14 @@ static bool do_hashtest( int* val_arr; int hsize; int longest; + int* iter; ss_dfprintf(stderr, "testhash : creating hash table of size %d, including %d " - "elements in total.", + "elements in total, at time %g.", argsize, - argelems); + argelems, + (double)clock()-start); val_arr = (int *)malloc(sizeof(void *)*argelems); @@ -56,17 +124,33 @@ static bool do_hashtest( val_arr[i] = i; hashtable_add(h, (void *)&val_arr[i], (void *)&val_arr[i]); } - + if (argelems > 1000) ss_dfprintf(stderr, "\t..done\nOperation took %g", (double)clock()-start); + ss_dfprintf(stderr, "\t..done\nRead hash table statistics."); hashtable_get_stats((void *)h, &hsize, &nelems, &longest); ss_dfprintf(stderr, "\t..done\nValidate read values."); - ss_info_dassert(hsize == argsize, "Invalid hash size"); + 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) ss_dfprintf(stderr, "\t..done\nOperation took %g", (double)clock()-start); + + ss_dfprintf(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) ss_dfprintf(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) ss_dfprintf(stderr, "\t..done\nOperation took %g", (double)clock()-start); ss_dfprintf(stderr, "\t\t..done\n\nTest completed successfully.\n\n"); @@ -91,11 +175,13 @@ return_succp: 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; diff --git a/server/core/test/testspinlock.c b/server/core/test/testspinlock.c index bcbfa2a3f..ecdbdf108 100644 --- a/server/core/test/testspinlock.c +++ b/server/core/test/testspinlock.c @@ -55,18 +55,18 @@ SPINLOCK lck; spinlock_acquire(&lck); if (spinlock_acquire_nowait(&lck)) { - fprintf(stderr, "spinlock_acquire_nowait: test 1 failed.\n"); + fprintf(stderr, "spinlock_acquire_nowait: test 1.1 failed.\n"); return 1; } spinlock_release(&lck); if (!spinlock_acquire_nowait(&lck)) { - fprintf(stderr, "spinlock_acquire_nowait: test 2 failed.\n"); + fprintf(stderr, "spinlock_acquire_nowait: test 1.2 failed.\n"); return 1; } if (spinlock_acquire_nowait(&lck)) { - fprintf(stderr, "spinlock_acquire_nowait: test 3 failed.\n"); + fprintf(stderr, "spinlock_acquire_nowait: test 1.3 failed.\n"); return 1; } spinlock_release(&lck); @@ -89,6 +89,8 @@ unsigned long t1 = time(0); } /** + * test2 spinlock_acquire tests + * * Check that spinlock correctly blocks another thread whilst the spinlock * is held. * @@ -114,7 +116,7 @@ void *handle; if (acquire_time < 8) { - fprintf(stderr, "spinlock: test 1 failed.\n"); + fprintf(stderr, "spinlock: test 2 failed.\n"); return 1; } return 0;