This commit is contained in:
Jan Lindström
2013-08-06 20:09:50 +03:00
12 changed files with 263 additions and 44 deletions

View File

@ -774,7 +774,7 @@ static char* blockbuf_get_writepos(
ss_dassert(pos == NULL); ss_dassert(pos == NULL);
ss_dassert(!(bb->bb_isfull || bb->bb_buf_left < str_len)); ss_dassert(!(bb->bb_isfull || bb->bb_buf_left < str_len));
ss_dassert(bb_list->mlist_nodecount <= nodecount_max); ss_dassert(bb_list->mlist_nodecount <= bb_list->mlist_nodecount_max);
/** /**
* Registration to blockbuf adds reference for the write operation. * Registration to blockbuf adds reference for the write operation.
@ -816,7 +816,7 @@ static char* blockbuf_get_writepos(
/** Unlock buffer */ /** Unlock buffer */
simple_mutex_unlock(&bb->bb_mutex); simple_mutex_unlock(&bb->bb_mutex);
ss_dassert(bb_list->mlist_mutex->sm_lock_thr != pthread_self()); ss_dassert(bb_list->mlist_mutex.sm_lock_thr != pthread_self());
return pos; return pos;
} }
@ -856,11 +856,12 @@ int skygw_log_write_flush(
goto return_err; goto return_err;
} }
CHK_LOGMANAGER(lm); CHK_LOGMANAGER(lm);
#if 0
ss_dfprintf(stderr, ss_dfprintf(stderr,
"skygw_log_write_flush writes to %s :\n\t%s.\n", "skygw_log_write_flush writes to %s :\n\t%s.\n",
STRLOGID(id), STRLOGID(id),
str); str);
#endif
/** /**
* Find out the length of log string (to be formatted str). * Find out the length of log string (to be formatted str).
*/ */
@ -882,8 +883,9 @@ int skygw_log_write_flush(
fprintf(stderr, "skygw_log_write_flush failed.\n"); fprintf(stderr, "skygw_log_write_flush failed.\n");
goto return_unregister; goto return_unregister;
} }
#if 0
ss_dfprintf(stderr, "skygw_log_write_flush succeeed.\n"); ss_dfprintf(stderr, "skygw_log_write_flush succeeed.\n");
#endif
return_unregister: return_unregister:
logmanager_unregister(); logmanager_unregister();
return_err: return_err:
@ -907,10 +909,12 @@ int skygw_log_write(
goto return_err; goto return_err;
} }
CHK_LOGMANAGER(lm); CHK_LOGMANAGER(lm);
#if 0
ss_dfprintf(stderr, ss_dfprintf(stderr,
"skygw_log_write writes to %s :\n\t%s.\n", "skygw_log_write writes to %s :\n\t%s.\n",
STRLOGID(id), STRLOGID(id),
str); str);
#endif
/** /**
* Find out the length of log string (to be formatted str). * Find out the length of log string (to be formatted str).
*/ */
@ -932,9 +936,9 @@ int skygw_log_write(
fprintf(stderr, "skygw_log_write failed.\n"); fprintf(stderr, "skygw_log_write failed.\n");
goto return_unregister; goto return_unregister;
} }
#if 0
ss_dfprintf(stderr, "skygw_log_write succeeed.\n"); ss_dfprintf(stderr, "skygw_log_write succeeed.\n");
#endif
return_unregister: return_unregister:
logmanager_unregister(); logmanager_unregister();
return_err: return_err:
@ -960,9 +964,11 @@ int skygw_log_flush(
fprintf(stderr, "skygw_log_flush failed.\n"); fprintf(stderr, "skygw_log_flush failed.\n");
goto return_unregister; goto return_unregister;
} }
#if 0
ss_dfprintf(stderr, ss_dfprintf(stderr,
"skygw_log_flush : flushed %s successfully.\n", "skygw_log_flush : flushed %s successfully.\n",
STRLOGID(id)); STRLOGID(id));
#endif
return_unregister: return_unregister:
logmanager_unregister(); logmanager_unregister();
return_err: return_err:

View File

@ -25,7 +25,6 @@ testcomp:
-Wl,-rpath,$(DEST)/lib \ -Wl,-rpath,$(DEST)/lib \
-Wl,-rpath,$(LOG_MANAGER_PATH)/ \ -Wl,-rpath,$(LOG_MANAGER_PATH)/ \
-o testlog -DSS_DEBUG \ -o testlog -DSS_DEBUG \
-I$(SOLIDDB_SRC_PATH)/include \
-I$(MARIADB_SRC_PATH)/include \ -I$(MARIADB_SRC_PATH)/include \
-I$(LOG_MANAGER_PATH) -I$(ROOT_PATH)/utils testlog.c \ -I$(LOG_MANAGER_PATH) -I$(ROOT_PATH)/utils testlog.c \
-llog_manager $(LDLIBS) \ -llog_manager $(LDLIBS) \

