From 43071993e19135c2f59fc6f013aa5522abcc2554 Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 15 Sep 2011 19:28:00 +0200 Subject: [PATCH 1/5] Implemented --latency in redis-cli --- src/redis-cli.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/redis-cli.c b/src/redis-cli.c index d0c9d979f..3bda064ce 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -61,6 +61,7 @@ static struct config { int shutdown; int monitor_mode; int pubsub_mode; + int latency_mode; int stdinarg; /* get last arg from stdin. (-x option) */ char *auth; int raw_output; /* output mode per command */ @@ -567,6 +568,8 @@ static int parseOptions(int argc, char **argv) { i++; } else if (!strcmp(argv[i],"--raw")) { config.raw_output = 1; + } else if (!strcmp(argv[i],"--latency")) { + config.latency_mode = 1; } else if (!strcmp(argv[i],"-d") && !lastarg) { sdsfree(config.mb_delim); config.mb_delim = sdsnew(argv[i+1]); @@ -617,6 +620,7 @@ static void usage() { " -x Read last argument from STDIN\n" " -d Multi-bulk delimiter in for raw formatting (default: \\n)\n" " --raw Use raw formatting for replies (default when STDOUT is not a tty)\n" +" --latency Enter a special mode continuously sampling latency.\n" " --help Output this help and exit\n" " --version Output version and exit\n" "\n" @@ -739,6 +743,37 @@ static int noninteractive(int argc, char **argv) { return retval; } +static void latencyMode(void) { + redisReply *reply; + long long start, latency, min, max, tot, count = 0; + double avg; + + if (!context) exit(1); + while(1) { + start = mstime(); + reply = redisCommand(context,"PING"); + if (reply == NULL) { + fprintf(stderr,"\nI/O error\n"); + exit(1); + } + latency = mstime()-start; + freeReplyObject(reply); + count++; + if (count == 1) { + min = max = tot = latency; + avg = (double) latency; + } else { + if (latency < min) min = latency; + if (latency > max) max = latency; + avg = (double) tot/count; + } + printf("\x1b[0G\x1b[2Kmin: %lld, max: %lld, avg: %.2f (%lld samples)", + min, max, avg, count); + fflush(stdout); + usleep(10000); + } +} + int main(int argc, char **argv) { int firstarg; @@ -752,6 +787,7 @@ int main(int argc, char **argv) { config.shutdown = 0; config.monitor_mode = 0; config.pubsub_mode = 0; + config.latency_mode = 0; config.stdinarg = 0; config.auth = NULL; config.raw_output = !isatty(fileno(stdout)) && (getenv("FAKETTY") == NULL); @@ -762,6 +798,12 @@ int main(int argc, char **argv) { argc -= firstarg; argv += firstarg; + /* Start in latency mode if appropriate */ + if (config.latency_mode) { + cliConnect(0); + latencyMode(); + } + /* Start interactive mode when no command is provided */ if (argc == 0) { /* Note that in repl mode we don't abort on connection error. From 96674b6d95c8990cc7dae885b27c76f377ddeb91 Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 15 Sep 2011 19:32:25 +0200 Subject: [PATCH 2/5] Fixed a bug in the average latency metering of redis-cli --latency --- src/redis-cli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/redis-cli.c b/src/redis-cli.c index 3bda064ce..328cd3df2 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -765,6 +765,7 @@ static void latencyMode(void) { } else { if (latency < min) min = latency; if (latency > max) max = latency; + tot += latency; avg = (double) tot/count; } printf("\x1b[0G\x1b[2Kmin: %lld, max: %lld, avg: %.2f (%lld samples)", From 5f54a5e615efca2c15a8990c336986d9c9497453 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Wed, 17 Aug 2011 18:15:06 +0200 Subject: [PATCH 3/5] Fix AOF race that may duplicate commands --- src/aof.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/aof.c b/src/aof.c index 7b15acb82..42f153bef 100644 --- a/src/aof.c +++ b/src/aof.c @@ -766,6 +766,11 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { server.appendseldb = -1; /* Make sure SELECT is re-issued */ aofUpdateCurrentSize(); server.auto_aofrewrite_base_size = server.appendonly_current_size; + + /* Clear regular AOF buffer since its contents was just written to + * the new AOF from the background rewrite buffer. */ + sdsfree(server.aofbuf); + server.aofbuf = sdsempty(); } redisLog(REDIS_NOTICE, "Background AOF rewrite successful"); From bdbf3acff5ffc5d114f18c1383b103fe6f45829e Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Wed, 17 Aug 2011 17:06:19 +0200 Subject: [PATCH 4/5] Enforce upper bound for number of requests in redis-benchmark --- src/redis-benchmark.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index 7295dc32a..e4a40e13a 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -53,9 +53,10 @@ static struct config { int hostport; const char *hostsocket; int numclients; - int requests; int liveclients; - int donerequests; + int requests; + int requests_issued; + int requests_finished; int keysize; int datasize; int randomkeys; @@ -148,7 +149,7 @@ static void randomizeClientKey(client c) { } static void clientDone(client c) { - if (config.donerequests == config.requests) { + if (config.requests_finished == config.requests) { freeClient(c); aeStop(config.el); return; @@ -189,8 +190,8 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) { exit(1); } - if (config.donerequests < config.requests) - config.latency[config.donerequests++] = c->latency; + if (config.requests_finished < config.requests) + config.latency[config.requests_finished++] = c->latency; clientDone(c); } } @@ -202,8 +203,15 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) { REDIS_NOTUSED(fd); REDIS_NOTUSED(mask); - /* When nothing was written yet, randomize keys and set start time. */ + /* Initialize request when nothing was written. */ if (c->written == 0) { + /* Enforce upper bound to number of requests. */ + if (config.requests_issued++ >= config.requests) { + freeClient(c); + return; + } + + /* Really initialize: randomize keys and set start time. */ if (config.randomkeys) randomizeClientKey(c); c->start = ustime(); c->latency = -1; @@ -286,10 +294,10 @@ static void showLatencyReport(void) { int i, curlat = 0; float perc, reqpersec; - reqpersec = (float)config.donerequests/((float)config.totlatency/1000); + reqpersec = (float)config.requests_finished/((float)config.totlatency/1000); if (!config.quiet) { printf("====== %s ======\n", config.title); - printf(" %d requests completed in %.2f seconds\n", config.donerequests, + printf(" %d requests completed in %.2f seconds\n", config.requests_finished, (float)config.totlatency/1000); printf(" %d parallel clients\n", config.numclients); printf(" %d bytes payload\n", config.datasize); @@ -314,7 +322,8 @@ static void benchmark(const char *title, const char *cmd, int len) { client c; config.title = title; - config.donerequests = 0; + config.requests_issued = 0; + config.requests_finished = 0; c = createClient(cmd,len); createMissingClients(c); @@ -416,7 +425,7 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData REDIS_NOTUSED(clientData); float dt = (float)(mstime()-config.start)/1000.0; - float rps = (float)config.donerequests/dt; + float rps = (float)config.requests_finished/dt; printf("%s: %.2f\r", config.title, rps); fflush(stdout); return 250; /* every 250ms */ @@ -438,7 +447,6 @@ int main(int argc, const char **argv) { config.el = aeCreateEventLoop(); aeCreateTimeEvent(config.el,1,showThroughput,NULL,NULL); config.keepalive = 1; - config.donerequests = 0; config.datasize = 3; config.randomkeys = 0; config.randomkeys_keyspacelen = 0; From 3aa4b0097062b13031506b6b52fc8fc4bfec6dfc Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Wed, 17 Aug 2011 18:09:01 +0200 Subject: [PATCH 5/5] Failing test related to AOF rewrite buffers --- tests/integration/aof-race.tcl | 35 ++++++++++++++++++++++++++++++++++ tests/test_helper.tcl | 1 + 2 files changed, 36 insertions(+) create mode 100644 tests/integration/aof-race.tcl diff --git a/tests/integration/aof-race.tcl b/tests/integration/aof-race.tcl new file mode 100644 index 000000000..207f20739 --- /dev/null +++ b/tests/integration/aof-race.tcl @@ -0,0 +1,35 @@ +set defaults { appendonly {yes} appendfilename {appendonly.aof} } +set server_path [tmpdir server.aof] +set aof_path "$server_path/appendonly.aof" + +proc start_server_aof {overrides code} { + upvar defaults defaults srv srv server_path server_path + set config [concat $defaults $overrides] + start_server [list overrides $config] $code +} + +tags {"aof"} { + # Specific test for a regression where internal buffers were not properly + # cleaned after a child responsible for an AOF rewrite exited. This buffer + # was subsequently appended to the new AOF, resulting in duplicate commands. + start_server_aof [list dir $server_path] { + set client [redis [srv host] [srv port]] + set bench [open "|src/redis-benchmark -q -p [srv port] -c 20 -n 20000 incr foo" "r+"] + after 100 + + # Benchmark should be running by now: start background rewrite + $client bgrewriteaof + + # Read until benchmark pipe reaches EOF + while {[string length [read $bench]] > 0} {} + + # Check contents of foo + assert_equal 20000 [$client get foo] + } + + # Restart server to replay AOF + start_server_aof [list dir $server_path] { + set client [redis [srv host] [srv port]] + assert_equal 20000 [$client get foo] + } +} diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl index 4f3cf01ec..476b58703 100644 --- a/tests/test_helper.tcl +++ b/tests/test_helper.tcl @@ -29,6 +29,7 @@ set ::all_tests { integration/replication-2 integration/replication-3 integration/aof + integration/aof-race unit/pubsub unit/slowlog unit/scripting