From 7db39b7fd3d9b3991c7cbda75ecbde6c491b358b Mon Sep 17 00:00:00 2001 From: mattcollier Date: Sun, 25 Jan 2015 14:01:39 -0500 Subject: [PATCH 01/11] Update redis-cli.c Code was adding '\n' (line 521) to the end of NIL values exlusively making csv output inconsistent. Removed '\n' --- src/redis-cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redis-cli.c b/src/redis-cli.c index ecb57e96..c364f9a9 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -493,7 +493,7 @@ static sds cliFormatReplyCSV(redisReply *r) { out = sdscatrepr(out,r->str,r->len); break; case REDIS_REPLY_NIL: - out = sdscat(out,"NIL\n"); + out = sdscat(out,"NIL"); break; case REDIS_REPLY_ARRAY: for (i = 0; i < r->elements; i++) { From 560823f54c18101b1591786066851eef77ac44ea Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 3 Feb 2015 09:34:20 +0100 Subject: [PATCH 02/11] Ignore config.sh inside create-cluster script dir. --- utils/create-cluster/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 utils/create-cluster/.gitignore diff --git a/utils/create-cluster/.gitignore b/utils/create-cluster/.gitignore new file mode 100644 index 00000000..cdd7c19c --- /dev/null +++ b/utils/create-cluster/.gitignore @@ -0,0 +1 @@ +config.sh From bee03daca7937600b26d3718a3e7cd30c732824e Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 10 Feb 2015 14:47:45 +0100 Subject: [PATCH 03/11] Faster memory efficiency test. This test on Linux was extremely slow, since in Tcl we can't enable easily tcp-nodelay, so the busy loop used to take *a lot* with bigger writes. Fixed using pipelining. --- tests/unit/memefficiency.tcl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/unit/memefficiency.tcl b/tests/unit/memefficiency.tcl index 14e135ce..7ca9a705 100644 --- a/tests/unit/memefficiency.tcl +++ b/tests/unit/memefficiency.tcl @@ -1,15 +1,20 @@ proc test_memory_efficiency {range} { r flushall + set rd [redis_deferring_client] set base_mem [s used_memory] set written 0 for {set j 0} {$j < 10000} {incr j} { set key key:$j set val [string repeat A [expr {int(rand()*$range)}]] - r set $key $val + $rd set $key $val incr written [string length $key] incr written [string length $val] incr written 2 ;# A separator is the minimum to store key-value data. } + for {set j 0} {$j < 10000} {incr j} { + $rd read ; # Discard replies + } + set current_mem [s used_memory] set used [expr {$current_mem-$base_mem}] set efficiency [expr {double($written)/$used}] From cdf30ba8c7b28e2595a0aaf656246b343481fd24 Mon Sep 17 00:00:00 2001 From: antirez Date: Sat, 7 Feb 2015 14:50:12 +0100 Subject: [PATCH 04/11] Initial implementation of redis-cli --latency-dist. --- src/redis-cli.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/src/redis-cli.c b/src/redis-cli.c index c364f9a9..cdd4f99c 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -44,6 +44,7 @@ #include #include #include +#include #include "hiredis.h" #include "sds.h" @@ -74,6 +75,7 @@ static struct config { int monitor_mode; int pubsub_mode; int latency_mode; + int latency_dist_mode; int latency_history; int cluster_mode; int cluster_reissue_command; @@ -742,6 +744,8 @@ static int parseOptions(int argc, char **argv) { config.output = OUTPUT_CSV; } else if (!strcmp(argv[i],"--latency")) { config.latency_mode = 1; + } else if (!strcmp(argv[i],"--latency-dist")) { + config.latency_dist_mode = 1; } else if (!strcmp(argv[i],"--latency-history")) { config.latency_mode = 1; config.latency_history = 1; @@ -834,6 +838,8 @@ static void usage(void) { " --latency Enter a special mode continuously sampling latency.\n" " --latency-history Like --latency but tracking latency changes over time.\n" " Default time interval is 15 sec. Change it using -i.\n" +" --latency-dist Shows latency as a spectrum, requires xterm 256 colors.\n" +" Default time interval is 1 sec. Change it using -i.\n" " --slave Simulate a slave showing commands received from the master.\n" " --rdb Transfer an RDB dump from remote server to local file.\n" " --pipe Transfer raw Redis protocol from stdin to server.\n" @@ -1080,6 +1086,146 @@ static void latencyMode(void) { } } +/*------------------------------------------------------------------------------ + * Latency distribution mode -- requires 256 colors xterm + *--------------------------------------------------------------------------- */ + +#define LATENCY_DIST_DEFAULT_INTERVAL 1000 /* milliseconds. */ +#define LATENCY_DIST_MIN_GRAY 233 /* Less than that is too hard to see gray. */ +#define LATENCY_DIST_MAX_GRAY 255 +#define LATENCY_DIST_GRAYS (LATENCY_DIST_MAX_GRAY-LATENCY_DIST_MIN_GRAY+1) + +/* Structure to store samples distribution. */ +struct distsamples { + long long max; /* Max latency to fit into this interval (usec). */ + long long count; /* Number of samples in this interval. */ + int character; /* Associated character in visualization. */ +}; + +/* Helper function for latencyDistMode(). Performs the spectrum visualization + * of the collected samples targeting an xterm 256 terminal. + * + * Takes an array of distsamples structures, ordered from smaller to bigger + * 'max' value. Last sample max must be 0, to mean that it olds all the + * samples greater than the previous one, and is also the stop sentinel. + * + * "tot' is the total number of samples in the different buckets, so it + * is the SUM(samples[i].conut) for i to 0 up to the max sample. + * + * As a side effect the function sets all the buckets count to 0. */ +void showLatencyDistSamples(struct distsamples *samples, long long tot) { + int j; + + /* We convert samples into a number between 0 and DIST_GRAYS, + * proportional to the percentage a given bucket represents. + * This way intensity of the different parts of the spectrum + * don't change relative to the number of requests, which avoids to + * pollute the visualization with non-latency related info. */ + printf("\033[38;5;0m"); /* Set foreground color to black. */ + for (j = 0; ; j++) { + float color = (float) samples[j].count / tot * LATENCY_DIST_GRAYS; + color = ceil(color) + (LATENCY_DIST_MIN_GRAY-1); + if (color == LATENCY_DIST_MIN_GRAY-1) { + printf("\033[48;5;0m "); + } else { + printf("\033[48;5;%dm%c", (int)color, samples[j].character); + } + samples[j].count = 0; + if (samples[j].max == 0) break; /* Last sample. */ + } + printf("\033[0m\n"); + fflush(stdout); +} + +/* Show the legend: different buckets values and colors meaning, so + * that the spectrum is more easily readable. */ +void showLatencyDistLegend(void) { + printf(". - * 0.01 0.125 0.5 milliseconds\n"); + printf("1,2,3,...,9 from 1 to 9 milliseconds\n"); + printf("A,B,C,D,E 10,20,30,40,50 milliseconds\n"); + printf("F,G,H,I,J .1,.2,.3,.4,.5 seconds\n"); + printf("K,L,M,N,O,P,Q,? 1,2,4,8,16,30,60,>60 seconds\n"); + printf("---------------------------------------------\n"); +} + +static void latencyDistMode(void) { + redisReply *reply; + long long start, latency, count = 0; + long long history_interval = + config.interval ? config.interval/1000 : + LATENCY_DIST_DEFAULT_INTERVAL; + long long history_start = ustime(); + int j, outputs = 0; + + struct distsamples samples[] = { + /* We use a mostly logarithmic scale, with certain linear intervals + * which are more interesting than others, like 1-10 milliseconds + * range. */ + {10,0,'.'}, /* 0.01 ms */ + {125,0,'-'}, /* 0.125 ms */ + {250,0,'*'}, /* 0.25 ms */ + {500,0,'#'}, /* 0.5 ms */ + {1000,0,'1'}, /* 1 ms */ + {2000,0,'2'}, /* 2 ms */ + {3000,0,'3'}, /* 3 ms */ + {4000,0,'4'}, /* 4 ms */ + {5000,0,'5'}, /* 5 ms */ + {6000,0,'6'}, /* 6 ms */ + {7000,0,'7'}, /* 7 ms */ + {8000,0,'8'}, /* 8 ms */ + {9000,0,'9'}, /* 9 ms */ + {10000,0,'A'}, /* 10 ms */ + {20000,0,'B'}, /* 20 ms */ + {30000,0,'C'}, /* 30 ms */ + {40000,0,'D'}, /* 40 ms */ + {50000,0,'E'}, /* 50 ms */ + {100000,0,'F'}, /* 0.1 s */ + {200000,0,'G'}, /* 0.2 s */ + {300000,0,'H'}, /* 0.3 s */ + {400000,0,'I'}, /* 0.4 s */ + {500000,0,'J'}, /* 0.5 s */ + {1000000,0,'K'}, /* 1 s */ + {2000000,0,'L'}, /* 2 s */ + {4000000,0,'M'}, /* 4 s */ + {8000000,0,'N'}, /* 8 s */ + {16000000,0,'O'}, /* 16 s */ + {30000000,0,'P'}, /* 30 s */ + {60000000,0,'Q'}, /* 1 minute */ + {0,0,'?'}, /* > 1 minute */ + }; + + if (!context) exit(1); + while(1) { + start = ustime(); + reply = redisCommand(context,"PING"); + if (reply == NULL) { + fprintf(stderr,"\nI/O error\n"); + exit(1); + } + latency = ustime()-start; + freeReplyObject(reply); + count++; + + /* Populate the relevant bucket. */ + for (j = 0; ; j++) { + if (samples[j].max == 0 || latency <= samples[j].max) { + samples[j].count++; + break; + } + } + + /* From time to time show the spectrum. */ + if (count && (ustime()-history_start)/1000 > history_interval) { + if ((outputs++ % 20) == 0) + showLatencyDistLegend(); + showLatencyDistSamples(samples,count); + history_start = ustime(); + count = 0; + } + usleep(LATENCY_SAMPLE_RATE * 1000); + } +} + /*------------------------------------------------------------------------------ * Slave mode *--------------------------------------------------------------------------- */ @@ -1896,6 +2042,7 @@ int main(int argc, char **argv) { config.monitor_mode = 0; config.pubsub_mode = 0; config.latency_mode = 0; + config.latency_dist_mode = 0; config.latency_history = 0; config.cluster_mode = 0; config.slave_mode = 0; @@ -1930,6 +2077,12 @@ int main(int argc, char **argv) { latencyMode(); } + /* Latency distribution mode */ + if (config.latency_dist_mode) { + if (cliConnect(0) == REDIS_ERR) exit(1); + latencyDistMode(); + } + /* Slave mode */ if (config.slave_mode) { if (cliConnect(0) == REDIS_ERR) exit(1); From 630634a37a9b0f96e14f4ef7821275874a993b99 Mon Sep 17 00:00:00 2001 From: antirez Date: Sat, 7 Feb 2015 15:05:40 +0100 Subject: [PATCH 05/11] Add missing latency-dest legend symbol. --- src/redis-cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redis-cli.c b/src/redis-cli.c index cdd4f99c..8f92f3d0 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -1140,7 +1140,7 @@ void showLatencyDistSamples(struct distsamples *samples, long long tot) { /* Show the legend: different buckets values and colors meaning, so * that the spectrum is more easily readable. */ void showLatencyDistLegend(void) { - printf(". - * 0.01 0.125 0.5 milliseconds\n"); + printf(". - * # .01 .125 .25 .5 milliseconds\n"); printf("1,2,3,...,9 from 1 to 9 milliseconds\n"); printf("A,B,C,D,E 10,20,30,40,50 milliseconds\n"); printf("F,G,H,I,J .1,.2,.3,.4,.5 seconds\n"); From b857578ba250389c9aea90b59d38400f87c7519f Mon Sep 17 00:00:00 2001 From: antirez Date: Sat, 7 Feb 2015 18:06:10 +0100 Subject: [PATCH 06/11] redis-cli latency dist: add new top HL. --- src/redis-cli.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/redis-cli.c b/src/redis-cli.c index 8f92f3d0..682641d0 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -1140,6 +1140,7 @@ void showLatencyDistSamples(struct distsamples *samples, long long tot) { /* Show the legend: different buckets values and colors meaning, so * that the spectrum is more easily readable. */ void showLatencyDistLegend(void) { + printf("---------------------------------------------\n"); printf(". - * # .01 .125 .25 .5 milliseconds\n"); printf("1,2,3,...,9 from 1 to 9 milliseconds\n"); printf("A,B,C,D,E 10,20,30,40,50 milliseconds\n"); From ad9976cd90ae60716515c1f34552661679f37ca4 Mon Sep 17 00:00:00 2001 From: antirez Date: Sat, 7 Feb 2015 20:15:40 +0100 Subject: [PATCH 07/11] redis-cli --latency-dist now uses a color palette. Still not happy with the result but low grays are hard to see in certain monitors with a non perfect gamma. --- src/redis-cli.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/redis-cli.c b/src/redis-cli.c index 682641d0..67bf9cde 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -1095,6 +1095,15 @@ static void latencyMode(void) { #define LATENCY_DIST_MAX_GRAY 255 #define LATENCY_DIST_GRAYS (LATENCY_DIST_MAX_GRAY-LATENCY_DIST_MIN_GRAY+1) +/* Gray palette. Currently not used. + * int spectrum_palette_size = 24; +* int spectrum_palette[] = {0, 233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255}; +*/ + +/* Color palette from https://github.com/draios/sysdig */ +int spectrum_palette[] = {0, 22, 28, 64, 34, 2, 76, 46, 118, 154, 191, 227, 226, 11, 220, 209, 208, 202, 197, 9, 1}; +int spectrum_palette_size = 21; + /* Structure to store samples distribution. */ struct distsamples { long long max; /* Max latency to fit into this interval (usec). */ @@ -1116,20 +1125,17 @@ struct distsamples { void showLatencyDistSamples(struct distsamples *samples, long long tot) { int j; - /* We convert samples into a number between 0 and DIST_GRAYS, + /* We convert samples into a index inside the palette * proportional to the percentage a given bucket represents. * This way intensity of the different parts of the spectrum * don't change relative to the number of requests, which avoids to * pollute the visualization with non-latency related info. */ printf("\033[38;5;0m"); /* Set foreground color to black. */ for (j = 0; ; j++) { - float color = (float) samples[j].count / tot * LATENCY_DIST_GRAYS; - color = ceil(color) + (LATENCY_DIST_MIN_GRAY-1); - if (color == LATENCY_DIST_MIN_GRAY-1) { - printf("\033[48;5;0m "); - } else { - printf("\033[48;5;%dm%c", (int)color, samples[j].character); - } + int coloridx = + ceil((float) samples[j].count / tot * (spectrum_palette_size-1)); + int color = spectrum_palette[coloridx]; + printf("\033[48;5;%dm%c", (int)color, samples[j].character); samples[j].count = 0; if (samples[j].max == 0) break; /* Last sample. */ } From 9a4d71e92e27049ba115eb188b4c6c45540521d7 Mon Sep 17 00:00:00 2001 From: antirez Date: Sun, 8 Feb 2015 17:39:42 +0100 Subject: [PATCH 08/11] redis-cli --latecy-dist reverted to gray scale. So far not able to find a color palette within the 256 colors which is not confusing. However I believe it is a possible task, so will try better later. --- src/redis-cli.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/redis-cli.c b/src/redis-cli.c index 67bf9cde..3eba86ce 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -1095,14 +1095,9 @@ static void latencyMode(void) { #define LATENCY_DIST_MAX_GRAY 255 #define LATENCY_DIST_GRAYS (LATENCY_DIST_MAX_GRAY-LATENCY_DIST_MIN_GRAY+1) -/* Gray palette. Currently not used. - * int spectrum_palette_size = 24; -* int spectrum_palette[] = {0, 233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255}; -*/ - -/* Color palette from https://github.com/draios/sysdig */ -int spectrum_palette[] = {0, 22, 28, 64, 34, 2, 76, 46, 118, 154, 191, 227, 226, 11, 220, 209, 208, 202, 197, 9, 1}; -int spectrum_palette_size = 21; +/* Gray palette. */ +int spectrum_palette_size = 24; +int spectrum_palette[] = {0, 233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255}; /* Structure to store samples distribution. */ struct distsamples { @@ -1146,12 +1141,19 @@ void showLatencyDistSamples(struct distsamples *samples, long long tot) { /* Show the legend: different buckets values and colors meaning, so * that the spectrum is more easily readable. */ void showLatencyDistLegend(void) { + int j; + printf("---------------------------------------------\n"); printf(". - * # .01 .125 .25 .5 milliseconds\n"); printf("1,2,3,...,9 from 1 to 9 milliseconds\n"); printf("A,B,C,D,E 10,20,30,40,50 milliseconds\n"); printf("F,G,H,I,J .1,.2,.3,.4,.5 seconds\n"); printf("K,L,M,N,O,P,Q,? 1,2,4,8,16,30,60,>60 seconds\n"); + printf("From 0 to 100%%: "); + for (j = 0; j < spectrum_palette_size; j++) { + printf("\033[48;5;%dm ", spectrum_palette[j]); + } + printf("\033[0m\n"); printf("---------------------------------------------\n"); } From 4793ea982a74fad63f79e1f47a1de9d71ce80d70 Mon Sep 17 00:00:00 2001 From: antirez Date: Sun, 8 Feb 2015 23:28:27 +0100 Subject: [PATCH 09/11] redis-cli: interactive reconnection for latency modes. --stat mode already used to reconnect automatically if the server is no longer available. This is useful since this is an interactive mode used for debugging, however the same applies to --latency and --latency-dist modes, so now both use the reconnecting command execution as well. The reconnection code was modified to use basic VT100 escape sequences in order to play better with different kinds of output on the screen when the reconnection happens, and to hide the reconnection attempt output when finally the reconnection happens. --- src/redis-cli.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/redis-cli.c b/src/redis-cli.c index 3eba86ce..0bf09d38 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -674,16 +674,17 @@ static int cliSendCommand(int argc, char **argv, int repeat) { return REDIS_OK; } -/* Send the INFO command, reconnecting the link if needed. */ -static redisReply *reconnectingInfo(void) { - redisContext *c = context; +/* Send a command reconnecting the link if needed. */ +static redisReply *reconnectingRedisCommand(redisContext *c, const char *fmt, ...) { redisReply *reply = NULL; int tries = 0; + va_list ap; assert(!c->err); while(reply == NULL) { while (c->err & (REDIS_ERR_IO | REDIS_ERR_EOF)) { - printf("Reconnecting (%d)...\r", ++tries); + printf("\r\x1b[0K"); /* Cursor to left edge + clear line. */ + printf("Reconnecting... %d\r", ++tries); fflush(stdout); redisFree(c); @@ -691,12 +692,15 @@ static redisReply *reconnectingInfo(void) { usleep(1000000); } - reply = redisCommand(c,"INFO"); + va_start(ap,fmt); + reply = redisvCommand(c,fmt,ap); + va_end(ap); + if (c->err && !(c->err & (REDIS_ERR_IO | REDIS_ERR_EOF))) { fprintf(stderr, "Error: %s\n", c->errstr); exit(1); } else if (tries > 0) { - printf("\n"); + printf("\r\x1b[0K"); /* Cursor to left edge + clear line. */ } } @@ -1056,7 +1060,7 @@ static void latencyMode(void) { if (!context) exit(1); while(1) { start = mstime(); - reply = redisCommand(context,"PING"); + reply = reconnectingRedisCommand(context,"PING"); if (reply == NULL) { fprintf(stderr,"\nI/O error\n"); exit(1); @@ -1206,7 +1210,7 @@ static void latencyDistMode(void) { if (!context) exit(1); while(1) { start = ustime(); - reply = redisCommand(context,"PING"); + reply = reconnectingRedisCommand(context,"PING"); if (reply == NULL) { fprintf(stderr,"\nI/O error\n"); exit(1); @@ -1854,7 +1858,7 @@ static void statMode(void) { char buf[64]; int j; - reply = reconnectingInfo(); + reply = reconnectingRedisCommand(context,"INFO"); if (reply->type == REDIS_REPLY_ERROR) { printf("ERROR: %s\n", reply->str); exit(1); From c3a5ad20184384b1c02e40e7d8e4ebe94cfd3316 Mon Sep 17 00:00:00 2001 From: antirez Date: Mon, 9 Feb 2015 11:06:44 +0100 Subject: [PATCH 10/11] redis-cli --lru-test implemented (cache workload simulator). --- src/redis-cli.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/src/redis-cli.c b/src/redis-cli.c index 0bf09d38..5f4d8a54 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -77,6 +77,8 @@ static struct config { int latency_mode; int latency_dist_mode; int latency_history; + int lru_test_mode; + long long lru_test_sample_size; int cluster_mode; int cluster_reissue_command; int slave_mode; @@ -753,6 +755,9 @@ static int parseOptions(int argc, char **argv) { } else if (!strcmp(argv[i],"--latency-history")) { config.latency_mode = 1; config.latency_history = 1; + } else if (!strcmp(argv[i],"--lru-test") && !lastarg) { + config.lru_test_mode = 1; + config.lru_test_sample_size = strtoll(argv[++i],NULL,10); } else if (!strcmp(argv[i],"--slave")) { config.slave_mode = 1; } else if (!strcmp(argv[i],"--stat")) { @@ -844,6 +849,7 @@ static void usage(void) { " Default time interval is 15 sec. Change it using -i.\n" " --latency-dist Shows latency as a spectrum, requires xterm 256 colors.\n" " Default time interval is 1 sec. Change it using -i.\n" +" --lru-test Simulate a cache workload with an 80-20 distribution.\n" " --slave Simulate a slave showing commands received from the master.\n" " --rdb Transfer an RDB dump from remote server to local file.\n" " --pipe Transfer raw Redis protocol from stdin to server.\n" @@ -1964,6 +1970,94 @@ static void scanMode(void) { exit(0); } +/*------------------------------------------------------------------------------ + * LRU test mode + *--------------------------------------------------------------------------- */ + +/* Return an integer from min to max (both inclusive) using a power-law + * distribution, depending on the value of alpha: the greater the alpha + * the more bias towards lower values. + * + * With alpha = 6.2 the output follows the 80-20 rule where 20% of + * the returned numbers will account for 80% of the frequency. */ +long long powerLawRand(long long min, long long max, double alpha) { + double pl, r; + + max += 1; + r = ((double)rand()) / RAND_MAX; + pl = pow( + ((pow(max,alpha+1) - pow(min,alpha+1))*r + pow(min,alpha+1)), + (1.0/(alpha+1))); + return (max-1-(long long)pl)+min; +} + +/* Generates a key name among a set of lru_test_sample_size keys, using + * an 80-20 distribution. */ +void LRUTestGenKey(char *buf, size_t buflen) { + snprintf(buf, buflen, "lru:%lld\n", + powerLawRand(1, config.lru_test_sample_size, 6.2)); +} + +#define LRU_CYCLE_PERIOD 1000 /* 1000 milliseconds. */ +#define LRU_CYCLE_PIPELINE_SIZE 250 +static void LRUTestMode(void) { + redisReply *reply; + char key[128]; + long long start_cycle; + int j; + + srand(time(NULL)^getpid()); + while(1) { + /* Perform cycles of 1 second with 50% writes and 50% reads. + * We use pipelining batching writes / reads N times per cycle in order + * to fill the target instance easily. */ + start_cycle = mstime(); + long long hits = 0, misses = 0; + while(mstime() - start_cycle < 1000) { + /* Write cycle. */ + for (j = 0; j < LRU_CYCLE_PIPELINE_SIZE; j++) { + LRUTestGenKey(key,sizeof(key)); + redisAppendCommand(context, "SET %s val",key); + } + for (j = 0; j < LRU_CYCLE_PIPELINE_SIZE; j++) + redisGetReply(context, (void**)&reply); + + /* Read cycle. */ + for (j = 0; j < LRU_CYCLE_PIPELINE_SIZE; j++) { + LRUTestGenKey(key,sizeof(key)); + redisAppendCommand(context, "GET %s",key); + } + for (j = 0; j < LRU_CYCLE_PIPELINE_SIZE; j++) { + if (redisGetReply(context, (void**)&reply) == REDIS_OK) { + switch(reply->type) { + case REDIS_REPLY_ERROR: + printf("%s\n", reply->str); + break; + case REDIS_REPLY_NIL: + misses++; + break; + default: + hits++; + break; + } + } + } + + if (context->err) { + fprintf(stderr,"I/O error during LRU test\n"); + exit(1); + } + } + /* Print stats. */ + printf( + "%lld Gets/sec | Hits: %lld (%.2f%%) | Misses: %lld (%.2f%%)\n", + hits+misses, + hits, (double)hits/(hits+misses)*100, + misses, (double)misses/(hits+misses)*100); + } + exit(0); +} + /*------------------------------------------------------------------------------ * Intrisic latency mode. * @@ -2057,6 +2151,8 @@ int main(int argc, char **argv) { config.latency_mode = 0; config.latency_dist_mode = 0; config.latency_history = 0; + config.lru_test_mode = 0; + config.lru_test_sample_size = 0; config.cluster_mode = 0; config.slave_mode = 0; config.getrdb_mode = 0; @@ -2133,6 +2229,12 @@ int main(int argc, char **argv) { scanMode(); } + /* LRU test mode */ + if (config.lru_test_mode) { + if (cliConnect(0) == REDIS_ERR) exit(1); + LRUTestMode(); + } + /* Intrinsic latency mode */ if (config.intrinsic_latency_mode) intrinsicLatencyMode(); From 3a0e69f391a0bff8006ff6c9404d321533fb0230 Mon Sep 17 00:00:00 2001 From: Charles Hooper Date: Mon, 10 Nov 2014 22:40:25 -0800 Subject: [PATCH 11/11] override histfile from env - fixes #831 and copies #833 --- src/redis-cli.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/redis-cli.c b/src/redis-cli.c index 5f4d8a54..8773d8e7 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -61,6 +61,8 @@ #define OUTPUT_CSV 2 #define REDIS_CLI_KEEPALIVE_INTERVAL 15 /* seconds */ #define REDIS_CLI_DEFAULT_PIPE_TIMEOUT 30 /* seconds */ +#define REDIS_CLI_HISTFILE_ENV "REDISCLI_HISTFILE" +#define REDIS_CLI_HISTFILE_DEFAULT ".rediscli_history" static redisContext *context; static struct config { @@ -142,6 +144,30 @@ static void cliRefreshPrompt(void) { snprintf(config.prompt+len,sizeof(config.prompt)-len,"> "); } +static sds getHistoryPath() { + char *path = NULL; + sds historyPath = NULL; + + /* check the env for a histfile override */ + path = getenv(REDIS_CLI_HISTFILE_ENV); + if (path != NULL && *path != '\0') { + if (!strcmp("/dev/null", path)) { + return NULL; + } + + /* if the env is set, return it */ + historyPath = sdscatprintf(sdsempty(), "%s", path); + } else { + char *home = getenv("HOME"); + if (home != NULL && *home != '\0') { + /* otherwise, return the default */ + historyPath = sdscatprintf(sdsempty(), "%s/%s", home, REDIS_CLI_HISTFILE_DEFAULT); + } + } + + return historyPath; +} + /*------------------------------------------------------------------------------ * Help functions *--------------------------------------------------------------------------- */ @@ -934,10 +960,9 @@ static void repl(void) { /* Only use history when stdin is a tty. */ if (isatty(fileno(stdin))) { - history = 1; - - if (getenv("HOME") != NULL) { - historyfile = sdscatprintf(sdsempty(),"%s/.rediscli_history",getenv("HOME")); + historyfile = getHistoryPath(); + if (historyfile != NULL) { + history = 1; linenoiseHistoryLoad(historyfile); } }