View File

@ -42,7 +42,7 @@ clean:
(cd modules/monitor; touch depend.mk ; make clean) (cd modules/monitor; touch depend.mk ; make clean)
depend: depend:
(cd core; make depend) (cd core; touch depend.mk ; make depend)
(cd modules/routing; touch depend.mk ; make depend) (cd modules/routing; touch depend.mk ; make depend)
(cd modules/protocol; touch depend.mk ; make depend) (cd modules/protocol; touch depend.mk ; make depend)
(cd modules/monitor; touch depend.mk ; make depend) (cd modules/monitor; touch depend.mk ; make depend)

View File

@ -55,8 +55,7 @@ static char *ADMIN_ERR_FILEAPPEND = "Unable to append to password file";
static char *ADMIN_ERR_PWDFILEOPEN = "Failed to open password file"; static char *ADMIN_ERR_PWDFILEOPEN = "Failed to open password file";
static char *ADMIN_ERR_TMPFILEOPEN = "Failed to open temporary password file"; static char *ADMIN_ERR_TMPFILEOPEN = "Failed to open temporary password file";
static char *ADMIN_ERR_PWDFILEACCESS = "Failed to access password file"; static char *ADMIN_ERR_PWDFILEACCESS = "Failed to access password file";
static char *ADMIN_ERR_DELLASTUSER = "Deleting user failed, deleting the " static char *ADMIN_ERR_DELLASTUSER = "Deleting the last user is forbidden";
"last user is forbidden";
static char *ADMIN_SUCCESS = NULL; static char *ADMIN_SUCCESS = NULL;
static const int LINELEN=80; static const int LINELEN=80;
@ -354,5 +353,5 @@ dcb_PrintAdminUsers(DCB *dcb)
if (users) if (users)
dcb_usersPrint(dcb, users); dcb_usersPrint(dcb, users);
else else
dcb_printf(dcb, "No administrtion users have been defined.\n"); dcb_printf(dcb, "No administration users have been defined.\n");
} }

View File

@ -688,3 +688,35 @@ dcb_isclient(DCB *dcb)
return 0; 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);
}

View File

