From 590d55a2064bdb8363145e8a4826a3cf6c6d420e Mon Sep 17 00:00:00 2001 From: antirez Date: Sat, 21 Apr 2012 19:20:03 +0200 Subject: [PATCH] Limit memory used by big SLOWLOG entries. Two limits are added: 1) Up to SLOWLOG_ENTRY_MAX_ARGV arguments are logged. 2) Up to SLOWLOG_ENTRY_MAX_STRING bytes per argument are logged. 3) slowlog-max-len is set to 128 by default (was 1024). The number of remaining arguments / bytes is logged in the entry so that the user can understand better the nature of the logged command. --- redis.conf | 2 +- src/redis.h | 2 +- src/slowlog.c | 35 +++++++++++++++++++++++++++++------ src/slowlog.h | 3 +++ tests/unit/slowlog.tcl | 17 +++++++++++++++++ 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/redis.conf b/redis.conf index bcad01e0..f5e15f69 100644 --- a/redis.conf +++ b/redis.conf @@ -428,7 +428,7 @@ slowlog-log-slower-than 10000 # There is no limit to this length. Just be aware that it will consume memory. # You can reclaim memory used by the slow log with SLOWLOG RESET. -slowlog-max-len 1024 +slowlog-max-len 128 ############################### ADVANCED CONFIG ############################### diff --git a/src/redis.h b/src/redis.h index 9702010e..2084dfd2 100644 --- a/src/redis.h +++ b/src/redis.h @@ -52,7 +52,7 @@ #define REDIS_AOF_REWRITE_MIN_SIZE (1024*1024) #define REDIS_AOF_REWRITE_ITEMS_PER_CMD 64 #define REDIS_SLOWLOG_LOG_SLOWER_THAN 10000 -#define REDIS_SLOWLOG_MAX_LEN 64 +#define REDIS_SLOWLOG_MAX_LEN 128 #define REDIS_MAX_CLIENTS 10000 #define REDIS_REPL_TIMEOUT 60 diff --git a/src/slowlog.c b/src/slowlog.c index cfd66dc6..53c44a01 100644 --- a/src/slowlog.c +++ b/src/slowlog.c @@ -16,13 +16,36 @@ * this function. */ slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) { slowlogEntry *se = zmalloc(sizeof(*se)); - int j; + int j, slargc = argc; + + if (slargc > SLOWLOG_ENTRY_MAX_ARGC) slargc = SLOWLOG_ENTRY_MAX_ARGC; + se->argc = slargc; + se->argv = zmalloc(sizeof(robj*)*slargc); + for (j = 0; j < slargc; j++) { + /* Logging too many arguments is a useless memory waste, so we stop + * at SLOWLOG_ENTRY_MAX_ARGC, but use the last argument to specify + * how many remaining arguments there were in the original command. */ + if (slargc != argc && j == slargc-1) { + se->argv[j] = createObject(REDIS_STRING, + sdscatprintf(sdsempty(),"... (%d more arguments)", + argc-slargc+1)); + } else { + /* Trim too long strings as well... */ + if (argv[j]->type == REDIS_STRING && + argv[j]->encoding == REDIS_ENCODING_RAW && + sdslen(argv[j]->ptr) > SLOWLOG_ENTRY_MAX_STRING) + { + sds s = sdsnewlen(argv[j]->ptr, SLOWLOG_ENTRY_MAX_STRING); - se->argc = argc; - se->argv = zmalloc(sizeof(robj*)*argc); - for (j = 0; j < argc; j++) { - se->argv[j] = argv[j]; - incrRefCount(argv[j]); + s = sdscatprintf(s,"... (%lu more bytes)", + (unsigned long) + sdslen(argv[j]->ptr) - SLOWLOG_ENTRY_MAX_STRING); + se->argv[j] = createObject(REDIS_STRING,s); + } else { + se->argv[j] = argv[j]; + incrRefCount(argv[j]); + } + } } se->time = time(NULL); se->duration = duration; diff --git a/src/slowlog.h b/src/slowlog.h index bad770db..bcc961cc 100644 --- a/src/slowlog.h +++ b/src/slowlog.h @@ -1,3 +1,6 @@ +#define SLOWLOG_ENTRY_MAX_ARGC 32 +#define SLOWLOG_ENTRY_MAX_STRING 128 + /* This structure defines an entry inside the slow log list */ typedef struct slowlogEntry { robj **argv; diff --git a/tests/unit/slowlog.tcl b/tests/unit/slowlog.tcl index 55a71e98..2216e925 100644 --- a/tests/unit/slowlog.tcl +++ b/tests/unit/slowlog.tcl @@ -38,4 +38,21 @@ start_server {tags {"slowlog"} overrides {slowlog-log-slower-than 1000000}} { assert_equal [expr {[lindex $e 2] > 100000}] 1 assert_equal [lindex $e 3] {debug sleep 0.2} } + + test {SLOWLOG - commands with too many arguments are trimmed} { + r config set slowlog-log-slower-than 0 + r slowlog reset + r sadd set 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 + set e [lindex [r slowlog get] 0] + lindex $e 3 + } {sadd set 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 {... (2 more arguments)}} + + test {SLOWLOG - too long arguments are trimmed} { + r config set slowlog-log-slower-than 0 + r slowlog reset + set arg [string repeat A 129] + r sadd set foo $arg + set e [lindex [r slowlog get] 0] + lindex $e 3 + } {sadd set foo {AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... (1 more bytes)}} } -- 2.45.2