Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
66d8818c
Commit
66d8818c
authored
Nov 08, 2011
by
antirez
Browse files
Merge branch 'unstable' into ttlres
parents
6a7841eb
b9031458
Changes
8
Hide whitespace changes
Inline
Side-by-side
deps/hiredis/hiredis.c
View file @
66d8818c
...
@@ -520,13 +520,14 @@ void redisReplyReaderFeed(void *reader, const char *buf, size_t len) {
...
@@ -520,13 +520,14 @@ void redisReplyReaderFeed(void *reader, const char *buf, size_t len) {
/* Copy the provided buffer. */
/* Copy the provided buffer. */
if
(
buf
!=
NULL
&&
len
>=
1
)
{
if
(
buf
!=
NULL
&&
len
>=
1
)
{
#if 0
/* Destroy internal buffer when it is empty and is quite large. */
/* Destroy internal buffer when it is empty and is quite large. */
if (r->len == 0 && sdsavail(r->buf) > 16*1024) {
if (r->len == 0 && sdsavail(r->buf) > 16*1024) {
sdsfree(r->buf);
sdsfree(r->buf);
r->buf = sdsempty();
r->buf = sdsempty();
r->pos = 0;
r->pos = 0;
}
}
#endif
r
->
buf
=
sdscatlen
(
r
->
buf
,
buf
,
len
);
r
->
buf
=
sdscatlen
(
r
->
buf
,
buf
,
len
);
r
->
len
=
sdslen
(
r
->
buf
);
r
->
len
=
sdslen
(
r
->
buf
);
}
}
...
@@ -901,7 +902,7 @@ static void __redisCreateReplyReader(redisContext *c) {
...
@@ -901,7 +902,7 @@ static void __redisCreateReplyReader(redisContext *c) {
* After this function is called, you may use redisContextReadReply to
* After this function is called, you may use redisContextReadReply to
* see if there is a reply available. */
* see if there is a reply available. */
int
redisBufferRead
(
redisContext
*
c
)
{
int
redisBufferRead
(
redisContext
*
c
)
{
char
buf
[
2048
];
char
buf
[
1024
*
16
];
int
nread
=
read
(
c
->
fd
,
buf
,
sizeof
(
buf
));
int
nread
=
read
(
c
->
fd
,
buf
,
sizeof
(
buf
));
if
(
nread
==
-
1
)
{
if
(
nread
==
-
1
)
{
if
(
errno
==
EAGAIN
&&
!
(
c
->
flags
&
REDIS_BLOCK
))
{
if
(
errno
==
EAGAIN
&&
!
(
c
->
flags
&
REDIS_BLOCK
))
{
...
...
src/networking.c
View file @
66d8818c
...
@@ -767,6 +767,17 @@ int processMultibulkBuffer(redisClient *c) {
...
@@ -767,6 +767,17 @@ int processMultibulkBuffer(redisClient *c) {
}
}
pos
+=
newline
-
(
c
->
querybuf
+
pos
)
+
2
;
pos
+=
newline
-
(
c
->
querybuf
+
pos
)
+
2
;
if
(
ll
>=
REDIS_MBULK_BIG_ARG
)
{
/* If we are going to read a large object from network
* try to make it likely that it will start at c->querybuf
* boundary so that we can optimized object creation
* avoiding a large copy of data. */
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
pos
,
-
1
);
pos
=
0
;
/* Hint the sds library about the amount of bytes this string is
* going to contain. */
c
->
querybuf
=
sdsMakeRoomFor
(
c
->
querybuf
,
ll
+
2
);
}
c
->
bulklen
=
ll
;
c
->
bulklen
=
ll
;
}
}
...
@@ -775,15 +786,32 @@ int processMultibulkBuffer(redisClient *c) {
...
@@ -775,15 +786,32 @@ int processMultibulkBuffer(redisClient *c) {
/* Not enough data (+2 == trailing \r\n) */
/* Not enough data (+2 == trailing \r\n) */
break
;
break
;
}
else
{
}
else
{
c
->
argv
[
c
->
argc
++
]
=
createStringObject
(
c
->
querybuf
+
pos
,
c
->
bulklen
);
/* Optimization: if the buffer contanins JUST our bulk element
pos
+=
c
->
bulklen
+
2
;
* instead of creating a new object by *copying* the sds we
* just use the current sds string. */
if
(
pos
==
0
&&
c
->
bulklen
>=
REDIS_MBULK_BIG_ARG
&&
(
signed
)
sdslen
(
c
->
querybuf
)
==
c
->
bulklen
+
2
)
{
c
->
argv
[
c
->
argc
++
]
=
createObject
(
REDIS_STRING
,
c
->
querybuf
);
sdsIncrLen
(
c
->
querybuf
,
-
2
);
/* remove CRLF */
c
->
querybuf
=
sdsempty
();
/* Assume that if we saw a fat argument we'll see another one
* likely... */
c
->
querybuf
=
sdsMakeRoomFor
(
c
->
querybuf
,
c
->
bulklen
+
2
);
pos
=
0
;
}
else
{
c
->
argv
[
c
->
argc
++
]
=
createStringObject
(
c
->
querybuf
+
pos
,
c
->
bulklen
);
pos
+=
c
->
bulklen
+
2
;
}
c
->
bulklen
=
-
1
;
c
->
bulklen
=
-
1
;
c
->
multibulklen
--
;
c
->
multibulklen
--
;
}
}
}
}
/* Trim to pos */
/* Trim to pos */
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
pos
,
-
1
);
if
(
pos
)
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
pos
,
-
1
);
/* We're done when c->multibulk == 0 */
/* We're done when c->multibulk == 0 */
if
(
c
->
multibulklen
==
0
)
{
if
(
c
->
multibulklen
==
0
)
{
...
@@ -833,12 +861,29 @@ void processInputBuffer(redisClient *c) {
...
@@ -833,12 +861,29 @@ void processInputBuffer(redisClient *c) {
void
readQueryFromClient
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
)
{
void
readQueryFromClient
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
)
{
redisClient
*
c
=
(
redisClient
*
)
privdata
;
redisClient
*
c
=
(
redisClient
*
)
privdata
;
char
buf
[
REDIS_IOBUF_LEN
]
;
int
nread
,
readlen
;
int
nread
;
size_t
qblen
;
REDIS_NOTUSED
(
el
);
REDIS_NOTUSED
(
el
);
REDIS_NOTUSED
(
mask
);
REDIS_NOTUSED
(
mask
);
nread
=
read
(
fd
,
buf
,
REDIS_IOBUF_LEN
);
readlen
=
REDIS_IOBUF_LEN
;
/* If this is a multi bulk request, and we are processing a bulk reply
* that is large enough, try to maximize the probabilty that the query
* buffer contains excatly the SDS string representing the object, even
* at the risk of requring more read(2) calls. This way the function
* processMultiBulkBuffer() can avoid copying buffers to create the
* Redis Object representing the argument. */
if
(
c
->
reqtype
==
REDIS_REQ_MULTIBULK
&&
c
->
multibulklen
&&
c
->
bulklen
!=
-
1
&&
c
->
bulklen
>=
REDIS_MBULK_BIG_ARG
)
{
int
remaining
=
(
unsigned
)(
c
->
bulklen
+
2
)
-
sdslen
(
c
->
querybuf
);
if
(
remaining
<
readlen
)
readlen
=
remaining
;
}
qblen
=
sdslen
(
c
->
querybuf
);
c
->
querybuf
=
sdsMakeRoomFor
(
c
->
querybuf
,
readlen
);
nread
=
read
(
fd
,
c
->
querybuf
+
qblen
,
readlen
);
if
(
nread
==
-
1
)
{
if
(
nread
==
-
1
)
{
if
(
errno
==
EAGAIN
)
{
if
(
errno
==
EAGAIN
)
{
nread
=
0
;
nread
=
0
;
...
@@ -853,7 +898,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
...
@@ -853,7 +898,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
return
;
return
;
}
}
if
(
nread
)
{
if
(
nread
)
{
c
->
querybuf
=
sdscatl
en
(
c
->
querybuf
,
buf
,
nread
);
sdsIncrL
en
(
c
->
querybuf
,
nread
);
c
->
lastinteraction
=
time
(
NULL
);
c
->
lastinteraction
=
time
(
NULL
);
}
else
{
}
else
{
return
;
return
;
...
...
src/redis-benchmark.c
View file @
66d8818c
...
@@ -68,8 +68,10 @@ static struct config {
...
@@ -68,8 +68,10 @@ static struct config {
const
char
*
title
;
const
char
*
title
;
list
*
clients
;
list
*
clients
;
int
quiet
;
int
quiet
;
int
csv
;
int
loop
;
int
loop
;
int
idlemode
;
int
idlemode
;
char
*
tests
;
}
config
;
}
config
;
typedef
struct
_client
{
typedef
struct
_client
{
...
@@ -295,7 +297,7 @@ static void showLatencyReport(void) {
...
@@ -295,7 +297,7 @@ static void showLatencyReport(void) {
float
perc
,
reqpersec
;
float
perc
,
reqpersec
;
reqpersec
=
(
float
)
config
.
requests_finished
/
((
float
)
config
.
totlatency
/
1000
);
reqpersec
=
(
float
)
config
.
requests_finished
/
((
float
)
config
.
totlatency
/
1000
);
if
(
!
config
.
quiet
)
{
if
(
!
config
.
quiet
&&
!
config
.
csv
)
{
printf
(
"====== %s ======
\n
"
,
config
.
title
);
printf
(
"====== %s ======
\n
"
,
config
.
title
);
printf
(
" %d requests completed in %.2f seconds
\n
"
,
config
.
requests_finished
,
printf
(
" %d requests completed in %.2f seconds
\n
"
,
config
.
requests_finished
,
(
float
)
config
.
totlatency
/
1000
);
(
float
)
config
.
totlatency
/
1000
);
...
@@ -313,6 +315,8 @@ static void showLatencyReport(void) {
...
@@ -313,6 +315,8 @@ static void showLatencyReport(void) {
}
}
}
}
printf
(
"%.2f requests per second
\n\n
"
,
reqpersec
);
printf
(
"%.2f requests per second
\n\n
"
,
reqpersec
);
}
else
if
(
config
.
csv
)
{
printf
(
"
\"
%s
\"
,
\"
%.2f
\"\n
"
,
config
.
title
,
reqpersec
);
}
else
{
}
else
{
printf
(
"%s: %.2f requests per second
\n
"
,
config
.
title
,
reqpersec
);
printf
(
"%s: %.2f requests per second
\n
"
,
config
.
title
,
reqpersec
);
}
}
...
@@ -367,7 +371,7 @@ int parseOptions(int argc, const char **argv) {
...
@@ -367,7 +371,7 @@ int parseOptions(int argc, const char **argv) {
if
(
lastarg
)
goto
invalid
;
if
(
lastarg
)
goto
invalid
;
config
.
datasize
=
atoi
(
argv
[
++
i
]);
config
.
datasize
=
atoi
(
argv
[
++
i
]);
if
(
config
.
datasize
<
1
)
config
.
datasize
=
1
;
if
(
config
.
datasize
<
1
)
config
.
datasize
=
1
;
if
(
config
.
datasize
>
1024
*
1024
)
config
.
datasize
=
1024
*
1024
;
if
(
config
.
datasize
>
1024
*
1024
*
1024
)
config
.
datasize
=
1024
*
1024
*
1024
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-r"
))
{
}
else
if
(
!
strcmp
(
argv
[
i
],
"-r"
))
{
if
(
lastarg
)
goto
invalid
;
if
(
lastarg
)
goto
invalid
;
config
.
randomkeys
=
1
;
config
.
randomkeys
=
1
;
...
@@ -376,10 +380,23 @@ int parseOptions(int argc, const char **argv) {
...
@@ -376,10 +380,23 @@ int parseOptions(int argc, const char **argv) {
config
.
randomkeys_keyspacelen
=
0
;
config
.
randomkeys_keyspacelen
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-q"
))
{
}
else
if
(
!
strcmp
(
argv
[
i
],
"-q"
))
{
config
.
quiet
=
1
;
config
.
quiet
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--csv"
))
{
config
.
csv
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-l"
))
{
}
else
if
(
!
strcmp
(
argv
[
i
],
"-l"
))
{
config
.
loop
=
1
;
config
.
loop
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-I"
))
{
}
else
if
(
!
strcmp
(
argv
[
i
],
"-I"
))
{
config
.
idlemode
=
1
;
config
.
idlemode
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-t"
))
{
if
(
lastarg
)
goto
invalid
;
/* We get the list of tests to run as a string in the form
* get,set,lrange,...,test_N. Then we add a comma before and
* after the string in order to make sure that searching
* for ",testname," will always get a match if the test is
* enabled. */
config
.
tests
=
sdsnew
(
","
);
config
.
tests
=
sdscat
(
config
.
tests
,(
char
*
)
argv
[
++
i
]);
config
.
tests
=
sdscat
(
config
.
tests
,
","
);
sdstolower
(
config
.
tests
);
}
else
if
(
!
strcmp
(
argv
[
i
],
"--help"
))
{
}
else
if
(
!
strcmp
(
argv
[
i
],
"--help"
))
{
exit_status
=
0
;
exit_status
=
0
;
goto
usage
;
goto
usage
;
...
@@ -398,24 +415,38 @@ invalid:
...
@@ -398,24 +415,38 @@ invalid:
printf
(
"Invalid option
\"
%s
\"
or option argument missing
\n\n
"
,
argv
[
i
]);
printf
(
"Invalid option
\"
%s
\"
or option argument missing
\n\n
"
,
argv
[
i
]);
usage:
usage:
printf
(
"Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]
\n\n
"
);
printf
(
printf
(
" -h <hostname> Server hostname (default 127.0.0.1)
\n
"
);
"Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]
\n\n
"
printf
(
" -p <port> Server port (default 6379)
\n
"
);
" -h <hostname> Server hostname (default 127.0.0.1)
\n
"
printf
(
" -s <socket> Server socket (overrides host and port)
\n
"
);
" -p <port> Server port (default 6379)
\n
"
printf
(
" -c <clients> Number of parallel connections (default 50)
\n
"
);
" -s <socket> Server socket (overrides host and port)
\n
"
printf
(
" -n <requests> Total number of requests (default 10000)
\n
"
);
" -c <clients> Number of parallel connections (default 50)
\n
"
printf
(
" -d <size> Data size of SET/GET value in bytes (default 2)
\n
"
);
" -n <requests> Total number of requests (default 10000)
\n
"
printf
(
" -k <boolean> 1=keep alive 0=reconnect (default 1)
\n
"
);
" -d <size> Data size of SET/GET value in bytes (default 2)
\n
"
printf
(
" -r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD
\n
"
);
" -k <boolean> 1=keep alive 0=reconnect (default 1)
\n
"
printf
(
" Using this option the benchmark will get/set keys
\n
"
);
" -r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD
\n
"
printf
(
" in the form mykey_rand000000012456 instead of constant
\n
"
);
" Using this option the benchmark will get/set keys
\n
"
printf
(
" keys, the <keyspacelen> argument determines the max
\n
"
);
" in the form mykey_rand000000012456 instead of constant
\n
"
printf
(
" number of values for the random number. For instance
\n
"
);
" keys, the <keyspacelen> argument determines the max
\n
"
printf
(
" if set to 10 only rand000000000000 - rand000000000009
\n
"
);
" number of values for the random number. For instance
\n
"
printf
(
" range will be allowed.
\n
"
);
" if set to 10 only rand000000000000 - rand000000000009
\n
"
printf
(
" -q Quiet. Just show query/sec values
\n
"
);
" range will be allowed.
\n
"
printf
(
" -l Loop. Run the tests forever
\n
"
);
" -q Quiet. Just show query/sec values
\n
"
printf
(
" -I Idle mode. Just open N idle connections and wait.
\n
"
);
" --csv Output in CSV format
\n
"
" -l Loop. Run the tests forever
\n
"
" -t <tests> Only run the comma separated list of tests. The test
\n
"
" names are the same as the ones produced as output.
\n
"
" -I Idle mode. Just open N idle connections and wait.
\n\n
"
"Examples:
\n\n
"
" Run the benchmark with the default configuration against 127.0.0.1:6379:
\n
"
" $ redis-benchmark
\n\n
"
" Use 20 parallel clients, for a total of 100k requests, against 192.168.1.1:
\n
"
" $ redis-benchmark -h 192.168.1.1 -p 6379 -n 100000 -c 20
\n\n
"
" Fill 127.0.0.1:6379 with about 1 million keys only using the SET test:
\n
"
" $ redis-benchmark -t set -n 1000000 -r 100000000
\n\n
"
" Benchmark 127.0.0.1:6379 for a few commands producing CSV output:
\n
"
" $ redis-benchmark -t ping,set,get -n 100000 --csv
\n\n
"
);
exit
(
exit_status
);
exit
(
exit_status
);
}
}
...
@@ -424,6 +455,7 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
...
@@ -424,6 +455,7 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
REDIS_NOTUSED
(
id
);
REDIS_NOTUSED
(
id
);
REDIS_NOTUSED
(
clientData
);
REDIS_NOTUSED
(
clientData
);
if
(
config
.
csv
)
return
250
;
float
dt
=
(
float
)(
mstime
()
-
config
.
start
)
/
1000
.
0
;
float
dt
=
(
float
)(
mstime
()
-
config
.
start
)
/
1000
.
0
;
float
rps
=
(
float
)
config
.
requests_finished
/
dt
;
float
rps
=
(
float
)
config
.
requests_finished
/
dt
;
printf
(
"%s: %.2f
\r
"
,
config
.
title
,
rps
);
printf
(
"%s: %.2f
\r
"
,
config
.
title
,
rps
);
...
@@ -431,6 +463,20 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
...
@@ -431,6 +463,20 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
return
250
;
/* every 250ms */
return
250
;
/* every 250ms */
}
}
/* Return true if the named test was selected using the -t command line
* switch, or if all the tests are selected (no -t passed by user). */
int
test_is_selected
(
char
*
name
)
{
char
buf
[
256
];
int
l
=
strlen
(
name
);
if
(
config
.
tests
==
NULL
)
return
1
;
buf
[
0
]
=
','
;
memcpy
(
buf
+
1
,
name
,
l
);
buf
[
l
+
1
]
=
','
;
buf
[
l
+
2
]
=
'\0'
;
return
strstr
(
config
.
tests
,
buf
)
!=
NULL
;
}
int
main
(
int
argc
,
const
char
**
argv
)
{
int
main
(
int
argc
,
const
char
**
argv
)
{
int
i
;
int
i
;
char
*
data
,
*
cmd
;
char
*
data
,
*
cmd
;
...
@@ -451,6 +497,7 @@ int main(int argc, const char **argv) {
...
@@ -451,6 +497,7 @@ int main(int argc, const char **argv) {
config
.
randomkeys
=
0
;
config
.
randomkeys
=
0
;
config
.
randomkeys_keyspacelen
=
0
;
config
.
randomkeys_keyspacelen
=
0
;
config
.
quiet
=
0
;
config
.
quiet
=
0
;
config
.
csv
=
0
;
config
.
loop
=
0
;
config
.
loop
=
0
;
config
.
idlemode
=
0
;
config
.
idlemode
=
0
;
config
.
latency
=
NULL
;
config
.
latency
=
NULL
;
...
@@ -458,6 +505,7 @@ int main(int argc, const char **argv) {
...
@@ -458,6 +505,7 @@ int main(int argc, const char **argv) {
config
.
hostip
=
"127.0.0.1"
;
config
.
hostip
=
"127.0.0.1"
;
config
.
hostport
=
6379
;
config
.
hostport
=
6379
;
config
.
hostsocket
=
NULL
;
config
.
hostsocket
=
NULL
;
config
.
tests
=
NULL
;
i
=
parseOptions
(
argc
,
argv
);
i
=
parseOptions
(
argc
,
argv
);
argc
-=
i
;
argc
-=
i
;
...
@@ -500,71 +548,106 @@ int main(int argc, const char **argv) {
...
@@ -500,71 +548,106 @@ int main(int argc, const char **argv) {
memset
(
data
,
'x'
,
config
.
datasize
);
memset
(
data
,
'x'
,
config
.
datasize
);
data
[
config
.
datasize
]
=
'\0'
;
data
[
config
.
datasize
]
=
'\0'
;
benchmark
(
"PING (inline)"
,
"PING
\r\n
"
,
6
);
if
(
test_is_selected
(
"ping_inline"
)
||
test_is_selected
(
"ping"
))
benchmark
(
"PING_INLINE"
,
"PING
\r\n
"
,
6
);
len
=
redisFormatCommand
(
&
cmd
,
"PING"
);
if
(
test_is_selected
(
"ping_mbulk"
)
||
test_is_selected
(
"ping"
))
{
benchmark
(
"PING"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"PING"
);
free
(
cmd
);
benchmark
(
"PING_BULK"
,
cmd
,
len
);
free
(
cmd
);
}
const
char
*
argv
[
21
];
if
(
test_is_selected
(
"set"
))
{
argv
[
0
]
=
"MSET"
;
len
=
redisFormatCommand
(
&
cmd
,
"SET foo:rand:000000000000 %s"
,
data
);
for
(
i
=
1
;
i
<
21
;
i
+=
2
)
{
benchmark
(
"SET"
,
cmd
,
len
);
argv
[
i
]
=
"foo:rand:000000000000"
;
free
(
cmd
);
argv
[
i
+
1
]
=
data
;
}
}
len
=
redisFormatCommandArgv
(
&
cmd
,
21
,
argv
,
NULL
);
benchmark
(
"MSET (10 keys)"
,
cmd
,
len
);
free
(
cmd
);
len
=
redisFormatCommand
(
&
cmd
,
"SET foo:rand:000000000000 %s"
,
data
);
if
(
test_is_selected
(
"get"
))
{
benchmark
(
"SET"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"GET foo:rand:000000000000"
);
free
(
cmd
);
benchmark
(
"GET"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"GET foo:rand:000000000000"
);
if
(
test_is_selected
(
"incr"
))
{
benchmark
(
"GET"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"INCR counter:rand:000000000000"
);
free
(
cmd
);
benchmark
(
"INCR"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"INCR counter:rand:000000000000"
);
if
(
test_is_selected
(
"lpush"
))
{
benchmark
(
"INCR"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"LPUSH mylist %s"
,
data
);
free
(
cmd
);
benchmark
(
"LPUSH"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LPUSH mylist %s"
,
data
);
if
(
test_is_selected
(
"lpop"
))
{
benchmark
(
"LPUSH"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"LPOP mylist"
);
free
(
cmd
);
benchmark
(
"LPOP"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LPOP mylist"
);
if
(
test_is_selected
(
"sadd"
))
{
benchmark
(
"LPOP"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
free
(
cmd
);
"SADD myset counter:rand:000000000000"
);
benchmark
(
"SADD"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"SADD myset counter:rand:000000000000"
);
if
(
test_is_selected
(
"spop"
))
{
benchmark
(
"SADD"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"SPOP myset"
);
free
(
cmd
);
benchmark
(
"SPOP"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"SPOP myset"
);
if
(
test_is_selected
(
"lrange"
)
||
benchmark
(
"SPOP"
,
cmd
,
len
);
test_is_selected
(
"lrange_100"
)
||
free
(
cmd
);
test_is_selected
(
"lrange_300"
)
||
test_is_selected
(
"lrange_500"
)
||
test_is_selected
(
"lrange_600"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"LPUSH mylist %s"
,
data
);
benchmark
(
"LPUSH (needed to benchmark LRANGE)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LPUSH mylist %s"
,
data
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_100"
))
{
benchmark
(
"LPUSH (again, in order to bench LRANGE)"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 99"
);
free
(
cmd
);
benchmark
(
"LRANGE_100 (first 100 elements)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 99"
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_300"
))
{
benchmark
(
"LRANGE (first 100 elements)"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 299"
);
free
(
cmd
);
benchmark
(
"LRANGE_300 (first 300 elements)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 299"
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_500"
))
{
benchmark
(
"LRANGE (first 300 elements)"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 449"
);
free
(
cmd
);
benchmark
(
"LRANGE_500 (first 450 elements)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 449"
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_600"
))
{
benchmark
(
"LRANGE (first 450 elements)"
,
cmd
,
len
);
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 599"
);
free
(
cmd
);
benchmark
(
"LRANGE_600 (first 600 elements)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 599"
);
if
(
test_is_selected
(
"mset"
))
{
benchmark
(
"LRANGE (first 600 elements)"
,
cmd
,
len
);
const
char
*
argv
[
21
];
free
(
cmd
);
argv
[
0
]
=
"MSET"
;
for
(
i
=
1
;
i
<
21
;
i
+=
2
)
{
argv
[
i
]
=
"foo:rand:000000000000"
;
argv
[
i
+
1
]
=
data
;
}
len
=
redisFormatCommandArgv
(
&
cmd
,
21
,
argv
,
NULL
);
benchmark
(
"MSET (10 keys)"
,
cmd
,
len
);
free
(
cmd
);
}
printf
(
"
\n
"
);
if
(
!
config
.
csv
)
printf
(
"
\n
"
);
}
while
(
config
.
loop
);
}
while
(
config
.
loop
);
return
0
;
return
0
;
...
...
src/redis.h
View file @
66d8818c
...
@@ -40,7 +40,7 @@
...
@@ -40,7 +40,7 @@
/* Static server configuration */
/* Static server configuration */
#define REDIS_SERVERPORT 6379
/* TCP port */
#define REDIS_SERVERPORT 6379
/* TCP port */
#define REDIS_MAXIDLETIME (60*5)
/* default client timeout */
#define REDIS_MAXIDLETIME (60*5)
/* default client timeout */
#define REDIS_IOBUF_LEN 1024
#define REDIS_IOBUF_LEN
(
1024
*16)
#define REDIS_LOADBUF_LEN 1024
#define REDIS_LOADBUF_LEN 1024
#define REDIS_DEFAULT_DBNUM 16
#define REDIS_DEFAULT_DBNUM 16
#define REDIS_CONFIGLINE_MAX 1024
#define REDIS_CONFIGLINE_MAX 1024
...
@@ -49,7 +49,7 @@
...
@@ -49,7 +49,7 @@
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256)
/* max bytes in inline command */
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256)
/* max bytes in inline command */
#define REDIS_SHARED_INTEGERS 10000
#define REDIS_SHARED_INTEGERS 10000
#define REDIS_REPLY_CHUNK_BYTES (
5*1500)
/* 5 TCP packets with default MTU
*/
#define REDIS_REPLY_CHUNK_BYTES (
16*1024)
/* 16k output buffer
*/
#define REDIS_MAX_LOGMSG_LEN 1024
/* Default maximum length of syslog messages */
#define REDIS_MAX_LOGMSG_LEN 1024
/* Default maximum length of syslog messages */
#define REDIS_AUTO_AOFREWRITE_PERC 100
#define REDIS_AUTO_AOFREWRITE_PERC 100
#define REDIS_AUTO_AOFREWRITE_MIN_SIZE (1024*1024)
#define REDIS_AUTO_AOFREWRITE_MIN_SIZE (1024*1024)
...
@@ -59,6 +59,7 @@
...
@@ -59,6 +59,7 @@
#define REDIS_REPL_TIMEOUT 60
#define REDIS_REPL_TIMEOUT 60
#define REDIS_REPL_PING_SLAVE_PERIOD 10
#define REDIS_REPL_PING_SLAVE_PERIOD 10
#define REDIS_MBULK_BIG_ARG (1024*32)
/* Hash table parameters */
/* Hash table parameters */
#define REDIS_HT_MINFILL 10
/* Minimal hash table fill 10% */
#define REDIS_HT_MINFILL 10
/* Minimal hash table fill 10% */
...
...
src/sds.c
View file @
66d8818c
...
@@ -40,6 +40,7 @@
...
@@ -40,6 +40,7 @@
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <ctype.h>
#include <ctype.h>
#include <assert.h>
#include "sds.h"
#include "sds.h"
#include "zmalloc.h"
#include "zmalloc.h"
...
@@ -101,7 +102,13 @@ void sdsclear(sds s) {
...
@@ -101,7 +102,13 @@ void sdsclear(sds s) {
sh
->
buf
[
0
]
=
'\0'
;
sh
->
buf
[
0
]
=
'\0'
;
}
}
static
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
)
{
/* Enlarge the free space at the end of the sds string so that the caller
* is sure that after calling this function can overwrite up to addlen
* bytes after the end of the string, plus one more byte for nul term.
*
* Note: this does not change the *size* of the sds string as returned
* by sdslen(), but only the free buffer space we have. */
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
)
{
struct
sdshdr
*
sh
,
*
newsh
;
struct
sdshdr
*
sh
,
*
newsh
;
size_t
free
=
sdsavail
(
s
);
size_t
free
=
sdsavail
(
s
);
size_t
len
,
newlen
;
size_t
len
,
newlen
;
...
@@ -121,6 +128,37 @@ static sds sdsMakeRoomFor(sds s, size_t addlen) {
...
@@ -121,6 +128,37 @@ static sds sdsMakeRoomFor(sds s, size_t addlen) {
return
newsh
->
buf
;
return
newsh
->
buf
;
}
}
/* Increment the sds length and decrements the left free space at the
* end of the string accordingly to 'incr'. Also set the null term
* in the new end of the string.
*
* This function is used in order to fix the string length after the
* user calls sdsMakeRoomFor(), writes something after the end of
* the current string, and finally needs to set the new length.
*
* Note: it is possible to use a negative increment in order to
* right-trim the string.
*
* Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
* following schema to cat bytes coming from the kerenl to the end of an
* sds string new things without copying into an intermediate buffer:
*
* oldlen = sdslen(s);
* s = sdsMakeRoomFor(s, BUFFER_SIZE);
* nread = read(fd, s+oldlen, BUFFER_SIZE);
* ... check for nread <= 0 and handle it ...
* sdsIncrLen(s, nhread);
*/
void
sdsIncrLen
(
sds
s
,
int
incr
)
{
struct
sdshdr
*
sh
=
(
void
*
)
(
s
-
(
sizeof
(
struct
sdshdr
)));
assert
(
sh
->
free
>=
incr
);
sh
->
len
+=
incr
;
sh
->
free
-=
incr
;
assert
(
sh
->
free
>=
0
);
s
[
sh
->
len
]
=
'\0'
;
}
/* Grow the sds to have the specified length. Bytes that were not part of
/* Grow the sds to have the specified length. Bytes that were not part of
* the original length of the sds will be set to zero. */
* the original length of the sds will be set to zero. */
sds
sdsgrowzero
(
sds
s
,
size_t
len
)
{
sds
sdsgrowzero
(
sds
s
,
size_t
len
)
{
...
@@ -609,6 +647,7 @@ sds sdsmapchars(sds s, char *from, char *to, size_t setlen) {
...
@@ -609,6 +647,7 @@ sds sdsmapchars(sds s, char *from, char *to, size_t setlen) {
int
main
(
void
)
{
int
main
(
void
)
{
{
{
struct
sdshdr
*
sh
;
sds
x
=
sdsnew
(
"foo"
),
y
;
sds
x
=
sdsnew
(
"foo"
),
y
;
test_cond
(
"Create a string and obtain the length"
,
test_cond
(
"Create a string and obtain the length"
,
...
@@ -688,7 +727,26 @@ int main(void) {
...
@@ -688,7 +727,26 @@ int main(void) {
x
=
sdsnew
(
"aar"
);
x
=
sdsnew
(
"aar"
);
y
=
sdsnew
(
"bar"
);
y
=
sdsnew
(
"bar"
);
test_cond
(
"sdscmp(bar,bar)"
,
sdscmp
(
x
,
y
)
<
0
)
test_cond
(
"sdscmp(bar,bar)"
,
sdscmp
(
x
,
y
)
<
0
)
{
int
oldfree
;
sdsfree
(
x
);
x
=
sdsnew
(
"0"
);
sh
=
(
void
*
)
(
x
-
(
sizeof
(
struct
sdshdr
)));
test_cond
(
"sdsnew() free/len buffers"
,
sh
->
len
==
1
&&
sh
->
free
==
0
);
x
=
sdsMakeRoomFor
(
x
,
1
);
sh
=
(
void
*
)
(
x
-
(
sizeof
(
struct
sdshdr
)));
test_cond
(
"sdsMakeRoomFor()"
,
sh
->
len
==
1
&&
sh
->
free
>
0
);
oldfree
=
sh
->
free
;
x
[
1
]
=
'1'
;
sdsIncrLen
(
x
,
1
);
test_cond
(
"sdsIncrLen() -- content"
,
x
[
0
]
==
'0'
&&
x
[
1
]
==
'1'
);
test_cond
(
"sdsIncrLen() -- len"
,
sh
->
len
==
2
);
test_cond
(
"sdsIncrLen() -- free"
,
sh
->
free
==
oldfree
-
1
);
}
}
}
test_report
()
test_report
()
return
0
;
}
}
#endif
#endif
src/sds.h
View file @
66d8818c
...
@@ -88,4 +88,8 @@ sds *sdssplitargs(char *line, int *argc);
...
@@ -88,4 +88,8 @@ sds *sdssplitargs(char *line, int *argc);
void
sdssplitargs_free
(
sds
*
argv
,
int
argc
);
void
sdssplitargs_free
(
sds
*
argv
,
int
argc
);
sds
sdsmapchars
(
sds
s
,
char
*
from
,
char
*
to
,
size_t
setlen
);
sds
sdsmapchars
(
sds
s
,
char
*
from
,
char
*
to
,
size_t
setlen
);
/* Low level functions exposed to the user API */
sds
sdsMakeRoomFor
(
sds
s
,
size_t
addlen
);
void
sdsIncrLen
(
sds
s
,
int
incr
);
#endif
#endif
src/testhelp.h
View file @
66d8818c
...
@@ -48,6 +48,7 @@ int __test_num = 0;
...
@@ -48,6 +48,7 @@ int __test_num = 0;
__test_num-__failed_tests, __failed_tests); \
__test_num-__failed_tests, __failed_tests); \
if (__failed_tests) { \
if (__failed_tests) { \
printf("=== WARNING === We have failed tests here...\n"); \
printf("=== WARNING === We have failed tests here...\n"); \
exit(1); \
} \
} \
} while(0);
} while(0);
...
...
utils/speed-regression.tcl
0 → 100755
View file @
66d8818c
#!/usr/bin/env tclsh8.5
# Copyright
(
C
)
2011 Salvatore Sanfilippo
# Released under the BSD license like Redis itself
source ../tests/support/redis.tcl
set ::port 12123
set ::tests
{
PING,SET,GET,INCR,LPUSH,LPOP,SADD,SPOP,LRANGE_100,LRANGE_600,MSET
}
set ::datasize 16
set ::requests 100000
proc run-tests branches
{
set runs
{}
set branch_id 0
foreach b $branches
{
cd ../src
puts
"Benchmarking
$b
"
exec -ignorestderr git checkout $b 2> /dev/null
exec -ignorestderr make clean 2> /dev/null
puts
" compiling..."
exec -ignorestderr make 2> /dev/null
if
{
$branch
_id == 0
}
{
puts
" copy redis-benchmark from unstable to /tmp..."
exec -ignorestderr cp ./redis-benchmark /tmp
incr branch_id
continue
}
# Start the Redis server
puts
" starting the server...
[
exec ./redis-server -v
]
"
set pids
[
exec echo
"port
$::port
\n
loglevel warning
\n
"
| ./redis-server - > /dev/null 2> /dev/null &
]
puts
" pids:
$pids
"
after 1000
puts
" running the benchmark"
set r
[
redis 127.0.0.1 $::port
]
set i
[
$r
info
]
puts
" redis INFO shows version:
[
lindex
[
split $i
]
0
]
"
$r close
set output
[
exec /tmp/redis-benchmark -n $::requests -t $::tests -d $::datasize --csv -p $::port
]
lappend runs $b $output
puts
" killing server..."
catch
{
exec kill -9
[
lindex $pids 0
]}
catch
{
exec kill -9
[
lindex $pids 1
]}
incr branch_id
}
return $runs
}
proc get-result-with-name
{
output name
}
{
foreach line
[
split $output
"
\n
"
]
{
lassign
[
split $line
","
]
key value
set key
[
string tolower
[
string range $key 1 end-1
]]
set value
[
string range $value 1 end-1
]
if
{
$key
eq
[
string tolower $name
]}
{
return $value
}
}
return
"n/a"
}
proc get-test-names output
{
set names
{}
foreach line
[
split $output
"
\n
"
]
{
lassign
[
split $line
","
]
key value
set key
[
string tolower
[
string range $key 1 end-1
]]
lappend names $key
}
return $names
}
proc combine-results
{
results
}
{
set tests
[
get-test-names
[
lindex $results 1
]]
foreach test $tests
{
puts $test
foreach
{
branch output
}
$results
{
puts
[
format
"%-20s %s"
\
$branch
[
get-result-with-name $output $test
]]
}
puts
{}
}
}
proc main
{}
{
# Note: the first branch is only used in order to get the redis-benchmark
# executable. Tests are performed starting from the second branch.
set branches
{
slowset 2.2.0 2.4.0 unstable slowset
}
set results
[
run-tests $branches
]
puts
"
\n
"
puts
"# Test results: datasize=
$::datasize
requests=
$::requests
"
puts
[
combine-results $results
]
}
# Force the user to run the script from the 'utils' directory.
if
{
!
[
file exists speed-regression.tcl
]}
{
puts
"Please make sure to run speed-regression.tcl while inside /utils."
puts
"Example: cd utils; ./speed-regression.tcl"
exit 1
}
# Make sure there is not already a server runnign on port 12123
set is_not_running
[
catch
{
set r
[
redis 127.0.0.1 $::port
]}]
if
{
!$is_not_running
}
{
puts
"Sorry, you have a running server on port
$::port
"
exit 1
}
# parse arguments
for
{
set j 0
}
{
$j
<
[
llength $argv
]}
{
incr j
}
{
set opt
[
lindex $argv $j
]
set arg
[
lindex $argv
[
expr $j+1
]]
if
{
$opt
eq
{
--tests
}}
{
set ::tests $arg
incr j
}
elseif
{
$opt
eq
{
--datasize
}}
{
set ::datasize $arg
incr j
}
elseif
{
$opt
eq
{
--requests
}}
{
set ::requests $arg
incr j
}
else
{
puts
"Wrong argument:
$opt
"
exit 1
}
}
main
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