diff --git a/src/cluster.c b/src/cluster.c index e87ca45a..57243132 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -210,7 +210,7 @@ void clusterInit(void) { exit(1); } if (aeCreateFileEvent(server.el, server.cfd, AE_READABLE, - clusterAcceptHandler, NULL) == AE_ERR) oom("creating file event"); + clusterAcceptHandler, NULL) == AE_ERR) redisPanic("Unrecoverable error creating Redis Cluster file event."); server.cluster.slots_to_keys = zslCreate(); } diff --git a/src/debug.c b/src/debug.c index e5686288..566b2b95 100644 --- a/src/debug.c +++ b/src/debug.c @@ -218,6 +218,10 @@ void computeDatasetDigest(unsigned char *final) { void debugCommand(redisClient *c) { if (!strcasecmp(c->argv[1]->ptr,"segfault")) { *((char*)-1) = 'x'; + } else if (!strcasecmp(c->argv[1]->ptr,"oom")) { + void *ptr = zmalloc(ULONG_MAX); /* Should trigger an out of memory. */ + zfree(ptr); + addReply(c,shared.ok); } else if (!strcasecmp(c->argv[1]->ptr,"assert")) { if (c->argc >= 3) c->argv[2] = tryObjectEncoding(c->argv[2]); redisAssertWithInfo(c,c->argv[0],1 == 2); diff --git a/src/redis.c b/src/redis.c index f2c5e2c7..92f1323b 100644 --- a/src/redis.c +++ b/src/redis.c @@ -334,17 +334,6 @@ err: if (server.logfile) close(fd); } -/* Redis generally does not try to recover from out of memory conditions - * when allocating objects or strings, it is not clear if it will be possible - * to report this condition to the client since the networking layer itself - * is based on heap allocation for send buffers, so we simply abort. - * At least the code will be simpler to read... */ -void oom(const char *msg) { - redisLog(REDIS_WARNING, "%s: Out of memory\n",msg); - sleep(1); - abort(); -} - /* Return the UNIX time in microseconds */ long long ustime(void) { struct timeval tv; @@ -1337,9 +1326,9 @@ void initServer() { server.stop_writes_on_bgsave_err = 1; aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL); if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE, - acceptTcpHandler,NULL) == AE_ERR) oom("creating file event"); + acceptTcpHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.ipfd file event."); if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE, - acceptUnixHandler,NULL) == AE_ERR) oom("creating file event"); + acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event."); if (server.aof_state == REDIS_AOF_ON) { server.aof_fd = open(server.aof_filename, @@ -2535,11 +2524,18 @@ void loadDataFromDisk(void) { } } +void redisOutOfMemoryHandler(size_t allocation_size) { + redisLog(REDIS_WARNING,"Out Of Memory allocating %zu bytes!", + allocation_size); + redisPanic("OOM"); +} + int main(int argc, char **argv) { struct timeval tv; /* We need to initialize our libraries, and the server configuration. */ zmalloc_enable_thread_safeness(); + zmalloc_set_oom_handler(redisOutOfMemoryHandler); srand(time(NULL)^getpid()); gettimeofday(&tv,NULL); dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid()); diff --git a/src/zmalloc.c b/src/zmalloc.c index 79b56158..afa9fda8 100644 --- a/src/zmalloc.c +++ b/src/zmalloc.c @@ -109,17 +109,19 @@ static size_t used_memory = 0; static int zmalloc_thread_safe = 0; pthread_mutex_t used_memory_mutex = PTHREAD_MUTEX_INITIALIZER; -static void zmalloc_oom(size_t size) { +static void zmalloc_default_oom(size_t size) { fprintf(stderr, "zmalloc: Out of memory trying to allocate %zu bytes\n", size); fflush(stderr); abort(); } +static void (*zmalloc_oom_handler)(size_t) = zmalloc_default_oom; + void *zmalloc(size_t size) { void *ptr = malloc(size+PREFIX_SIZE); - if (!ptr) zmalloc_oom(size); + if (!ptr) zmalloc_oom_handler(size); #ifdef HAVE_MALLOC_SIZE update_zmalloc_stat_alloc(zmalloc_size(ptr),size); return ptr; @@ -133,7 +135,7 @@ void *zmalloc(size_t size) { void *zcalloc(size_t size) { void *ptr = calloc(1, size+PREFIX_SIZE); - if (!ptr) zmalloc_oom(size); + if (!ptr) zmalloc_oom_handler(size); #ifdef HAVE_MALLOC_SIZE update_zmalloc_stat_alloc(zmalloc_size(ptr),size); return ptr; @@ -155,7 +157,7 @@ void *zrealloc(void *ptr, size_t size) { #ifdef HAVE_MALLOC_SIZE oldsize = zmalloc_size(ptr); newptr = realloc(ptr,size); - if (!newptr) zmalloc_oom(size); + if (!newptr) zmalloc_oom_handler(size); update_zmalloc_stat_free(oldsize); update_zmalloc_stat_alloc(zmalloc_size(newptr),size); @@ -236,6 +238,10 @@ void zmalloc_enable_thread_safeness(void) { zmalloc_thread_safe = 1; } +void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) { + zmalloc_oom_handler = oom_handler; +} + /* Get the RSS information in an OS-specific way. * * WARNING: the function zmalloc_get_rss() is not designed to be fast diff --git a/src/zmalloc.h b/src/zmalloc.h index 89f5b6ee..14e79534 100644 --- a/src/zmalloc.h +++ b/src/zmalloc.h @@ -72,6 +72,7 @@ void zfree(void *ptr); char *zstrdup(const char *s); size_t zmalloc_used_memory(void); void zmalloc_enable_thread_safeness(void); +void zmalloc_set_oom_handler(void (*oom_handler)(size_t)); float zmalloc_get_fragmentation_ratio(void); size_t zmalloc_get_rss(void); void zlibc_free(void *ptr);