Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Turbo码先生
redis
提交
21dbc649
R
redis
项目概览
Turbo码先生
/
redis
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
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,发现更多精彩内容 >>
提交
21dbc649
编写于
10月 28, 2010
作者:
A
antirez
浏览文件
操作
浏览文件
下载
差异文件
merge conflict resolved
上级
73abd0a9
4794d88f
变更
21
展开全部
隐藏空白更改
内联
并排
Showing
21 changed file
with
546 addition
and
480 deletion
+546
-480
src/Makefile
src/Makefile
+1
-1
src/aof.c
src/aof.c
+0
-3
src/config.c
src/config.c
+6
-7
src/networking.c
src/networking.c
+174
-97
src/redis-benchmark.c
src/redis-benchmark.c
+22
-4
src/redis-cli.c
src/redis-cli.c
+0
-4
src/redis.c
src/redis.c
+128
-240
src/redis.h
src/redis.h
+19
-14
src/t_list.c
src/t_list.c
+7
-2
src/t_set.c
src/t_set.c
+4
-1
src/t_string.c
src/t_string.c
+5
-0
src/t_zset.c
src/t_zset.c
+5
-0
tests/support/redis.tcl
tests/support/redis.tcl
+15
-37
tests/support/server.tcl
tests/support/server.tcl
+6
-10
tests/support/test.tcl
tests/support/test.tcl
+3
-1
tests/test_helper.tcl
tests/test_helper.tcl
+40
-2
tests/unit/basic.tcl
tests/unit/basic.tcl
+1
-1
tests/unit/other.tcl
tests/unit/other.tcl
+1
-1
tests/unit/protocol.tcl
tests/unit/protocol.tcl
+60
-46
tests/unit/quit.tcl
tests/unit/quit.tcl
+40
-0
tests/unit/sort.tcl
tests/unit/sort.tcl
+9
-9
未找到文件。
src/Makefile
浏览文件 @
21dbc649
...
...
@@ -132,7 +132,7 @@ dep:
$(CC)
-MM
*
.c
test
:
(
cd
..
;
tclsh8.5 tests/test_helper.tcl
--tags
"
${TAGS}
"
)
(
cd
..
;
tclsh8.5 tests/test_helper.tcl
--tags
"
${TAGS}
"
--file
"
${FILE}
"
)
bench
:
./redis-benchmark
...
...
src/aof.c
浏览文件 @
21dbc649
...
...
@@ -266,9 +266,6 @@ int loadAppendOnlyFile(char *filename) {
redisLog
(
REDIS_WARNING
,
"Unknown command '%s' reading the append only file"
,
argv
[
0
]
->
ptr
);
exit
(
1
);
}
/* Try object encoding */
if
(
cmd
->
flags
&
REDIS_CMD_BULK
)
argv
[
argc
-
1
]
=
tryObjectEncoding
(
argv
[
argc
-
1
]);
/* Run the command in the context of a fake client */
fakeClient
->
argc
=
argc
;
fakeClient
->
argv
=
argv
;
...
...
src/config.c
浏览文件 @
21dbc649
...
...
@@ -246,8 +246,11 @@ loaderr:
*----------------------------------------------------------------------------*/
void
configSetCommand
(
redisClient
*
c
)
{
robj
*
o
=
getDecodedObject
(
c
->
argv
[
3
])
;
robj
*
o
;
long
long
ll
;
redisAssert
(
c
->
argv
[
2
]
->
encoding
==
REDIS_ENCODING_RAW
);
redisAssert
(
c
->
argv
[
3
]
->
encoding
==
REDIS_ENCODING_RAW
);
o
=
c
->
argv
[
3
];
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"dbfilename"
))
{
zfree
(
server
.
dbfilename
);
...
...
@@ -312,7 +315,6 @@ void configSetCommand(redisClient *c) {
if
(
startAppendOnly
()
==
REDIS_ERR
)
{
addReplyError
(
c
,
"Unable to turn on AOF. Check server logs."
);
decrRefCount
(
o
);
return
;
}
}
...
...
@@ -354,10 +356,8 @@ void configSetCommand(redisClient *c) {
}
else
{
addReplyErrorFormat
(
c
,
"Unsupported CONFIG parameter: %s"
,
(
char
*
)
c
->
argv
[
2
]
->
ptr
);
decrRefCount
(
o
);
return
;
}
decrRefCount
(
o
);
addReply
(
c
,
shared
.
ok
);
return
;
...
...
@@ -365,15 +365,15 @@ badfmt: /* Bad format errors */
addReplyErrorFormat
(
c
,
"Invalid argument '%s' for CONFIG SET '%s'"
,
(
char
*
)
o
->
ptr
,
(
char
*
)
c
->
argv
[
2
]
->
ptr
);
decrRefCount
(
o
);
}
void
configGetCommand
(
redisClient
*
c
)
{
robj
*
o
=
getDecodedObject
(
c
->
argv
[
2
])
;
robj
*
o
=
c
->
argv
[
2
]
;
void
*
replylen
=
addDeferredMultiBulkLength
(
c
);
char
*
pattern
=
o
->
ptr
;
char
buf
[
128
];
int
matches
=
0
;
redisAssert
(
o
->
encoding
==
REDIS_ENCODING_RAW
);
if
(
stringmatch
(
pattern
,
"dbfilename"
,
0
))
{
addReplyBulkCString
(
c
,
"dbfilename"
);
...
...
@@ -462,7 +462,6 @@ void configGetCommand(redisClient *c) {
sdsfree
(
buf
);
matches
++
;
}
decrRefCount
(
o
);
setDeferredMultiBulkLength
(
c
,
replylen
,
matches
*
2
);
}
...
...
src/networking.c
浏览文件 @
21dbc649
...
...
@@ -28,13 +28,11 @@ redisClient *createClient(int fd) {
selectDb
(
c
,
0
);
c
->
fd
=
fd
;
c
->
querybuf
=
sdsempty
();
c
->
newline
=
NULL
;
c
->
reqtype
=
0
;
c
->
argc
=
0
;
c
->
argv
=
NULL
;
c
->
multibulklen
=
0
;
c
->
bulklen
=
-
1
;
c
->
multibulk
=
0
;
c
->
mbargc
=
0
;
c
->
mbargv
=
NULL
;
c
->
sentlen
=
0
;
c
->
flags
=
0
;
c
->
lastinteraction
=
time
(
NULL
);
...
...
@@ -57,7 +55,12 @@ redisClient *createClient(int fd) {
return
c
;
}
/* Set the event loop to listen for write events on the client's socket.
* Typically gets called every time a reply is built. */
int
_installWriteEvent
(
redisClient
*
c
)
{
/* When CLOSE_AFTER_REPLY is set, no more replies may be added! */
redisAssert
(
!
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
));
if
(
c
->
fd
<=
0
)
return
REDIS_ERR
;
if
(
c
->
bufpos
==
0
&&
listLength
(
c
->
reply
)
==
0
&&
(
c
->
replstate
==
REDIS_REPL_NONE
||
...
...
@@ -374,13 +377,9 @@ void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
static
void
freeClientArgv
(
redisClient
*
c
)
{
int
j
;
for
(
j
=
0
;
j
<
c
->
argc
;
j
++
)
decrRefCount
(
c
->
argv
[
j
]);
for
(
j
=
0
;
j
<
c
->
mbargc
;
j
++
)
decrRefCount
(
c
->
mbargv
[
j
]);
c
->
argc
=
0
;
c
->
mbargc
=
0
;
}
void
freeClient
(
redisClient
*
c
)
{
...
...
@@ -461,7 +460,6 @@ void freeClient(redisClient *c) {
}
/* Release memory */
zfree
(
c
->
argv
);
zfree
(
c
->
mbargv
);
freeClientMultiState
(
c
);
zfree
(
c
);
}
...
...
@@ -546,6 +544,9 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
if
(
listLength
(
c
->
reply
)
==
0
)
{
c
->
sentlen
=
0
;
aeDeleteFileEvent
(
server
.
el
,
c
->
fd
,
AE_WRITABLE
);
/* Close connection after entire reply has been sent. */
if
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
)
freeClient
(
c
);
}
}
...
...
@@ -630,9 +631,9 @@ void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
/* resetClient prepare the client to process the next command */
void
resetClient
(
redisClient
*
c
)
{
freeClientArgv
(
c
);
c
->
reqtype
=
0
;
c
->
multibulklen
=
0
;
c
->
bulklen
=
-
1
;
c
->
multibulk
=
0
;
c
->
newline
=
NULL
;
}
void
closeTimedoutClients
(
void
)
{
...
...
@@ -663,90 +664,172 @@ void closeTimedoutClients(void) {
}
}
void
processInputBuffer
(
redisClient
*
c
)
{
int
seeknewline
=
0
;
again:
/* Before to process the input buffer, make sure the client is not
* waitig for a blocking operation such as BLPOP. Note that the first
* iteration the client is never blocked, otherwise the processInputBuffer
* would not be called at all, but after the execution of the first commands
* in the input buffer the client may be blocked, and the "goto again"
* will try to reiterate. The following line will make it return asap. */
if
(
c
->
flags
&
REDIS_BLOCKED
||
c
->
flags
&
REDIS_IO_WAIT
)
return
;
if
(
seeknewline
&&
c
->
bulklen
==
-
1
)
c
->
newline
=
strchr
(
c
->
querybuf
,
'\n'
);
seeknewline
=
1
;
if
(
c
->
bulklen
==
-
1
)
{
/* Read the first line of the query */
size_t
querylen
;
if
(
c
->
newline
)
{
char
*
p
=
c
->
newline
;
sds
query
,
*
argv
;
int
argc
,
j
;
c
->
newline
=
NULL
;
query
=
c
->
querybuf
;
c
->
querybuf
=
sdsempty
();
querylen
=
1
+
(
p
-
(
query
));
if
(
sdslen
(
query
)
>
querylen
)
{
/* leave data after the first line of the query in the buffer */
c
->
querybuf
=
sdscatlen
(
c
->
querybuf
,
query
+
querylen
,
sdslen
(
query
)
-
querylen
);
}
*
p
=
'\0'
;
/* remove "\n" */
if
(
*
(
p
-
1
)
==
'\r'
)
*
(
p
-
1
)
=
'\0'
;
/* and "\r" if any */
sdsupdatelen
(
query
);
/* Now we can split the query in arguments */
argv
=
sdssplitlen
(
query
,
sdslen
(
query
),
" "
,
1
,
&
argc
);
sdsfree
(
query
);
if
(
c
->
argv
)
zfree
(
c
->
argv
);
c
->
argv
=
zmalloc
(
sizeof
(
robj
*
)
*
argc
);
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
if
(
sdslen
(
argv
[
j
]))
{
c
->
argv
[
c
->
argc
]
=
createObject
(
REDIS_STRING
,
argv
[
j
]);
c
->
argc
++
;
}
else
{
sdsfree
(
argv
[
j
]);
int
processInlineBuffer
(
redisClient
*
c
)
{
char
*
newline
=
strstr
(
c
->
querybuf
,
"
\r\n
"
);
int
argc
,
j
;
sds
*
argv
;
size_t
querylen
;
/* Nothing to do without a \r\n */
if
(
newline
==
NULL
)
return
REDIS_ERR
;
/* Split the input buffer up to the \r\n */
querylen
=
newline
-
(
c
->
querybuf
);
argv
=
sdssplitlen
(
c
->
querybuf
,
querylen
,
" "
,
1
,
&
argc
);
/* Leave data after the first line of the query in the buffer */
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
querylen
+
2
,
-
1
);
/* Setup argv array on client structure */
if
(
c
->
argv
)
zfree
(
c
->
argv
);
c
->
argv
=
zmalloc
(
sizeof
(
robj
*
)
*
argc
);
/* Create redis objects for all arguments. */
for
(
c
->
argc
=
0
,
j
=
0
;
j
<
argc
;
j
++
)
{
if
(
sdslen
(
argv
[
j
]))
{
c
->
argv
[
c
->
argc
]
=
createObject
(
REDIS_STRING
,
argv
[
j
]);
c
->
argc
++
;
}
else
{
sdsfree
(
argv
[
j
]);
}
}
zfree
(
argv
);
return
REDIS_OK
;
}
/* Helper function. Trims query buffer to make the function that processes
* multi bulk requests idempotent. */
static
void
setProtocolError
(
redisClient
*
c
,
int
pos
)
{
c
->
flags
|=
REDIS_CLOSE_AFTER_REPLY
;
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
pos
,
-
1
);
}
int
processMultibulkBuffer
(
redisClient
*
c
)
{
char
*
newline
=
NULL
;
char
*
eptr
;
int
pos
=
0
,
tolerr
;
long
bulklen
;
if
(
c
->
multibulklen
==
0
)
{
/* The client should have been reset */
redisAssert
(
c
->
argc
==
0
);
/* Multi bulk length cannot be read without a \r\n */
newline
=
strstr
(
c
->
querybuf
,
"
\r\n
"
);
if
(
newline
==
NULL
)
return
REDIS_ERR
;
/* We know for sure there is a whole line since newline != NULL,
* so go ahead and find out the multi bulk length. */
redisAssert
(
c
->
querybuf
[
0
]
==
'*'
);
c
->
multibulklen
=
strtol
(
c
->
querybuf
+
1
,
&
eptr
,
10
);
pos
=
(
newline
-
c
->
querybuf
)
+
2
;
if
(
c
->
multibulklen
<=
0
)
{
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
pos
,
-
1
);
return
REDIS_OK
;
}
else
if
(
c
->
multibulklen
>
1024
*
1024
)
{
addReplyError
(
c
,
"Protocol error: invalid multibulk length"
);
setProtocolError
(
c
,
pos
);
return
REDIS_ERR
;
}
/* Setup argv array on client structure */
if
(
c
->
argv
)
zfree
(
c
->
argv
);
c
->
argv
=
zmalloc
(
sizeof
(
robj
*
)
*
c
->
multibulklen
);
/* Search new newline */
newline
=
strstr
(
c
->
querybuf
+
pos
,
"
\r\n
"
);
}
redisAssert
(
c
->
multibulklen
>
0
);
while
(
c
->
multibulklen
)
{
/* Read bulk length if unknown */
if
(
c
->
bulklen
==
-
1
)
{
newline
=
strstr
(
c
->
querybuf
+
pos
,
"
\r\n
"
);
if
(
newline
!=
NULL
)
{
if
(
c
->
querybuf
[
pos
]
!=
'$'
)
{
addReplyErrorFormat
(
c
,
"Protocol error: expected '$', got '%c'"
,
c
->
querybuf
[
pos
]);
setProtocolError
(
c
,
pos
);
return
REDIS_ERR
;
}
bulklen
=
strtol
(
c
->
querybuf
+
pos
+
1
,
&
eptr
,
10
);
tolerr
=
(
eptr
[
0
]
!=
'\r'
);
if
(
tolerr
||
bulklen
==
LONG_MIN
||
bulklen
==
LONG_MAX
||
bulklen
<
0
||
bulklen
>
1024
*
1024
*
1024
)
{
addReplyError
(
c
,
"Protocol error: invalid bulk length"
);
setProtocolError
(
c
,
pos
);
return
REDIS_ERR
;
}
pos
+=
eptr
-
(
c
->
querybuf
+
pos
)
+
2
;
c
->
bulklen
=
bulklen
;
}
else
{
/* No newline in current buffer, so wait for more data */
break
;
}
zfree
(
argv
);
if
(
c
->
argc
)
{
/* Execute the command. If the client is still valid
* after processCommand() return and there is something
* on the query buffer try to process the next command. */
if
(
processCommand
(
c
)
&&
sdslen
(
c
->
querybuf
))
goto
again
;
}
/* Read bulk argument */
if
(
sdslen
(
c
->
querybuf
)
-
pos
<
(
unsigned
)(
c
->
bulklen
+
2
))
{
/* Not enough data (+2 == trailing \r\n) */
break
;
}
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
);
/* We're done when c->multibulk == 0 */
if
(
c
->
multibulklen
==
0
)
{
return
REDIS_OK
;
}
return
REDIS_ERR
;
}
void
processInputBuffer
(
redisClient
*
c
)
{
/* Keep processing while there is something in the input buffer */
while
(
sdslen
(
c
->
querybuf
))
{
/* Immediately abort if the client is in the middle of something. */
if
(
c
->
flags
&
REDIS_BLOCKED
||
c
->
flags
&
REDIS_IO_WAIT
)
return
;
/* REDIS_CLOSE_AFTER_REPLY closes the connection once the reply is
* written to the client. Make sure to not let the reply grow after
* this flag has been set (i.e. don't process more commands). */
if
(
c
->
flags
&
REDIS_CLOSE_AFTER_REPLY
)
return
;
/* Determine request type when unknown. */
if
(
!
c
->
reqtype
)
{
if
(
c
->
querybuf
[
0
]
==
'*'
)
{
c
->
reqtype
=
REDIS_REQ_MULTIBULK
;
}
else
{
/* Nothing to process, argc == 0. Just process the query
* buffer if it's not empty or return to the caller */
if
(
sdslen
(
c
->
querybuf
))
goto
again
;
c
->
reqtype
=
REDIS_REQ_INLINE
;
}
return
;
}
else
if
(
sdslen
(
c
->
querybuf
)
>=
REDIS_REQUEST_MAX_SIZE
)
{
redisLog
(
REDIS_VERBOSE
,
"Client protocol error"
);
freeClient
(
c
);
return
;
}
}
else
{
/* Bulk read handling. Note that if we are at this point
the client already sent a command terminated with a newline,
we are reading the bulk data that is actually the last
argument of the command. */
int
qbl
=
sdslen
(
c
->
querybuf
);
if
(
c
->
bulklen
<=
qbl
)
{
/* Copy everything but the final CRLF as final argument */
c
->
argv
[
c
->
argc
]
=
createStringObject
(
c
->
querybuf
,
c
->
bulklen
-
2
);
c
->
argc
++
;
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
c
->
bulklen
,
-
1
);
/* Process the command. If the client is still valid after
* the processing and there is more data in the buffer
* try to parse it. */
if
(
processCommand
(
c
)
&&
sdslen
(
c
->
querybuf
))
goto
again
;
return
;
if
(
c
->
reqtype
==
REDIS_REQ_INLINE
)
{
if
(
processInlineBuffer
(
c
)
!=
REDIS_OK
)
break
;
}
else
if
(
c
->
reqtype
==
REDIS_REQ_MULTIBULK
)
{
if
(
processMultibulkBuffer
(
c
)
!=
REDIS_OK
)
break
;
}
else
{
redisPanic
(
"Unknown request type"
);
}
/* Multibulk processing could see a <= 0 length. */
if
(
c
->
argc
==
0
)
{
resetClient
(
c
);
}
else
{
/* Only reset the client when the command was executed. */
if
(
processCommand
(
c
)
==
REDIS_OK
)
resetClient
(
c
);
}
}
}
...
...
@@ -773,14 +856,8 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
return
;
}
if
(
nread
)
{
size_t
oldlen
=
sdslen
(
c
->
querybuf
);
c
->
querybuf
=
sdscatlen
(
c
->
querybuf
,
buf
,
nread
);
c
->
querybuf
=
sdscatlen
(
c
->
querybuf
,
buf
,
nread
);
c
->
lastinteraction
=
time
(
NULL
);
/* Scan this new piece of the query for the newline. We do this
* here in order to make sure we perform this scan just one time
* per piece of buffer, leading to an O(N) scan instead of O(N*N) */
if
(
c
->
bulklen
==
-
1
&&
c
->
newline
==
NULL
)
c
->
newline
=
strchr
(
c
->
querybuf
+
oldlen
,
'\n'
);
}
else
{
return
;
}
...
...
src/redis-benchmark.c
浏览文件 @
21dbc649
...
...
@@ -575,10 +575,28 @@ int main(int argc, char **argv) {
aeMain
(
config
.
el
);
endBenchmark
();
prepareForBenchmark
(
"MSET (10 keys, multi bulk)"
);
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
c
->
obuf
=
sdscatprintf
(
c
->
obuf
,
"*%d
\r\n
$4
\r\n
MSET
\r\n
"
,
11
);
{
int
i
;
char
*
data
=
zmalloc
(
config
.
datasize
+
2
);
memset
(
data
,
'x'
,
config
.
datasize
);
for
(
i
=
0
;
i
<
10
;
i
++
)
{
c
->
obuf
=
sdscatprintf
(
c
->
obuf
,
"$%d
\r\n
%s
\r\n
"
,
config
.
datasize
,
data
);
}
zfree
(
data
);
}
prepareClientForReply
(
c
,
REPLY_RETCODE
);
createMissingClients
(
c
);
aeMain
(
config
.
el
);
endBenchmark
();
prepareForBenchmark
(
"SET"
);
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
c
->
obuf
=
sdscat
printf
(
c
->
obuf
,
"SET foo_rand000000000000 %d
\r\n
"
,
config
.
datasize
);
c
->
obuf
=
sdscat
(
c
->
obuf
,
"SET foo_rand000000000000 "
);
{
char
*
data
=
zmalloc
(
config
.
datasize
+
2
);
memset
(
data
,
'x'
,
config
.
datasize
);
...
...
@@ -612,7 +630,7 @@ int main(int argc, char **argv) {
prepareForBenchmark
(
"LPUSH"
);
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
c
->
obuf
=
sdscat
(
c
->
obuf
,
"LPUSH mylist
3
\r\n
bar
\r\n
"
);
c
->
obuf
=
sdscat
(
c
->
obuf
,
"LPUSH mylist bar
\r\n
"
);
prepareClientForReply
(
c
,
REPLY_INT
);
createMissingClients
(
c
);
aeMain
(
config
.
el
);
...
...
@@ -630,7 +648,7 @@ int main(int argc, char **argv) {
prepareForBenchmark
(
"SADD"
);
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
c
->
obuf
=
sdscat
(
c
->
obuf
,
"SADD myset
24
\r\n
counter_rand000000000000
\r\n
"
);
c
->
obuf
=
sdscat
(
c
->
obuf
,
"SADD myset counter_rand000000000000
\r\n
"
);
prepareClientForReply
(
c
,
REPLY_RETCODE
);
createMissingClients
(
c
);
aeMain
(
config
.
el
);
...
...
@@ -648,7 +666,7 @@ int main(int argc, char **argv) {
prepareForBenchmark
(
"LPUSH (again, in order to bench LRANGE)"
);
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
c
->
obuf
=
sdscat
(
c
->
obuf
,
"LPUSH mylist
3
\r\n
bar
\r\n
"
);
c
->
obuf
=
sdscat
(
c
->
obuf
,
"LPUSH mylist bar
\r\n
"
);
prepareClientForReply
(
c
,
REPLY_RETCODE
);
createMissingClients
(
c
);
aeMain
(
config
.
el
);
...
...
src/redis-cli.c
浏览文件 @
21dbc649
...
...
@@ -45,10 +45,6 @@
#include "zmalloc.h"
#include "linenoise.h"
#define REDIS_CMD_INLINE 1
#define REDIS_CMD_BULK 2
#define REDIS_CMD_MULTIBULK 4
#define REDIS_NOTUSED(V) ((void) V)
static
struct
config
{
...
...
src/redis.c
浏览文件 @
21dbc649
此差异已折叠。
点击以展开。
src/redis.h
浏览文件 @
21dbc649
...
...
@@ -57,15 +57,15 @@
/* Hash table parameters */
#define REDIS_HT_MINFILL 10
/* Minimal hash table fill 10% */
/* Command flags
*/
#define REDIS_CMD_BULK 1
/* Bulk write command */
#define REDIS_CMD_INLINE 2
/* Inline command */
/* REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
this flags will return an error when the 'maxmemory' option is set in the
config file and the server is using more than maxmemory bytes of memory.
In short this commands are denied on low memory conditions
. */
#define REDIS_CMD_DENYOOM
4
#define REDIS_CMD_FORCE_REPLICATION 8
/* Force replication even if dirty is 0 */
/* Command flags
:
* REDIS_CMD_DENYOOM:
* Commands marked with this flag will return an error when 'maxmemory' is
* set and the server is using more than 'maxmemory' bytes of memory.
* In short: commands with this flag are denied on low memory conditions.
* REDIS_CMD_FORCE_REPLICATION:
* Force replication even if dirty is 0
. */
#define REDIS_CMD_DENYOOM 4
#define REDIS_CMD_FORCE_REPLICATION 8
/* Object types */
#define REDIS_STRING 0
...
...
@@ -144,6 +144,11 @@
#define REDIS_BLOCKED 16
/* The client is waiting in a blocking operation */
#define REDIS_IO_WAIT 32
/* The client is waiting for Virtual Memory I/O */
#define REDIS_DIRTY_CAS 64
/* Watched keys modified. EXEC will fail. */
#define REDIS_CLOSE_AFTER_REPLY 128
/* Close after writing entire reply. */
/* Client request types */
#define REDIS_REQ_INLINE 1
#define REDIS_REQ_MULTIBULK 2
/* Slave replication state - slave side */
#define REDIS_REPL_NONE 0
/* No active replication */
...
...
@@ -294,11 +299,11 @@ typedef struct redisClient {
redisDb
*
db
;
int
dictid
;
sds
querybuf
;
robj
**
argv
,
**
mbargv
;
char
*
newline
;
/* pointing to the detected newline in querybuf */
int
argc
,
mbargc
;
long
bulklen
;
/* bulk read len. -1 if not in bulk read mode
*/
int
multibulk
;
/* multi bulk command format active
*/
int
argc
;
robj
**
argv
;
int
reqtype
;
int
multibulklen
;
/* number of multi bulk arguments left to read
*/
long
bulklen
;
/* length of bulk argument in multi bulk request
*/
list
*
reply
;
int
sentlen
;
time_t
lastinteraction
;
/* time of the last interaction, used for timeout */
...
...
src/t_list.c
浏览文件 @
21dbc649
...
...
@@ -260,6 +260,7 @@ void listTypeConvert(robj *subject, int enc) {
void
pushGenericCommand
(
redisClient
*
c
,
int
where
)
{
robj
*
lobj
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
lobj
==
NULL
)
{
if
(
handleClientsWaitingListPush
(
c
,
c
->
argv
[
1
],
c
->
argv
[
2
]))
{
addReply
(
c
,
shared
.
cone
);
...
...
@@ -346,14 +347,17 @@ void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) {
}
void
lpushxCommand
(
redisClient
*
c
)
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
pushxGenericCommand
(
c
,
NULL
,
c
->
argv
[
2
],
REDIS_HEAD
);
}
void
rpushxCommand
(
redisClient
*
c
)
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
pushxGenericCommand
(
c
,
NULL
,
c
->
argv
[
2
],
REDIS_TAIL
);
}
void
linsertCommand
(
redisClient
*
c
)
{
c
->
argv
[
4
]
=
tryObjectEncoding
(
c
->
argv
[
4
]);
if
(
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"after"
)
==
0
)
{
pushxGenericCommand
(
c
,
c
->
argv
[
3
],
c
->
argv
[
4
],
REDIS_TAIL
);
}
else
if
(
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"before"
)
==
0
)
{
...
...
@@ -409,7 +413,7 @@ void lsetCommand(redisClient *c) {
robj
*
o
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
nokeyerr
);
if
(
o
==
NULL
||
checkType
(
c
,
o
,
REDIS_LIST
))
return
;
int
index
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
robj
*
value
=
c
->
argv
[
3
]
;
robj
*
value
=
(
c
->
argv
[
3
]
=
tryObjectEncoding
(
c
->
argv
[
3
]))
;
listTypeTryConversion
(
o
,
value
);
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
{
...
...
@@ -559,7 +563,8 @@ void ltrimCommand(redisClient *c) {
}
void
lremCommand
(
redisClient
*
c
)
{
robj
*
subject
,
*
obj
=
c
->
argv
[
3
];
robj
*
subject
,
*
obj
;
obj
=
c
->
argv
[
3
]
=
tryObjectEncoding
(
c
->
argv
[
3
]);
int
toremove
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
int
removed
=
0
;
listTypeEntry
entry
;
...
...
src/t_set.c
浏览文件 @
21dbc649
...
...
@@ -178,6 +178,7 @@ void saddCommand(redisClient *c) {
robj
*
set
;
set
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
set
==
NULL
)
{
set
=
setTypeCreate
(
c
->
argv
[
2
]);
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
set
);
...
...
@@ -202,6 +203,7 @@ void sremCommand(redisClient *c) {
if
((
set
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
set
,
REDIS_SET
))
return
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
setTypeRemove
(
set
,
c
->
argv
[
2
]))
{
if
(
setTypeSize
(
set
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
...
...
@@ -216,7 +218,7 @@ void smoveCommand(redisClient *c) {
robj
*
srcset
,
*
dstset
,
*
ele
;
srcset
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
dstset
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
2
]);
ele
=
c
->
argv
[
3
];
ele
=
c
->
argv
[
3
]
=
tryObjectEncoding
(
c
->
argv
[
3
])
;
/* If the source key does not exist return 0 */
if
(
srcset
==
NULL
)
{
...
...
@@ -264,6 +266,7 @@ void sismemberCommand(redisClient *c) {
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
set
,
REDIS_SET
))
return
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
setTypeIsMember
(
set
,
c
->
argv
[
2
]))
addReply
(
c
,
shared
.
cone
);
else
...
...
src/t_string.c
浏览文件 @
21dbc649
...
...
@@ -37,14 +37,17 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
}
void
setCommand
(
redisClient
*
c
)
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
setGenericCommand
(
c
,
0
,
c
->
argv
[
1
],
c
->
argv
[
2
],
NULL
);
}
void
setnxCommand
(
redisClient
*
c
)
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
setGenericCommand
(
c
,
1
,
c
->
argv
[
1
],
c
->
argv
[
2
],
NULL
);
}
void
setexCommand
(
redisClient
*
c
)
{
c
->
argv
[
3
]
=
tryObjectEncoding
(
c
->
argv
[
3
]);
setGenericCommand
(
c
,
0
,
c
->
argv
[
1
],
c
->
argv
[
3
],
c
->
argv
[
2
]);
}
...
...
@@ -69,6 +72,7 @@ void getCommand(redisClient *c) {
void
getsetCommand
(
redisClient
*
c
)
{
if
(
getGenericCommand
(
c
)
==
REDIS_ERR
)
return
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
incrRefCount
(
c
->
argv
[
2
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
...
...
@@ -180,6 +184,7 @@ void appendCommand(redisClient *c) {
robj
*
o
;
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
o
==
NULL
)
{
/* Create the key */
retval
=
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
...
...
src/t_zset.c
浏览文件 @
21dbc649
...
...
@@ -440,12 +440,14 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double score, int
void
zaddCommand
(
redisClient
*
c
)
{
double
scoreval
;
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
scoreval
,
NULL
)
!=
REDIS_OK
)
return
;
c
->
argv
[
3
]
=
tryObjectEncoding
(
c
->
argv
[
3
]);
zaddGenericCommand
(
c
,
c
->
argv
[
1
],
c
->
argv
[
3
],
scoreval
,
0
);
}
void
zincrbyCommand
(
redisClient
*
c
)
{
double
scoreval
;
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
scoreval
,
NULL
)
!=
REDIS_OK
)
return
;
c
->
argv
[
3
]
=
tryObjectEncoding
(
c
->
argv
[
3
]);
zaddGenericCommand
(
c
,
c
->
argv
[
1
],
c
->
argv
[
3
],
scoreval
,
1
);
}
...
...
@@ -460,6 +462,7 @@ void zremCommand(redisClient *c) {
checkType
(
c
,
zsetobj
,
REDIS_ZSET
))
return
;
zs
=
zsetobj
->
ptr
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
if
(
de
==
NULL
)
{
addReply
(
c
,
shared
.
czero
);
...
...
@@ -1004,6 +1007,7 @@ void zscoreCommand(redisClient *c) {
checkType
(
c
,
o
,
REDIS_ZSET
))
return
;
zs
=
o
->
ptr
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
if
(
!
de
)
{
addReply
(
c
,
shared
.
nullbulk
);
...
...
@@ -1027,6 +1031,7 @@ void zrankGenericCommand(redisClient *c, int reverse) {
zs
=
o
->
ptr
;
zsl
=
zs
->
zsl
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
if
(
!
de
)
{
addReply
(
c
,
shared
.
nullbulk
);
...
...
tests/support/redis.tcl
浏览文件 @
21dbc649
...
...
@@ -36,25 +36,6 @@ array set ::redis::deferred {}
array set ::redis::callback
{}
array set ::redis::state
{}
;
# State in non-blocking reply reading
array set ::redis::statestack
{}
;
# Stack of states, for nested mbulks
array set ::redis::bulkarg
{}
array set ::redis::multibulkarg
{}
# Flag commands requiring last argument as a bulk write operation
foreach redis_bulk_cmd
{
set setnx rpush lpush rpushx lpushx linsert lset lrem sadd srem sismember echo getset smove zadd zrem zscore zincrby append zrank zrevrank hget hdel hexists setex publish
}
{
set ::redis::bulkarg
(
$redis
_bulk_cmd
)
{}
}
# Flag commands requiring last argument as a bulk write operation
foreach redis_multibulk_cmd
{
mset msetnx hset hsetnx hmset hmget
}
{
set ::redis::multibulkarg
(
$redis
_multibulk_cmd
)
{}
}
unset redis_bulk_cmd
unset redis_multibulk_cmd
proc redis
{{
server 127.0.0.1
}
{
port 6379
}
{
defer 0
}}
{
set fd
[
socket $server $port
]
...
...
@@ -79,25 +60,14 @@ proc ::redis::__dispatch__ {id method args} {
set args
[
lrange $args 0 end-1
]
}
if
{[
info command ::redis::__method__$method
]
eq
{}}
{
if
{[
info exists ::redis::bulkarg
(
$method
)]}
{
set cmd
"
$method
"
append cmd
[
join
[
lrange $args 0 end-1
]]
append cmd
"
[
string length
[
lindex $args end
]]
\r\n
"
append cmd
[
lindex $args end
]
::redis::redis_writenl $fd $cmd
}
elseif
{[
info exists ::redis::multibulkarg
(
$method
)]}
{
set cmd
"*
[
expr
{[
llength $args
]
+1
}]
\r\n
"
append cmd
"
$
[
string length $method
]
\r\n
$method
\r\n
"
foreach a $args
{
append cmd
"
$
[
string length $a
]
\r\n
$a
\r\n
"
}
::redis::redis_write $fd $cmd
flush $fd
}
else
{
set cmd
"
$method
"
append cmd
[
join $args
]
::redis::redis_writenl $fd $cmd
set cmd
"*
[
expr
{[
llength $args
]
+1
}]
\r\n
"
append cmd
"
$
[
string length $method
]
\r\n
$method
\r\n
"
foreach a $args
{
append cmd
"
$
[
string length $a
]
\r\n
$a
\r\n
"
}
::redis::redis_write $fd $cmd
flush $fd
if
{
!$deferred
}
{
if
{
$blocking
}
{
::redis::redis_read_reply $fd
...
...
@@ -123,6 +93,14 @@ proc ::redis::__method__read {id fd} {
::redis::redis_read_reply $fd
}
proc ::redis::__method__write
{
id fd buf
}
{
::redis::redis_write $fd $buf
}
proc ::redis::__method__flush
{
id fd
}
{
flush $fd
}
proc ::redis::__method__close
{
id fd
}
{
catch
{
close $fd
}
catch
{
unset ::redis::fd
(
$id
)}
...
...
tests/support/server.tcl
浏览文件 @
21dbc649
...
...
@@ -215,7 +215,8 @@ proc start_server {options {code undefined}} {
if
{[
dict exists $config port
]}
{
set port
[
dict get $config port
]
}
# setup config dict
dict set srv
"config"
$config_file
dict set srv
"config_file"
$config_file
dict set srv
"config"
$config
dict set srv
"pid"
$pid
dict set srv
"host"
$host
dict set srv
"port"
$port
...
...
@@ -238,17 +239,12 @@ proc start_server {options {code undefined}} {
after 10
}
set client
[
redis $host $port
]
dict set srv
"client"
$client
# select the right db when we don't have to authenticate
if
{
!
[
dict exists $config requirepass
]}
{
$client select 9
}
# append the server to the stack
lappend ::servers $srv
# connect client
(
after server dict is put on the stack
)
reconnect
# execute provided block
set curnum $::testnum
if
{
!
[
catch
{
uplevel 1 $code
}
err
]}
{
...
...
tests/support/test.tcl
浏览文件 @
21dbc649
...
...
@@ -90,8 +90,10 @@ proc test {name code {okpattern notspecified}} {
}
}
if
{
$::traceleaks
}
{
if
{
!
[
string match
{
*0 leaks*
}
[
exec leaks redis-server
]]}
{
set output
[
exec leaks redis-server
]
if
{
!
[
string match
{
*0 leaks*
}
$output
]}
{
puts
"--------- Test
$::testnum
LEAKED! --------"
puts $output
exit 1
}
}
...
...
tests/test_helper.tcl
浏览文件 @
21dbc649
...
...
@@ -16,6 +16,7 @@ set ::valgrind 0
set ::denytags
{}
set ::allowtags
{}
set ::external 0
;
# If
"1"
this means, we are running against external instance
set ::file
""
;
# If set, runs only the tests in this comma separated list
proc execute_tests name
{
source
"tests/
$name.tcl
"
...
...
@@ -49,6 +50,28 @@ proc r {args} {
[
srv $level
"client"
]
{*}
$args
}
proc reconnect
{
args
}
{
set level
[
lindex $args 0
]
if
{[
string length $level
]
== 0 || !
[
string is integer $level
]}
{
set level 0
}
set srv
[
lindex $::servers end+$level
]
set host
[
dict get $srv
"host"
]
set port
[
dict get $srv
"port"
]
set config
[
dict get $srv
"config"
]
set client
[
redis $host $port
]
dict set srv
"client"
$client
# select the right db when we don't have to authenticate
if
{
!
[
dict exists $config
"requirepass"
]}
{
$client select 9
}
# re-set $srv in the servers list
set ::servers
[
lreplace $::servers end+$level 1 $srv
]
}
proc redis_deferring_client
{
args
}
{
set level 0
if
{[
llength $args
]
> 0 &&
[
string is integer
[
lindex $args 0
]]}
{
...
...
@@ -80,8 +103,7 @@ proc cleanup {} {
catch
{
exec rm -rf
{*}
[
glob tests/tmp/server.*
]}
}
proc main
{}
{
cleanup
proc execute_everything
{}
{
execute_tests
"unit/auth"
execute_tests
"unit/protocol"
execute_tests
"unit/basic"
...
...
@@ -93,6 +115,7 @@ proc main {} {
execute_tests
"unit/expire"
execute_tests
"unit/other"
execute_tests
"unit/cas"
execute_tests
"unit/quit"
execute_tests
"integration/replication"
execute_tests
"integration/aof"
# execute_tests
"integration/redis-cli"
...
...
@@ -110,6 +133,18 @@ proc main {} {
execute_tests
"unit/expire"
execute_tests
"unit/other"
execute_tests
"unit/cas"
}
proc main
{}
{
cleanup
if
{[
string length $::file
]
> 0
}
{
foreach
{
file
}
[
split $::file ,
]
{
execute_tests $file
}
}
else
{
execute_everything
}
cleanup
puts
"
\n
[
expr $::passed+$::failed
]
tests,
$::passed
passed,
$::failed
failed"
...
...
@@ -132,6 +167,9 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
}
}
incr j
}
elseif
{
$opt
eq
{
--file
}}
{
set ::file $arg
incr j
}
elseif
{
$opt
eq
{
--host
}}
{
set ::external 1
set ::host $arg
...
...
tests/unit/basic.tcl
浏览文件 @
21dbc649
...
...
@@ -172,7 +172,7 @@ start_server {tags {"basic"}} {
test
{
Commands pipelining
}
{
set fd
[
r channel
]
puts -nonewline $fd
"SET k1
4
\r\n
xyzk
\r\n
GET k1
\r\n
PING
\r\n
"
puts -nonewline $fd
"SET k1 xyzk
\r\n
GET k1
\r\n
PING
\r\n
"
flush $fd
set res
{}
append res
[
string match OK*
[
::redis::redis_read_reply $fd
]]
...
...
tests/unit/other.tcl
浏览文件 @
21dbc649
...
...
@@ -123,7 +123,7 @@ start_server {tags {"other"}} {
for
{
set i 0
}
{
$i
< 100000
}
{
incr i
}
{
set q
{}
set val
"0000
${i}
0000"
append q
"SET key:
$i
[
string length $val
]
\r\n
$val
\r\n
"
append q
"SET key:
$i
$val
\r\n
"
puts -nonewline $fd2 $q
set q
{}
append q
"GET key:
$i
\r\n
"
...
...
tests/unit/protocol.tcl
浏览文件 @
21dbc649
start_server
{
tags
{
"protocol"
}}
{
test
{
Handle an empty query well
}
{
set fd
[
r channel
]
puts -nonewline $fd
"
\r\n
"
flush $fd
r ping
}
{
PONG
}
test
{
Negative multi bulk command does not create problems
}
{
set fd
[
r channel
]
puts -nonewline $fd
"*-10
\r\n
"
flush $fd
r ping
}
{
PONG
}
test
{
Negative multi bulk payload
}
{
set fd
[
r channel
]
puts -nonewline $fd
"SET x -10
\r\n
"
flush $fd
gets $fd
}
{
*invalid bulk*
}
test
{
Too big bulk payload
}
{
set fd
[
r channel
]
puts -nonewline $fd
"SET x 2000000000
\r\n
"
flush $fd
gets $fd
}
{
*invalid bulk*count*
}
test
{
bulk payload is not a number
}
{
set fd
[
r channel
]
puts -nonewline $fd
"SET x blabla
\r\n
"
flush $fd
gets $fd
}
{
*invalid bulk*count*
}
test
{
Multi bulk request not followed by bulk args
}
{
set fd
[
r channel
]
puts -nonewline $fd
"*1
\r\n
foo
\r\n
"
flush $fd
gets $fd
}
{
*protocol error*
}
test
{
Generic wrong number of args
}
{
catch
{
r ping x y z
}
err
set _ $err
}
{
*wrong*arguments*ping*
}
test
"Handle an empty query"
{
reconnect
r write
"
\r\n
"
r flush
assert_equal
"PONG"
[
r ping
]
}
test
"Negative multibulk length"
{
reconnect
r write
"*-10
\r\n
"
r flush
assert_equal PONG
[
r ping
]
}
test
"Out of range multibulk length"
{
reconnect
r write
"*20000000
\r\n
"
r flush
assert_error
"*invalid multibulk length*"
{
r read
}
}
test
"Wrong multibulk payload header"
{
reconnect
r write
"*3
\r\n\$
3
\r\n
SET
\r\n\$
1
\r\n
x
\r\n
fooz
\r\n
"
r flush
assert_error
"*expected '
$
', got 'f'*"
{
r read
}
}
test
"Negative multibulk payload length"
{
reconnect
r write
"*3
\r\n\$
3
\r\n
SET
\r\n\$
1
\r\n
x
\r\n\$
-10
\r\n
"
r flush
assert_error
"*invalid bulk length*"
{
r read
}
}
test
"Out of range multibulk payload length"
{
reconnect
r write
"*3
\r\n\$
3
\r\n
SET
\r\n\$
1
\r\n
x
\r\n\$
2000000000
\r\n
"
r flush
assert_error
"*invalid bulk length*"
{
r read
}
}
test
"Non-number multibulk payload length"
{
reconnect
r write
"*3
\r\n\$
3
\r\n
SET
\r\n\$
1
\r\n
x
\r\n\$
blabla
\r\n
"
r flush
assert_error
"*invalid bulk length*"
{
r read
}
}
test
"Multi bulk request not followed by bulk arguments"
{
reconnect
r write
"*1
\r\n
foo
\r\n
"
r flush
assert_error
"*expected '
$
', got 'f'*"
{
r read
}
}
test
"Generic wrong number of args"
{
reconnect
assert_error
"*wrong*arguments*ping*"
{
r ping x y z
}
}
}
tests/unit/quit.tcl
0 → 100644
浏览文件 @
21dbc649
start_server
{
tags
{
"quit"
}}
{
proc format_command
{
args
}
{
set cmd
"*
[
llength $args
]
\r\n
"
foreach a $args
{
append cmd
"
$
[
string length $a
]
\r\n
$a
\r\n
"
}
set _ $cmd
}
test
"QUIT returns OK"
{
reconnect
assert_equal OK
[
r quit
]
assert_error *
{
r ping
}
}
test
"Pipelined commands after QUIT must not be executed"
{
reconnect
r write
[
format_command quit
]
r write
[
format_command set foo bar
]
r flush
assert_equal OK
[
r read
]
assert_error *
{
r read
}
reconnect
assert_equal
{}
[
r get foo
]
}
test
"Pipelined commands after QUIT that exceed read buffer size"
{
reconnect
r write
[
format_command quit
]
r write
[
format_command set foo
[
string repeat
"x"
1024
]]
r flush
assert_equal OK
[
r read
]
assert_error *
{
r read
}
reconnect
assert_equal
{}
[
r get foo
]
}
}
tests/unit/sort.tcl
浏览文件 @
21dbc649
...
...
@@ -47,11 +47,11 @@ start_server {
assert_encoding $enc tosort
test
"
$title:
SORT BY key"
{
assert_equal $result
[
r sort tosort
{
BY weight_*
}
]
assert_equal $result
[
r sort tosort
BY weight_*
]
}
test
"
$title:
SORT BY hash field"
{
assert_equal $result
[
r sort tosort
{
BY wobj_*->weight
}
]
assert_equal $result
[
r sort tosort
BY wobj_*->weight
]
}
}
...
...
@@ -78,21 +78,21 @@ start_server {
}
test
"SORT BY key STORE"
{
r sort tosort
{
BY weight_*
}
store sort-res
r sort tosort
BY weight_*
store sort-res
assert_equal $result
[
r lrange sort-res 0 -1
]
assert_equal 16
[
r llen sort-res
]
assert_encoding ziplist sort-res
}
test
"SORT BY hash field STORE"
{
r sort tosort
{
BY wobj_*->weight
}
store sort-res
r sort tosort
BY wobj_*->weight
store sort-res
assert_equal $result
[
r lrange sort-res 0 -1
]
assert_equal 16
[
r llen sort-res
]
assert_encoding ziplist sort-res
}
test
"SORT DESC"
{
assert_equal
[
lsort -decreasing -integer $result
]
[
r sort tosort
{
DESC
}
]
assert_equal
[
lsort -decreasing -integer $result
]
[
r sort tosort
DESC
]
}
test
"SORT ALPHA against integer encoded strings"
{
...
...
@@ -141,7 +141,7 @@ start_server {
test
"SORT speed,
$num
element list BY key, 100 times"
{
set start
[
clock clicks -milliseconds
]
for
{
set i 0
}
{
$i
< 100
}
{
incr i
}
{
set sorted
[
r sort tosort
{
BY weight_* LIMIT 0 10
}
]
set sorted
[
r sort tosort
BY weight_* LIMIT 0 10
]
}
set elapsed
[
expr
[
clock clicks -milliseconds
]
-$start
]
puts -nonewline
"
\n
Average time to sort:
[
expr double
(
$elapsed
)
/100
]
milliseconds "
...
...
@@ -151,7 +151,7 @@ start_server {
test
"SORT speed,
$num
element list BY hash field, 100 times"
{
set start
[
clock clicks -milliseconds
]
for
{
set i 0
}
{
$i
< 100
}
{
incr i
}
{
set sorted
[
r sort tosort
{
BY wobj_*->weight LIMIT 0 10
}
]
set sorted
[
r sort tosort
BY wobj_*->weight LIMIT 0 10
]
}
set elapsed
[
expr
[
clock clicks -milliseconds
]
-$start
]
puts -nonewline
"
\n
Average time to sort:
[
expr double
(
$elapsed
)
/100
]
milliseconds "
...
...
@@ -161,7 +161,7 @@ start_server {
test
"SORT speed,
$num
element list directly, 100 times"
{
set start
[
clock clicks -milliseconds
]
for
{
set i 0
}
{
$i
< 100
}
{
incr i
}
{
set sorted
[
r sort tosort
{
LIMIT 0 10
}
]
set sorted
[
r sort tosort
LIMIT 0 10
]
}
set elapsed
[
expr
[
clock clicks -milliseconds
]
-$start
]
puts -nonewline
"
\n
Average time to sort:
[
expr double
(
$elapsed
)
/100
]
milliseconds "
...
...
@@ -171,7 +171,7 @@ start_server {
test
"SORT speed,
$num
element list BY <const>, 100 times"
{
set start
[
clock clicks -milliseconds
]
for
{
set i 0
}
{
$i
< 100
}
{
incr i
}
{
set sorted
[
r sort tosort
{
BY nokey LIMIT 0 10
}
]
set sorted
[
r sort tosort
BY nokey LIMIT 0 10
]
}
set elapsed
[
expr
[
clock clicks -milliseconds
]
-$start
]
puts -nonewline
"
\n
Average time to sort:
[
expr double
(
$elapsed
)
/100
]
milliseconds "
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录