@ -90,6 +90,10 @@ HASHTABLE *rval;
if ((rval = malloc(sizeof(HASHTABLE))) == NULL) if ((rval = malloc(sizeof(HASHTABLE))) == NULL)
return NULL; return NULL;
rval->ht_chk_top = CHK_NUM_HASHTABLE;
rval->ht_chk_tail = CHK_NUM_HASHTABLE;
rval->hashsize = size; rval->hashsize = size;
rval->hashfn = hashfn; rval->hashfn = hashfn;
rval->cmpfn = cmpfn; rval->cmpfn = cmpfn;
@ -163,9 +167,14 @@ hashtable_memory_fns(HASHTABLE *table, HASHMEMORYFN copyfn, HASHMEMORYFN freefn)
int int
hashtable_add(HASHTABLE *table, void *key, void *value) hashtable_add(HASHTABLE *table, void *key, void *value)
{ {
int hashkey = table->hashfn(key) % table->hashsize; int hashkey;
HASHENTRIES *entry; HASHENTRIES *entry;
if (table->hashsize <= 0) {
return 0;
} else {
hashkey = table->hashfn(key) % table->hashsize;
}
hashtable_write_lock(table); hashtable_write_lock(table);
entry = table->entries[hashkey % table->hashsize]; entry = table->entries[hashkey % table->hashsize];
while (entry && table->cmpfn(key, entry->key) != 0) while (entry && table->cmpfn(key, entry->key) != 0)
@ -322,40 +331,62 @@ HASHENTRIES *entries;
} }
/** /**
* Print hash table statistics to a DCB * @node Produces stat output about hashtable
*
* Parameters:
* @param table - <usage>
* <description>
*
* @param hashsize - <usage>
* <description>
*
* @param nelems - <usage>
* <description>
*
* @param longest - <usage>
* <description>
*
* @return void
*
*
* @details (write detailed description here)
* *
* @param dcb The DCB to send the information to
* @param table The hash table
*/ */
void void hashtable_get_stats(
dcb_hashtable_stats(DCB *dcb, HASHTABLE *table) void* table,
int* hashsize,
int* nelems,
int* longest)
{ {
int total, longest, i, j; HASHTABLE* ht;
HASHENTRIES *entries; HASHENTRIES* entries;
int i;
int j;
dcb_printf(dcb, "Hashtable: %p, size %d\n", table, table->hashsize); ht = (HASHTABLE *)table;
total = 0; CHK_HASHTABLE(ht);
longest = 0;
hashtable_read_lock(table); hashtable_read_lock(ht);
for (i = 0; i < table->hashsize; i++)
for (i = 0; i < ht->hashsize; i++)
{ {
j = 0; j = 0;
entries = table->entries[i]; entries = ht->entries[i];
while (entries) while (entries)
{ {
j++; j++;
entries = entries->next; entries = entries->next;
} }
total += j; *nelems += j;
if (j > longest) if (j > *longest) {
longest = j; *longest = j;
} }
hashtable_read_unlock(table); }
dcb_printf(dcb, "\tNo. of entries: %d\n", total); *hashsize = ht->hashsize;
dcb_printf(dcb, "\tAverage chain length: %.1f\n", (float)total / table->hashsize); hashtable_read_unlock(ht);
dcb_printf(dcb, "\tLongest chain length: %d\n", longest);
} }
/** /**
* Take a read lock on the hashtable. * Take a read lock on the hashtable.
* *

32
server/core/test/makefile Normal file
View File

@ -0,0 +1,32 @@
include ../../../build_gateway.inc
include ../../../makefile.inc
CC=cc
clean:
- $(DEL) *.o
- $(DEL) testhash
- $(DEL) *~
all:
$(MAKE) clean
$(MAKE) buildall
$(MAKE) runall
buildall :
$(CC) $(CFLAGS) \
-I$(ROOT_PATH)/server/include \
-I$(ROOT_PATH)/utils \
testhash.c ../hashtable.o ../atomic.o ../spinlock.o -o testhash \
runall:
- @./testhash 0 1
- @./testhash 10 1
- @./testhash 1000 10
- @./testhash 10 0
- @./testhash 1500 17
- @./testhash 1 1
- @./testhash 10000 133
- @./testhash 1000 1000
- @./testhash 1000 100000

108
server/core/test/testhash.c Normal file
View File

@ -0,0 +1,108 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../include/hashtable.h"
static int hfun(void* key);
static int cmpfun (void *, void *);
static int hfun(
void* key)
{
return *(int *)key;
}
static int cmpfun(
void* v1,
void* v2)
{
int i1;
int i2;
i1 = *(int *)v1;
i2 = *(int *)v2;
return (i1 < i2 ? -1 : (i1 > i2 ? 1 : 0));
}
/**
* @node Simple test which creates hashtable and frees it. Size and number of entries
* sre specified by user and passed as arguments.
*
* Parameters:
* @param argc - <usage>
* <description>
*
* @param argv - <usage>
* <description>
*
* @return
*
*
* @details (write detailed description here)
*
*/
int main(int argc, char** argv)
{
HASHTABLE* h;
int nelems;
int i;
int* val_arr;
int argsize;
int hsize;
int argelems;
int longest;
if (argc != 3) {
fprintf(stderr, "\nWrong number of arguments. Usage "
":\n\n\ttesthash <# of elements> <# hash size> "
"<hash function> <compare function>\n\n");
return 1;
}
argelems = strtol(argv[1], NULL, 10);
argsize = strtol(argv[2], NULL, 10);
ss_dfprintf(stderr,
"testhash : creating hash table of size %d, including %d "
"elements in total.",
argsize,
argelems);
val_arr = (int *)malloc(sizeof(void *)*argelems);
h = hashtable_alloc(argsize, hfun, cmpfun);
ss_dfprintf(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]);
}
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((nelems == argelems) || (nelems == 0 && argsize == 0),
"Invalid element count");
ss_info_dassert(longest <= nelems, "Too large longest list value");
ss_dfprintf(stderr, "\t\t..done\n\nTest completed successfully.\n\n");
CHK_HASHTABLE(h);
hashtable_free(h);
return 0;
}

View File

