Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
别团等shy哥发育
redis
提交
d4f37363
R
redis
项目概览
别团等shy哥发育
/
redis
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
redis
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
d4f37363
编写于
2月 10, 2015
作者:
A
antirez
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'testing' into 3.0
上级
9c40565b
3a0e69f3
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
305 addition
and
12 deletion
+305
-12
src/redis-cli.c
src/redis-cli.c
+305
-12
未找到文件。
src/redis-cli.c
浏览文件 @
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
)))
{
history
=
1
;
if
(
getenv
(
"HOME"
)
!=
NULL
)
{
historyfile
=
sdscatprintf
(
sdsempty
(),
"%s/.rediscli_history"
,
getenv
(
"HOME"
));
historyfile
=
getHistoryPath
();
if
(
historyfile
!=
NULL
)
{
history
=
1
;
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
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录