Add conditionally compiled mechanism to "show buffers" to give a list of the currently allocated buffers, with a trace for each one of the calls that led to its creation.

This commit is contained in:
counterpoint 2015-11-11 09:03:48 +00:00
parent 72072778de
commit 1fc6b00211
3 changed files with 140 additions and 3 deletions

View File

@ -35,7 +35,9 @@
* 15/07/2014 Mark Riddoch Addition of properties
* 28/08/2014 Mark Riddoch Adition of tail pointer to speed
* the gwbuf_append process
*
* 09/11/2015 Martin Brampton Add buffer tracing (conditional compilation),
* accessed by "show buffers" maxadmin command
*
* @endverbatim
*/
#include <stdlib.h>
@ -47,6 +49,13 @@
#include <log_manager.h>
#include <errno.h>
#if defined(BUFFER_TRACE)
#include <hashtable.h>
#include <execinfo.h>
static HASHTABLE *buffer_hashtable = NULL;
#endif
/** Defined in log_manager.cc */
extern int lm_enabled_logfiles_bitmask;
extern size_t log_ses_count[];
@ -56,6 +65,12 @@ static buffer_object_t* gwbuf_remove_buffer_object(
GWBUF* buf,
buffer_object_t* bufobj);
#if defined(BUFFER_TRACE)
static void gwbuf_add_to_hashtable(GWBUF *buf);
static int bhashfn (void *key);
static int bcmpfn (void *key1, void *key2);
static void gwbuf_remove_from_hashtable(GWBUF *buf);
#endif
/**
* Allocate a new gateway buffer structure of size bytes.
@ -119,9 +134,111 @@ retblock:
"Error : Memory allocation failed due to %s.",
strerror_r(errno, errbuf, sizeof(errbuf)))));
}
#if defined(BUFFER_TRACE)
else
{
gwbuf_add_to_hashtable(rval);
}
#endif
return rval;
}
#if defined(BUFFER_TRACE)
/**
* Store a trace of buffer creation
*
* @param buf The buffer to record
*/
static void
gwbuf_add_to_hashtable(GWBUF *buf)
{
void *array[16];
size_t size, i, total;
char **strings;
char *tracetext;
size = backtrace (array, 16);
strings = backtrace_symbols (array, size);
total = (2 * size) + 1;
for (i = 0; i < size; i++)
{
total += strlen(strings[i]);
}
tracetext = (char *)malloc(total);
if (tracetext)
{
char *ptr = tracetext;
for (i = 0; i < size; i++)
{
sprintf(ptr, "\t%s\n", strings[i]);
ptr += (strlen(strings[i]) + 2);
}
free (strings);
if (NULL == buffer_hashtable)
{
buffer_hashtable = hashtable_alloc(10000, bhashfn, bcmpfn);
hashtable_memory_fns(buffer_hashtable,NULL,NULL,NULL,(HASHMEMORYFN)free);
}
hashtable_add(buffer_hashtable, buf, (void *)tracetext);
}
}
/**
* Hash a buffer (address) to an integer
*
* @param key The pointer to the buffer
*/
static int
bhashfn(void *key)
{
return (int)((uintptr_t) key % INT_MAX);
}
/**
* Compare two buffer keys (pointers)
*
* @param key1 The pointer to the first buffer
* @param key2 The pointer to the second buffer
*/
static int
bcmpfn(void *key1, void *key2)
{
return key1 == key2 ? 0 : 1;
}
/**
* Remove a buffer from the store of buffer traces
*
* @param buf The buffer to be removed
*/
static void
gwbuf_remove_from_hashtable(GWBUF *buf)
{
hashtable_delete(buffer_hashtable, buf);
}
/**
* Print all buffer traces via a given print DCB
*
* @param pdcb Print DCB for output
*/
void
dprintAllBuffers(void *pdcb)
{
void *buf;
char *backtrace;
HASHITERATOR *buffers = hashtable_iterator(buffer_hashtable);
while (NULL != (buf = hashtable_next(buffers)))
{
dcb_printf((DCB *)pdcb, "Buffer: %p\n", (void *)buf);
backtrace = hashtable_fetch(buffer_hashtable, buf);
dcb_printf((DCB *)pdcb, "%s", backtrace);
}
hashtable_iterator_free(buffers);
}
#endif
/**
* Free a gateway buffer
*
@ -162,6 +279,9 @@ BUF_PROPERTY *prop;
buf->hint = buf->hint->next;
hint_free(h);
}
#if defined(BUFFER_TRACE)
gwbuf_remove_from_hashtable(buf);
#endif
free(buf);
}
@ -201,6 +321,9 @@ GWBUF *rval;
rval->tail = rval;
rval->next = NULL;
CHK_GWBUF(rval);
#if defined(BUFFER_TRACE)
gwbuf_add_to_hashtable(rval);
#endif
return rval;
}
@ -268,6 +391,9 @@ GWBUF *gwbuf_clone_portion(
clonebuf->next = NULL;
clonebuf->tail = clonebuf;
CHK_GWBUF(clonebuf);
#if defined(BUFFER_TRACE)
gwbuf_add_to_hashtable(clonebuf);
#endif
return clonebuf;
}

View File

@ -43,6 +43,7 @@
* 03/10/2014 Martin Brampton Pointer arithmetic standard conformity
* Add more buffer handling macros
* Add gwbuf_rtrim (handle chains)
* 09/11/2014 Martin Brampton Add dprintAllBuffers (conditional compilation)
*
* @endverbatim
*/
@ -52,7 +53,6 @@
#include <spinlock.h>
#include <stdint.h>
EXTERN_C_BLOCK_BEGIN
/**
@ -202,6 +202,9 @@ void gwbuf_add_buffer_object(GWBUF* buf,
void* data,
void (*donefun_fp)(void *));
void* gwbuf_get_buffer_object_data(GWBUF* buf, bufobj_id_t id);
#if defined(BUFFER_TRACE)
extern void dprintAllBuffers(void *pdcb);
#endif
EXTERN_C_BLOCK_END

View File

@ -43,7 +43,8 @@
* 29/05/14 Mark Riddoch Add Filter support
* 16/10/14 Mark Riddoch Add show eventq
* 05/03/15 Massimiliano Pinto Added enable/disable feedback
* 27/05/15 Martin Brampton Add show persistent [server]
* 27/05/15 Martin Brampton Add show persistent [server]
* 06/11/15 Martin Brampton Add show buffers (conditional compilation)
*
* @endverbatim
*/
@ -60,6 +61,7 @@
#include <atomic.h>
#include <server.h>
#include <spinlock.h>
#include <buffer.h>
#include <dcb.h>
#include <poll.h>
#include <users.h>
@ -107,6 +109,12 @@ static void telnetdShowUsers(DCB *);
* The subcommands of the show command
*/
struct subcommand showoptions[] = {
#if defined(BUFFER_TRACE)
{ "buffers", 0, dprintAllBuffers,
"Show all buffers with backtrace",
"Show all buffers with backtrace",
{0, 0, 0} },
#endif
{ "dcbs", 0, dprintAllDCBs,
"Show all descriptor control blocks (network connections)",
"Show all descriptor control blocks (network connections)",