diff --git a/CMakeLists.txt b/CMakeLists.txt index e83ee7861..e21a14d5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,7 @@ if(NOT ( ${DEBBUILD} STREQUAL "DEBBUILD-NOTFOUND" ) ) set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB") execute_process(COMMAND dpgk --print-architecture OUTPUT_VARIABLE DEB_ARCHITECTURE) set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${DEB_ARCHITECTURE}) + set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) message(STATUS "Generating DEB packages for ${DEB_ARCHITECTURE}") endif() @@ -125,7 +126,6 @@ set(CPACK_RPM_SPEC_INSTALL_POST "/sbin/ldconfig") set(CPACK_RPM_PACKAGE_NAME "maxscale") set(CPACK_RPM_PACKAGE_VENDOR "MariaDB Corporation Ab") set(CPACK_RPM_PACKAGE_LICENSE "GPLv2") -set(CPACK_RPM_PACKAGE_AUTOREQPROV " no") set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/etc /etc/ld.so.conf.d /etc/init.d /etc/rc.d/init.d") set(CPACK_RPM_SPEC_MORE_DEFINE "%define ignore \#") set(CPACK_RPM_USER_FILELIST "%ignore /etc/init.d") @@ -136,6 +136,6 @@ add_custom_target(testall COMMAND ${CMAKE_COMMAND} -DDEPS_OK=Y -DBUILD_TESTS=Y -DBUILD_TYPE=Debug -DINSTALL_DIR=${CMAKE_BINARY_DIR} -DINSTALL_SYSTEM_FILES=N ${CMAKE_SOURCE_DIR} COMMAND make install COMMAND /bin/sh -c "${CMAKE_BINARY_DIR}/bin/maxscale -c ${CMAKE_BINARY_DIR} &>/dev/null" - COMMAND make test - COMMAND /bin/sh -c "killall -KILL maxscale" - COMMENT "Running full test suite") \ No newline at end of file + COMMAND /bin/sh -c "make test || echo \"Test results written to: ${CMAKE_BINARY_DIR}/Testing/Temporary/\"" + COMMAND killall maxscale + COMMENT "Running full test suite" VERBATIM) \ No newline at end of file diff --git a/server/core/Makefile b/server/core/Makefile index a5db8d9fe..26c6482eb 100644 --- a/server/core/Makefile +++ b/server/core/Makefile @@ -47,7 +47,7 @@ CC=cc CFLAGS=-c -I/usr/include -I../include -I../modules/include -I../inih \ $(MYSQL_HEADERS) \ -I$(LOGPATH) -I$(UTILSPATH) \ - -Wall -g + -Wall -pedantic -g LDFLAGS=-rdynamic -L$(LOGPATH) \ -Wl,-rpath,$(DEST)/lib \ diff --git a/server/core/buffer.c b/server/core/buffer.c index 279d793b8..bb40a8d40 100644 --- a/server/core/buffer.c +++ b/server/core/buffer.c @@ -1,5 +1,5 @@ /* - * This file is distributed as part of the MariaDB Corporation MaxScale. It is free + * This file is distributed as part of the SkySQL Gateway. 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. @@ -13,11 +13,11 @@ * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright MariaDB Corporation Ab 2013-2014 + * Copyright SkySQL Ab 2013 */ /** - * @file buffer.h - The MaxScale buffer management functions + * @file buffer.h - The Gateway buffer management functions * * The buffer management is based on the principle of a linked list * of variable size buffer, the intention beign to allow longer @@ -65,20 +65,20 @@ gwbuf_alloc(unsigned int size) GWBUF *rval; SHARED_BUF *sbuf; - // Allocate the buffer header + /* Allocate the buffer header */ if ((rval = (GWBUF *)malloc(sizeof(GWBUF))) == NULL) { return NULL; } - // Allocate the shared data buffer + /* Allocate the shared data buffer */ if ((sbuf = (SHARED_BUF *)malloc(sizeof(SHARED_BUF))) == NULL) { free(rval); return NULL; } - // Allocate the space for the actual data + /* Allocate the space for the actual data */ if ((sbuf->data = (unsigned char *)malloc(size)) == NULL) { free(rval); @@ -87,7 +87,7 @@ SHARED_BUF *sbuf; } spinlock_init(&rval->gwbuf_lock); rval->start = sbuf->data; - rval->end = (void*)((uint8_t*)rval->start + size); + rval->end = (void *)((char *)rval->start+size); sbuf->refcount = 1; rval->sbuf = sbuf; rval->next = NULL; @@ -197,8 +197,8 @@ GWBUF *gwbuf_clone_portion( atomic_add(&buf->sbuf->refcount, 1); clonebuf->sbuf = buf->sbuf; clonebuf->gwbuf_type = buf->gwbuf_type; /*< clone info bits too */ - clonebuf->start = (void *)((char*)buf->start)+start_offset; - clonebuf->end = (void *)((char *)clonebuf->start)+length; + clonebuf->start = (void *)((char*)buf->start+start_offset); + clonebuf->end = (void *)((char *)clonebuf->start+length); clonebuf->gwbuf_type = buf->gwbuf_type; /*< clone the type for now */ clonebuf->properties = NULL; clonebuf->hint = NULL; @@ -277,8 +277,6 @@ return_clonebuf: GWBUF * gwbuf_append(GWBUF *head, GWBUF *tail) { -GWBUF *ptr = head; - if (!head) return tail; CHK_GWBUF(head); @@ -311,7 +309,7 @@ GWBUF *rval = head; CHK_GWBUF(head); GWBUF_CONSUME(head, length); - CHK_GWBUF(head); + CHK_GWBUF(head); if (GWBUF_EMPTY(head)) { @@ -370,11 +368,36 @@ gwbuf_trim(GWBUF *buf, unsigned int n_bytes) gwbuf_consume(buf, GWBUF_LENGTH(buf)); return NULL; } - buf->end -= n_bytes; + buf->end = (void *)((char *)buf->end - n_bytes); return buf; } +/** + * Trim bytes from the end of a GWBUF structure that may be the first + * in a list. If the buffer has n_bytes or less then it will be freed and + * the next buffer in the list will be returned, or if none, NULL. + * + * @param head The buffer to trim + * @param n_bytes The number of bytes to trim off + * @return The buffer chain or NULL if buffer chain now empty + */ +GWBUF * +gwbuf_rtrim(GWBUF *head, unsigned int n_bytes) +{ +GWBUF *rval = head; + CHK_GWBUF(head); + GWBUF_RTRIM(head, n_bytes); + CHK_GWBUF(head); + + if (GWBUF_EMPTY(head)) + { + rval = head->next; + gwbuf_free(head); + } + return rval; +} + /** * Set given type to all buffers on the list. * * diff --git a/server/core/config.c b/server/core/config.c index 0255f8c2c..ead016000 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -131,7 +131,7 @@ CONFIG_PARAMETER *param, *p1; ptr->element = NULL; cntxt->next = ptr; } - /* Check to see if the paramter already exists for the section */ + /* Check to see if the parameter already exists for the section */ p1 = ptr->parameters; while (p1) { diff --git a/server/core/dcb.c b/server/core/dcb.c index e624a4526..36e088dfc 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -32,7 +32,7 @@ * 12/06/13 Mark Riddoch Initial implementation * 21/06/13 Massimiliano Pinto free_dcb is used * 25/06/13 Massimiliano Pinto Added checks to session and router_session - * 28/06/13 Mark Riddoch Changed the free mechanism ti + * 28/06/13 Mark Riddoch Changed the free mechanism to * introduce a zombie state for the * dcb * 02/07/2013 Massimiliano Pinto Addition of delayqlock, delayq and @@ -73,7 +73,7 @@ extern int lm_enabled_logfiles_bitmask; -static DCB *allDCBs = NULL; /* Diagnotics need a list of DCBs */ +static DCB *allDCBs = NULL; /* Diagnostics need a list of DCBs */ static DCB *zombies = NULL; static SPINLOCK dcbspin = SPINLOCK_INIT; static SPINLOCK zombiespin = SPINLOCK_INIT; @@ -88,6 +88,7 @@ static DCB* dcb_get_next (DCB* dcb); static int dcb_null_write(DCB *dcb, GWBUF *buf); static int dcb_null_close(DCB *dcb); static int dcb_null_auth(DCB *dcb, SERVER *server, SESSION *session, GWBUF *buf); +static int dcb_isvalid_nolock(DCB *dcb); /** * Return the pointer to the lsit of zombie DCB's @@ -1893,20 +1894,40 @@ dcb_isvalid(DCB *dcb) DCB *ptr; int rval = 0; + if (dcb) + { spinlock_acquire(&dcbspin); + rval = dcb_isvalid_nolock(dcb); + spinlock_release(&dcbspin); + } + + return rval; +} + + +/** + * Check the passed DCB to ensure it is in the list of allDCBS. + * Requires that the DCB list is already locked before call. + * + * @param dcb The DCB to check + * @return 1 if the DCB is in the list, otherwise 0 + */ +static int +dcb_isvalid_nolock(DCB *dcb) +{ +DCB *ptr; +int rval = 0; + + if (dcb) + { ptr = allDCBs; - while (ptr) + while (ptr && ptr != dcb) { - if (ptr == dcb) - { - rval = 1; - break; - } ptr = ptr->next; } - spinlock_release(&dcbspin); - - return rval; + rval = (ptr == dcb); + } + return rval; } @@ -1919,33 +1940,11 @@ int rval = 0; static DCB * dcb_get_next (DCB* dcb) { - DCB* p; - spinlock_acquire(&dcbspin); - - p = allDCBs; - - if (dcb == NULL || p == NULL) - { - dcb = p; - - } - else - { - while (p != NULL && dcb != p) - { - p = p->next; - } - - if (p != NULL) - { - dcb = p->next; - } - else - { - dcb = NULL; - } + if (dcb) { + dcb = dcb_isvalid_nolock(dcb) ? dcb->next : NULL; } + else dcb = allDCBs; spinlock_release(&dcbspin); return dcb; diff --git a/server/core/gw_utils.c b/server/core/gw_utils.c index e89d72041..d5ee3e429 100644 --- a/server/core/gw_utils.c +++ b/server/core/gw_utils.c @@ -34,6 +34,7 @@ * 25-09-2013 Massimiliano Pinto setipaddress uses getaddrinfo * 06-02-2014 Mark Riddoch Added parse_bindconfig * 10-02-2014 Massimiliano Pinto Added return code to setipaddress + * 02-09-2014 Martin Brampton Replace C++ comment with C comment * *@endverbatim */ @@ -148,7 +149,7 @@ void gw_daemonize(void) { } if (pid != 0) { - // exit from main + /* exit from main */ exit(0); } diff --git a/server/core/service.c b/server/core/service.c index 040746f42..bf32846ce 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -91,10 +91,10 @@ static void service_add_qualified_param( * @param servname The service name * @param router Name of the router module this service uses * - * @return The newly created service or NULL if an error occured + * @return The newly created service or NULL if an error occurred */ SERVICE * -service_alloc(char *servname, char *router) +service_alloc(const char *servname, const char *router) { SERVICE *service; @@ -152,7 +152,7 @@ SERVICE *service; /** * Check to see if a service pointer is valid * - * @param service The poitner to check + * @param service The pointer to check * @return 1 if the service is in the list of all services */ int diff --git a/server/core/spinlock.c b/server/core/spinlock.c index 614d1249b..871ec42bb 100644 --- a/server/core/spinlock.c +++ b/server/core/spinlock.c @@ -30,6 +30,7 @@ #include #include +#include /** * Initialise a spinlock. @@ -39,13 +40,13 @@ void spinlock_init(SPINLOCK *lock) { - lock->lock = 0; + lock->lock = 0; #if SPINLOCK_PROFILE - lock->spins = 0; - lock->acquired = 0; - lock->waiting = 0; - lock->max_waiting = 0; - lock->contended = 0; + lock->spins = 0; + lock->acquired = 0; + lock->waiting = 0; + lock->max_waiting = 0; + lock->contended = 0; #endif } @@ -62,24 +63,30 @@ int spins = 0; atomic_add(&(lock->waiting), 1); #endif - while (atomic_add(&(lock->lock), 1) != 0) - { - atomic_add(&(lock->lock), -1); + +#ifdef __GNUC__ + while (__sync_lock_test_and_set(&(lock->lock), 1)) + while (lock->lock) { +#else + while (atomic_add(&(lock->lock), 1) != 0) + { + atomic_add(&(lock->lock), -1); +#endif #if SPINLOCK_PROFILE atomic_add(&(lock->spins), 1); spins++; #endif } #if SPINLOCK_PROFILE - if (spins) - { - lock->contended++; - if (lock->maxspins < spins) - lock->maxspins = spins; - } - lock->acquired++; - lock->owner = THREAD_SHELF(); - atomic_add(&(lock->waiting), -1); + if (spins) + { + lock->contended++; + if (lock->maxspins < spins) + lock->maxspins = spins; + } + lock->acquired++; + lock->owner = THREAD_SHELF(); + atomic_add(&(lock->waiting), -1); #endif } @@ -92,16 +99,20 @@ int spins = 0; int spinlock_acquire_nowait(SPINLOCK *lock) { - if (atomic_add(&(lock->lock), 1) != 0) - { - atomic_add(&(lock->lock), -1); - return FALSE; - } -#if SPINLOCK_PROFILE - lock->acquired++; - lock->owner = THREAD_SHELF(); +#ifdef __GNUC__ + if (__sync_lock_test_and_set(&(lock->lock), 1)) return FALSE; +#else + if (atomic_add(&(lock->lock), 1) != 0) + { + atomic_add(&(lock->lock), -1); + return FALSE; + } #endif - return TRUE; +#if SPINLOCK_PROFILE + lock->acquired++; + lock->owner = THREAD_SHELF(); +#endif + return TRUE; } /* @@ -112,11 +123,16 @@ spinlock_acquire_nowait(SPINLOCK *lock) void spinlock_release(SPINLOCK *lock) { -#if SPINLOCK_PROFILE - if (lock->waiting > lock->max_waiting) - lock->max_waiting = lock->waiting; + #if SPINLOCK_PROFILE + if (lock->waiting > lock->max_waiting) + lock->max_waiting = lock->waiting; +#endif +#ifdef __GNUC__ + __sync_synchronize(); /* Memory barrier. */ + lock->lock = 0; +#else + atomic_add(&(lock->lock), -1); #endif - atomic_add(&(lock->lock), -1); } /** diff --git a/server/core/test/makefile b/server/core/test/makefile index 14f2828f2..ed0bbc23e 100644 --- a/server/core/test/makefile +++ b/server/core/test/makefile @@ -18,10 +18,11 @@ LDFLAGS=-rdynamic -L$(LOGPATH) -L$(EMBEDDED_LIB) \ -Wl,-rpath,$(LOGPATH) -Wl,-rpath,$(UTILSPATH) \ -Wl,-rpath,$(EMBEDDED_LIB) -LIBS= -lz -lm -lcrypt -lcrypto -ldl -laio -lrt -pthread -llog_manager \ - -L../../inih/extra -linih -lssl -lstdc++ -lmysqld +LIBS= -L$(EMBEDDED_LIB) -lmysqld \ + -lz -lm -lcrypt -lcrypto -ldl -laio -lrt -pthread -llog_manager \ + -L../../inih/extra -linih -lssl -lstdc++ -TESTS=testhash testspinlock testfilter testadminusers +TESTS=testhash testspinlock testbuffer testmodutil testpoll testservice testdcb testfilter testadminusers cleantests: - $(DEL) *.o @@ -47,6 +48,39 @@ testspinlock: testspinlock.c -I$(ROOT_PATH)/utils \ testspinlock.c ../spinlock.o ../atomic.o ../thread.o -o testspinlock +testmodutil: testmodutil.c + $(CC) $(CFLAGS) \ + -I$(ROOT_PATH)/server/include \ + -I$(ROOT_PATH)/utils \ + testmodutil.c ../modutil.o ../buffer.o ../atomic.o -o testmodutil + +testbuffer: testbuffer.c + $(CC) $(CFLAGS) \ + -I$(ROOT_PATH)/server/include \ + -I$(ROOT_PATH)/utils \ + testbuffer.c ../buffer.o ../atomic.o -o testbuffer + +testpoll: testpoll.c + $(CC) $(CFLAGS) $(LDFLAGS) \ + -I$(ROOT_PATH)/server/include \ + -I$(ROOT_PATH)/utils \ + -I$(ROOT_PATH)/log_manager \ + testpoll.c libcore.a $(UTILSPATH)/skygw_utils.o $(LIBS) -o testpoll + +testservice: testservice.c + $(CC) $(CFLAGS) $(LDFLAGS) \ + -I$(ROOT_PATH)/server/include \ + -I$(ROOT_PATH)/utils \ + -I$(ROOT_PATH)/log_manager \ + testservice.c libcore.a $(UTILSPATH)/skygw_utils.o $(LIBS) -o testservice + +testdcb: testdcb.c + $(CC) $(CFLAGS) $(LDFLAGS) \ + -I$(ROOT_PATH)/server/include \ + -I$(ROOT_PATH)/utils \ + -I$(ROOT_PATH)/log_manager \ + testdcb.c libcore.a $(UTILSPATH)/skygw_utils.o $(LIBS) -o testdcb + testfilter: testfilter.c libcore.a $(CC) $(CFLAGS) $(LDFLAGS) \ -I$(ROOT_PATH)/server/include \ diff --git a/server/core/test/testspinlock.c b/server/core/test/testspinlock.c index f6ea810c8..14501cea5 100644 --- a/server/core/test/testspinlock.c +++ b/server/core/test/testspinlock.c @@ -105,12 +105,16 @@ test2() { SPINLOCK lck; void *handle; +struct timespec sleeptime; + + sleeptime.tv_sec = 10; + sleeptime.tv_nsec = 0; acquire_time = 0; spinlock_init(&lck); spinlock_acquire(&lck); handle = thread_start(test2_helper, (void *)&lck); - sleep(10); + nanosleep(&sleeptime, NULL); spinlock_release(&lck); thread_wait(handle); @@ -122,12 +126,118 @@ void *handle; return 0; } -main(int argc, char **argv) +/** + * test3 spinlock_acquire tests process bound threads + * + * Check that spinlock correctly blocks all other threads whilst the spinlock + * is held. + * + * Start multiple threads that obtain spinlock and run process bound + */ +#define THREADS 5 +#define ITERATIONS 50000 +#define PROCESS_LOOP 10000 +#define SECONDS 15 +#define NANOTIME 100000 + +static int times_run, failures; +static volatile int active; +static int threadrun[THREADS]; +static int nowait[THREADS]; +static SPINLOCK lck; +static void +test3_helper(void *data) +{ +// SPINLOCK *lck = (SPINLOCK *)data; +int i; +int n = *(int *)data; +struct timespec sleeptime; +time_t rawtime; + + sleeptime.tv_sec = 0; + sleeptime.tv_nsec = 1; + + while (1) { + if (spinlock_acquire_nowait(&lck)) { + nowait[n]++; + } + else { + spinlock_acquire(&lck); + } + if (times_run++ > ITERATIONS) { + break; + } + threadrun[n]++; + /* + if (99 == (times_run % 100)) { + time ( &rawtime ); + fprintf(stderr, "%s Done %d iterations of test, in thread %d.\n", asctime (localtime ( &rawtime )), times_run, n); + } + */ + if (0 != active) { + fprintf(stderr, "spinlock: test 3 failed with active non-zero after lock obtained.\n"); + failures++; + } + else { + active = 1; + for (i=0; i= '0' && X <= '9' ? X-'0' :\ X >= 'A' && X <= 'Z' ? X-'A'+10 :\ X >= 'a' && X <= 'z' ? X-'a'+10 :\ '\177') -// used in the bin2hex function +/* used in the bin2hex function */ char hex_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char hex_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; -////////////////////////////////////////// -//backend read event triggered by EPOLLIN -////////////////////////////////////////// +/***************************************** + * backend read event triggered by EPOLLIN +*****************************************/ int setnonblocking(int fd) { @@ -91,17 +92,17 @@ char *gw_strend(register const char *s) { return (char*) (s-1); } -/////////////////////////////// -// generate a random char -////////////////////////////// +/***************************************** +* generate a random char +*****************************************/ static char gw_randomchar() { return (char)((rand() % 78) + 30); } -///////////////////////////////// -// generate a random string -// output must be pre allocated -///////////////////////////////// +/***************************************** + * generate a random string + * output must be pre allocated +*****************************************/ int gw_generate_random_str(char *output, int len) { int i; @@ -116,10 +117,10 @@ int gw_generate_random_str(char *output, int len) { return 0; } -///////////////////////////////// -// hex string to binary data -// output must be pre allocated -///////////////////////////////// +/***************************************** + * hex string to binary data + * output must be pre allocated +*****************************************/ int gw_hex2bin(uint8_t *out, const char *in, unsigned int len) { const char *in_end= in + len; @@ -140,10 +141,10 @@ int gw_hex2bin(uint8_t *out, const char *in, unsigned int len) { return 0; } -///////////////////////////////// -// binary data to hex string -// output must be pre allocated -///////////////////////////////// +/***************************************** + * binary data to hex string + * output must be pre allocated +*****************************************/ char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len) { const uint8_t *in_end= in + len; if (len == 0 || in == NULL) { @@ -159,12 +160,12 @@ char *gw_bin2hex(char *out, const uint8_t *in, unsigned int len) { return out; } -/////////////////////////////////////////////////////// -// fill a preallocated buffer with XOR(str1, str2) -// XOR between 2 equal len strings -// note that XOR(str1, XOR(str1 CONCAT str2)) == str2 -// and that XOR(str1, str2) == XOR(str2, str1) -/////////////////////////////////////////////////////// +/**************************************************** + * fill a preallocated buffer with XOR(str1, str2) + * XOR between 2 equal len strings + * note that XOR(str1, XOR(str1 CONCAT str2)) == str2 + * and that XOR(str1, str2) == XOR(str2, str1) +*****************************************************/ void gw_str_xor(uint8_t *output, const uint8_t *input1, const uint8_t *input2, unsigned int len) { const uint8_t *input1_end = NULL; input1_end = input1 + len; @@ -175,10 +176,10 @@ void gw_str_xor(uint8_t *output, const uint8_t *input1, const uint8_t *input2, u *output = '\0'; } -///////////////////////////////////////////////////////////// -// fill a 20 bytes preallocated with SHA1 digest (160 bits) -// for one input on in_len bytes -///////////////////////////////////////////////////////////// +/********************************************************** + * fill a 20 bytes preallocated with SHA1 digest (160 bits) + * for one input on in_len bytes +**********************************************************/ void gw_sha1_str(const uint8_t *in, int in_len, uint8_t *out) { unsigned char hash[SHA_DIGEST_LENGTH]; @@ -186,10 +187,10 @@ void gw_sha1_str(const uint8_t *in, int in_len, uint8_t *out) { memcpy(out, hash, SHA_DIGEST_LENGTH); } -///////////////////////////////////////////////////////////// -// fill 20 bytes preallocated with SHA1 digest (160 bits) -// for two inputs, in_len and in2_len bytes -///////////////////////////////////////////////////////////// +/******************************************************** + * fill 20 bytes preallocated with SHA1 digest (160 bits) + * for two inputs, in_len and in2_len bytes +********************************************************/ void gw_sha1_2_str(const uint8_t *in, int in_len, const uint8_t *in2, int in2_len, uint8_t *out) { SHA_CTX context; unsigned char hash[SHA_DIGEST_LENGTH]; diff --git a/server/include/buffer.h b/server/include/buffer.h index c8b9f1418..76eebe63d 100644 --- a/server/include/buffer.h +++ b/server/include/buffer.h @@ -40,6 +40,9 @@ * 16/07/2013 Massimiliano Pinto Added command type for the queue * 10/07/2014 Mark Riddoch Addition of hints * 15/07/2014 Mark Riddoch Added buffer properties + * 03/10/2014 Martin Brampton Pointer arithmetic standard conformity + * Add more buffer handling macros + * Add gwbuf_rtrim (handle chains) * * @endverbatim */ @@ -147,19 +150,25 @@ typedef struct gwbuf { /*< * Macros to access the data in the buffers */ -/*< First valid, uncomsumed byte in the buffer */ +/*< First valid, unconsumed byte in the buffer */ #define GWBUF_DATA(b) ((b)->start) /*< Number of bytes in the individual buffer */ -#define GWBUF_LENGTH(b) ((unsigned int)(((uint8_t*)(b)->end) - ((uint8_t*)(b)->start))) +#define GWBUF_LENGTH(b) ((char *)(b)->end - (char *)(b)->start) + +/*< Return the byte at offset byte from the start of the unconsumed portion of the buffer */ +#define GWBUF_DATA_CHAR(b, byte) (GWBUF_LENGTH(b) < ((byte)+1) ? -1 : *(((char *)(b)->start)+4)) + +/*< Check that the data in a buffer has the SQL marker*/ +#define GWBUF_IS_SQL(b) (0x03 == GWBUF_DATA_CHAR(b,4)) /*< True if all bytes in the buffer have been consumed */ -#define GWBUF_EMPTY(b) ((b)->start == (b)->end) +#define GWBUF_EMPTY(b) ((char *)(b)->start >= (char *)(b)->end) /*< Consume a number of bytes in the buffer */ -#define GWBUF_CONSUME(b, bytes) (b)->start = (void*)((uint8_t*)(b)->start + (bytes)) +#define GWBUF_CONSUME(b, bytes) ((b)->start = bytes > ((char *)(b)->end - (char *)(b)->start) ? (b)->end : (void *)((char *)(b)->start + (bytes))); -#define GWBUF_RTRIM(b, bytes) (b)->end = (void*)((uint8_t*)(b)->end - (bytes)) +#define GWBUF_RTRIM(b, bytes) ((b)->end = bytes > ((char *)(b)->end - (char *)(b)->start) ? (b)->start : (void *)((char *)(b)->end - (bytes))); #define GWBUF_TYPE(b) (b)->gwbuf_type /*< @@ -171,6 +180,7 @@ extern GWBUF *gwbuf_clone(GWBUF *buf); extern GWBUF *gwbuf_append(GWBUF *head, GWBUF *tail); extern GWBUF *gwbuf_consume(GWBUF *head, unsigned int length); extern GWBUF *gwbuf_trim(GWBUF *head, unsigned int length); +extern GWBUF *gwbuf_rtrim(GWBUF *head, unsigned int length); extern unsigned int gwbuf_length(GWBUF *head); extern GWBUF *gwbuf_clone_portion(GWBUF *head, size_t offset, size_t len); extern GWBUF *gwbuf_clone_transform(GWBUF *head, gwbuf_type_t type); diff --git a/server/include/service.h b/server/include/service.h index 28daeb1c6..659e422aa 100644 --- a/server/include/service.h +++ b/server/include/service.h @@ -142,7 +142,7 @@ typedef enum count_spec_t {COUNT_NONE=0, COUNT_ATLEAST, COUNT_EXACT, COUNT_ATMOS #define SERVICE_STATE_ALLOC 1 /**< The service has been allocated */ #define SERVICE_STATE_STARTED 2 /**< The service has been started */ -extern SERVICE *service_alloc(char *, char *); +extern SERVICE *service_alloc(const char *, const char *); extern int service_free(SERVICE *); extern SERVICE *service_find(char *); extern int service_isvalid(SERVICE *); diff --git a/test.inc b/test.inc index 7c5e5c571..5249b8159 100644 --- a/test.inc +++ b/test.inc @@ -43,4 +43,5 @@ TMASTER_ID := # Global test log where all log is gathered # TEST_MAXSCALE_LOG := $(ROOT_PATH)/test/test_maxscale.log # -TEST_MAXSCALE_LOG := +TEST_MAXSCALE_LOG := /home/mbrampton/Dropbox/skygit/MaxScale/test/testserver.log + diff --git a/utils/skygw_debug.h b/utils/skygw_debug.h index 0b966ece0..1d22fbdbd 100644 --- a/utils/skygw_debug.h +++ b/utils/skygw_debug.h @@ -474,7 +474,7 @@ typedef enum skygw_chk_t { } #define CHK_GWBUF(b) { \ - ss_info_dassert(((b)->start <= (b)->end), \ + ss_info_dassert(((char *)(b)->start <= (char *)(b)->end), \ "gwbuf start has passed the endpoint"); \ }