Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
d4f37363
Commit
d4f37363
authored
Feb 10, 2015
by
antirez
Browse files
Merge branch 'testing' into 3.0
parents
9c40565b
3a0e69f3
Changes
1
Show whitespace changes
Inline
Side-by-side
src/redis-cli.c
View file @
d4f37363
...
...
@@ -44,6 +44,7 @@
#include <assert.h>
#include <fcntl.h>
#include <limits.h>
#include <math.h>
#include "hiredis.h"
#include "sds.h"
...
...
@@ -60,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
{
...
...
@@ -74,7 +77,10 @@ static struct config {
int
monitor_mode
;
int
pubsub_mode
;
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
;
...
...
@@ -138,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
*--------------------------------------------------------------------------- */
...
...
@@ -672,16 +702,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
);
...
...
@@ -689,12 +720,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. */
}
}
...
...
@@ -742,9 +776,14 @@ 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
;
}
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"
))
{
...
...
@@ -834,6 +873,9 @@ 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
"
" --lru-test <keys> Simulate a cache workload with an 80-20 distribution.
\n
"
" --slave Simulate a slave showing commands received from the master.
\n
"
" --rdb <filename> Transfer an RDB dump from remote server to local file.
\n
"
" --pipe Transfer raw Redis protocol from stdin to server.
\n
"
...
...
@@ -918,10 +960,9 @@ static void repl(void) {
/* Only use history when stdin is a tty. */
if
(
isatty
(
fileno
(
stdin
)))
{
historyfile
=
getHistoryPath
();
if
(
historyfile
!=
NULL
)
{
history
=
1
;
if
(
getenv
(
"HOME"
)
!=
NULL
)
{
historyfile
=
sdscatprintf
(
sdsempty
(),
"%s/.rediscli_history"
,
getenv
(
"HOME"
));
linenoiseHistoryLoad
(
historyfile
);
}
}
...
...
@@ -1050,7 +1091,7 @@ static void latencyMode(void) {
if
(
!
context
)
exit
(
1
);
while
(
1
)
{
start
=
mstime
();
reply
=
redisCommand
(
context
,
"PING"
);
reply
=
re
connectingRe
disCommand
(
context
,
"PING"
);
if
(
reply
==
NULL
)
{
fprintf
(
stderr
,
"
\n
I/O error
\n
"
);
exit
(
1
);
...
...
@@ -1080,6 +1121,155 @@ 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)
/* 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
{
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 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
++
)
{
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. */
}
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
)
{
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
"
);
}
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
=
reconnectingRedisCommand
(
context
,
"PING"
);
if
(
reply
==
NULL
)
{
fprintf
(
stderr
,
"
\n
I/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
*--------------------------------------------------------------------------- */
...
...
@@ -1699,7 +1889,7 @@ static void statMode(void) {
char
buf
[
64
];
int
j
;
reply
=
reconnecting
Info
(
);
reply
=
reconnecting
RedisCommand
(
context
,
"INFO"
);
if
(
reply
->
type
==
REDIS_REPLY_ERROR
)
{
printf
(
"ERROR: %s
\n
"
,
reply
->
str
);
exit
(
1
);
...
...
@@ -1805,6 +1995,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.
*
...
...
@@ -1896,7 +2174,10 @@ 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
.
lru_test_mode
=
0
;
config
.
lru_test_sample_size
=
0
;
config
.
cluster_mode
=
0
;
config
.
slave_mode
=
0
;
config
.
getrdb_mode
=
0
;
...
...
@@ -1930,6 +2211,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
);
...
...
@@ -1967,6 +2254,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
();
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment