diff --git a/server/core/dcb.c b/server/core/dcb.c index c92e2e2de..5c55be7dd 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -58,6 +58,7 @@ * 04/09/2015 Martin Brampton Changes to ensure DCB always has session pointer * 28/09/2015 Martin Brampton Add counters, maxima for DCBs and zombies * 29/05/2015 Martin Brampton Impose locking in dcb_call_foreach callbacks + * 17/10/2015 Martin Brampton Add hangup for each and bitmask display MaxAdmin * * @endverbatim */ @@ -544,6 +545,7 @@ dcb_process_victim_queue(DCB *listofdcb) /*< * Stop dcb's listening and modify state accordingly. */ + spinlock_acquire(&dcb->dcb_initlock); if (dcb->state == DCB_STATE_POLLING || dcb->state == DCB_STATE_LISTENING) { if (dcb->state == DCB_STATE_LISTENING) @@ -560,6 +562,7 @@ dcb_process_victim_queue(DCB *listofdcb) } else { /* Must be DCB_STATE_POLLING */ + spinlock_release(&dcb->dcb_initlock); if (0 == dcb->persistentstart && dcb_maybe_add_persistent(dcb)) { /* Have taken DCB into persistent pool, no further killing */ @@ -635,6 +638,7 @@ dcb_process_victim_queue(DCB *listofdcb) dcb->state = DCB_STATE_DISCONNECTED; nextdcb = dcb->memdata.next; + spinlock_release(&dcb->dcb_initlock); dcb_final_free(dcb); dcb = nextdcb; } @@ -1831,7 +1835,10 @@ dcb_close(DCB *dcb) /*< Set bit for each maxscale thread. This should be done before * the state is changed, so as to protect the DCB from premature * destruction. */ - bitmask_copy(&dcb->memdata.bitmask, poll_bitmask()); + if (dcb->server) + { + bitmask_copy(&dcb->memdata.bitmask, poll_bitmask()); + } } spinlock_release(&zombiespin); } @@ -2036,6 +2043,15 @@ dprintOneDCB(DCB *pdcb, DCB *dcb) dcb_printf(pdcb, "\tRole: %s\n", rolename); free(rolename); } + if (!bitmask_isallclear(&dcb->memdata.bitmask)) + { + char *bitmasktext = bitmask_render_readable(&dcb->memdata.bitmask); + if (bitmasktext) + { + dcb_printf(pdcb, "\tBitMask: %s\n", bitmasktext); + free(bitmasktext); + } + } dcb_printf(pdcb, "\tStatistics:\n"); dcb_printf(pdcb, "\t\tNo. of Reads: %d\n", dcb->stats.n_reads); dcb_printf(pdcb, "\t\tNo. of Writes: %d\n", dcb->stats.n_writes); @@ -2245,7 +2261,7 @@ gw_dcb_state2string (int state) case DCB_STATE_POLLING: return "DCB in the polling loop"; case DCB_STATE_NOPOLLING: - return "DCB not in the polling loop"; + return "DCB not in polling loop"; case DCB_STATE_LISTENING: return "DCB for listening socket"; case DCB_STATE_DISCONNECTED: diff --git a/server/core/gwbitmask.c b/server/core/gwbitmask.c index 765864d72..294a64c0f 100644 --- a/server/core/gwbitmask.c +++ b/server/core/gwbitmask.c @@ -17,6 +17,7 @@ */ #include #include +#include #include /** @@ -47,10 +48,14 @@ * Date Who Description * 28/06/13 Mark Riddoch Initial implementation * 20/08/15 Martin Brampton Added caveats about limitations (above) + * 17/10/15 Martin Brampton Added display of bitmask * * @endverbatim */ +static int bitmask_isset_without_spinlock(GWBITMASK *bitmask, int bit); +static int bitmask_count_bits_set(GWBITMASK *bitmask); + /** * Initialise a bitmask * @@ -151,19 +156,42 @@ unsigned char mask; * Return a non-zero value if the bit at the specified bit * position in the bitmask is set. * The bitmask will automatically be extended if the bit is - * beyond the current bitmask length. This could be optimised - * by assuming that a bit beyond the length is unset. + * beyond the current bitmask length. The work is done in the function + * bitmask_isset_without_spinlock, which can be called when a spinlock + * has already been acquired. * * @param bitmask Pointer the bitmask - * @param bit Bit to clear + * @param bit Bit to test */ int bitmask_isset(GWBITMASK *bitmask, int bit) { +int result; + + spinlock_acquire(&bitmask->lock); + result = bitmask_isset_without_spinlock(bitmask, bit); + spinlock_release(&bitmask->lock); + return result; +} + +/** + * Return a non-zero value if the bit at the specified bit + * position in the bitmask is set. Should be called while holding a + * lock on the bitmask. + * + * The bitmask will automatically be extended if the bit is + * beyond the current bitmask length. This could be optimised + * by assuming that a bit beyond the length is unset. + * + * @param bitmask Pointer the bitmask + * @param bit Bit to test + */ +static int +bitmask_isset_without_spinlock(GWBITMASK *bitmask, int bit) +{ unsigned char *ptr; unsigned char mask; - spinlock_acquire(&bitmask->lock); if (bit >= bitmask->length) { bitmask->bits = realloc(bitmask->bits, @@ -174,7 +202,6 @@ unsigned char mask; } ptr = bitmask->bits + (bit / 8); mask = 1 << (bit % 8); - spinlock_release(&bitmask->lock); return *ptr & mask; } @@ -239,3 +266,90 @@ bitmask_copy(GWBITMASK *dest, GWBITMASK *src) spinlock_release(&src->lock); } +/** + * Return a comma separated list of the numbers of the bits that are set in + * a bitmask, numbering starting at zero. Constrained to reject requests that + * could require more than three digit numbers. The returned string must be + * freed by the caller (unless it is null on account of memory allocation + * failure). + * + * @param bitmask Bitmap to make readable + * @return pointer to the newly allocated string, or null if no memory + */ +char * +bitmask_render_readable(GWBITMASK *bitmask) +{ + char *toobig = "Bitmask is too large to render readable"; + char *empty = "No bits are set";t + char onebit[5]; + char *result; + int count_set = 0; + + spinlock_acquire(&bitmask->lock); + if (999 < bitmask->length) + { + result = malloc(strlen(toobig)); + if (result) + { + strcpy(result, toobig); + } + } + else + { + count_set = bitmask_count_bits_set(bitmask); + if (count_set) + { + result = malloc(1 + (4 * count_set)); + if (result) + { + result[0] = 0; + for (int i = 0; ilength; i++) + { + if (bitmask_isset_without_spinlock(bitmask, i)) + { + sprintf(onebit, "%d,", i); + strcat(result, onebit); + } + } + result[strlen(result)-1] = 0; + } + } + else + { + result = malloc(strlen(empty)); + if (result) + { + strcpy(result, empty); + } + } + } + spinlock_release(&bitmask->lock); + return result; +} + +/** + * Return a count of the number of bits set in a bitmask. Helpful for setting + * the size of string needed to show the set bits in readable form. + * + * @param bitmask Bitmap whose bits are to be counted + * @return int Number of set bits + */ +static int +bitmask_count_bits_set(GWBITMASK *bitmask) +{ + const unsigned char oneBits[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4}; + unsigned char partresults; + int result = 0; + unsigned char *ptr, *eptr; + + ptr = bitmask->bits; + eptr = ptr + (bitmask->length / 8); + while (ptr < eptr) + { + partresults = oneBits[*ptr&0x0f]; + partresults += oneBits[*ptr>>4]; + result += partresults; + ptr++; + } + return result; +} \ No newline at end of file diff --git a/server/include/gwbitmask.h b/server/include/gwbitmask.h index baeb1ef77..26d5e3621 100644 --- a/server/include/gwbitmask.h +++ b/server/include/gwbitmask.h @@ -27,6 +27,7 @@ * * Date Who Description * 28/06/13 Mark Riddoch Initial implementation + * 17/10/15 Martin Brampton Add bitmask_render_readable * * @endverbatim */ @@ -51,4 +52,6 @@ extern void bitmask_clear(GWBITMASK *, int); extern int bitmask_isset(GWBITMASK *, int); extern int bitmask_isallclear(GWBITMASK *); extern void bitmask_copy(GWBITMASK *, GWBITMASK *); +extern char *bitmask_render_readable(GWBITMASK *bitmask); + #endif diff --git a/server/include/poll.h b/server/include/poll.h index e778c580c..f054667d4 100644 --- a/server/include/poll.h +++ b/server/include/poll.h @@ -29,6 +29,7 @@ * * Date Who Description * 19/06/13 Mark Riddoch Initial implementation + * 17/10/15 Martin Brampton Declare fake event functions * * @endverbatim */ @@ -60,9 +61,11 @@ extern void poll_set_maxwait(unsigned int); extern void poll_set_nonblocking_polls(unsigned int); extern void dprintPollStats(DCB *); extern void dShowThreads(DCB *dcb); -void poll_add_epollin_event_to_dcb(DCB* dcb, GWBUF* buf); +void poll_add_epollin_event_to_dcb(DCB* dcb, GWBUF* buf); extern void dShowEventQ(DCB *dcb); extern void dShowEventStats(DCB *dcb); -extern int poll_get_stat(POLL_STAT stat); +extern int poll_get_stat(POLL_STAT stat); extern RESULTSET *eventTimesGetList(); +extern void poll_fake_hangup_event(DCB *dcb); +extern void poll_fake_write_event(DCB *dcb); #endif diff --git a/server/modules/monitor/galeramon.c b/server/modules/monitor/galeramon.c index 2e3dd4ddd..5dde7a401 100644 --- a/server/modules/monitor/galeramon.c +++ b/server/modules/monitor/galeramon.c @@ -35,6 +35,7 @@ * 20/04/15 Guillaume Lefranc Added availableWhenDonor feature * 22/04/15 Martin Brampton Addition of disableMasterRoleSetting * 08/05/15 Markus Makela Addition of launchable scripts + * 17/10/15 Martin Brampton Change DCB callback to hangup * * @endverbatim */ @@ -541,13 +542,13 @@ monitor_event_t evtype; if (!(SERVER_IS_RUNNING(ptr->server)) || !(SERVER_IS_IN_CLUSTER(ptr->server))) { - dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING); + dcb_hangup_foreach(ptr->server); } if (SERVER_IS_DOWN(ptr->server)) { /** Increase this server'e error count */ - dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING); + dcb_hangup_foreach(ptr->server); ptr->mon_err_count += 1; } diff --git a/server/modules/monitor/mmmon.c b/server/modules/monitor/mmmon.c index 248fb92fd..1ada6ad8d 100644 --- a/server/modules/monitor/mmmon.c +++ b/server/modules/monitor/mmmon.c @@ -25,6 +25,7 @@ * Date Who Description * 08/09/14 Massimiliano Pinto Initial implementation * 08/05/15 Markus Makela Addition of launchable scripts + * 17/10/15 Martin Brampton Change DCB callback to hangup * * @endverbatim */ @@ -625,7 +626,7 @@ detect_stale_master = handle->detectStaleMaster; if (mon_status_changed(ptr)) { - dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING); + dcb_hangup_foreach(ptr->server); } if (mon_status_changed(ptr) || diff --git a/server/modules/monitor/mysql_mon.c b/server/modules/monitor/mysql_mon.c index 4bb8a59b5..aca071c21 100644 --- a/server/modules/monitor/mysql_mon.c +++ b/server/modules/monitor/mysql_mon.c @@ -47,6 +47,7 @@ * 18/11/14 Massimiliano Pinto One server only in configuration becomes master. * servers=server1 must be present in mysql_mon and in router sections as well. * 08/05/15 Markus Makela Added launchable scripts + * 17/10/15 Martin Brampton Change DCB callback to hangup * * @endverbatim */ @@ -861,8 +862,7 @@ detect_stale_master = handle->detectStaleMaster; if (!(SERVER_IS_RUNNING(ptr->server)) || !(SERVER_IS_IN_CLUSTER(ptr->server))) { - dcb_call_foreach(ptr->server,DCB_REASON_NOT_RESPONDING); - + dcb_hangup_foreach(ptr->server); }