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:
@ -35,6 +35,8 @@
|
|||||||
* 15/07/2014 Mark Riddoch Addition of properties
|
* 15/07/2014 Mark Riddoch Addition of properties
|
||||||
* 28/08/2014 Mark Riddoch Adition of tail pointer to speed
|
* 28/08/2014 Mark Riddoch Adition of tail pointer to speed
|
||||||
* the gwbuf_append process
|
* the gwbuf_append process
|
||||||
|
* 09/11/2015 Martin Brampton Add buffer tracing (conditional compilation),
|
||||||
|
* accessed by "show buffers" maxadmin command
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -47,6 +49,13 @@
|
|||||||
#include <log_manager.h>
|
#include <log_manager.h>
|
||||||
#include <errno.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 */
|
/** Defined in log_manager.cc */
|
||||||
extern int lm_enabled_logfiles_bitmask;
|
extern int lm_enabled_logfiles_bitmask;
|
||||||
extern size_t log_ses_count[];
|
extern size_t log_ses_count[];
|
||||||
@ -56,6 +65,12 @@ static buffer_object_t* gwbuf_remove_buffer_object(
|
|||||||
GWBUF* buf,
|
GWBUF* buf,
|
||||||
buffer_object_t* bufobj);
|
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.
|
* Allocate a new gateway buffer structure of size bytes.
|
||||||
@ -119,9 +134,111 @@ retblock:
|
|||||||
"Error : Memory allocation failed due to %s.",
|
"Error : Memory allocation failed due to %s.",
|
||||||
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
strerror_r(errno, errbuf, sizeof(errbuf)))));
|
||||||
}
|
}
|
||||||
|
#if defined(BUFFER_TRACE)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gwbuf_add_to_hashtable(rval);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return rval;
|
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
|
* Free a gateway buffer
|
||||||
*
|
*
|
||||||
@ -162,6 +279,9 @@ BUF_PROPERTY *prop;
|
|||||||
buf->hint = buf->hint->next;
|
buf->hint = buf->hint->next;
|
||||||
hint_free(h);
|
hint_free(h);
|
||||||
}
|
}
|
||||||
|
#if defined(BUFFER_TRACE)
|
||||||
|
gwbuf_remove_from_hashtable(buf);
|
||||||
|
#endif
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +321,9 @@ GWBUF *rval;
|
|||||||
rval->tail = rval;
|
rval->tail = rval;
|
||||||
rval->next = NULL;
|
rval->next = NULL;
|
||||||
CHK_GWBUF(rval);
|
CHK_GWBUF(rval);
|
||||||
|
#if defined(BUFFER_TRACE)
|
||||||
|
gwbuf_add_to_hashtable(rval);
|
||||||
|
#endif
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +391,9 @@ GWBUF *gwbuf_clone_portion(
|
|||||||
clonebuf->next = NULL;
|
clonebuf->next = NULL;
|
||||||
clonebuf->tail = clonebuf;
|
clonebuf->tail = clonebuf;
|
||||||
CHK_GWBUF(clonebuf);
|
CHK_GWBUF(clonebuf);
|
||||||
|
#if defined(BUFFER_TRACE)
|
||||||
|
gwbuf_add_to_hashtable(clonebuf);
|
||||||
|
#endif
|
||||||
return clonebuf;
|
return clonebuf;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
* 03/10/2014 Martin Brampton Pointer arithmetic standard conformity
|
* 03/10/2014 Martin Brampton Pointer arithmetic standard conformity
|
||||||
* Add more buffer handling macros
|
* Add more buffer handling macros
|
||||||
* Add gwbuf_rtrim (handle chains)
|
* Add gwbuf_rtrim (handle chains)
|
||||||
|
* 09/11/2014 Martin Brampton Add dprintAllBuffers (conditional compilation)
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -52,7 +53,6 @@
|
|||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
EXTERN_C_BLOCK_BEGIN
|
EXTERN_C_BLOCK_BEGIN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -202,6 +202,9 @@ void gwbuf_add_buffer_object(GWBUF* buf,
|
|||||||
void* data,
|
void* data,
|
||||||
void (*donefun_fp)(void *));
|
void (*donefun_fp)(void *));
|
||||||
void* gwbuf_get_buffer_object_data(GWBUF* buf, bufobj_id_t id);
|
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
|
EXTERN_C_BLOCK_END
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
* 16/10/14 Mark Riddoch Add show eventq
|
* 16/10/14 Mark Riddoch Add show eventq
|
||||||
* 05/03/15 Massimiliano Pinto Added enable/disable feedback
|
* 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
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -60,6 +61,7 @@
|
|||||||
#include <atomic.h>
|
#include <atomic.h>
|
||||||
#include <server.h>
|
#include <server.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
|
#include <buffer.h>
|
||||||
#include <dcb.h>
|
#include <dcb.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <users.h>
|
#include <users.h>
|
||||||
@ -107,6 +109,12 @@ static void telnetdShowUsers(DCB *);
|
|||||||
* The subcommands of the show command
|
* The subcommands of the show command
|
||||||
*/
|
*/
|
||||||
struct subcommand showoptions[] = {
|
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,
|
{ "dcbs", 0, dprintAllDCBs,
|
||||||
"Show all descriptor control blocks (network connections)",
|
"Show all descriptor control blocks (network connections)",
|
||||||
"Show all descriptor control blocks (network connections)",
|
"Show all descriptor control blocks (network connections)",
|
||||||
|
Reference in New Issue
Block a user