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
21dbc649
Commit
21dbc649
authored
Oct 28, 2010
by
antirez
Browse files
merge conflict resolved
parents
73abd0a9
4794d88f
Changes
21
Show whitespace changes
Inline
Side-by-side
src/Makefile
View file @
21dbc649
...
@@ -132,7 +132,7 @@ dep:
...
@@ -132,7 +132,7 @@ dep:
$(CC)
-MM
*
.c
$(CC)
-MM
*
.c
test
:
test
:
(
cd
..
;
tclsh8.5 tests/test_helper.tcl
--tags
"
${TAGS}
"
)
(
cd
..
;
tclsh8.5 tests/test_helper.tcl
--tags
"
${TAGS}
"
--file
"
${FILE}
"
)
bench
:
bench
:
./redis-benchmark
./redis-benchmark
...
...
src/aof.c
View file @
21dbc649
...
@@ -266,9 +266,6 @@ int loadAppendOnlyFile(char *filename) {
...
@@ -266,9 +266,6 @@ int loadAppendOnlyFile(char *filename) {
redisLog
(
REDIS_WARNING
,
"Unknown command '%s' reading the append only file"
,
argv
[
0
]
->
ptr
);
redisLog
(
REDIS_WARNING
,
"Unknown command '%s' reading the append only file"
,
argv
[
0
]
->
ptr
);
exit
(
1
);
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 */
/* Run the command in the context of a fake client */
fakeClient
->
argc
=
argc
;
fakeClient
->
argc
=
argc
;
fakeClient
->
argv
=
argv
;
fakeClient
->
argv
=
argv
;
...
...
src/config.c
View file @
21dbc649
...
@@ -246,8 +246,11 @@ loaderr:
...
@@ -246,8 +246,11 @@ loaderr:
*----------------------------------------------------------------------------*/
*----------------------------------------------------------------------------*/
void
configSetCommand
(
redisClient
*
c
)
{
void
configSetCommand
(
redisClient
*
c
)
{
robj
*
o
=
getDecodedObject
(
c
->
argv
[
3
])
;
robj
*
o
;
long
long
ll
;
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"
))
{
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"dbfilename"
))
{
zfree
(
server
.
dbfilename
);
zfree
(
server
.
dbfilename
);
...
@@ -312,7 +315,6 @@ void configSetCommand(redisClient *c) {
...
@@ -312,7 +315,6 @@ void configSetCommand(redisClient *c) {
if
(
startAppendOnly
()
==
REDIS_ERR
)
{
if
(
startAppendOnly
()
==
REDIS_ERR
)
{
addReplyError
(
c
,
addReplyError
(
c
,
"Unable to turn on AOF. Check server logs."
);
"Unable to turn on AOF. Check server logs."
);
decrRefCount
(
o
);
return
;
return
;
}
}
}
}
...
@@ -354,10 +356,8 @@ void configSetCommand(redisClient *c) {
...
@@ -354,10 +356,8 @@ void configSetCommand(redisClient *c) {
}
else
{
}
else
{
addReplyErrorFormat
(
c
,
"Unsupported CONFIG parameter: %s"
,
addReplyErrorFormat
(
c
,
"Unsupported CONFIG parameter: %s"
,
(
char
*
)
c
->
argv
[
2
]
->
ptr
);
(
char
*
)
c
->
argv
[
2
]
->
ptr
);
decrRefCount
(
o
);
return
;
return
;
}
}
decrRefCount
(
o
);
addReply
(
c
,
shared
.
ok
);
addReply
(
c
,
shared
.
ok
);
return
;
return
;
...
@@ -365,15 +365,15 @@ badfmt: /* Bad format errors */
...
@@ -365,15 +365,15 @@ badfmt: /* Bad format errors */
addReplyErrorFormat
(
c
,
"Invalid argument '%s' for CONFIG SET '%s'"
,
addReplyErrorFormat
(
c
,
"Invalid argument '%s' for CONFIG SET '%s'"
,
(
char
*
)
o
->
ptr
,
(
char
*
)
o
->
ptr
,
(
char
*
)
c
->
argv
[
2
]
->
ptr
);
(
char
*
)
c
->
argv
[
2
]
->
ptr
);
decrRefCount
(
o
);
}
}
void
configGetCommand
(
redisClient
*
c
)
{
void
configGetCommand
(
redisClient
*
c
)
{
robj
*
o
=
getDecodedObject
(
c
->
argv
[
2
]
)
;
robj
*
o
=
c
->
argv
[
2
];
void
*
replylen
=
addDeferredMultiBulkLength
(
c
);
void
*
replylen
=
addDeferredMultiBulkLength
(
c
);
char
*
pattern
=
o
->
ptr
;
char
*
pattern
=
o
->
ptr
;
char
buf
[
128
];
char
buf
[
128
];
int
matches
=
0
;
int
matches
=
0
;
redisAssert
(
o
->
encoding
==
REDIS_ENCODING_RAW
);
if
(
stringmatch
(
pattern
,
"dbfilename"
,
0
))
{
if
(
stringmatch
(
pattern
,
"dbfilename"
,
0
))
{
addReplyBulkCString
(
c
,
"dbfilename"
);
addReplyBulkCString
(
c
,
"dbfilename"
);
...
@@ -462,7 +462,6 @@ void configGetCommand(redisClient *c) {
...
@@ -462,7 +462,6 @@ void configGetCommand(redisClient *c) {
sdsfree
(
buf
);
sdsfree
(
buf
);
matches
++
;
matches
++
;
}
}
decrRefCount
(
o
);
setDeferredMultiBulkLength
(
c
,
replylen
,
matches
*
2
);
setDeferredMultiBulkLength
(
c
,
replylen
,
matches
*
2
);
}
}
...
...
src/networking.c
View file @
21dbc649
...
@@ -28,13 +28,11 @@ redisClient *createClient(int fd) {
...
@@ -28,13 +28,11 @@ redisClient *createClient(int fd) {
selectDb
(
c
,
0
);
selectDb
(
c
,
0
);
c
->
fd
=
fd
;
c
->
fd
=
fd
;
c
->
querybuf
=
sdsempty
();
c
->
querybuf
=
sdsempty
();
c
->
newline
=
NULL
;
c
->
reqtype
=
0
;
c
->
argc
=
0
;
c
->
argc
=
0
;
c
->
argv
=
NULL
;
c
->
argv
=
NULL
;
c
->
multibulklen
=
0
;
c
->
bulklen
=
-
1
;
c
->
bulklen
=
-
1
;
c
->
multibulk
=
0
;
c
->
mbargc
=
0
;
c
->
mbargv
=
NULL
;
c
->
sentlen
=
0
;
c
->
sentlen
=
0
;
c
->
flags
=
0
;
c
->
flags
=
0
;
c
->
lastinteraction
=
time
(
NULL
);
c
->
lastinteraction
=
time
(
NULL
);
...
@@ -57,7 +55,12 @@ redisClient *createClient(int fd) {
...
@@ -57,7 +55,12 @@ redisClient *createClient(int fd) {
return
c
;
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
)
{
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
->
fd
<=
0
)
return
REDIS_ERR
;
if
(
c
->
bufpos
==
0
&&
listLength
(
c
->
reply
)
==
0
&&
if
(
c
->
bufpos
==
0
&&
listLength
(
c
->
reply
)
==
0
&&
(
c
->
replstate
==
REDIS_REPL_NONE
||
(
c
->
replstate
==
REDIS_REPL_NONE
||
...
@@ -374,13 +377,9 @@ void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
...
@@ -374,13 +377,9 @@ void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
static
void
freeClientArgv
(
redisClient
*
c
)
{
static
void
freeClientArgv
(
redisClient
*
c
)
{
int
j
;
int
j
;
for
(
j
=
0
;
j
<
c
->
argc
;
j
++
)
for
(
j
=
0
;
j
<
c
->
argc
;
j
++
)
decrRefCount
(
c
->
argv
[
j
]);
decrRefCount
(
c
->
argv
[
j
]);
for
(
j
=
0
;
j
<
c
->
mbargc
;
j
++
)
decrRefCount
(
c
->
mbargv
[
j
]);
c
->
argc
=
0
;
c
->
argc
=
0
;
c
->
mbargc
=
0
;
}
}
void
freeClient
(
redisClient
*
c
)
{
void
freeClient
(
redisClient
*
c
)
{
...
@@ -461,7 +460,6 @@ void freeClient(redisClient *c) {
...
@@ -461,7 +460,6 @@ void freeClient(redisClient *c) {
}
}
/* Release memory */
/* Release memory */
zfree
(
c
->
argv
);
zfree
(
c
->
argv
);
zfree
(
c
->
mbargv
);
freeClientMultiState
(
c
);
freeClientMultiState
(
c
);
zfree
(
c
);
zfree
(
c
);
}
}
...
@@ -546,6 +544,9 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
...
@@ -546,6 +544,9 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
if
(
listLength
(
c
->
reply
)
==
0
)
{
if
(
listLength
(
c
->
reply
)
==
0
)
{
c
->
sentlen
=
0
;
c
->
sentlen
=
0
;
aeDeleteFileEvent
(
server
.
el
,
c
->
fd
,
AE_WRITABLE
);
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)
...
@@ -630,9 +631,9 @@ void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask)
/* resetClient prepare the client to process the next command */
/* resetClient prepare the client to process the next command */
void
resetClient
(
redisClient
*
c
)
{
void
resetClient
(
redisClient
*
c
)
{
freeClientArgv
(
c
);
freeClientArgv
(
c
);
c
->
reqtype
=
0
;
c
->
multibulklen
=
0
;
c
->
bulklen
=
-
1
;
c
->
bulklen
=
-
1
;
c
->
multibulk
=
0
;
c
->
newline
=
NULL
;
}
}
void
closeTimedoutClients
(
void
)
{
void
closeTimedoutClients
(
void
)
{
...
@@ -663,49 +664,29 @@ void closeTimedoutClients(void) {
...
@@ -663,49 +664,29 @@ void closeTimedoutClients(void) {
}
}
}
}
void
processInputBuffer
(
redisClient
*
c
)
{
int
processInlineBuffer
(
redisClient
*
c
)
{
int
seeknewline
=
0
;
char
*
newline
=
strstr
(
c
->
querybuf
,
"
\r\n
"
);
int
argc
,
j
;
again:
sds
*
argv
;
/* 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
;
size_t
querylen
;
if
(
c
->
newline
)
{
/* Nothing to do without a \r\n */
char
*
p
=
c
->
newline
;
if
(
newline
==
NULL
)
sds
query
,
*
argv
;
return
REDIS_ERR
;
int
argc
,
j
;
c
->
newline
=
NULL
;
/* Split the input buffer up to the \r\n */
query
=
c
->
querybuf
;
querylen
=
newline
-
(
c
->
querybuf
);
c
->
querybuf
=
sdsempty
();
argv
=
sdssplitlen
(
c
->
querybuf
,
querylen
,
" "
,
1
,
&
argc
);
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 */
/* Leave data after the first line of the query in the buffer */
argv
=
sdssplitlen
(
query
,
sdslen
(
query
),
" "
,
1
,
&
argc
);
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
querylen
+
2
,
-
1
);
sdsfree
(
query
);
/* Setup argv array on client structure */
if
(
c
->
argv
)
zfree
(
c
->
argv
);
if
(
c
->
argv
)
zfree
(
c
->
argv
);
c
->
argv
=
zmalloc
(
sizeof
(
robj
*
)
*
argc
);
c
->
argv
=
zmalloc
(
sizeof
(
robj
*
)
*
argc
);
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
/* Create redis objects for all arguments. */
for
(
c
->
argc
=
0
,
j
=
0
;
j
<
argc
;
j
++
)
{
if
(
sdslen
(
argv
[
j
]))
{
if
(
sdslen
(
argv
[
j
]))
{
c
->
argv
[
c
->
argc
]
=
createObject
(
REDIS_STRING
,
argv
[
j
]);
c
->
argv
[
c
->
argc
]
=
createObject
(
REDIS_STRING
,
argv
[
j
]);
c
->
argc
++
;
c
->
argc
++
;
...
@@ -714,39 +695,141 @@ again:
...
@@ -714,39 +695,141 @@ again:
}
}
}
}
zfree
(
argv
);
zfree
(
argv
);
if
(
c
->
argc
)
{
return
REDIS_OK
;
/* 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. */
/* Helper function. Trims query buffer to make the function that processes
if
(
processCommand
(
c
)
&&
sdslen
(
c
->
querybuf
))
goto
again
;
* 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
{
}
else
{
/* Nothing to process, argc == 0. Just process the query
/* No newline in current buffer, so wait for more data */
* buffer if it's not empty or return to the caller */
break
;
if
(
sdslen
(
c
->
querybuf
))
goto
again
;
}
}
return
;
}
else
if
(
sdslen
(
c
->
querybuf
)
>=
REDIS_REQUEST_MAX_SIZE
)
{
redisLog
(
REDIS_VERBOSE
,
"Client protocol error"
);
freeClient
(
c
);
return
;
}
}
/* Read bulk argument */
if
(
sdslen
(
c
->
querybuf
)
-
pos
<
(
unsigned
)(
c
->
bulklen
+
2
))
{
/* Not enough data (+2 == trailing \r\n) */
break
;
}
else
{
}
else
{
/* Bulk read handling. Note that if we are at this point
c
->
argv
[
c
->
argc
++
]
=
createStringObject
(
c
->
querybuf
+
pos
,
c
->
bulklen
);
the client already sent a command terminated with a newline,
pos
+=
c
->
bulklen
+
2
;
we are reading the bulk data that is actually the last
c
->
bulklen
=
-
1
;
argument of the command. */
c
->
multibulklen
--
;
int
qbl
=
sdslen
(
c
->
querybuf
);
}
}
if
(
c
->
bulklen
<=
qbl
)
{
/* Copy everything but the final CRLF as final argument */
/* Trim to pos */
c
->
argv
[
c
->
argc
]
=
createStringObject
(
c
->
querybuf
,
c
->
bulklen
-
2
);
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
pos
,
-
1
);
c
->
argc
++
;
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
c
->
bulklen
,
-
1
);
/* We're done when c->multibulk == 0 */
/* Process the command. If the client is still valid after
if
(
c
->
multibulklen
==
0
)
{
* the processing and there is more data in the buffer
return
REDIS_OK
;
* try to parse it. */
}
if
(
processCommand
(
c
)
&&
sdslen
(
c
->
querybuf
))
goto
again
;
return
REDIS_ERR
;
return
;
}
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
{
c
->
reqtype
=
REDIS_REQ_INLINE
;
}
}
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) {
...
@@ -773,14 +856,8 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
return
;
return
;
}
}
if
(
nread
)
{
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
);
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
{
}
else
{
return
;
return
;
}
}
...
...
src/redis-benchmark.c
View file @
21dbc649
...
@@ -575,10 +575,28 @@ int main(int argc, char **argv) {
...
@@ -575,10 +575,28 @@ int main(int argc, char **argv) {
aeMain
(
config
.
el
);
aeMain
(
config
.
el
);
endBenchmark
();
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"
);
prepareForBenchmark
(
"SET"
);
c
=
createClient
();
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
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
);
char
*
data
=
zmalloc
(
config
.
datasize
+
2
);
memset
(
data
,
'x'
,
config
.
datasize
);
memset
(
data
,
'x'
,
config
.
datasize
);
...
@@ -612,7 +630,7 @@ int main(int argc, char **argv) {
...
@@ -612,7 +630,7 @@ int main(int argc, char **argv) {
prepareForBenchmark
(
"LPUSH"
);
prepareForBenchmark
(
"LPUSH"
);
c
=
createClient
();
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
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
);
prepareClientForReply
(
c
,
REPLY_INT
);
createMissingClients
(
c
);
createMissingClients
(
c
);
aeMain
(
config
.
el
);
aeMain
(
config
.
el
);
...
@@ -630,7 +648,7 @@ int main(int argc, char **argv) {
...
@@ -630,7 +648,7 @@ int main(int argc, char **argv) {
prepareForBenchmark
(
"SADD"
);
prepareForBenchmark
(
"SADD"
);
c
=
createClient
();
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
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
);
prepareClientForReply
(
c
,
REPLY_RETCODE
);
createMissingClients
(
c
);
createMissingClients
(
c
);
aeMain
(
config
.
el
);
aeMain
(
config
.
el
);
...
@@ -648,7 +666,7 @@ int main(int argc, char **argv) {
...
@@ -648,7 +666,7 @@ int main(int argc, char **argv) {
prepareForBenchmark
(
"LPUSH (again, in order to bench LRANGE)"
);
prepareForBenchmark
(
"LPUSH (again, in order to bench LRANGE)"
);
c
=
createClient
();
c
=
createClient
();
if
(
!
c
)
exit
(
1
);
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
);
prepareClientForReply
(
c
,
REPLY_RETCODE
);
createMissingClients
(
c
);
createMissingClients
(
c
);
aeMain
(
config
.
el
);
aeMain
(
config
.
el
);
...
...
src/redis-cli.c
View file @
21dbc649
...
@@ -45,10 +45,6 @@
...
@@ -45,10 +45,6 @@
#include "zmalloc.h"
#include "zmalloc.h"
#include "linenoise.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)
#define REDIS_NOTUSED(V) ((void) V)
static
struct
config
{
static
struct
config
{
...
...
src/redis.c
View file @
21dbc649
...
@@ -69,120 +69,120 @@ double R_Zero, R_PosInf, R_NegInf, R_Nan;
...
@@ -69,120 +69,120 @@ double R_Zero, R_PosInf, R_NegInf, R_Nan;
struct
redisServer
server
;
/* server global state */
struct
redisServer
server
;
/* server global state */
struct
redisCommand
*
commandTable
;
struct
redisCommand
*
commandTable
;
struct
redisCommand
readonlyCommandTable
[]
=
{
struct
redisCommand
readonlyCommandTable
[]
=
{
{
"get"
,
getCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"get"
,
getCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"set"
,
setCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
0
,
0
,
0
},
{
"set"
,
setCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
0
,
0
,
0
},
{
"setnx"
,
setnxCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
0
,
0
,
0
},
{
"setnx"
,
setnxCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
0
,
0
,
0
},
{
"setex"
,
setexCommand
,
4
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
0
,
0
,
0
},
{
"setex"
,
setexCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
0
,
0
,
0
},
{
"append"
,
appendCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"append"
,
appendCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"substr"
,
substrCommand
,
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"substr"
,
substrCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"strlen"
,
strlenCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"strlen"
,
strlenCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"del"
,
delCommand
,
-
2
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"del"
,
delCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"exists"
,
existsCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"exists"
,
existsCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"incr"
,
incrCommand
,
2
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"incr"
,
incrCommand
,
2
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"decr"
,
decrCommand
,
2
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"decr"
,
decrCommand
,
2
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"mget"
,
mgetCommand
,
-
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
-
1
,
1
},
{
"mget"
,
mgetCommand
,
-
2
,
0
,
NULL
,
1
,
-
1
,
1
},
{
"rpush"
,
rpushCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"rpush"
,
rpushCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"lpush"
,
lpushCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"lpush"
,
lpushCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"rpushx"
,
rpushxCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"rpushx"
,
rpushxCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"lpushx"
,
lpushxCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"lpushx"
,
lpushxCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"linsert"
,
linsertCommand
,
5
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"linsert"
,
linsertCommand
,
5
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"rpop"
,
rpopCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"rpop"
,
rpopCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"lpop"
,
lpopCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"lpop"
,
lpopCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"brpop"
,
brpopCommand
,
-
3
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"brpop"
,
brpopCommand
,
-
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"blpop"
,
blpopCommand
,
-
3
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"blpop"
,
blpopCommand
,
-
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"llen"
,
llenCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"llen"
,
llenCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"lindex"
,
lindexCommand
,
3
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"lindex"
,
lindexCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"lset"
,
lsetCommand
,
4
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"lset"
,
lsetCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"lrange"
,
lrangeCommand
,
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"lrange"
,
lrangeCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"ltrim"
,
ltrimCommand
,
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"ltrim"
,
ltrimCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"lrem"
,
lremCommand
,
4
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"lrem"
,
lremCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"rpoplpush"
,
rpoplpushcommand
,
3
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
2
,
1
},
{
"rpoplpush"
,
rpoplpushcommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
2
,
1
},
{
"sadd"
,
saddCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"sadd"
,
saddCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"srem"
,
sremCommand
,
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"srem"
,
sremCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"smove"
,
smoveCommand
,
4
,
REDIS_CMD_BULK
,
NULL
,
1
,
2
,
1
},
{
"smove"
,
smoveCommand
,
4
,
0
,
NULL
,
1
,
2
,
1
},
{
"sismember"
,
sismemberCommand
,
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"sismember"
,
sismemberCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"scard"
,
scardCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"scard"
,
scardCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"spop"
,
spopCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"spop"
,
spopCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"srandmember"
,
srandmemberCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"srandmember"
,
srandmemberCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"sinter"
,
sinterCommand
,
-
2
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
-
1
,
1
},
{
"sinter"
,
sinterCommand
,
-
2
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
-
1
,
1
},
{
"sinterstore"
,
sinterstoreCommand
,
-
3
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
2
,
-
1
,
1
},
{
"sinterstore"
,
sinterstoreCommand
,
-
3
,
REDIS_CMD_DENYOOM
,
NULL
,
2
,
-
1
,
1
},
{
"sunion"
,
sunionCommand
,
-
2
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
-
1
,
1
},
{
"sunion"
,
sunionCommand
,
-
2
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
-
1
,
1
},
{
"sunionstore"
,
sunionstoreCommand
,
-
3
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
2
,
-
1
,
1
},
{
"sunionstore"
,
sunionstoreCommand
,
-
3
,
REDIS_CMD_DENYOOM
,
NULL
,
2
,
-
1
,
1
},
{
"sdiff"
,
sdiffCommand
,
-
2
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
-
1
,
1
},
{
"sdiff"
,
sdiffCommand
,
-
2
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
-
1
,
1
},
{
"sdiffstore"
,
sdiffstoreCommand
,
-
3
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
2
,
-
1
,
1
},
{
"sdiffstore"
,
sdiffstoreCommand
,
-
3
,
REDIS_CMD_DENYOOM
,
NULL
,
2
,
-
1
,
1
},
{
"smembers"
,
sinterCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"smembers"
,
sinterCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"zadd"
,
zaddCommand
,
4
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"zadd"
,
zaddCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"zincrby"
,
zincrbyCommand
,
4
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"zincrby"
,
zincrbyCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"zrem"
,
zremCommand
,
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"zrem"
,
zremCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"zremrangebyscore"
,
zremrangebyscoreCommand
,
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"zremrangebyscore"
,
zremrangebyscoreCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"zremrangebyrank"
,
zremrangebyrankCommand
,
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"zremrangebyrank"
,
zremrangebyrankCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"zunionstore"
,
zunionstoreCommand
,
-
4
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
zunionInterBlockClientOnSwappedKeys
,
0
,
0
,
0
},
{
"zunionstore"
,
zunionstoreCommand
,
-
4
,
REDIS_CMD_DENYOOM
,
zunionInterBlockClientOnSwappedKeys
,
0
,
0
,
0
},
{
"zinterstore"
,
zinterstoreCommand
,
-
4
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
zunionInterBlockClientOnSwappedKeys
,
0
,
0
,
0
},
{
"zinterstore"
,
zinterstoreCommand
,
-
4
,
REDIS_CMD_DENYOOM
,
zunionInterBlockClientOnSwappedKeys
,
0
,
0
,
0
},
{
"zrange"
,
zrangeCommand
,
-
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"zrange"
,
zrangeCommand
,
-
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"zrangebyscore"
,
zrangebyscoreCommand
,
-
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"zrangebyscore"
,
zrangebyscoreCommand
,
-
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"zrevrangebyscore"
,
zrevrangebyscoreCommand
,
-
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"zrevrangebyscore"
,
zrevrangebyscoreCommand
,
-
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"zcount"
,
zcountCommand
,
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"zcount"
,
zcountCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"zrevrange"
,
zrevrangeCommand
,
-
4
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"zrevrange"
,
zrevrangeCommand
,
-
4
,
0
,
NULL
,
1
,
1
,
1
},
{
"zcard"
,
zcardCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"zcard"
,
zcardCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"zscore"
,
zscoreCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"zscore"
,
zscoreCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"zrank"
,
zrankCommand
,
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"zrank"
,
zrankCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"zrevrank"
,
zrevrankCommand
,
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"zrevrank"
,
zrevrankCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"hset"
,
hsetCommand
,
4
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"hset"
,
hsetCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"hsetnx"
,
hsetnxCommand
,
4
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"hsetnx"
,
hsetnxCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"hget"
,
hgetCommand
,
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"hget"
,
hgetCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"hmset"
,
hmsetCommand
,
-
4
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"hmset"
,
hmsetCommand
,
-
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"hmget"
,
hmgetCommand
,
-
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"hmget"
,
hmgetCommand
,
-
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"hincrby"
,
hincrbyCommand
,
4
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"hincrby"
,
hincrbyCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"hdel"
,
hdelCommand
,
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"hdel"
,
hdelCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"hlen"
,
hlenCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"hlen"
,
hlenCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"hkeys"
,
hkeysCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"hkeys"
,
hkeysCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"hvals"
,
hvalsCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"hvals"
,
hvalsCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"hgetall"
,
hgetallCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"hgetall"
,
hgetallCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"hexists"
,
hexistsCommand
,
3
,
REDIS_CMD_BULK
,
NULL
,
1
,
1
,
1
},
{
"hexists"
,
hexistsCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"incrby"
,
incrbyCommand
,
3
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"incrby"
,
incrbyCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"decrby"
,
decrbyCommand
,
3
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"decrby"
,
decrbyCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"getset"
,
getsetCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"getset"
,
getsetCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"mset"
,
msetCommand
,
-
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
-
1
,
2
},
{
"mset"
,
msetCommand
,
-
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
-
1
,
2
},
{
"msetnx"
,
msetnxCommand
,
-
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
-
1
,
2
},
{
"msetnx"
,
msetnxCommand
,
-
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
-
1
,
2
},
{
"randomkey"
,
randomkeyCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"randomkey"
,
randomkeyCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"select"
,
selectCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"select"
,
selectCommand
,
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"move"
,
moveCommand
,
3
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"move"
,
moveCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"rename"
,
renameCommand
,
3
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"rename"
,
renameCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"renamenx"
,
renamenxCommand
,
3
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"renamenx"
,
renamenxCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
},
{
"expire"
,
expireCommand
,
3
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"expire"
,
expireCommand
,
3
,
0
,
NULL
,
0
,
0
,
0
},
{
"expireat"
,
expireatCommand
,
3
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"expireat"
,
expireatCommand
,
3
,
0
,
NULL
,
0
,
0
,
0
},
{
"keys"
,
keysCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"keys"
,
keysCommand
,
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"dbsize"
,
dbsizeCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"dbsize"
,
dbsizeCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"auth"
,
authCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"auth"
,
authCommand
,
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"ping"
,
pingCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"ping"
,
pingCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"echo"
,
echoCommand
,
2
,
REDIS_CMD_BULK
,
NULL
,
0
,
0
,
0
},
{
"echo"
,
echoCommand
,
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"save"
,
saveCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"save"
,
saveCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"bgsave"
,
bgsaveCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"bgsave"
,
bgsaveCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"bgrewriteaof"
,
bgrewriteaofCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"bgrewriteaof"
,
bgrewriteaofCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"shutdown"
,
shutdownCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"shutdown"
,
shutdownCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"lastsave"
,
lastsaveCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"lastsave"
,
lastsaveCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"type"
,
typeCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"type"
,
typeCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"multi"
,
multiCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"multi"
,
multiCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"exec"
,
execCommand
,
1
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
execBlockClientOnSwappedKeys
,
0
,
0
,
0
},
{
"exec"
,
execCommand
,
1
,
REDIS_CMD_DENYOOM
,
execBlockClientOnSwappedKeys
,
0
,
0
,
0
},
{
"discard"
,
discardCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"discard"
,
discardCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"sync"
,
syncCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"sync"
,
syncCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"flushdb"
,
flushdbCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"flushdb"
,
flushdbCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"flushall"
,
flushallCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"flushall"
,
flushallCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"sort"
,
sortCommand
,
-
2
,
REDIS_CMD_
INLINE
|
REDIS_CMD_
DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"sort"
,
sortCommand
,
-
2
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
},
{
"info"
,
infoCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"info"
,
infoCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"monitor"
,
monitorCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"monitor"
,
monitorCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"ttl"
,
ttlCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"ttl"
,
ttlCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"persist"
,
persistCommand
,
2
,
REDIS_CMD_INLINE
,
NULL
,
1
,
1
,
1
},
{
"persist"
,
persistCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
},
{
"slaveof"
,
slaveofCommand
,
3
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"slaveof"
,
slaveofCommand
,
3
,
0
,
NULL
,
0
,
0
,
0
},
{
"debug"
,
debugCommand
,
-
2
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"debug"
,
debugCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"config"
,
configCommand
,
-
2
,
REDIS_CMD_BULK
,
NULL
,
0
,
0
,
0
},
{
"config"
,
configCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"subscribe"
,
subscribeCommand
,
-
2
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"subscribe"
,
subscribeCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"unsubscribe"
,
unsubscribeCommand
,
-
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"unsubscribe"
,
unsubscribeCommand
,
-
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"psubscribe"
,
psubscribeCommand
,
-
2
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"psubscribe"
,
psubscribeCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"punsubscribe"
,
punsubscribeCommand
,
-
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"punsubscribe"
,
punsubscribeCommand
,
-
1
,
0
,
NULL
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
REDIS_CMD_
BULK
|
REDIS_CMD_
FORCE_REPLICATION
,
NULL
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
REDIS_CMD_FORCE_REPLICATION
,
NULL
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
},
{
"unwatch"
,
unwatchCommand
,
1
,
REDIS_CMD_INLINE
,
NULL
,
0
,
0
,
0
}
{
"unwatch"
,
unwatchCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
}
};
};
/*============================ Utility functions ============================ */
/*============================ Utility functions ============================ */
...
@@ -899,84 +899,14 @@ void call(redisClient *c, struct redisCommand *cmd) {
...
@@ -899,84 +899,14 @@ void call(redisClient *c, struct redisCommand *cmd) {
int
processCommand
(
redisClient
*
c
)
{
int
processCommand
(
redisClient
*
c
)
{
struct
redisCommand
*
cmd
;
struct
redisCommand
*
cmd
;
/* Handle the multi bulk command type. This is an alternative protocol
/* The QUIT command is handled separately. Normal command procs will
* supported by Redis in order to receive commands that are composed of
* go through checking for replication and QUIT will cause trouble
* multiple binary-safe "bulk" arguments. The latency of processing is
* when FORCE_REPLICATION is enabled and would be implemented in
* a bit higher but this allows things like multi-sets, so if this
* a regular command proc. */
* protocol is used only for MSET and similar commands this is a big win. */
if
(
c
->
multibulk
==
0
&&
c
->
argc
==
1
&&
((
char
*
)(
c
->
argv
[
0
]
->
ptr
))[
0
]
==
'*'
)
{
c
->
multibulk
=
atoi
(((
char
*
)
c
->
argv
[
0
]
->
ptr
)
+
1
);
if
(
c
->
multibulk
<=
0
)
{
resetClient
(
c
);
return
1
;
}
else
{
decrRefCount
(
c
->
argv
[
c
->
argc
-
1
]);
c
->
argc
--
;
return
1
;
}
}
else
if
(
c
->
multibulk
)
{
if
(
c
->
bulklen
==
-
1
)
{
if
(((
char
*
)
c
->
argv
[
0
]
->
ptr
)[
0
]
!=
'$'
)
{
addReplyError
(
c
,
"multi bulk protocol error"
);
resetClient
(
c
);
return
1
;
}
else
{
char
*
eptr
;
long
bulklen
=
strtol
(((
char
*
)
c
->
argv
[
0
]
->
ptr
)
+
1
,
&
eptr
,
10
);
int
perr
=
eptr
[
0
]
!=
'\0'
;
decrRefCount
(
c
->
argv
[
0
]);
if
(
perr
||
bulklen
==
LONG_MIN
||
bulklen
==
LONG_MAX
||
bulklen
<
0
||
bulklen
>
1024
*
1024
*
1024
)
{
c
->
argc
--
;
addReplyError
(
c
,
"invalid bulk write count"
);
resetClient
(
c
);
return
1
;
}
c
->
argc
--
;
c
->
bulklen
=
bulklen
+
2
;
/* add two bytes for CR+LF */
return
1
;
}
}
else
{
c
->
mbargv
=
zrealloc
(
c
->
mbargv
,(
sizeof
(
robj
*
))
*
(
c
->
mbargc
+
1
));
c
->
mbargv
[
c
->
mbargc
]
=
c
->
argv
[
0
];
c
->
mbargc
++
;
c
->
argc
--
;
c
->
multibulk
--
;
if
(
c
->
multibulk
==
0
)
{
robj
**
auxargv
;
int
auxargc
;
/* Here we need to swap the multi-bulk argc/argv with the
* normal argc/argv of the client structure. */
auxargv
=
c
->
argv
;
c
->
argv
=
c
->
mbargv
;
c
->
mbargv
=
auxargv
;
auxargc
=
c
->
argc
;
c
->
argc
=
c
->
mbargc
;
c
->
mbargc
=
auxargc
;
/* We need to set bulklen to something different than -1
* in order for the code below to process the command without
* to try to read the last argument of a bulk command as
* a special argument. */
c
->
bulklen
=
0
;
/* continue below and process the command */
}
else
{
c
->
bulklen
=
-
1
;
return
1
;
}
}
}
/* -- end of multi bulk commands processing -- */
/* The QUIT command is handled as a special case. Normal command
* procs are unable to close the client connection safely */
if
(
!
strcasecmp
(
c
->
argv
[
0
]
->
ptr
,
"quit"
))
{
if
(
!
strcasecmp
(
c
->
argv
[
0
]
->
ptr
,
"quit"
))
{
freeClient
(
c
);
addReply
(
c
,
shared
.
ok
);
return
0
;
c
->
flags
|=
REDIS_CLOSE_AFTER_REPLY
;
return
REDIS_ERR
;
}
}
/* Now lookup the command and check ASAP about trivial error conditions
/* Now lookup the command and check ASAP about trivial error conditions
...
@@ -985,55 +915,18 @@ int processCommand(redisClient *c) {
...
@@ -985,55 +915,18 @@ int processCommand(redisClient *c) {
if
(
!
cmd
)
{
if
(
!
cmd
)
{
addReplyErrorFormat
(
c
,
"unknown command '%s'"
,
addReplyErrorFormat
(
c
,
"unknown command '%s'"
,
(
char
*
)
c
->
argv
[
0
]
->
ptr
);
(
char
*
)
c
->
argv
[
0
]
->
ptr
);
resetClient
(
c
);
return
REDIS_OK
;
return
1
;
}
else
if
((
cmd
->
arity
>
0
&&
cmd
->
arity
!=
c
->
argc
)
||
}
else
if
((
cmd
->
arity
>
0
&&
cmd
->
arity
!=
c
->
argc
)
||
(
c
->
argc
<
-
cmd
->
arity
))
{
(
c
->
argc
<
-
cmd
->
arity
))
{
addReplyErrorFormat
(
c
,
"wrong number of arguments for '%s' command"
,
addReplyErrorFormat
(
c
,
"wrong number of arguments for '%s' command"
,
cmd
->
name
);
cmd
->
name
);
resetClient
(
c
);
return
REDIS_OK
;
return
1
;
}
else
if
(
cmd
->
flags
&
REDIS_CMD_BULK
&&
c
->
bulklen
==
-
1
)
{
/* This is a bulk command, we have to read the last argument yet. */
char
*
eptr
;
long
bulklen
=
strtol
(
c
->
argv
[
c
->
argc
-
1
]
->
ptr
,
&
eptr
,
10
);
int
perr
=
eptr
[
0
]
!=
'\0'
;
decrRefCount
(
c
->
argv
[
c
->
argc
-
1
]);
if
(
perr
||
bulklen
==
LONG_MAX
||
bulklen
==
LONG_MIN
||
bulklen
<
0
||
bulklen
>
1024
*
1024
*
1024
)
{
c
->
argc
--
;
addReplyError
(
c
,
"invalid bulk write count"
);
resetClient
(
c
);
return
1
;
}
c
->
argc
--
;
c
->
bulklen
=
bulklen
+
2
;
/* add two bytes for CR+LF */
/* It is possible that the bulk read is already in the
* buffer. Check this condition and handle it accordingly.
* This is just a fast path, alternative to call processInputBuffer().
* It's a good idea since the code is small and this condition
* happens most of the times. */
if
((
signed
)
sdslen
(
c
->
querybuf
)
>=
c
->
bulklen
)
{
c
->
argv
[
c
->
argc
]
=
createStringObject
(
c
->
querybuf
,
c
->
bulklen
-
2
);
c
->
argc
++
;
c
->
querybuf
=
sdsrange
(
c
->
querybuf
,
c
->
bulklen
,
-
1
);
}
else
{
/* Otherwise return... there is to read the last argument
* from the socket. */
return
1
;
}
}
}
/* Let's try to encode the bulk object to save space. */
if
(
cmd
->
flags
&
REDIS_CMD_BULK
)
c
->
argv
[
c
->
argc
-
1
]
=
tryObjectEncoding
(
c
->
argv
[
c
->
argc
-
1
]);
/* Check if the user is authenticated */
/* Check if the user is authenticated */
if
(
server
.
requirepass
&&
!
c
->
authenticated
&&
cmd
->
proc
!=
authCommand
)
{
if
(
server
.
requirepass
&&
!
c
->
authenticated
&&
cmd
->
proc
!=
authCommand
)
{
addReplyError
(
c
,
"operation not permitted"
);
addReplyError
(
c
,
"operation not permitted"
);
resetClient
(
c
);
return
REDIS_OK
;
return
1
;
}
}
/* Handle the maxmemory directive.
/* Handle the maxmemory directive.
...
@@ -1046,8 +939,7 @@ int processCommand(redisClient *c) {
...
@@ -1046,8 +939,7 @@ int processCommand(redisClient *c) {
zmalloc_used_memory
()
>
server
.
maxmemory
)
zmalloc_used_memory
()
>
server
.
maxmemory
)
{
{
addReplyError
(
c
,
"command not allowed when used memory > 'maxmemory'"
);
addReplyError
(
c
,
"command not allowed when used memory > 'maxmemory'"
);
resetClient
(
c
);
return
REDIS_OK
;
return
1
;
}
}
/* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
/* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
...
@@ -1056,8 +948,7 @@ int processCommand(redisClient *c) {
...
@@ -1056,8 +948,7 @@ int processCommand(redisClient *c) {
cmd
->
proc
!=
subscribeCommand
&&
cmd
->
proc
!=
unsubscribeCommand
&&
cmd
->
proc
!=
subscribeCommand
&&
cmd
->
proc
!=
unsubscribeCommand
&&
cmd
->
proc
!=
psubscribeCommand
&&
cmd
->
proc
!=
punsubscribeCommand
)
{
cmd
->
proc
!=
psubscribeCommand
&&
cmd
->
proc
!=
punsubscribeCommand
)
{
addReplyError
(
c
,
"only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context"
);
addReplyError
(
c
,
"only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context"
);
resetClient
(
c
);
return
REDIS_OK
;
return
1
;
}
}
/* Exec the command */
/* Exec the command */
...
@@ -1069,13 +960,10 @@ int processCommand(redisClient *c) {
...
@@ -1069,13 +960,10 @@ int processCommand(redisClient *c) {
addReply
(
c
,
shared
.
queued
);
addReply
(
c
,
shared
.
queued
);
}
else
{
}
else
{
if
(
server
.
vm_enabled
&&
server
.
vm_max_threads
>
0
&&
if
(
server
.
vm_enabled
&&
server
.
vm_max_threads
>
0
&&
blockClientOnSwappedKeys
(
c
,
cmd
))
return
1
;
blockClientOnSwappedKeys
(
c
,
cmd
))
return
REDIS_ERR
;
call
(
c
,
cmd
);
call
(
c
,
cmd
);
}
}
return
REDIS_OK
;
/* Prepare the client for the next command */
resetClient
(
c
);
return
1
;
}
}
/*================================== Shutdown =============================== */
/*================================== Shutdown =============================== */
...
...
src/redis.h
View file @
21dbc649
...
@@ -57,15 +57,15 @@
...
@@ -57,15 +57,15 @@
/* 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% */
/* Command flags
*/
/* Command flags
:
#define
REDIS_CMD_
BULK 1
/* Bulk write command */
*
REDIS_CMD_
DENYOOM:
#define REDIS_CMD_INLINE 2
/* Inline command */
* Commands marked with this flag will return an error when 'maxmemory' is
/
*
REDIS_CMD_DENYOOM reserves a longer comment: all the commands marked with
*
set and the server is using more than 'maxmemory' bytes of memory.
this flags will return an error when the 'maxmemory' option is set in the
*
In short: commands with this flag are denied on low memory conditions.
config file and the server is using more than maxmemory bytes of memory.
* REDIS_CMD_FORCE_REPLICATION:
In short this commands are denied on low memory conditions
. */
*
Force replication even if dirty is 0
. */
#define REDIS_CMD_DENYOOM 4
#define REDIS_CMD_DENYOOM 4
#define REDIS_CMD_FORCE_REPLICATION 8
/* Force replication even if dirty is 0 */
#define REDIS_CMD_FORCE_REPLICATION 8
/* Object types */
/* Object types */
#define REDIS_STRING 0
#define REDIS_STRING 0
...
@@ -144,6 +144,11 @@
...
@@ -144,6 +144,11 @@
#define REDIS_BLOCKED 16
/* The client is waiting in a blocking operation */
#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_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_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 */
/* Slave replication state - slave side */
#define REDIS_REPL_NONE 0
/* No active replication */
#define REDIS_REPL_NONE 0
/* No active replication */
...
@@ -294,11 +299,11 @@ typedef struct redisClient {
...
@@ -294,11 +299,11 @@ typedef struct redisClient {
redisDb
*
db
;
redisDb
*
db
;
int
dictid
;
int
dictid
;
sds
querybuf
;
sds
querybuf
;
robj
**
argv
,
**
mbargv
;
int
argc
;
char
*
newline
;
/* pointing to the detected newline in querybuf */
robj
**
argv
;
int
argc
,
mbargc
;
int
reqtype
;
long
bulklen
;
/* bulk read len. -1 if not in bulk read mode
*/
int
multi
bulklen
;
/* number of multi bulk arguments left to read
*/
int
multibulk
;
/* multi bulk command format active
*/
long
bulklen
;
/* length of bulk argument in multi bulk request
*/
list
*
reply
;
list
*
reply
;
int
sentlen
;
int
sentlen
;
time_t
lastinteraction
;
/* time of the last interaction, used for timeout */
time_t
lastinteraction
;
/* time of the last interaction, used for timeout */
...
...
src/t_list.c
View file @
21dbc649
...
@@ -260,6 +260,7 @@ void listTypeConvert(robj *subject, int enc) {
...
@@ -260,6 +260,7 @@ void listTypeConvert(robj *subject, int enc) {
void
pushGenericCommand
(
redisClient
*
c
,
int
where
)
{
void
pushGenericCommand
(
redisClient
*
c
,
int
where
)
{
robj
*
lobj
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
robj
*
lobj
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
lobj
==
NULL
)
{
if
(
lobj
==
NULL
)
{
if
(
handleClientsWaitingListPush
(
c
,
c
->
argv
[
1
],
c
->
argv
[
2
]))
{
if
(
handleClientsWaitingListPush
(
c
,
c
->
argv
[
1
],
c
->
argv
[
2
]))
{
addReply
(
c
,
shared
.
cone
);
addReply
(
c
,
shared
.
cone
);
...
@@ -346,14 +347,17 @@ void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) {
...
@@ -346,14 +347,17 @@ void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int where) {
}
}
void
lpushxCommand
(
redisClient
*
c
)
{
void
lpushxCommand
(
redisClient
*
c
)
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
pushxGenericCommand
(
c
,
NULL
,
c
->
argv
[
2
],
REDIS_HEAD
);
pushxGenericCommand
(
c
,
NULL
,
c
->
argv
[
2
],
REDIS_HEAD
);
}
}
void
rpushxCommand
(
redisClient
*
c
)
{
void
rpushxCommand
(
redisClient
*
c
)
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
pushxGenericCommand
(
c
,
NULL
,
c
->
argv
[
2
],
REDIS_TAIL
);
pushxGenericCommand
(
c
,
NULL
,
c
->
argv
[
2
],
REDIS_TAIL
);
}
}
void
linsertCommand
(
redisClient
*
c
)
{
void
linsertCommand
(
redisClient
*
c
)
{
c
->
argv
[
4
]
=
tryObjectEncoding
(
c
->
argv
[
4
]);
if
(
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"after"
)
==
0
)
{
if
(
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"after"
)
==
0
)
{
pushxGenericCommand
(
c
,
c
->
argv
[
3
],
c
->
argv
[
4
],
REDIS_TAIL
);
pushxGenericCommand
(
c
,
c
->
argv
[
3
],
c
->
argv
[
4
],
REDIS_TAIL
);
}
else
if
(
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"before"
)
==
0
)
{
}
else
if
(
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"before"
)
==
0
)
{
...
@@ -409,7 +413,7 @@ void lsetCommand(redisClient *c) {
...
@@ -409,7 +413,7 @@ void lsetCommand(redisClient *c) {
robj
*
o
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
nokeyerr
);
robj
*
o
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
nokeyerr
);
if
(
o
==
NULL
||
checkType
(
c
,
o
,
REDIS_LIST
))
return
;
if
(
o
==
NULL
||
checkType
(
c
,
o
,
REDIS_LIST
))
return
;
int
index
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
int
index
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
robj
*
value
=
c
->
argv
[
3
];
robj
*
value
=
(
c
->
argv
[
3
]
=
tryObjectEncoding
(
c
->
argv
[
3
]))
;
listTypeTryConversion
(
o
,
value
);
listTypeTryConversion
(
o
,
value
);
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
{
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
{
...
@@ -559,7 +563,8 @@ void ltrimCommand(redisClient *c) {
...
@@ -559,7 +563,8 @@ void ltrimCommand(redisClient *c) {
}
}
void
lremCommand
(
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
toremove
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
int
removed
=
0
;
int
removed
=
0
;
listTypeEntry
entry
;
listTypeEntry
entry
;
...
...
src/t_set.c
View file @
21dbc649
...
@@ -178,6 +178,7 @@ void saddCommand(redisClient *c) {
...
@@ -178,6 +178,7 @@ void saddCommand(redisClient *c) {
robj
*
set
;
robj
*
set
;
set
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
set
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
set
==
NULL
)
{
if
(
set
==
NULL
)
{
set
=
setTypeCreate
(
c
->
argv
[
2
]);
set
=
setTypeCreate
(
c
->
argv
[
2
]);
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
set
);
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
set
);
...
@@ -202,6 +203,7 @@ void sremCommand(redisClient *c) {
...
@@ -202,6 +203,7 @@ void sremCommand(redisClient *c) {
if
((
set
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
if
((
set
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
set
,
REDIS_SET
))
return
;
checkType
(
c
,
set
,
REDIS_SET
))
return
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
setTypeRemove
(
set
,
c
->
argv
[
2
]))
{
if
(
setTypeRemove
(
set
,
c
->
argv
[
2
]))
{
if
(
setTypeSize
(
set
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
if
(
setTypeSize
(
set
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
...
@@ -216,7 +218,7 @@ void smoveCommand(redisClient *c) {
...
@@ -216,7 +218,7 @@ void smoveCommand(redisClient *c) {
robj
*
srcset
,
*
dstset
,
*
ele
;
robj
*
srcset
,
*
dstset
,
*
ele
;
srcset
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
srcset
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
dstset
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
2
]);
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 the source key does not exist return 0 */
if
(
srcset
==
NULL
)
{
if
(
srcset
==
NULL
)
{
...
@@ -264,6 +266,7 @@ void sismemberCommand(redisClient *c) {
...
@@ -264,6 +266,7 @@ void sismemberCommand(redisClient *c) {
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
set
,
REDIS_SET
))
return
;
checkType
(
c
,
set
,
REDIS_SET
))
return
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
setTypeIsMember
(
set
,
c
->
argv
[
2
]))
if
(
setTypeIsMember
(
set
,
c
->
argv
[
2
]))
addReply
(
c
,
shared
.
cone
);
addReply
(
c
,
shared
.
cone
);
else
else
...
...
src/t_string.c
View file @
21dbc649
...
@@ -37,14 +37,17 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
...
@@ -37,14 +37,17 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
}
}
void
setCommand
(
redisClient
*
c
)
{
void
setCommand
(
redisClient
*
c
)
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
setGenericCommand
(
c
,
0
,
c
->
argv
[
1
],
c
->
argv
[
2
],
NULL
);
setGenericCommand
(
c
,
0
,
c
->
argv
[
1
],
c
->
argv
[
2
],
NULL
);
}
}
void
setnxCommand
(
redisClient
*
c
)
{
void
setnxCommand
(
redisClient
*
c
)
{
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
setGenericCommand
(
c
,
1
,
c
->
argv
[
1
],
c
->
argv
[
2
],
NULL
);
setGenericCommand
(
c
,
1
,
c
->
argv
[
1
],
c
->
argv
[
2
],
NULL
);
}
}
void
setexCommand
(
redisClient
*
c
)
{
void
setexCommand
(
redisClient
*
c
)
{
c
->
argv
[
3
]
=
tryObjectEncoding
(
c
->
argv
[
3
]);
setGenericCommand
(
c
,
0
,
c
->
argv
[
1
],
c
->
argv
[
3
],
c
->
argv
[
2
]);
setGenericCommand
(
c
,
0
,
c
->
argv
[
1
],
c
->
argv
[
3
],
c
->
argv
[
2
]);
}
}
...
@@ -69,6 +72,7 @@ void getCommand(redisClient *c) {
...
@@ -69,6 +72,7 @@ void getCommand(redisClient *c) {
void
getsetCommand
(
redisClient
*
c
)
{
void
getsetCommand
(
redisClient
*
c
)
{
if
(
getGenericCommand
(
c
)
==
REDIS_ERR
)
return
;
if
(
getGenericCommand
(
c
)
==
REDIS_ERR
)
return
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
incrRefCount
(
c
->
argv
[
2
]);
incrRefCount
(
c
->
argv
[
2
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
...
@@ -180,6 +184,7 @@ void appendCommand(redisClient *c) {
...
@@ -180,6 +184,7 @@ void appendCommand(redisClient *c) {
robj
*
o
;
robj
*
o
;
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
if
(
o
==
NULL
)
{
if
(
o
==
NULL
)
{
/* Create the key */
/* Create the key */
retval
=
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
retval
=
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
...
...
src/t_zset.c
View file @
21dbc649
...
@@ -440,12 +440,14 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double score, int
...
@@ -440,12 +440,14 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double score, int
void
zaddCommand
(
redisClient
*
c
)
{
void
zaddCommand
(
redisClient
*
c
)
{
double
scoreval
;
double
scoreval
;
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
scoreval
,
NULL
)
!=
REDIS_OK
)
return
;
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
);
zaddGenericCommand
(
c
,
c
->
argv
[
1
],
c
->
argv
[
3
],
scoreval
,
0
);
}
}
void
zincrbyCommand
(
redisClient
*
c
)
{
void
zincrbyCommand
(
redisClient
*
c
)
{
double
scoreval
;
double
scoreval
;
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
scoreval
,
NULL
)
!=
REDIS_OK
)
return
;
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
);
zaddGenericCommand
(
c
,
c
->
argv
[
1
],
c
->
argv
[
3
],
scoreval
,
1
);
}
}
...
@@ -460,6 +462,7 @@ void zremCommand(redisClient *c) {
...
@@ -460,6 +462,7 @@ void zremCommand(redisClient *c) {
checkType
(
c
,
zsetobj
,
REDIS_ZSET
))
return
;
checkType
(
c
,
zsetobj
,
REDIS_ZSET
))
return
;
zs
=
zsetobj
->
ptr
;
zs
=
zsetobj
->
ptr
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
if
(
de
==
NULL
)
{
if
(
de
==
NULL
)
{
addReply
(
c
,
shared
.
czero
);
addReply
(
c
,
shared
.
czero
);
...
@@ -1004,6 +1007,7 @@ void zscoreCommand(redisClient *c) {
...
@@ -1004,6 +1007,7 @@ void zscoreCommand(redisClient *c) {
checkType
(
c
,
o
,
REDIS_ZSET
))
return
;
checkType
(
c
,
o
,
REDIS_ZSET
))
return
;
zs
=
o
->
ptr
;
zs
=
o
->
ptr
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
if
(
!
de
)
{
if
(
!
de
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
(
c
,
shared
.
nullbulk
);
...
@@ -1027,6 +1031,7 @@ void zrankGenericCommand(redisClient *c, int reverse) {
...
@@ -1027,6 +1031,7 @@ void zrankGenericCommand(redisClient *c, int reverse) {
zs
=
o
->
ptr
;
zs
=
o
->
ptr
;
zsl
=
zs
->
zsl
;
zsl
=
zs
->
zsl
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
de
=
dictFind
(
zs
->
dict
,
c
->
argv
[
2
]);
if
(
!
de
)
{
if
(
!
de
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
(
c
,
shared
.
nullbulk
);
...
...
tests/support/redis.tcl
View file @
21dbc649
...
@@ -36,25 +36,6 @@ array set ::redis::deferred {}
...
@@ -36,25 +36,6 @@ array set ::redis::deferred {}
array set ::redis::callback
{}
array set ::redis::callback
{}
array set ::redis::state
{}
;
# State in non-blocking reply reading
array set ::redis::state
{}
;
# State in non-blocking reply reading
array set ::redis::statestack
{}
;
# Stack of states, for nested mbulks
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
}}
{
proc redis
{{
server 127.0.0.1
}
{
port 6379
}
{
defer 0
}}
{
set fd
[
socket $server $port
]
set fd
[
socket $server $port
]
...
@@ -79,13 +60,6 @@ proc ::redis::__dispatch__ {id method args} {
...
@@ -79,13 +60,6 @@ proc ::redis::__dispatch__ {id method args} {
set args
[
lrange $args 0 end-1
]
set args
[
lrange $args 0 end-1
]
}
}
if
{[
info command ::redis::__method__$method
]
eq
{}}
{
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
"
set cmd
"*
[
expr
{[
llength $args
]
+1
}]
\r\n
"
append cmd
"
$
[
string length $method
]
\r\n
$method
\r\n
"
append cmd
"
$
[
string length $method
]
\r\n
$method
\r\n
"
foreach a $args
{
foreach a $args
{
...
@@ -93,11 +67,7 @@ proc ::redis::__dispatch__ {id method args} {
...
@@ -93,11 +67,7 @@ proc ::redis::__dispatch__ {id method args} {
}
}
::redis::redis_write $fd $cmd
::redis::redis_write $fd $cmd
flush $fd
flush $fd
}
else
{
set cmd
"
$method
"
append cmd
[
join $args
]
::redis::redis_writenl $fd $cmd
}
if
{
!$deferred
}
{
if
{
!$deferred
}
{
if
{
$blocking
}
{
if
{
$blocking
}
{
::redis::redis_read_reply $fd
::redis::redis_read_reply $fd
...
@@ -123,6 +93,14 @@ proc ::redis::__method__read {id fd} {
...
@@ -123,6 +93,14 @@ proc ::redis::__method__read {id fd} {
::redis::redis_read_reply $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
}
{
proc ::redis::__method__close
{
id fd
}
{
catch
{
close $fd
}
catch
{
close $fd
}
catch
{
unset ::redis::fd
(
$id
)}
catch
{
unset ::redis::fd
(
$id
)}
...
...
tests/support/server.tcl
View file @
21dbc649
...
@@ -215,7 +215,8 @@ proc start_server {options {code undefined}} {
...
@@ -215,7 +215,8 @@ proc start_server {options {code undefined}} {
if
{[
dict exists $config port
]}
{
set port
[
dict get $config port
]
}
if
{[
dict exists $config port
]}
{
set port
[
dict get $config port
]
}
# setup config dict
# 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
"pid"
$pid
dict set srv
"host"
$host
dict set srv
"host"
$host
dict set srv
"port"
$port
dict set srv
"port"
$port
...
@@ -238,17 +239,12 @@ proc start_server {options {code undefined}} {
...
@@ -238,17 +239,12 @@ proc start_server {options {code undefined}} {
after 10
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
# append the server to the stack
lappend ::servers $srv
lappend ::servers $srv
# connect client
(
after server dict is put on the stack
)
reconnect
# execute provided block
# execute provided block
set curnum $::testnum
set curnum $::testnum
if
{
!
[
catch
{
uplevel 1 $code
}
err
]}
{
if
{
!
[
catch
{
uplevel 1 $code
}
err
]}
{
...
...
tests/support/test.tcl
View file @
21dbc649
...
@@ -90,8 +90,10 @@ proc test {name code {okpattern notspecified}} {
...
@@ -90,8 +90,10 @@ proc test {name code {okpattern notspecified}} {
}
}
}
}
if
{
$::traceleaks
}
{
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
"--------- Test
$::testnum
LEAKED! --------"
puts $output
exit 1
exit 1
}
}
}
}
...
...
tests/test_helper.tcl
View file @
21dbc649
...
@@ -16,6 +16,7 @@ set ::valgrind 0
...
@@ -16,6 +16,7 @@ set ::valgrind 0
set ::denytags
{}
set ::denytags
{}
set ::allowtags
{}
set ::allowtags
{}
set ::external 0
;
# If
"1"
this means, we are running against external instance
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
{
proc execute_tests name
{
source
"tests/
$name.tcl
"
source
"tests/
$name.tcl
"
...
@@ -49,6 +50,28 @@ proc r {args} {
...
@@ -49,6 +50,28 @@ proc r {args} {
[
srv $level
"client"
]
{*}
$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
}
{
proc redis_deferring_client
{
args
}
{
set level 0
set level 0
if
{[
llength $args
]
> 0 &&
[
string is integer
[
lindex $args 0
]]}
{
if
{[
llength $args
]
> 0 &&
[
string is integer
[
lindex $args 0
]]}
{
...
@@ -80,8 +103,7 @@ proc cleanup {} {
...
@@ -80,8 +103,7 @@ proc cleanup {} {
catch
{
exec rm -rf
{*}
[
glob tests/tmp/server.*
]}
catch
{
exec rm -rf
{*}
[
glob tests/tmp/server.*
]}
}
}
proc main
{}
{
proc execute_everything
{}
{
cleanup
execute_tests
"unit/auth"
execute_tests
"unit/auth"
execute_tests
"unit/protocol"
execute_tests
"unit/protocol"
execute_tests
"unit/basic"
execute_tests
"unit/basic"
...
@@ -93,6 +115,7 @@ proc main {} {
...
@@ -93,6 +115,7 @@ proc main {} {
execute_tests
"unit/expire"
execute_tests
"unit/expire"
execute_tests
"unit/other"
execute_tests
"unit/other"
execute_tests
"unit/cas"
execute_tests
"unit/cas"
execute_tests
"unit/quit"
execute_tests
"integration/replication"
execute_tests
"integration/replication"
execute_tests
"integration/aof"
execute_tests
"integration/aof"
# execute_tests
"integration/redis-cli"
# execute_tests
"integration/redis-cli"
...
@@ -110,6 +133,18 @@ proc main {} {
...
@@ -110,6 +133,18 @@ proc main {} {
execute_tests
"unit/expire"
execute_tests
"unit/expire"
execute_tests
"unit/other"
execute_tests
"unit/other"
execute_tests
"unit/cas"
execute_tests
"unit/cas"
}
proc main
{}
{
cleanup
if
{[
string length $::file
]
> 0
}
{
foreach
{
file
}
[
split $::file ,
]
{
execute_tests $file
}
}
else
{
execute_everything
}
cleanup
cleanup
puts
"
\n
[
expr $::passed+$::failed
]
tests,
$::passed
passed,
$::failed
failed"
puts
"
\n
[
expr $::passed+$::failed
]
tests,
$::passed
passed,
$::failed
failed"
...
@@ -132,6 +167,9 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
...
@@ -132,6 +167,9 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
}
}
}
}
incr j
incr j
}
elseif
{
$opt
eq
{
--file
}}
{
set ::file $arg
incr j
}
elseif
{
$opt
eq
{
--host
}}
{
}
elseif
{
$opt
eq
{
--host
}}
{
set ::external 1
set ::external 1
set ::host $arg
set ::host $arg
...
...
tests/unit/basic.tcl
View file @
21dbc649
...
@@ -172,7 +172,7 @@ start_server {tags {"basic"}} {
...
@@ -172,7 +172,7 @@ start_server {tags {"basic"}} {
test
{
Commands pipelining
}
{
test
{
Commands pipelining
}
{
set fd
[
r channel
]
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
flush $fd
set res
{}
set res
{}
append res
[
string match OK*
[
::redis::redis_read_reply $fd
]]
append res
[
string match OK*
[
::redis::redis_read_reply $fd
]]
...
...
tests/unit/other.tcl
View file @
21dbc649
...
@@ -123,7 +123,7 @@ start_server {tags {"other"}} {
...
@@ -123,7 +123,7 @@ start_server {tags {"other"}} {
for
{
set i 0
}
{
$i
< 100000
}
{
incr i
}
{
for
{
set i 0
}
{
$i
< 100000
}
{
incr i
}
{
set q
{}
set q
{}
set val
"0000
${i}
0000"
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
puts -nonewline $fd2 $q
set q
{}
set q
{}
append q
"GET key:
$i
\r\n
"
append q
"GET key:
$i
\r\n
"
...
...
tests/unit/protocol.tcl
View file @
21dbc649
start_server
{
tags
{
"protocol"
}}
{
start_server
{
tags
{
"protocol"
}}
{
test
{
Handle an empty query well
}
{
test
"Handle an empty query"
{
set fd
[
r channel
]
reconnect
puts -nonewline $fd
"
\r\n
"
r write
"
\r\n
"
flush $fd
r flush
r ping
assert_equal
"PONG"
[
r ping
]
}
{
PONG
}
}
test
{
Negative multi bulk command does not create problems
}
{
test
"Negative multibulk length"
{
set fd
[
r channel
]
reconnect
puts -nonewline $fd
"*-10
\r\n
"
r write
"*-10
\r\n
"
flush $fd
r flush
r ping
assert_equal PONG
[
r ping
]
}
{
PONG
}
}
test
{
Negative multi bulk payload
}
{
test
"Out of range multibulk length"
{
set fd
[
r channel
]
reconnect
puts -nonewline $fd
"SET x -10
\r\n
"
r write
"*20000000
\r\n
"
flush $fd
r flush
gets $fd
assert_error
"*invalid multibulk length*"
{
r read
}
}
{
*invalid bulk*
}
}
test
{
Too big bulk payload
}
{
test
"Wrong multibulk payload header"
{
set fd
[
r channel
]
reconnect
puts -nonewline $fd
"SET x 2000000000
\r\n
"
r write
"*3
\r\n\$
3
\r\n
SET
\r\n\$
1
\r\n
x
\r\n
fooz
\r\n
"
flush $fd
r flush
gets $fd
assert_error
"*expected '
$
', got 'f'*"
{
r read
}
}
{
*invalid bulk*count*
}
}
test
{
bulk payload is not a number
}
{
test
"Negative multibulk payload length"
{
set fd
[
r channel
]
reconnect
puts -nonewline $fd
"SET x blabla
\r\n
"
r write
"*3
\r\n\$
3
\r\n
SET
\r\n\$
1
\r\n
x
\r\n\$
-10
\r\n
"
flush $fd
r flush
gets $fd
assert_error
"*invalid bulk length*"
{
r read
}
}
{
*invalid bulk*count*
}
}
test
{
Multi bulk request not followed by bulk args
}
{
test
"Out of range multibulk payload length"
{
set fd
[
r channel
]
reconnect
puts -nonewline $fd
"*1
\r\n
foo
\r\n
"
r write
"*3
\r\n\$
3
\r\n
SET
\r\n\$
1
\r\n
x
\r\n\$
2000000000
\r\n
"
flush $fd
r flush
gets $fd
assert_error
"*invalid bulk length*"
{
r read
}
}
{
*protocol error*
}
}
test
{
Generic wrong number of args
}
{
test
"Non-number multibulk payload length"
{
catch
{
r ping x y z
}
err
reconnect
set _ $err
r write
"*3
\r\n\$
3
\r\n
SET
\r\n\$
1
\r\n
x
\r\n\$
blabla
\r\n
"
}
{
*wrong*arguments*ping*
}
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
View file @
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
]
}
}
Prev
1
2
Next
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