mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-24 06:36:55 +00:00
MINOR: debug: Add an option that causes random allocation failures.
When compiling with DEBUG_FAIL_ALLOC, add a new option, tune.fail-alloc, that gives the percentage of chances an allocation fails. This is useful to check that allocation failures are always handled gracefully.
This commit is contained in:
parent
9c9da5ee89
commit
dc21ff778b
@ -1648,6 +1648,12 @@ tune.lua.service-timeout <timeout>
|
||||
counts only the pure Lua runtime. If the Lua does a sleep, the sleep is
|
||||
not taken in account. The default timeout is 4s.
|
||||
|
||||
tune.fail-alloc
|
||||
If compiled with DEBUG_FAIL_ALLOC, gives the percentage of chances an
|
||||
allocation attempt fails. Must be between 0 (no failure) and 100 (no
|
||||
success). This is useful to debug and make sure memory failures are handled
|
||||
gracefully.
|
||||
|
||||
tune.maxaccept <number>
|
||||
Sets the maximum number of consecutive connections a process may accept in a
|
||||
row before switching to other work. In single process mode, higher numbers
|
||||
|
@ -51,7 +51,7 @@
|
||||
/* On architectures supporting threads and double-word CAS, we can implement
|
||||
* lock-less memory pools. This isn't supported for debugging modes however.
|
||||
*/
|
||||
#if defined(USE_THREAD) && defined(HA_HAVE_CAS_DW) && !defined(DEBUG_NO_LOCKLESS_POOLS) && !defined(DEBUG_UAF)
|
||||
#if defined(USE_THREAD) && defined(HA_HAVE_CAS_DW) && !defined(DEBUG_NO_LOCKLESS_POOLS) && !defined(DEBUG_UAF) && !defined(DEBUG_FAIL_ALLOC)
|
||||
#define CONFIG_HAP_LOCKLESS_POOLS
|
||||
#ifndef CONFIG_HAP_POOL_CACHE_SIZE
|
||||
#define CONFIG_HAP_POOL_CACHE_SIZE 524288
|
||||
|
74
src/memory.c
74
src/memory.c
@ -16,6 +16,7 @@
|
||||
#include <types/global.h>
|
||||
#include <types/stats.h>
|
||||
|
||||
#include <common/cfgparse.h>
|
||||
#include <common/config.h>
|
||||
#include <common/debug.h>
|
||||
#include <common/hathreads.h>
|
||||
@ -46,6 +47,11 @@ THREAD_LOCAL size_t pool_cache_count = 0; /* #cache objects */
|
||||
static struct list pools = LIST_HEAD_INIT(pools);
|
||||
int mem_poison_byte = -1;
|
||||
|
||||
#ifdef DEBUG_FAIL_ALLOC
|
||||
static int mem_fail_rate = 0;
|
||||
static int mem_should_fail(const struct pool_head *);
|
||||
#endif
|
||||
|
||||
/* Try to find an existing shared pool with the same characteristics and
|
||||
* returns it, otherwise creates this one. NULL is returned if no memory
|
||||
* is available for a new creation. Two flags are supported :
|
||||
@ -301,6 +307,10 @@ void *__pool_refill_alloc(struct pool_head *pool, unsigned int avail)
|
||||
void *ptr = NULL;
|
||||
int failed = 0;
|
||||
|
||||
#ifdef DEBUG_FAIL_ALLOC
|
||||
if (mem_should_fail(pool))
|
||||
return NULL;
|
||||
#endif
|
||||
/* stop point */
|
||||
avail += pool->used;
|
||||
|
||||
@ -562,6 +572,70 @@ static struct cli_kw_list cli_kws = {{ },{
|
||||
|
||||
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
|
||||
|
||||
#ifdef DEBUG_FAIL_ALLOC
|
||||
#define MEM_FAIL_MAX_CHAR 32
|
||||
#define MEM_FAIL_MAX_STR 128
|
||||
static int mem_fail_cur_idx;
|
||||
static char mem_fail_str[MEM_FAIL_MAX_CHAR * MEM_FAIL_MAX_STR];
|
||||
__decl_hathreads(static HA_SPINLOCK_T mem_fail_lock);
|
||||
|
||||
int mem_should_fail(const struct pool_head *pool)
|
||||
{
|
||||
int ret;
|
||||
int n;
|
||||
|
||||
if (mem_fail_rate > 0 && !(global.mode & MODE_STARTING)) {
|
||||
int randnb = random() % 100;
|
||||
|
||||
if (mem_fail_rate > randnb)
|
||||
ret = 1;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
HA_SPIN_LOCK(START_LOCK, &mem_fail_lock);
|
||||
n = snprintf(&mem_fail_str[mem_fail_cur_idx * MEM_FAIL_MAX_CHAR],
|
||||
MEM_FAIL_MAX_CHAR - 2,
|
||||
"%d %.18s %d %d", mem_fail_cur_idx, pool->name, ret, tid);
|
||||
while (n < MEM_FAIL_MAX_CHAR - 1)
|
||||
mem_fail_str[mem_fail_cur_idx * MEM_FAIL_MAX_CHAR + n++] = ' ';
|
||||
if (mem_fail_cur_idx < MEM_FAIL_MAX_STR - 1)
|
||||
mem_fail_str[mem_fail_cur_idx * MEM_FAIL_MAX_CHAR + n] = '\n';
|
||||
else
|
||||
mem_fail_str[mem_fail_cur_idx * MEM_FAIL_MAX_CHAR + n] = 0;
|
||||
mem_fail_cur_idx++;
|
||||
if (mem_fail_cur_idx == MEM_FAIL_MAX_STR)
|
||||
mem_fail_cur_idx = 0;
|
||||
HA_SPIN_UNLOCK(START_LOCK, &mem_fail_lock);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/* config parser for global "tune.fail-alloc" */
|
||||
static int mem_parse_global_fail_alloc(char **args, int section_type, struct proxy *curpx,
|
||||
struct proxy *defpx, const char *file, int line,
|
||||
char **err)
|
||||
{
|
||||
if (too_many_args(1, args, err, NULL))
|
||||
return -1;
|
||||
mem_fail_rate = atoi(args[1]);
|
||||
if (mem_fail_rate < 0 || mem_fail_rate > 100) {
|
||||
memprintf(err, "'%s' expects a numeric value between 0 and 100.", args[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* register global config keywords */
|
||||
static struct cfg_kw_list mem_cfg_kws = {ILH, {
|
||||
#ifdef DEBUG_FAIL_ALLOC
|
||||
{ CFG_GLOBAL, "tune.fail-alloc", mem_parse_global_fail_alloc },
|
||||
#endif
|
||||
{ 0, NULL, NULL }
|
||||
}};
|
||||
|
||||
INITCALL1(STG_REGISTER, cfg_register_keywords, &mem_cfg_kws);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
|
Loading…
Reference in New Issue
Block a user