@ -55,7 +55,7 @@ users_alloc()
{ {
USERS *rval; USERS *rval;
if ((rval = malloc(sizeof(USERS))) == NULL) if ((rval = calloc(1, sizeof(USERS))) == NULL)
return NULL; return NULL;
if ((rval->data = hashtable_alloc(52, user_hash, strcmp)) == NULL) if ((rval->data = hashtable_alloc(52, user_hash, strcmp)) == NULL)

View File

@ -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 const char *gw_dcb_state2string(int); /* DCB state to string */
extern void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */ 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 int dcb_isclient(DCB *); /* the DCB is the client of the session */
extern void dcb_hashtable_stats(DCB *, void *); /**< Print statisitics */
#endif #endif

View File

@ -31,6 +31,7 @@
* *
* @endverbatim * @endverbatim
*/ */
#include <skygw_debug.h>
#include <spinlock.h> #include <spinlock.h>
#include <atomic.h> #include <atomic.h>
#include <dcb.h> #include <dcb.h>
@ -67,6 +68,7 @@ typedef void *(*HASHMEMORYFN)(void *);
* The general purpose hashtable struct. * The general purpose hashtable struct.
*/ */
typedef struct hashtable { typedef struct hashtable {
skygw_chk_t ht_chk_top;
int hashsize; /**< The number of HASHENTRIES */ int hashsize; /**< The number of HASHENTRIES */
HASHENTRIES **entries; /**< The entries themselves */ HASHENTRIES **entries; /**< The entries themselves */
int (*hashfn)(void *); /**< The hash function */ int (*hashfn)(void *); /**< The hash function */
@ -76,6 +78,7 @@ typedef struct hashtable {
SPINLOCK spin; /**< Internal spinlock for the hashtable */ SPINLOCK spin; /**< Internal spinlock for the hashtable */
int n_readers; /**< Number of clients reading the table */ int n_readers; /**< Number of clients reading the table */
int writelock; /**< The table is locked by a writer */ int writelock; /**< The table is locked by a writer */
skygw_chk_t ht_chk_tail;
} HASHTABLE; } HASHTABLE;
extern HASHTABLE *hashtable_alloc(int, int (*hashfn)(), int (*cmpfn)()); 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 *); extern void *hashtable_fetch(HASHTABLE *, void *);
/**< Fetch the data for a given key */ /**< Fetch the data for a given key */
extern void hashtable_stats(HASHTABLE *); /**< Print statisitics */ 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 *); extern HASHITERATOR *hashtable_iterator(HASHTABLE *);
/**< Allocate an iterator on the hashtable */ /**< Allocate an iterator on the hashtable */
extern void *hashtable_next(HASHITERATOR *); extern void *hashtable_next(HASHITERATOR *);

View File

@ -47,15 +47,13 @@
# define ss_prof(exp) # define ss_prof(exp)
#endif /* SS_DEBUG || SS_PROF */ #endif /* SS_DEBUG || SS_PROF */
#if defined(EI_SS_DEBUG) #if defined(SS_DEBUG)
# define ss_debug(exp) exp # define ss_debug(exp) exp
# define ss_dfprintf fprintf # define ss_dfprintf fprintf
# define ss_dfflush fflush # define ss_dfflush fflush
# define ss_dfwrite fwrite # define ss_dfwrite fwrite
# undef ss_dassert
# undef ss_info_dassert
#if !defined(ss_dassert)
# define ss_dassert(exp) \ # define ss_dassert(exp) \
{ \ { \
if (!(exp)) { \ if (!(exp)) { \
@ -67,9 +65,8 @@
assert(exp); \ assert(exp); \
} \ } \
} }
#endif /* !defined(ss_dassert) */
#if !defined(ss_info_dassert)
# define ss_info_dassert(exp, info) \ # define ss_info_dassert(exp, info) \
{ \ { \
if (!(exp)) { \ if (!(exp)) { \
@ -81,7 +78,6 @@
assert((exp)); \ assert((exp)); \
} \ } \
} }
#endif /* !defined(ss_info_dassert) */
#else /* SS_DEBUG */ #else /* SS_DEBUG */
@ -113,7 +109,8 @@ typedef enum skygw_chk_t {
CHK_NUM_FNAMES, CHK_NUM_FNAMES,
CHK_NUM_LOGMANAGER, CHK_NUM_LOGMANAGER,
CHK_NUM_FILE, CHK_NUM_FILE,
CHK_NUM_BLOCKBUF CHK_NUM_BLOCKBUF,
CHK_NUM_HASHTABLE
} skygw_chk_t; } skygw_chk_t;
# define STRBOOL(b) ((b) ? "TRUE" : "FALSE") # define STRBOOL(b) ((b) ? "TRUE" : "FALSE")
@ -319,4 +316,10 @@ typedef enum skygw_chk_t {
"Block buf under- or overflow"); \ "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 */ #endif /* SKYGW_DEBUG_H */