diff --git a/server/core/dcb.c b/server/core/dcb.c index 89f3fe901..1cebad9de 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -688,3 +688,35 @@ dcb_isclient(DCB *dcb) return 0; } + +/** + * Print hash table statistics to a DCB + * + * @param dcb The DCB to send the information to + * @param table The hash table + */ +void dcb_hashtable_stats( + DCB* dcb, + void* table) +{ + int total; + int longest; + int hashsize; + int i; + int j; + + total = 0; + longest = 0; + + hashtable_get_stats(table, &hashsize, &total, &longest); + + dcb_printf(dcb, + "Hashtable: %p, size %d\n", + table, + hashsize); + + dcb_printf(dcb, "\tNo. of entries: %d\n", total); + dcb_printf(dcb, "\tAverage chain length: %.1f\n", (float)total / hashsize); + dcb_printf(dcb, "\tLongest chain length: %d\n", longest); +} + diff --git a/server/core/hashtable.c b/server/core/hashtable.c index 15a1c3f3e..f81afb8ed 100644 --- a/server/core/hashtable.c +++ b/server/core/hashtable.c @@ -90,6 +90,10 @@ HASHTABLE *rval; if ((rval = malloc(sizeof(HASHTABLE))) == NULL) return NULL; + + rval->ht_chk_top = CHK_NUM_HASHTABLE; + rval->ht_chk_tail = CHK_NUM_HASHTABLE; + rval->hashsize = size; rval->hashfn = hashfn; rval->cmpfn = cmpfn; @@ -321,41 +325,63 @@ HASHENTRIES *entries; printf("\tLongest chain length: %d\n", longest); } -/** - * Print hash table statistics to a DCB +/** + * @node Produces stat output about hashtable + * + * Parameters: + * @param table - + * + * + * @param hashsize - + * + * + * @param nelems - + * + * + * @param longest - + * + * + * @return void + * + * + * @details (write detailed description here) * - * @param dcb The DCB to send the information to - * @param table The hash table */ -void -dcb_hashtable_stats(DCB *dcb, HASHTABLE *table) +void hashtable_get_stats( + void* table, + int* hashsize, + int* nelems, + int* longest) { -int total, longest, i, j; -HASHENTRIES *entries; + HASHTABLE* ht; + HASHENTRIES* entries; + int i; + int j; - dcb_printf(dcb, "Hashtable: %p, size %d\n", table, table->hashsize); - total = 0; - longest = 0; - hashtable_read_lock(table); - for (i = 0; i < table->hashsize; i++) + ht = (HASHTABLE *)table; + CHK_HASHTABLE(ht); + + hashtable_read_lock(ht); + + for (i = 0; i < ht->hashsize; i++) { j = 0; - entries = table->entries[i]; + entries = ht->entries[i]; while (entries) { j++; entries = entries->next; } - total += j; - if (j > longest) - longest = j; + *nelems += j; + if (j > *longest) { + *longest = j; + } } - hashtable_read_unlock(table); - dcb_printf(dcb, "\tNo. of entries: %d\n", total); - dcb_printf(dcb, "\tAverage chain length: %.1f\n", (float)total / table->hashsize); - dcb_printf(dcb, "\tLongest chain length: %d\n", longest); + *hashsize = ht->hashsize; + hashtable_read_unlock(ht); } + /** * Take a read lock on the hashtable. * diff --git a/server/include/dcb.h b/server/include/dcb.h index a47b439c9..31ae2e930 100644 --- a/server/include/dcb.h +++ b/server/include/dcb.h @@ -185,5 +185,6 @@ extern void dprintDCB(DCB *, DCB *); /* Debug to print a DCB in the system */ extern const char *gw_dcb_state2string(int); /* DCB state to string */ extern void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */ extern int dcb_isclient(DCB *); /* the DCB is the client of the session */ +extern void dcb_hashtable_stats(DCB *, void *); /**< Print statisitics */ #endif diff --git a/server/include/hashtable.h b/server/include/hashtable.h index be7075c2c..71df1f681 100644 --- a/server/include/hashtable.h +++ b/server/include/hashtable.h @@ -31,6 +31,7 @@ * * @endverbatim */ +#include #include #include #include @@ -67,6 +68,7 @@ typedef void *(*HASHMEMORYFN)(void *); * The general purpose hashtable struct. */ typedef struct hashtable { + skygw_chk_t ht_chk_top; int hashsize; /**< The number of HASHENTRIES */ HASHENTRIES **entries; /**< The entries themselves */ int (*hashfn)(void *); /**< The hash function */ @@ -76,6 +78,7 @@ typedef struct hashtable { 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 */ + skygw_chk_t ht_chk_tail; } HASHTABLE; extern HASHTABLE *hashtable_alloc(int, int (*hashfn)(), int (*cmpfn)()); @@ -91,7 +94,12 @@ extern int hashtable_delete(HASHTABLE *, void *); extern void *hashtable_fetch(HASHTABLE *, void *); /**< Fetch the data for a given key */ extern void hashtable_stats(HASHTABLE *); /**< Print statisitics */ -extern void dcb_hashtable_stats(DCB *, HASHTABLE *); /**< Print statisitics */ +void hashtable_get_stats( + void* hashtable, + int* hashsize, + int* nelems, + int* longest); + extern HASHITERATOR *hashtable_iterator(HASHTABLE *); /**< Allocate an iterator on the hashtable */ extern void *hashtable_next(HASHITERATOR *); diff --git a/utils/skygw_debug.h b/utils/skygw_debug.h index 0aa96e3e7..87d30c707 100644 --- a/utils/skygw_debug.h +++ b/utils/skygw_debug.h @@ -113,7 +113,8 @@ typedef enum skygw_chk_t { CHK_NUM_FNAMES, CHK_NUM_LOGMANAGER, CHK_NUM_FILE, - CHK_NUM_BLOCKBUF + CHK_NUM_BLOCKBUF, + CHK_NUM_HASHTABLE } skygw_chk_t; # define STRBOOL(b) ((b) ? "TRUE" : "FALSE") @@ -319,4 +320,10 @@ typedef enum skygw_chk_t { "Block buf under- or overflow"); \ } +#define CHK_HASHTABLE(t) { \ + ss_info_dassert(t->ht_chk_top == CHK_NUM_HASHTABLE && \ + t->ht_chk_tail == CHK_NUM_HASHTABLE, \ + "Hashtable under- or overflow"); \ + } + #endif /* SKYGW_DEBUG_H */