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
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) {
/* Copy the provided buffer. */
if
(
buf
!=
NULL
&&
len
>=
1
)
{
#if 0
/* Destroy internal buffer when it is empty and is quite large. */
if (r->len == 0 && sdsavail(r->buf) > 16*1024) {
sdsfree(r->buf);
r->buf = sdsempty();
r->pos = 0;
}
#endif
r
->
buf
=
sdscatlen
(
r
->
buf
,
buf
,
len
);
r
->
len
=
sdslen
(
r
->
buf
);
}
...
...
@@ -901,7 +902,7 @@ static void __redisCreateReplyReader(redisContext *c) {
* After this function is called, you may use redisContextReadReply to
* see if there is a reply available. */
int
redisBufferRead
(
redisContext
*
c
)
{
char
buf
[
2048
];
char
buf
[
1024
*
16
];
int
nread
=
read
(
c
->
fd
,
buf
,
sizeof
(
buf
));
if
(
nread
==
-
1
)
{
if
(
errno
==
EAGAIN
&&
!
(
c
->
flags
&
REDIS_BLOCK
))
{
...
...
src/networking.c
View file @
66d8818c
...
...
@@ -767,6 +767,17 @@ int processMultibulkBuffer(redisClient *c) {
}
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
;
}
...
...
@@ -775,15 +786,32 @@ int processMultibulkBuffer(redisClient *c) {
/* Not enough data (+2 == trailing \r\n) */
break
;
}
else
{
c
->
argv
[
c
->
argc
++
]
=
createStringObject
(
c
->
querybuf
+
pos
,
c
->
bulklen
);
pos
+=
c
->
bulklen
+
2
;
/* Optimization: if the buffer contanins JUST our bulk element
* 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
->
multibulklen
--
;
}
}
/* 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 */
if
(
c
->
multibulklen
==
0
)
{
...
...
@@ -833,12 +861,29 @@ void processInputBuffer(redisClient *c) {
void
readQueryFromClient
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
)
{
redisClient
*
c
=
(
redisClient
*
)
privdata
;
char
buf
[
REDIS_IOBUF_LEN
]
;
int
nread
;
int
nread
,
readlen
;
size_t
qblen
;
REDIS_NOTUSED
(
el
);
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
(
errno
==
EAGAIN
)
{
nread
=
0
;
...
...
@@ -853,7 +898,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
return
;
}
if
(
nread
)
{
c
->
querybuf
=
sdscatl
en
(
c
->
querybuf
,
buf
,
nread
);
sdsIncrL
en
(
c
->
querybuf
,
nread
);
c
->
lastinteraction
=
time
(
NULL
);
}
else
{
return
;
...
...
src/redis-benchmark.c
View file @
66d8818c
...
...
@@ -68,8 +68,10 @@ static struct config {
const
char
*
title
;
list
*
clients
;
int
quiet
;
int
csv
;
int
loop
;
int
idlemode
;
char
*
tests
;
}
config
;
typedef
struct
_client
{
...
...
@@ -295,7 +297,7 @@ static void showLatencyReport(void) {
float
perc
,
reqpersec
;
reqpersec
=
(
float
)
config
.
requests_finished
/
((
float
)
config
.
totlatency
/
1000
);
if
(
!
config
.
quiet
)
{
if
(
!
config
.
quiet
&&
!
config
.
csv
)
{
printf
(
"====== %s ======
\n
"
,
config
.
title
);
printf
(
" %d requests completed in %.2f seconds
\n
"
,
config
.
requests_finished
,
(
float
)
config
.
totlatency
/
1000
);
...
...
@@ -313,6 +315,8 @@ static void showLatencyReport(void) {
}
}
printf
(
"%.2f requests per second
\n\n
"
,
reqpersec
);
}
else
if
(
config
.
csv
)
{
printf
(
"
\"
%s
\"
,
\"
%.2f
\"\n
"
,
config
.
title
,
reqpersec
);
}
else
{
printf
(
"%s: %.2f requests per second
\n
"
,
config
.
title
,
reqpersec
);
}
...
...
@@ -367,7 +371,7 @@ int parseOptions(int argc, const char **argv) {
if
(
lastarg
)
goto
invalid
;
config
.
datasize
=
atoi
(
argv
[
++
i
]);
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"
))
{
if
(
lastarg
)
goto
invalid
;
config
.
randomkeys
=
1
;
...
...
@@ -376,10 +380,23 @@ int parseOptions(int argc, const char **argv) {
config
.
randomkeys_keyspacelen
=
0
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-q"
))
{
config
.
quiet
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--csv"
))
{
config
.
csv
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-l"
))
{
config
.
loop
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-I"
))
{
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"
))
{
exit_status
=
0
;
goto
usage
;
...
...
@@ -398,24 +415,38 @@ invalid:
printf
(
"Invalid option
\"
%s
\"
or option argument missing
\n\n
"
,
argv
[
i
]);
usage:
printf
(
"Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]
\n\n
"
);
printf
(
" -h <hostname> Server hostname (default 127.0.0.1)
\n
"
);
printf
(
" -p <port> Server port (default 6379)
\n
"
);
printf
(
" -s <socket> Server socket (overrides host and port)
\n
"
);
printf
(
" -c <clients> Number of parallel connections (default 50)
\n
"
);
printf
(
" -n <requests> Total number of requests (default 10000)
\n
"
);
printf
(
" -d <size> Data size of SET/GET value in bytes (default 2)
\n
"
);
printf
(
" -k <boolean> 1=keep alive 0=reconnect (default 1)
\n
"
);
printf
(
" -r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD
\n
"
);
printf
(
" Using this option the benchmark will get/set keys
\n
"
);
printf
(
" in the form mykey_rand000000012456 instead of constant
\n
"
);
printf
(
" keys, the <keyspacelen> argument determines the max
\n
"
);
printf
(
" number of values for the random number. For instance
\n
"
);
printf
(
" if set to 10 only rand000000000000 - rand000000000009
\n
"
);
printf
(
" range will be allowed.
\n
"
);
printf
(
" -q Quiet. Just show query/sec values
\n
"
);
printf
(
" -l Loop. Run the tests forever
\n
"
);
printf
(
" -I Idle mode. Just open N idle connections and wait.
\n
"
);
printf
(
"Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]
\n\n
"
" -h <hostname> Server hostname (default 127.0.0.1)
\n
"
" -p <port> Server port (default 6379)
\n
"
" -s <socket> Server socket (overrides host and port)
\n
"
" -c <clients> Number of parallel connections (default 50)
\n
"
" -n <requests> Total number of requests (default 10000)
\n
"
" -d <size> Data size of SET/GET value in bytes (default 2)
\n
"
" -k <boolean> 1=keep alive 0=reconnect (default 1)
\n
"
" -r <keyspacelen> Use random keys for SET/GET/INCR, random values for SADD
\n
"
" Using this option the benchmark will get/set keys
\n
"
" in the form mykey_rand000000012456 instead of constant
\n
"
" keys, the <keyspacelen> argument determines the max
\n
"
" number of values for the random number. For instance
\n
"
" if set to 10 only rand000000000000 - rand000000000009
\n
"
" range will be allowed.
\n
"
" -q Quiet. Just show query/sec values
\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
);
}
...
...
@@ -424,6 +455,7 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
REDIS_NOTUSED
(
id
);
REDIS_NOTUSED
(
clientData
);
if
(
config
.
csv
)
return
250
;
float
dt
=
(
float
)(
mstime
()
-
config
.
start
)
/
1000
.
0
;
float
rps
=
(
float
)
config
.
requests_finished
/
dt
;
printf
(
"%s: %.2f
\r
"
,
config
.
title
,
rps
);
...
...
@@ -431,6 +463,20 @@ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData
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
i
;
char
*
data
,
*
cmd
;
...
...
@@ -451,6 +497,7 @@ int main(int argc, const char **argv) {
config
.
randomkeys
=
0
;
config
.
randomkeys_keyspacelen
=
0
;
config
.
quiet
=
0
;
config
.
csv
=
0
;
config
.
loop
=
0
;
config
.
idlemode
=
0
;
config
.
latency
=
NULL
;
...
...
@@ -458,6 +505,7 @@ int main(int argc, const char **argv) {
config
.
hostip
=
"127.0.0.1"
;
config
.
hostport
=
6379
;
config
.
hostsocket
=
NULL
;
config
.
tests
=
NULL
;
i
=
parseOptions
(
argc
,
argv
);
argc
-=
i
;
...
...
@@ -500,71 +548,106 @@ int main(int argc, const char **argv) {
memset
(
data
,
'x'
,
config
.
datasize
);
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"
);
benchmark
(
"PING"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"ping_mbulk"
)
||
test_is_selected
(
"ping"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"PING"
);
benchmark
(
"PING_BULK"
,
cmd
,
len
);
free
(
cmd
);
}
const
char
*
argv
[
21
];
argv
[
0
]
=
"MSET"
;
for
(
i
=
1
;
i
<
21
;
i
+=
2
)
{
argv
[
i
]
=
"foo:rand:000000000000"
;
argv
[
i
+
1
]
=
data
;
if
(
test_is_selected
(
"set"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"SET foo:rand:000000000000 %s"
,
data
);
benchmark
(
"SET"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommandArgv
(
&
cmd
,
21
,
argv
,
NULL
);
benchmark
(
"MSET (10 keys)"
,
cmd
,
len
);
free
(
cmd
);
len
=
redisFormatCommand
(
&
cmd
,
"SET foo:rand:000000000000 %s"
,
data
);
benchmark
(
"SET"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"get"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"GET foo:rand:000000000000"
);
benchmark
(
"GET"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"GET foo:rand:000000000000"
);
benchmark
(
"GET"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"incr"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"INCR counter:rand:000000000000"
);
benchmark
(
"INCR"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"INCR counter:rand:000000000000"
);
benchmark
(
"INCR"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"lpush"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"LPUSH mylist %s"
,
data
);
benchmark
(
"LPUSH"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LPUSH mylist %s"
,
data
);
benchmark
(
"LPUSH"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"lpop"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"LPOP mylist"
);
benchmark
(
"LPOP"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LPOP mylist"
);
benchmark
(
"LPOP"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"sadd"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"SADD myset counter:rand:000000000000"
);
benchmark
(
"SADD"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"SADD myset counter:rand:000000000000"
);
benchmark
(
"SADD"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"spop"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"SPOP myset"
);
benchmark
(
"SPOP"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"SPOP myset"
);
benchmark
(
"SPOP"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_100"
)
||
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
);
benchmark
(
"LPUSH (again, in order to bench LRANGE)"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_100"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 99"
);
benchmark
(
"LRANGE_100 (first 100 elements)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 99"
);
benchmark
(
"LRANGE (first 100 elements)"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_300"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 299"
);
benchmark
(
"LRANGE_300 (first 300 elements)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 299"
);
benchmark
(
"LRANGE (first 300 elements)"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_500"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 449"
);
benchmark
(
"LRANGE_500 (first 450 elements)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 449"
);
benchmark
(
"LRANGE (first 450 elements)"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"lrange"
)
||
test_is_selected
(
"lrange_600"
))
{
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 599"
);
benchmark
(
"LRANGE_600 (first 600 elements)"
,
cmd
,
len
);
free
(
cmd
);
}
len
=
redisFormatCommand
(
&
cmd
,
"LRANGE mylist 0 599"
);
benchmark
(
"LRANGE (first 600 elements)"
,
cmd
,
len
);
free
(
cmd
);
if
(
test_is_selected
(
"mset"
))
{
const
char
*
argv
[
21
];
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
);
return
0
;
...
...
src/redis.h
View file @
66d8818c
...
...
@@ -40,7 +40,7 @@
/* Static server configuration */
#define REDIS_SERVERPORT 6379
/* TCP port */
#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_DEFAULT_DBNUM 16
#define REDIS_CONFIGLINE_MAX 1024
...
...
@@ -49,7 +49,7 @@
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256)
/* max bytes in inline command */
#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_AUTO_AOFREWRITE_PERC 100
#define REDIS_AUTO_AOFREWRITE_MIN_SIZE (1024*1024)
...
...
@@ -59,6 +59,7 @@
#define REDIS_REPL_TIMEOUT 60
#define REDIS_REPL_PING_SLAVE_PERIOD 10
#define REDIS_MBULK_BIG_ARG (1024*32)
/* Hash table parameters */
#define REDIS_HT_MINFILL 10
/* Minimal hash table fill 10% */
...
...
src/sds.c
View file @
66d8818c
...
...
@@ -40,6 +40,7 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "sds.h"
#include "zmalloc.h"
...
...
@@ -101,7 +102,13 @@ void sdsclear(sds s) {
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
;
size_t
free
=
sdsavail
(
s
);
size_t
len
,
newlen
;
...
...
@@ -121,6 +128,37 @@ static sds sdsMakeRoomFor(sds s, size_t addlen) {
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
* the original length of the sds will be set to zero. */
sds
sdsgrowzero
(
sds
s
,
size_t
len
)
{
...
...
@@ -609,6 +647,7 @@ sds sdsmapchars(sds s, char *from, char *to, size_t setlen) {
int
main
(
void
)
{
{
struct
sdshdr
*
sh
;
sds
x
=
sdsnew
(
"foo"
),
y
;
test_cond
(
"Create a string and obtain the length"
,
...
...
@@ -688,7 +727,26 @@ int main(void) {
x
=
sdsnew
(
"aar"
);
y
=
sdsnew
(
"bar"
);
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
()
return
0
;
}
#endif
src/sds.h
View file @
66d8818c
...
...
@@ -88,4 +88,8 @@ sds *sdssplitargs(char *line, int *argc);
void
sdssplitargs_free
(
sds
*
argv
,
int
argc
);
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
src/testhelp.h
View file @
66d8818c
...
...
@@ -48,6 +48,7 @@ int __test_num = 0;
__test_num-__failed_tests, __failed_tests); \
if (__failed_tests) { \
printf("=== WARNING === We have failed tests here...\n"); \
exit(1); \
} \
} 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