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
adfaf548
Unverified
Commit
adfaf548
authored
Jan 21, 2019
by
Salvatore Sanfilippo
Committed by
GitHub
Jan 21, 2019
Browse files
Merge branch 'unstable' into fixChildInfoPipeFdLeak
parents
440385de
cfdc800a
Changes
54
Show whitespace changes
Inline
Side-by-side
src/sentinel.c
View file @
adfaf548
...
...
@@ -453,7 +453,8 @@ struct redisCommand sentinelcmds[] = {
{
"role"
,
sentinelRoleCommand
,
1
,
"l"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"client"
,
clientCommand
,
-
2
,
"rs"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"shutdown"
,
shutdownCommand
,
-
1
,
""
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"auth"
,
authCommand
,
2
,
"sltF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
}
{
"auth"
,
authCommand
,
2
,
"sltF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"hello"
,
helloCommand
,
-
2
,
"sF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
}
};
/* This function overwrites a few normal Redis config default with Sentinel
...
...
@@ -885,17 +886,17 @@ void sentinelPendingScriptsCommand(client *c) {
listNode
*
ln
;
listIter
li
;
addReply
MultiBulk
Len
(
c
,
listLength
(
sentinel
.
scripts_queue
));
addReply
Array
Len
(
c
,
listLength
(
sentinel
.
scripts_queue
));
listRewind
(
sentinel
.
scripts_queue
,
&
li
);
while
((
ln
=
listNext
(
&
li
))
!=
NULL
)
{
sentinelScriptJob
*
sj
=
ln
->
value
;
int
j
=
0
;
addReplyM
ultiBulk
Len
(
c
,
10
);
addReplyM
ap
Len
(
c
,
5
);
addReplyBulkCString
(
c
,
"argv"
);
while
(
sj
->
argv
[
j
])
j
++
;
addReply
MultiBulk
Len
(
c
,
j
);
addReply
Array
Len
(
c
,
j
);
j
=
0
;
while
(
sj
->
argv
[
j
])
addReplyBulkCString
(
c
,
sj
->
argv
[
j
++
]);
...
...
@@ -1960,7 +1961,7 @@ void sentinelSendAuthIfNeeded(sentinelRedisInstance *ri, redisAsyncContext *c) {
}
else
if
(
ri
->
flags
&
SRI_SLAVE
)
{
auth_pass
=
ri
->
master
->
auth_pass
;
}
else
if
(
ri
->
flags
&
SRI_SENTINEL
)
{
if
(
server
.
requirepass
)
auth_pass
=
server
.
requirepass
;
auth_pass
=
ACLDefaultUserFirstPassword
()
;
}
if
(
auth_pass
)
{
...
...
@@ -2741,7 +2742,7 @@ void addReplySentinelRedisInstance(client *c, sentinelRedisInstance *ri) {
void
*
mbl
;
int
fields
=
0
;
mbl
=
addDeferred
MultiBulkLength
(
c
);
mbl
=
add
Reply
Deferred
Len
(
c
);
addReplyBulkCString
(
c
,
"name"
);
addReplyBulkCString
(
c
,
ri
->
name
);
...
...
@@ -2922,7 +2923,7 @@ void addReplySentinelRedisInstance(client *c, sentinelRedisInstance *ri) {
fields
++
;
}
setDeferredM
ultiBulkLength
(
c
,
mbl
,
fields
*
2
);
setDeferredM
apLen
(
c
,
mbl
,
fields
);
}
/* Output a number of instances contained inside a dictionary as
...
...
@@ -2932,7 +2933,7 @@ void addReplyDictOfRedisInstances(client *c, dict *instances) {
dictEntry
*
de
;
di
=
dictGetIterator
(
instances
);
addReply
MultiBulk
Len
(
c
,
dictSize
(
instances
));
addReply
Array
Len
(
c
,
dictSize
(
instances
));
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
sentinelRedisInstance
*
ri
=
dictGetVal
(
de
);
...
...
@@ -3062,7 +3063,7 @@ void sentinelCommand(client *c) {
/* Reply with a three-elements multi-bulk reply:
* down state, leader, vote epoch. */
addReply
MultiBulk
Len
(
c
,
3
);
addReply
Array
Len
(
c
,
3
);
addReply
(
c
,
isdown
?
shared
.
cone
:
shared
.
czero
);
addReplyBulkCString
(
c
,
leader
?
leader
:
"*"
);
addReplyLongLong
(
c
,
(
long
long
)
leader_epoch
);
...
...
@@ -3078,11 +3079,11 @@ void sentinelCommand(client *c) {
if
(
c
->
argc
!=
3
)
goto
numargserr
;
ri
=
sentinelGetMasterByName
(
c
->
argv
[
2
]
->
ptr
);
if
(
ri
==
NULL
)
{
addReply
(
c
,
shared
.
nullmultibulk
);
addReply
NullArray
(
c
);
}
else
{
sentinelAddr
*
addr
=
sentinelGetCurrentMasterAddress
(
ri
);
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
addReplyBulkCString
(
c
,
addr
->
ip
);
addReplyBulkLongLong
(
c
,
addr
->
port
);
}
...
...
@@ -3232,7 +3233,7 @@ void sentinelCommand(client *c) {
* 3.) other master name
* ...
*/
addReply
MultiBulk
Len
(
c
,
dictSize
(
masters_local
)
*
2
);
addReply
Array
Len
(
c
,
dictSize
(
masters_local
)
*
2
);
dictIterator
*
di
;
dictEntry
*
de
;
...
...
@@ -3240,25 +3241,25 @@ void sentinelCommand(client *c) {
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
sentinelRedisInstance
*
ri
=
dictGetVal
(
de
);
addReplyBulkCBuffer
(
c
,
ri
->
name
,
strlen
(
ri
->
name
));
addReply
MultiBulk
Len
(
c
,
dictSize
(
ri
->
slaves
)
+
1
);
/* +1 for self */
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
dictSize
(
ri
->
slaves
)
+
1
);
/* +1 for self */
addReply
Array
Len
(
c
,
2
);
addReplyLongLong
(
c
,
now
-
ri
->
info_refresh
);
if
(
ri
->
info
)
addReplyBulkCBuffer
(
c
,
ri
->
info
,
sdslen
(
ri
->
info
));
else
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
dictIterator
*
sdi
;
dictEntry
*
sde
;
sdi
=
dictGetIterator
(
ri
->
slaves
);
while
((
sde
=
dictNext
(
sdi
))
!=
NULL
)
{
sentinelRedisInstance
*
sri
=
dictGetVal
(
sde
);
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
addReplyLongLong
(
c
,
now
-
sri
->
info_refresh
);
if
(
sri
->
info
)
addReplyBulkCBuffer
(
c
,
sri
->
info
,
sdslen
(
sri
->
info
));
else
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
dictReleaseIterator
(
sdi
);
}
...
...
@@ -3282,7 +3283,7 @@ void sentinelCommand(client *c) {
serverLog
(
LL_WARNING
,
"Failure simulation: this Sentinel "
"will crash after promoting the selected replica to master"
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
j
]
->
ptr
,
"help"
))
{
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
addReplyBulkCString
(
c
,
"crash-after-election"
);
addReplyBulkCString
(
c
,
"crash-after-promotion"
);
}
else
{
...
...
@@ -3382,9 +3383,9 @@ void sentinelRoleCommand(client *c) {
dictIterator
*
di
;
dictEntry
*
de
;
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
addReplyBulkCBuffer
(
c
,
"sentinel"
,
8
);
addReply
MultiBulk
Len
(
c
,
dictSize
(
sentinel
.
masters
));
addReply
Array
Len
(
c
,
dictSize
(
sentinel
.
masters
));
di
=
dictGetIterator
(
sentinel
.
masters
);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
...
...
src/server.c
View file @
adfaf548
...
...
@@ -90,6 +90,7 @@ volatile unsigned long lru_clock; /* Server global current LRU time. */
* in MSET the step is two since arguments are key,val,key,val,...
* microseconds: microseconds of total execution time for this command.
* calls: total number of calls of this command.
* id: command bit identifier for ACLs.
*
* The flags, microseconds and calls fields are computed by Redis and should
* always be set to zero.
...
...
@@ -114,7 +115,7 @@ volatile unsigned long lru_clock; /* Server global current LRU time. */
* is deterministic.
* l: Allow command while loading the database.
* t: Allow command while a slave has stale data but is not allowed to
* serve
r
this data. Normally no command is accepted in this condition
* serve this data. Normally no command is accepted in this condition
* but just a few.
* M: Do not automatically propagate the command on MONITOR.
* k: Perform an implicit ASKING for this command, so the command will be
...
...
@@ -125,206 +126,208 @@ volatile unsigned long lru_clock; /* Server global current LRU time. */
* are not fast commands.
*/
struct
redisCommand
redisCommandTable
[]
=
{
{
"module"
,
moduleCommand
,
-
2
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"get"
,
getCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"set"
,
setCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"setnx"
,
setnxCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"setex"
,
setexCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"psetex"
,
psetexCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"append"
,
appendCommand
,
3
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"strlen"
,
strlenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"del"
,
delCommand
,
-
2
,
"w"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"unlink"
,
unlinkCommand
,
-
2
,
"wF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"exists"
,
existsCommand
,
-
2
,
"rF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"setbit"
,
setbitCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"getbit"
,
getbitCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"bitfield"
,
bitfieldCommand
,
-
2
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"setrange"
,
setrangeCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"getrange"
,
getrangeCommand
,
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"substr"
,
getrangeCommand
,
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"incr"
,
incrCommand
,
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"decr"
,
decrCommand
,
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"mget"
,
mgetCommand
,
-
2
,
"rF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"rpush"
,
rpushCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lpush"
,
lpushCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"rpushx"
,
rpushxCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lpushx"
,
lpushxCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"linsert"
,
linsertCommand
,
5
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"rpop"
,
rpopCommand
,
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lpop"
,
lpopCommand
,
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"brpop"
,
brpopCommand
,
-
3
,
"ws"
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
},
{
"brpoplpush"
,
brpoplpushCommand
,
4
,
"wms"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
},
{
"blpop"
,
blpopCommand
,
-
3
,
"ws"
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
},
{
"llen"
,
llenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lindex"
,
lindexCommand
,
3
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lset"
,
lsetCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lrange"
,
lrangeCommand
,
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"ltrim"
,
ltrimCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lrem"
,
lremCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"rpoplpush"
,
rpoplpushCommand
,
3
,
"wm"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
},
{
"sadd"
,
saddCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"srem"
,
sremCommand
,
-
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"smove"
,
smoveCommand
,
4
,
"wF"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
},
{
"sismember"
,
sismemberCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"scard"
,
scardCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"spop"
,
spopCommand
,
-
2
,
"wRF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"srandmember"
,
srandmemberCommand
,
-
2
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"sinter"
,
sinterCommand
,
-
2
,
"rS"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"sinterstore"
,
sinterstoreCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"sunion"
,
sunionCommand
,
-
2
,
"rS"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"sunionstore"
,
sunionstoreCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"sdiff"
,
sdiffCommand
,
-
2
,
"rS"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"sdiffstore"
,
sdiffstoreCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"smembers"
,
sinterCommand
,
2
,
"rS"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"sscan"
,
sscanCommand
,
-
3
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zadd"
,
zaddCommand
,
-
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zincrby"
,
zincrbyCommand
,
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrem"
,
zremCommand
,
-
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zremrangebyscore"
,
zremrangebyscoreCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zremrangebyrank"
,
zremrangebyrankCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zremrangebylex"
,
zremrangebylexCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zunionstore"
,
zunionstoreCommand
,
-
4
,
"wm"
,
0
,
zunionInterGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"zinterstore"
,
zinterstoreCommand
,
-
4
,
"wm"
,
0
,
zunionInterGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"zrange"
,
zrangeCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrangebyscore"
,
zrangebyscoreCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrevrangebyscore"
,
zrevrangebyscoreCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrangebylex"
,
zrangebylexCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrevrangebylex"
,
zrevrangebylexCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zcount"
,
zcountCommand
,
4
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zlexcount"
,
zlexcountCommand
,
4
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrevrange"
,
zrevrangeCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zcard"
,
zcardCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zscore"
,
zscoreCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrank"
,
zrankCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrevrank"
,
zrevrankCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zscan"
,
zscanCommand
,
-
3
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zpopmin"
,
zpopminCommand
,
-
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zpopmax"
,
zpopmaxCommand
,
-
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"bzpopmin"
,
bzpopminCommand
,
-
2
,
"wsF"
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
},
{
"bzpopmax"
,
bzpopmaxCommand
,
-
2
,
"wsF"
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
},
{
"hset"
,
hsetCommand
,
-
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hsetnx"
,
hsetnxCommand
,
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hget"
,
hgetCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hmset"
,
hsetCommand
,
-
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hmget"
,
hmgetCommand
,
-
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hincrby"
,
hincrbyCommand
,
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hincrbyfloat"
,
hincrbyfloatCommand
,
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hdel"
,
hdelCommand
,
-
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hlen"
,
hlenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hstrlen"
,
hstrlenCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hkeys"
,
hkeysCommand
,
2
,
"rS"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hvals"
,
hvalsCommand
,
2
,
"rS"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hgetall"
,
hgetallCommand
,
2
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hexists"
,
hexistsCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"hscan"
,
hscanCommand
,
-
3
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"incrby"
,
incrbyCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"decrby"
,
decrbyCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"incrbyfloat"
,
incrbyfloatCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"getset"
,
getsetCommand
,
3
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"mset"
,
msetCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
2
,
0
,
0
},
{
"msetnx"
,
msetnxCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
2
,
0
,
0
},
{
"randomkey"
,
randomkeyCommand
,
1
,
"rR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"select"
,
selectCommand
,
2
,
"lF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"swapdb"
,
swapdbCommand
,
3
,
"wF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"move"
,
moveCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"rename"
,
renameCommand
,
3
,
"w"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
},
{
"renamenx"
,
renamenxCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
},
{
"expire"
,
expireCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"expireat"
,
expireatCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pexpire"
,
pexpireCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pexpireat"
,
pexpireatCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"keys"
,
keysCommand
,
2
,
"rS"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"scan"
,
scanCommand
,
-
2
,
"rR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"dbsize"
,
dbsizeCommand
,
1
,
"rF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"auth"
,
authCommand
,
2
,
"sltF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"ping"
,
pingCommand
,
-
1
,
"tF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"echo"
,
echoCommand
,
2
,
"F"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"save"
,
saveCommand
,
1
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"bgsave"
,
bgsaveCommand
,
-
1
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"bgrewriteaof"
,
bgrewriteaofCommand
,
1
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"shutdown"
,
shutdownCommand
,
-
1
,
"aslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"lastsave"
,
lastsaveCommand
,
1
,
"RF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"type"
,
typeCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"multi"
,
multiCommand
,
1
,
"sF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"exec"
,
execCommand
,
1
,
"sM"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"discard"
,
discardCommand
,
1
,
"sF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"sync"
,
syncCommand
,
1
,
"ars"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"psync"
,
syncCommand
,
3
,
"ars"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"replconf"
,
replconfCommand
,
-
1
,
"aslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"flushdb"
,
flushdbCommand
,
-
1
,
"w"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"flushall"
,
flushallCommand
,
-
1
,
"w"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"sort"
,
sortCommand
,
-
2
,
"wm"
,
0
,
sortGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"info"
,
infoCommand
,
-
1
,
"ltR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"monitor"
,
monitorCommand
,
1
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"ttl"
,
ttlCommand
,
2
,
"rFR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"touch"
,
touchCommand
,
-
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pttl"
,
pttlCommand
,
2
,
"rFR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"persist"
,
persistCommand
,
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"slaveof"
,
replicaofCommand
,
3
,
"ast"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"replicaof"
,
replicaofCommand
,
3
,
"ast"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"role"
,
roleCommand
,
1
,
"lst"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"debug"
,
debugCommand
,
-
2
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"config"
,
configCommand
,
-
2
,
"last"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"subscribe"
,
subscribeCommand
,
-
2
,
"pslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"unsubscribe"
,
unsubscribeCommand
,
-
1
,
"pslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"psubscribe"
,
psubscribeCommand
,
-
2
,
"pslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"punsubscribe"
,
punsubscribeCommand
,
-
1
,
"pslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
"pltF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"pubsub"
,
pubsubCommand
,
-
2
,
"pltR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
"sF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"unwatch"
,
unwatchCommand
,
1
,
"sF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"cluster"
,
clusterCommand
,
-
2
,
"a"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"restore"
,
restoreCommand
,
-
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"restore-asking"
,
restoreCommand
,
-
4
,
"wmk"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"migrate"
,
migrateCommand
,
-
6
,
"wR"
,
0
,
migrateGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"asking"
,
askingCommand
,
1
,
"F"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"readonly"
,
readonlyCommand
,
1
,
"F"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"readwrite"
,
readwriteCommand
,
1
,
"F"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"dump"
,
dumpCommand
,
2
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"object"
,
objectCommand
,
-
2
,
"rR"
,
0
,
NULL
,
2
,
2
,
1
,
0
,
0
},
{
"memory"
,
memoryCommand
,
-
2
,
"rR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"client"
,
clientCommand
,
-
2
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"eval"
,
evalCommand
,
-
3
,
"s"
,
0
,
evalGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"evalsha"
,
evalShaCommand
,
-
3
,
"s"
,
0
,
evalGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"slowlog"
,
slowlogCommand
,
-
2
,
"aR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"script"
,
scriptCommand
,
-
2
,
"s"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"time"
,
timeCommand
,
1
,
"RF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"bitop"
,
bitopCommand
,
-
4
,
"wm"
,
0
,
NULL
,
2
,
-
1
,
1
,
0
,
0
},
{
"bitcount"
,
bitcountCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"bitpos"
,
bitposCommand
,
-
3
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"wait"
,
waitCommand
,
3
,
"s"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"command"
,
commandCommand
,
0
,
"ltR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"geoadd"
,
geoaddCommand
,
-
5
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"georadius"
,
georadiusCommand
,
-
6
,
"w"
,
0
,
georadiusGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"georadius_ro"
,
georadiusroCommand
,
-
6
,
"r"
,
0
,
georadiusGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"georadiusbymember"
,
georadiusbymemberCommand
,
-
5
,
"w"
,
0
,
georadiusGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"georadiusbymember_ro"
,
georadiusbymemberroCommand
,
-
5
,
"r"
,
0
,
georadiusGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"geohash"
,
geohashCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"geopos"
,
geoposCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"geodist"
,
geodistCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pfselftest"
,
pfselftestCommand
,
1
,
"a"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"pfadd"
,
pfaddCommand
,
-
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pfcount"
,
pfcountCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"pfmerge"
,
pfmergeCommand
,
-
2
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
},
{
"pfdebug"
,
pfdebugCommand
,
-
3
,
"w"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"xadd"
,
xaddCommand
,
-
5
,
"wmFR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xrange"
,
xrangeCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xrevrange"
,
xrevrangeCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xlen"
,
xlenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xread"
,
xreadCommand
,
-
4
,
"rs"
,
0
,
xreadGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"xreadgroup"
,
xreadCommand
,
-
7
,
"ws"
,
0
,
xreadGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"xgroup"
,
xgroupCommand
,
-
2
,
"wm"
,
0
,
NULL
,
2
,
2
,
1
,
0
,
0
},
{
"xsetid"
,
xsetidCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xack"
,
xackCommand
,
-
4
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xpending"
,
xpendingCommand
,
-
3
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xclaim"
,
xclaimCommand
,
-
6
,
"wRF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xinfo"
,
xinfoCommand
,
-
2
,
"rR"
,
0
,
NULL
,
2
,
2
,
1
,
0
,
0
},
{
"xdel"
,
xdelCommand
,
-
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"xtrim"
,
xtrimCommand
,
-
2
,
"wFR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"post"
,
securityWarningCommand
,
-
1
,
"lt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"host:"
,
securityWarningCommand
,
-
1
,
"lt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"latency"
,
latencyCommand
,
-
2
,
"aslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"lolwut"
,
lolwutCommand
,
-
1
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
}
{
"module"
,
moduleCommand
,
-
2
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"get"
,
getCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"set"
,
setCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"setnx"
,
setnxCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"setex"
,
setexCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"psetex"
,
psetexCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"append"
,
appendCommand
,
3
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"strlen"
,
strlenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"del"
,
delCommand
,
-
2
,
"w"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"unlink"
,
unlinkCommand
,
-
2
,
"wF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"exists"
,
existsCommand
,
-
2
,
"rF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"setbit"
,
setbitCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"getbit"
,
getbitCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"bitfield"
,
bitfieldCommand
,
-
2
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"setrange"
,
setrangeCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"getrange"
,
getrangeCommand
,
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"substr"
,
getrangeCommand
,
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"incr"
,
incrCommand
,
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"decr"
,
decrCommand
,
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"mget"
,
mgetCommand
,
-
2
,
"rF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"rpush"
,
rpushCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"lpush"
,
lpushCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"rpushx"
,
rpushxCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"lpushx"
,
lpushxCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"linsert"
,
linsertCommand
,
5
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"rpop"
,
rpopCommand
,
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"lpop"
,
lpopCommand
,
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"brpop"
,
brpopCommand
,
-
3
,
"ws"
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
,
0
},
{
"brpoplpush"
,
brpoplpushCommand
,
4
,
"wms"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
,
0
},
{
"blpop"
,
blpopCommand
,
-
3
,
"ws"
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
,
0
},
{
"llen"
,
llenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"lindex"
,
lindexCommand
,
3
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"lset"
,
lsetCommand
,
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"lrange"
,
lrangeCommand
,
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"ltrim"
,
ltrimCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"lrem"
,
lremCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"rpoplpush"
,
rpoplpushCommand
,
3
,
"wm"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
,
0
},
{
"sadd"
,
saddCommand
,
-
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"srem"
,
sremCommand
,
-
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"smove"
,
smoveCommand
,
4
,
"wF"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
,
0
},
{
"sismember"
,
sismemberCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"scard"
,
scardCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"spop"
,
spopCommand
,
-
2
,
"wRF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"srandmember"
,
srandmemberCommand
,
-
2
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"sinter"
,
sinterCommand
,
-
2
,
"rS"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"sinterstore"
,
sinterstoreCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"sunion"
,
sunionCommand
,
-
2
,
"rS"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"sunionstore"
,
sunionstoreCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"sdiff"
,
sdiffCommand
,
-
2
,
"rS"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"sdiffstore"
,
sdiffstoreCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"smembers"
,
sinterCommand
,
2
,
"rS"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"sscan"
,
sscanCommand
,
-
3
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zadd"
,
zaddCommand
,
-
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zincrby"
,
zincrbyCommand
,
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zrem"
,
zremCommand
,
-
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zremrangebyscore"
,
zremrangebyscoreCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zremrangebyrank"
,
zremrangebyrankCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zremrangebylex"
,
zremrangebylexCommand
,
4
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zunionstore"
,
zunionstoreCommand
,
-
4
,
"wm"
,
0
,
zunionInterGetKeys
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"zinterstore"
,
zinterstoreCommand
,
-
4
,
"wm"
,
0
,
zunionInterGetKeys
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"zrange"
,
zrangeCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zrangebyscore"
,
zrangebyscoreCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zrevrangebyscore"
,
zrevrangebyscoreCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zrangebylex"
,
zrangebylexCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zrevrangebylex"
,
zrevrangebylexCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zcount"
,
zcountCommand
,
4
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zlexcount"
,
zlexcountCommand
,
4
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zrevrange"
,
zrevrangeCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zcard"
,
zcardCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zscore"
,
zscoreCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zrank"
,
zrankCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zrevrank"
,
zrevrankCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zscan"
,
zscanCommand
,
-
3
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zpopmin"
,
zpopminCommand
,
-
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"zpopmax"
,
zpopmaxCommand
,
-
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"bzpopmin"
,
bzpopminCommand
,
-
2
,
"wsF"
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
,
0
},
{
"bzpopmax"
,
bzpopmaxCommand
,
-
2
,
"wsF"
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
,
0
},
{
"hset"
,
hsetCommand
,
-
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hsetnx"
,
hsetnxCommand
,
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hget"
,
hgetCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hmset"
,
hsetCommand
,
-
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hmget"
,
hmgetCommand
,
-
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hincrby"
,
hincrbyCommand
,
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hincrbyfloat"
,
hincrbyfloatCommand
,
4
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hdel"
,
hdelCommand
,
-
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hlen"
,
hlenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hstrlen"
,
hstrlenCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hkeys"
,
hkeysCommand
,
2
,
"rS"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hvals"
,
hvalsCommand
,
2
,
"rS"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hgetall"
,
hgetallCommand
,
2
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hexists"
,
hexistsCommand
,
3
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"hscan"
,
hscanCommand
,
-
3
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"incrby"
,
incrbyCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"decrby"
,
decrbyCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"incrbyfloat"
,
incrbyfloatCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"getset"
,
getsetCommand
,
3
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"mset"
,
msetCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
2
,
0
,
0
,
0
},
{
"msetnx"
,
msetnxCommand
,
-
3
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
2
,
0
,
0
,
0
},
{
"randomkey"
,
randomkeyCommand
,
1
,
"rR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"select"
,
selectCommand
,
2
,
"lF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"swapdb"
,
swapdbCommand
,
3
,
"wF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"move"
,
moveCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"rename"
,
renameCommand
,
3
,
"w"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
,
0
},
{
"renamenx"
,
renamenxCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
2
,
1
,
0
,
0
,
0
},
{
"expire"
,
expireCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"expireat"
,
expireatCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"pexpire"
,
pexpireCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"pexpireat"
,
pexpireatCommand
,
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"keys"
,
keysCommand
,
2
,
"rS"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"scan"
,
scanCommand
,
-
2
,
"rR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"dbsize"
,
dbsizeCommand
,
1
,
"rF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"auth"
,
authCommand
,
-
2
,
"sltF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"ping"
,
pingCommand
,
-
1
,
"tF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"echo"
,
echoCommand
,
2
,
"F"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"save"
,
saveCommand
,
1
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"bgsave"
,
bgsaveCommand
,
-
1
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"bgrewriteaof"
,
bgrewriteaofCommand
,
1
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"shutdown"
,
shutdownCommand
,
-
1
,
"aslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"lastsave"
,
lastsaveCommand
,
1
,
"RF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"type"
,
typeCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"multi"
,
multiCommand
,
1
,
"sF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"exec"
,
execCommand
,
1
,
"sM"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"discard"
,
discardCommand
,
1
,
"sF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"sync"
,
syncCommand
,
1
,
"ars"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"psync"
,
syncCommand
,
3
,
"ars"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"replconf"
,
replconfCommand
,
-
1
,
"aslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"flushdb"
,
flushdbCommand
,
-
1
,
"w"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"flushall"
,
flushallCommand
,
-
1
,
"w"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"sort"
,
sortCommand
,
-
2
,
"wm"
,
0
,
sortGetKeys
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"info"
,
infoCommand
,
-
1
,
"ltR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"monitor"
,
monitorCommand
,
1
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"ttl"
,
ttlCommand
,
2
,
"rFR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"touch"
,
touchCommand
,
-
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"pttl"
,
pttlCommand
,
2
,
"rFR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"persist"
,
persistCommand
,
2
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"slaveof"
,
replicaofCommand
,
3
,
"ast"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"replicaof"
,
replicaofCommand
,
3
,
"ast"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"role"
,
roleCommand
,
1
,
"lst"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"debug"
,
debugCommand
,
-
2
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"config"
,
configCommand
,
-
2
,
"last"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"subscribe"
,
subscribeCommand
,
-
2
,
"pslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"unsubscribe"
,
unsubscribeCommand
,
-
1
,
"pslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"psubscribe"
,
psubscribeCommand
,
-
2
,
"pslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"punsubscribe"
,
punsubscribeCommand
,
-
1
,
"pslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
"pltF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"pubsub"
,
pubsubCommand
,
-
2
,
"pltR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
"sF"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"unwatch"
,
unwatchCommand
,
1
,
"sF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"cluster"
,
clusterCommand
,
-
2
,
"a"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"restore"
,
restoreCommand
,
-
4
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"restore-asking"
,
restoreCommand
,
-
4
,
"wmk"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"migrate"
,
migrateCommand
,
-
6
,
"wR"
,
0
,
migrateGetKeys
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"asking"
,
askingCommand
,
1
,
"F"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"readonly"
,
readonlyCommand
,
1
,
"F"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"readwrite"
,
readwriteCommand
,
1
,
"F"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"dump"
,
dumpCommand
,
2
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"object"
,
objectCommand
,
-
2
,
"rR"
,
0
,
NULL
,
2
,
2
,
1
,
0
,
0
,
0
},
{
"memory"
,
memoryCommand
,
-
2
,
"rR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"client"
,
clientCommand
,
-
2
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"hello"
,
helloCommand
,
-
2
,
"sF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"eval"
,
evalCommand
,
-
3
,
"s"
,
0
,
evalGetKeys
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"evalsha"
,
evalShaCommand
,
-
3
,
"s"
,
0
,
evalGetKeys
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"slowlog"
,
slowlogCommand
,
-
2
,
"aR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"script"
,
scriptCommand
,
-
2
,
"s"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"time"
,
timeCommand
,
1
,
"RF"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"bitop"
,
bitopCommand
,
-
4
,
"wm"
,
0
,
NULL
,
2
,
-
1
,
1
,
0
,
0
,
0
},
{
"bitcount"
,
bitcountCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"bitpos"
,
bitposCommand
,
-
3
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"wait"
,
waitCommand
,
3
,
"s"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"command"
,
commandCommand
,
0
,
"ltR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"geoadd"
,
geoaddCommand
,
-
5
,
"wm"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"georadius"
,
georadiusCommand
,
-
6
,
"w"
,
0
,
georadiusGetKeys
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"georadius_ro"
,
georadiusroCommand
,
-
6
,
"r"
,
0
,
georadiusGetKeys
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"georadiusbymember"
,
georadiusbymemberCommand
,
-
5
,
"w"
,
0
,
georadiusGetKeys
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"georadiusbymember_ro"
,
georadiusbymemberroCommand
,
-
5
,
"r"
,
0
,
georadiusGetKeys
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"geohash"
,
geohashCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"geopos"
,
geoposCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"geodist"
,
geodistCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"pfselftest"
,
pfselftestCommand
,
1
,
"a"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"pfadd"
,
pfaddCommand
,
-
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"pfcount"
,
pfcountCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"pfmerge"
,
pfmergeCommand
,
-
2
,
"wm"
,
0
,
NULL
,
1
,
-
1
,
1
,
0
,
0
,
0
},
{
"pfdebug"
,
pfdebugCommand
,
-
3
,
"w"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"xadd"
,
xaddCommand
,
-
5
,
"wmFR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xrange"
,
xrangeCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xrevrange"
,
xrevrangeCommand
,
-
4
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xlen"
,
xlenCommand
,
2
,
"rF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xread"
,
xreadCommand
,
-
4
,
"rs"
,
0
,
xreadGetKeys
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xreadgroup"
,
xreadCommand
,
-
7
,
"ws"
,
0
,
xreadGetKeys
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xgroup"
,
xgroupCommand
,
-
2
,
"wm"
,
0
,
NULL
,
2
,
2
,
1
,
0
,
0
,
0
},
{
"xsetid"
,
xsetidCommand
,
3
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xack"
,
xackCommand
,
-
4
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xpending"
,
xpendingCommand
,
-
3
,
"rR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xclaim"
,
xclaimCommand
,
-
6
,
"wRF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xinfo"
,
xinfoCommand
,
-
2
,
"rR"
,
0
,
NULL
,
2
,
2
,
1
,
0
,
0
,
0
},
{
"xdel"
,
xdelCommand
,
-
3
,
"wF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"xtrim"
,
xtrimCommand
,
-
2
,
"wFR"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
,
0
},
{
"post"
,
securityWarningCommand
,
-
1
,
"lt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"host:"
,
securityWarningCommand
,
-
1
,
"lt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"latency"
,
latencyCommand
,
-
2
,
"aslt"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"lolwut"
,
lolwutCommand
,
-
1
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
},
{
"acl"
,
aclCommand
,
-
2
,
"ast"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
,
0
}
};
/*============================ Utility functions ============================ */
...
...
@@ -1428,10 +1431,7 @@ void createSharedObjects(void) {
shared
.
emptybulk
=
createObject
(
OBJ_STRING
,
sdsnew
(
"$0
\r\n\r\n
"
));
shared
.
czero
=
createObject
(
OBJ_STRING
,
sdsnew
(
":0
\r\n
"
));
shared
.
cone
=
createObject
(
OBJ_STRING
,
sdsnew
(
":1
\r\n
"
));
shared
.
cnegone
=
createObject
(
OBJ_STRING
,
sdsnew
(
":-1
\r\n
"
));
shared
.
nullbulk
=
createObject
(
OBJ_STRING
,
sdsnew
(
"$-1
\r\n
"
));
shared
.
nullmultibulk
=
createObject
(
OBJ_STRING
,
sdsnew
(
"*-1
\r\n
"
));
shared
.
emptymultibulk
=
createObject
(
OBJ_STRING
,
sdsnew
(
"*0
\r\n
"
));
shared
.
emptyarray
=
createObject
(
OBJ_STRING
,
sdsnew
(
"*0
\r\n
"
));
shared
.
pong
=
createObject
(
OBJ_STRING
,
sdsnew
(
"+PONG
\r\n
"
));
shared
.
queued
=
createObject
(
OBJ_STRING
,
sdsnew
(
"+QUEUED
\r\n
"
));
shared
.
emptyscan
=
createObject
(
OBJ_STRING
,
sdsnew
(
"*2
\r\n
$1
\r\n
0
\r\n
*0
\r\n
"
));
...
...
@@ -1471,6 +1471,17 @@ void createSharedObjects(void) {
shared
.
colon
=
createObject
(
OBJ_STRING
,
sdsnew
(
":"
));
shared
.
plus
=
createObject
(
OBJ_STRING
,
sdsnew
(
"+"
));
/* The shared NULL depends on the protocol version. */
shared
.
null
[
0
]
=
NULL
;
shared
.
null
[
1
]
=
NULL
;
shared
.
null
[
2
]
=
createObject
(
OBJ_STRING
,
sdsnew
(
"$-1
\r\n
"
));
shared
.
null
[
3
]
=
createObject
(
OBJ_STRING
,
sdsnew
(
"_
\r\n
"
));
shared
.
nullarray
[
0
]
=
NULL
;
shared
.
nullarray
[
1
]
=
NULL
;
shared
.
nullarray
[
2
]
=
createObject
(
OBJ_STRING
,
sdsnew
(
"*-1
\r\n
"
));
shared
.
nullarray
[
3
]
=
createObject
(
OBJ_STRING
,
sdsnew
(
"_
\r\n
"
));
for
(
j
=
0
;
j
<
PROTO_SHARED_SELECT_CMDS
;
j
++
)
{
char
dictid_str
[
64
];
int
dictid_len
;
...
...
@@ -1585,7 +1596,6 @@ void initServerConfig(void) {
server
.
pidfile
=
NULL
;
server
.
rdb_filename
=
zstrdup
(
CONFIG_DEFAULT_RDB_FILENAME
);
server
.
aof_filename
=
zstrdup
(
CONFIG_DEFAULT_AOF_FILENAME
);
server
.
requirepass
=
NULL
;
server
.
rdb_compression
=
CONFIG_DEFAULT_RDB_COMPRESSION
;
server
.
rdb_checksum
=
CONFIG_DEFAULT_RDB_CHECKSUM
;
server
.
stop_writes_on_bgsave_err
=
CONFIG_DEFAULT_STOP_WRITES_ON_BGSAVE_ERROR
;
...
...
@@ -2192,6 +2202,8 @@ void populateCommandTable(void) {
char
*
f
=
c
->
sflags
;
int
retval1
,
retval2
;
/* Translate the command string flags description into an actual
* set of flags. */
while
(
*
f
!=
'\0'
)
{
switch
(
*
f
)
{
case
'w'
:
c
->
flags
|=
CMD_WRITE
;
break
;
...
...
@@ -2212,6 +2224,7 @@ void populateCommandTable(void) {
f
++
;
}
c
->
id
=
ACLGetCommandID
(
c
->
name
);
/* Assign the ID used for ACL. */
retval1
=
dictAdd
(
server
.
commands
,
sdsnew
(
c
->
name
),
c
);
/* Populate an additional dictionary that will be unaffected
* by rename-command statements in redis.conf. */
...
...
@@ -2573,13 +2586,31 @@ int processCommand(client *c) {
}
/* Check if the user is authenticated */
if
(
server
.
requirepass
&&
!
c
->
authenticated
&&
c
->
cmd
->
proc
!=
authCommand
)
if
(
!
(
DefaultUser
->
flags
&
USER_FLAG_NOPASS
)
&&
!
c
->
authenticated
&&
(
c
->
cmd
->
proc
!=
authCommand
||
c
->
cmd
->
proc
==
helloCommand
))
{
flagTransaction
(
c
);
addReply
(
c
,
shared
.
noautherr
);
return
C_OK
;
}
/* Check if the user can run this command according to the current
* ACLs. */
int
acl_retval
=
ACLCheckCommandPerm
(
c
);
if
(
acl_retval
!=
ACL_OK
)
{
flagTransaction
(
c
);
if
(
acl_retval
==
ACL_DENIED_CMD
)
addReplyErrorFormat
(
c
,
"-NOPERM this user has no permissions to run "
"the '%s' command"
,
c
->
cmd
->
name
);
else
addReplyErrorFormat
(
c
,
"-NOPERM this user has no permissions to access "
"one of the keys used as arguments"
);
return
C_OK
;
}
/* If cluster is enabled perform the cluster redirection here.
* However we don't perform the redirection if:
* 1) The sender of this command is our master.
...
...
@@ -2672,8 +2703,9 @@ int processCommand(client *c) {
return
C_OK
;
}
/* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
if
(
c
->
flags
&
CLIENT_PUBSUB
&&
/* Only allow a subset of commands in the context of Pub/Sub if the
* connection is in RESP2 mode. With RESP3 there are no limits. */
if
((
c
->
flags
&
CLIENT_PUBSUB
&&
c
->
resp
==
2
)
&&
c
->
cmd
->
proc
!=
pingCommand
&&
c
->
cmd
->
proc
!=
subscribeCommand
&&
c
->
cmd
->
proc
!=
unsubscribeCommand
&&
...
...
@@ -2705,6 +2737,7 @@ int processCommand(client *c) {
/* Lua script too slow? Only allow a limited number of commands. */
if
(
server
.
lua_timedout
&&
c
->
cmd
->
proc
!=
authCommand
&&
c
->
cmd
->
proc
!=
helloCommand
&&
c
->
cmd
->
proc
!=
replconfCommand
&&
!
(
c
->
cmd
->
proc
==
shutdownCommand
&&
c
->
argc
==
2
&&
...
...
@@ -2851,58 +2884,49 @@ int writeCommandsDeniedByDiskError(void) {
}
}
/* Return zero if strings are the same, non-zero if they are not.
* The comparison is performed in a way that prevents an attacker to obtain
* information about the nature of the strings just monitoring the execution
* time of the function.
/* AUTH <passowrd>
* AUTH <username> <password> (Redis >= 6.0 form)
*
* Note that limiting the comparison length to strings up to 512 bytes we
* can avoid leaking any information about the password length and any
* possible branch misprediction related leak.
*/
int
time_independent_strcmp
(
char
*
a
,
char
*
b
)
{
char
bufa
[
CONFIG_AUTHPASS_MAX_LEN
],
bufb
[
CONFIG_AUTHPASS_MAX_LEN
];
/* The above two strlen perform len(a) + len(b) operations where either
* a or b are fixed (our password) length, and the difference is only
* relative to the length of the user provided string, so no information
* leak is possible in the following two lines of code. */
unsigned
int
alen
=
strlen
(
a
);
unsigned
int
blen
=
strlen
(
b
);
unsigned
int
j
;
int
diff
=
0
;
/* We can't compare strings longer than our static buffers.
* Note that this will never pass the first test in practical circumstances
* so there is no info leak. */
if
(
alen
>
sizeof
(
bufa
)
||
blen
>
sizeof
(
bufb
))
return
1
;
memset
(
bufa
,
0
,
sizeof
(
bufa
));
/* Constant time. */
memset
(
bufb
,
0
,
sizeof
(
bufb
));
/* Constant time. */
/* Again the time of the following two copies is proportional to
* len(a) + len(b) so no info is leaked. */
memcpy
(
bufa
,
a
,
alen
);
memcpy
(
bufb
,
b
,
blen
);
/* Always compare all the chars in the two buffers without
* conditional expressions. */
for
(
j
=
0
;
j
<
sizeof
(
bufa
);
j
++
)
{
diff
|=
(
bufa
[
j
]
^
bufb
[
j
]);
}
/* Length must be equal as well. */
diff
|=
alen
^
blen
;
return
diff
;
/* If zero strings are the same. */
}
* When the user is omitted it means that we are trying to authenticate
* against the default user. */
void
authCommand
(
client
*
c
)
{
if
(
!
server
.
requirepass
)
{
addReplyError
(
c
,
"Client sent AUTH, but no password is set"
);
}
else
if
(
!
time_independent_strcmp
(
c
->
argv
[
1
]
->
ptr
,
server
.
requirepass
))
{
/* Only two or three argument forms are allowed. */
if
(
c
->
argc
>
3
)
{
addReply
(
c
,
shared
.
syntaxerr
);
return
;
}
/* Handle the two different forms here. The form with two arguments
* will just use "default" as username. */
robj
*
username
,
*
password
;
if
(
c
->
argc
==
2
)
{
/* Mimic the old behavior of giving an error for the two commands
* from if no password is configured. */
if
(
DefaultUser
->
flags
&
USER_FLAG_NOPASS
)
{
addReplyError
(
c
,
"AUTH <password> called without any password "
"configured for the default user. Are you sure "
"your configuration is correct?"
);
return
;
}
username
=
createStringObject
(
"default"
,
7
);
password
=
c
->
argv
[
1
];
}
else
{
username
=
c
->
argv
[
1
];
password
=
c
->
argv
[
2
];
}
if
(
ACLCheckUserCredentials
(
username
,
password
)
==
C_OK
)
{
c
->
authenticated
=
1
;
c
->
user
=
ACLGetUserByName
(
username
->
ptr
,
sdslen
(
username
->
ptr
));
addReply
(
c
,
shared
.
ok
);
}
else
{
c
->
authenticated
=
0
;
addReplyError
(
c
,
"invalid password"
);
addReplyError
(
c
,
"-WRONGPASS invalid username-password pair"
);
}
/* Free the "default" string object we created for the two
* arguments form. */
if
(
c
->
argc
==
2
)
decrRefCount
(
username
);
}
/* The PING command. It works in a different way if the client is in
...
...
@@ -2915,7 +2939,7 @@ void pingCommand(client *c) {
return
;
}
if
(
c
->
flags
&
CLIENT_PUBSUB
)
{
if
(
c
->
flags
&
CLIENT_PUBSUB
&&
c
->
resp
==
2
)
{
addReply
(
c
,
shared
.
mbulkhdr
[
2
]);
addReplyBulkCBuffer
(
c
,
"pong"
,
4
);
if
(
c
->
argc
==
1
)
...
...
@@ -2940,7 +2964,7 @@ void timeCommand(client *c) {
/* gettimeofday() can only fail if &tv is a bad address so we
* don't check for errors. */
gettimeofday
(
&
tv
,
NULL
);
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
addReplyBulkLongLong
(
c
,
tv
.
tv_sec
);
addReplyBulkLongLong
(
c
,
tv
.
tv_usec
);
}
...
...
@@ -2957,15 +2981,15 @@ int addReplyCommandFlag(client *c, struct redisCommand *cmd, int f, char *reply)
/* Output the representation of a Redis command. Used by the COMMAND command. */
void
addReplyCommand
(
client
*
c
,
struct
redisCommand
*
cmd
)
{
if
(
!
cmd
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
/* We are adding: command name, arg count, flags, first, last, offset */
addReply
MultiBulk
Len
(
c
,
6
);
addReply
Array
Len
(
c
,
6
);
addReplyBulkCString
(
c
,
cmd
->
name
);
addReplyLongLong
(
c
,
cmd
->
arity
);
int
flagcount
=
0
;
void
*
flaglen
=
addDeferred
MultiBulkLength
(
c
);
void
*
flaglen
=
add
Reply
Deferred
Len
(
c
);
flagcount
+=
addReplyCommandFlag
(
c
,
cmd
,
CMD_WRITE
,
"write"
);
flagcount
+=
addReplyCommandFlag
(
c
,
cmd
,
CMD_READONLY
,
"readonly"
);
flagcount
+=
addReplyCommandFlag
(
c
,
cmd
,
CMD_DENYOOM
,
"denyoom"
);
...
...
@@ -2985,7 +3009,7 @@ void addReplyCommand(client *c, struct redisCommand *cmd) {
addReplyStatus
(
c
,
"movablekeys"
);
flagcount
+=
1
;
}
setDeferred
MultiBulkLength
(
c
,
flaglen
,
flagcount
);
setDeferred
SetLen
(
c
,
flaglen
,
flagcount
);
addReplyLongLong
(
c
,
cmd
->
firstkey
);
addReplyLongLong
(
c
,
cmd
->
lastkey
);
...
...
@@ -3008,7 +3032,7 @@ NULL
};
addReplyHelp
(
c
,
help
);
}
else
if
(
c
->
argc
==
1
)
{
addReply
MultiBulk
Len
(
c
,
dictSize
(
server
.
commands
));
addReply
Array
Len
(
c
,
dictSize
(
server
.
commands
));
di
=
dictGetIterator
(
server
.
commands
);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
addReplyCommand
(
c
,
dictGetVal
(
de
));
...
...
@@ -3016,7 +3040,7 @@ NULL
dictReleaseIterator
(
di
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
1
]
->
ptr
,
"info"
))
{
int
i
;
addReply
MultiBulk
Len
(
c
,
c
->
argc
-
2
);
addReply
Array
Len
(
c
,
c
->
argc
-
2
);
for
(
i
=
2
;
i
<
c
->
argc
;
i
++
)
{
addReplyCommand
(
c
,
dictFetchValue
(
server
.
commands
,
c
->
argv
[
i
]
->
ptr
));
}
...
...
@@ -3043,7 +3067,7 @@ NULL
if
(
!
keys
)
{
addReplyError
(
c
,
"Invalid arguments specified for command"
);
}
else
{
addReply
MultiBulk
Len
(
c
,
numkeys
);
addReply
Array
Len
(
c
,
numkeys
);
for
(
j
=
0
;
j
<
numkeys
;
j
++
)
addReplyBulk
(
c
,
c
->
argv
[
keys
[
j
]
+
2
]);
getKeysFreeResult
(
keys
);
}
...
...
@@ -4047,6 +4071,8 @@ int main(int argc, char **argv) {
dictSetHashFunctionSeed
((
uint8_t
*
)
hashseed
);
server
.
sentinel_mode
=
checkForSentinelMode
(
argc
,
argv
);
initServerConfig
();
ACLInit
();
/* The ACL subsystem must be initialized ASAP because the
basic networking code and client creation depends on it. */
moduleInitModulesSystem
();
/* Store the executable path and arguments in a safe place in order
...
...
src/server.h
View file @
adfaf548
...
...
@@ -707,11 +707,51 @@ typedef struct readyList {
robj
*
key
;
}
readyList
;
/* This structure represents a Redis user. This is useful for ACLs, the
* user is associated to the connection after the connection is authenticated.
* If there is no associated user, the connection uses the default user. */
#define USER_MAX_COMMAND_BIT 1024
/* The first *not valid* bit that
would overflow. So check for >= */
#define USER_FLAG_ENABLED (1<<0)
/* The user is active. */
#define USER_FLAG_ALLKEYS (1<<1)
/* The user can mention any key. */
#define USER_FLAG_ALLCOMMANDS (1<<2)
/* The user can run all commands. */
#define USER_FLAG_NOPASS (1<<3)
/* The user requires no password, any
provided password will work. For the
default user, this also means that
no AUTH is needed, and every
connection is immediately
authenticated. */
typedef
struct
user
{
sds
name
;
/* The username as an SDS string. */
uint64_t
flags
;
/* See USER_FLAG_* */
/* The bit in allowed_commands is set if this user has the right to
* execute this command. In commands having subcommands, if this bit is
* set, then all the subcommands are also available.
*
* If the bit for a given command is NOT set and the command has
* subcommands, Redis will also check allowed_subcommands in order to
* understand if the command can be executed. */
uint64_t
allowed_commands
[
USER_MAX_COMMAND_BIT
/
64
];
/* This array points, for each command ID (corresponding to the command
* bit set in allowed_commands), to an array of SDS strings, terminated by
* a NULL pointer, with all the sub commands that can be executed for
* this command. When no subcommands matching is used, the field is just
* set to NULL to avoid allocating USER_MAX_COMMAND_BIT pointers. */
sds
**
allowed_subcommands
;
list
*
passwords
;
/* A list of SDS valid passwords for this user. */
list
*
patterns
;
/* A list of allowed key patterns. If this field is NULL
the user cannot mention any key in a command, unless
the flag ALLKEYS is set in the user. */
}
user
;
/* With multiplexing we need to take per-client state.
* Clients are taken in a linked list. */
typedef
struct
client
{
uint64_t
id
;
/* Client incremental unique ID. */
int
fd
;
/* Client socket. */
int
resp
;
/* RESP protocol version. Can be 2 or 3. */
redisDb
*
db
;
/* Pointer to currently SELECTed DB. */
robj
*
name
;
/* As set by CLIENT SETNAME. */
sds
querybuf
;
/* Buffer we use to accumulate client queries. */
...
...
@@ -724,6 +764,9 @@ typedef struct client {
int
argc
;
/* Num of arguments of current command. */
robj
**
argv
;
/* Arguments of current command. */
struct
redisCommand
*
cmd
,
*
lastcmd
;
/* Last command executed. */
user
*
user
;
/* User associated with this connection. If the
user is set to NULL the connection can do
anything (admin). */
int
reqtype
;
/* Request protocol type: PROTO_REQ_* */
int
multibulklen
;
/* Number of multi bulk arguments left to read. */
long
bulklen
;
/* Length of bulk argument in multi bulk request. */
...
...
@@ -735,7 +778,7 @@ typedef struct client {
time_t
lastinteraction
;
/* Time of the last interaction, used for timeout */
time_t
obuf_soft_limit_reached_time
;
int
flags
;
/* Client flags: CLIENT_* macros. */
int
authenticated
;
/*
When requirepass is non-NULL
. */
int
authenticated
;
/*
Needed when the default user requires auth
. */
int
replstate
;
/* Replication state if this is a slave. */
int
repl_put_online_on_ack
;
/* Install slave write handler on ACK. */
int
repldbfd
;
/* Replication DB file descriptor. */
...
...
@@ -780,9 +823,9 @@ struct moduleLoadQueueEntry {
};
struct
sharedObjectsStruct
{
robj
*
crlf
,
*
ok
,
*
err
,
*
emptybulk
,
*
czero
,
*
cone
,
*
cnegone
,
*
pong
,
*
space
,
*
colon
,
*
nullbulk
,
*
nullmultibulk
,
*
queued
,
*
empty
multibulk
,
*
wrongtypeerr
,
*
nokeyerr
,
*
syntaxerr
,
*
sameobjecterr
,
robj
*
crlf
,
*
ok
,
*
err
,
*
emptybulk
,
*
czero
,
*
cone
,
*
pong
,
*
space
,
*
colon
,
*
queued
,
*
null
[
4
],
*
nullarray
[
4
]
,
*
empty
array
,
*
wrongtypeerr
,
*
nokeyerr
,
*
syntaxerr
,
*
sameobjecterr
,
*
outofrangeerr
,
*
noscripterr
,
*
loadingerr
,
*
slowscripterr
,
*
bgsaveerr
,
*
masterdownerr
,
*
roslaveerr
,
*
execaborterr
,
*
noautherr
,
*
noreplicaserr
,
*
busykeyerr
,
*
oomerr
,
*
plus
,
*
messagebulk
,
*
pmessagebulk
,
*
subscribebulk
,
...
...
@@ -945,7 +988,6 @@ struct redisServer {
int
shutdown_asap
;
/* SHUTDOWN needed ASAP */
int
activerehashing
;
/* Incremental rehash in serverCron() */
int
active_defrag_running
;
/* Active defragmentation running (holds current scan aggressiveness) */
char
*
requirepass
;
/* Pass for AUTH command, or NULL */
char
*
pidfile
;
/* PID file path */
int
arch_bits
;
/* 32 or 64 depending on sizeof(long) */
int
cronloops
;
/* Number of times the cron function run */
...
...
@@ -1304,6 +1346,11 @@ struct redisCommand {
int
lastkey
;
/* The last argument that's a key */
int
keystep
;
/* The step between first and last key */
long
long
microseconds
,
calls
;
int
id
;
/* Command ID. This is a progressive ID starting from 0 that
is assigned at runtime, and is used in order to check
ACLs. A connection is able to execute a given command if
the user associated to the connection has this command
bit set in the bitmap of allowed commands. */
};
struct
redisFunctionSym
{
...
...
@@ -1424,15 +1471,23 @@ void freeClient(client *c);
void
freeClientAsync
(
client
*
c
);
void
resetClient
(
client
*
c
);
void
sendReplyToClient
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
*
addDeferredMultiBulkLength
(
client
*
c
);
void
setDeferredMultiBulkLength
(
client
*
c
,
void
*
node
,
long
length
);
void
*
addReplyDeferredLen
(
client
*
c
);
void
setDeferredArrayLen
(
client
*
c
,
void
*
node
,
long
length
);
void
setDeferredMapLen
(
client
*
c
,
void
*
node
,
long
length
);
void
setDeferredSetLen
(
client
*
c
,
void
*
node
,
long
length
);
void
setDeferredAttributeLen
(
client
*
c
,
void
*
node
,
long
length
);
void
setDeferredPushLen
(
client
*
c
,
void
*
node
,
long
length
);
void
processInputBuffer
(
client
*
c
);
void
processInputBufferAndReplicate
(
client
*
c
);
void
acceptHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
acceptTcpHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
acceptUnixHandler
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
readQueryFromClient
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
addReplyString
(
client
*
c
,
const
char
*
s
,
size_t
len
);
void
addReplyNull
(
client
*
c
);
void
addReplyNullArray
(
client
*
c
);
void
addReplyBool
(
client
*
c
,
int
b
);
void
addReplyVerbatim
(
client
*
c
,
const
char
*
s
,
size_t
len
,
const
char
*
ext
);
void
addReplyProto
(
client
*
c
,
const
char
*
s
,
size_t
len
);
void
addReplyBulk
(
client
*
c
,
robj
*
obj
);
void
addReplyBulkCString
(
client
*
c
,
const
char
*
s
);
void
addReplyBulkCBuffer
(
client
*
c
,
const
void
*
p
,
size_t
len
);
...
...
@@ -1445,9 +1500,14 @@ void addReplyStatus(client *c, const char *status);
void
addReplyDouble
(
client
*
c
,
double
d
);
void
addReplyHumanLongDouble
(
client
*
c
,
long
double
d
);
void
addReplyLongLong
(
client
*
c
,
long
long
ll
);
void
addReplyMultiBulkLen
(
client
*
c
,
long
length
);
void
addReplyArrayLen
(
client
*
c
,
long
length
);
void
addReplyMapLen
(
client
*
c
,
long
length
);
void
addReplySetLen
(
client
*
c
,
long
length
);
void
addReplyAttributeLen
(
client
*
c
,
long
length
);
void
addReplyPushLen
(
client
*
c
,
long
length
);
void
addReplyHelp
(
client
*
c
,
const
char
**
help
);
void
addReplySubcommandSyntaxError
(
client
*
c
);
void
addReplyLoadedModules
(
client
*
c
);
void
copyClientOutputBuffer
(
client
*
dst
,
client
*
src
);
size_t
sdsZmallocSize
(
sds
s
);
size_t
getStringObjectSdsUsedMemory
(
robj
*
o
);
...
...
@@ -1634,6 +1694,20 @@ void closeChildInfoPipe(void);
void
sendChildInfo
(
int
process_type
);
void
receiveChildInfo
(
void
);
/* acl.c -- Authentication related prototypes. */
extern
user
*
DefaultUser
;
void
ACLInit
(
void
);
/* Return values for ACLCheckUserCredentials(). */
#define ACL_OK 0
#define ACL_DENIED_CMD 1
#define ACL_DENIED_KEY 2
int
ACLCheckUserCredentials
(
robj
*
username
,
robj
*
password
);
unsigned
long
ACLGetCommandID
(
const
char
*
cmdname
);
user
*
ACLGetUserByName
(
const
char
*
name
,
size_t
namelen
);
int
ACLCheckCommandPerm
(
client
*
c
);
int
ACLSetUser
(
user
*
u
,
const
char
*
op
,
ssize_t
oplen
);
sds
ACLDefaultUserFirstPassword
(
void
);
/* Sorted sets data type */
/* Input flags. */
...
...
@@ -2082,6 +2156,7 @@ void dumpCommand(client *c);
void
objectCommand
(
client
*
c
);
void
memoryCommand
(
client
*
c
);
void
clientCommand
(
client
*
c
);
void
helloCommand
(
client
*
c
);
void
evalCommand
(
client
*
c
);
void
evalShaCommand
(
client
*
c
);
void
scriptCommand
(
client
*
c
);
...
...
@@ -2123,6 +2198,7 @@ void xinfoCommand(client *c);
void
xdelCommand
(
client
*
c
);
void
xtrimCommand
(
client
*
c
);
void
lolwutCommand
(
client
*
c
);
void
aclCommand
(
client
*
c
);
#if defined(__GNUC__)
void
*
calloc
(
size_t
count
,
size_t
size
)
__attribute__
((
deprecated
));
...
...
src/slowlog.c
View file @
adfaf548
...
...
@@ -169,23 +169,23 @@ NULL
return
;
listRewind
(
server
.
slowlog
,
&
li
);
totentries
=
addDeferred
MultiBulkLength
(
c
);
totentries
=
add
Reply
Deferred
Len
(
c
);
while
(
count
--
&&
(
ln
=
listNext
(
&
li
)))
{
int
j
;
se
=
ln
->
value
;
addReply
MultiBulk
Len
(
c
,
6
);
addReply
Array
Len
(
c
,
6
);
addReplyLongLong
(
c
,
se
->
id
);
addReplyLongLong
(
c
,
se
->
time
);
addReplyLongLong
(
c
,
se
->
duration
);
addReply
MultiBulk
Len
(
c
,
se
->
argc
);
addReply
Array
Len
(
c
,
se
->
argc
);
for
(
j
=
0
;
j
<
se
->
argc
;
j
++
)
addReplyBulk
(
c
,
se
->
argv
[
j
]);
addReplyBulkCBuffer
(
c
,
se
->
peerid
,
sdslen
(
se
->
peerid
));
addReplyBulkCBuffer
(
c
,
se
->
cname
,
sdslen
(
se
->
cname
));
sent
++
;
}
setDeferred
MultiBulkLength
(
c
,
totentries
,
sent
);
setDeferred
ArrayLen
(
c
,
totentries
,
sent
);
}
else
{
addReplySubcommandSyntaxError
(
c
);
}
...
...
src/sort.c
View file @
adfaf548
...
...
@@ -505,7 +505,7 @@ void sortCommand(client *c) {
addReplyError
(
c
,
"One or more scores can't be converted into double"
);
}
else
if
(
storekey
==
NULL
)
{
/* STORE option not specified, sent the sorting result to client */
addReply
MultiBulk
Len
(
c
,
outputlen
);
addReply
Array
Len
(
c
,
outputlen
);
for
(
j
=
start
;
j
<=
end
;
j
++
)
{
listNode
*
ln
;
listIter
li
;
...
...
@@ -519,7 +519,7 @@ void sortCommand(client *c) {
if
(
sop
->
type
==
SORT_OP_GET
)
{
if
(
!
val
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
addReplyBulk
(
c
,
val
);
decrRefCount
(
val
);
...
...
src/t_hash.c
View file @
adfaf548
...
...
@@ -641,7 +641,7 @@ static void addHashFieldToReply(client *c, robj *o, sds field) {
int
ret
;
if
(
o
==
NULL
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
return
;
}
...
...
@@ -652,7 +652,7 @@ static void addHashFieldToReply(client *c, robj *o, sds field) {
ret
=
hashTypeGetFromZiplist
(
o
,
field
,
&
vstr
,
&
vlen
,
&
vll
);
if
(
ret
<
0
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
if
(
vstr
)
{
addReplyBulkCBuffer
(
c
,
vstr
,
vlen
);
...
...
@@ -664,7 +664,7 @@ static void addHashFieldToReply(client *c, robj *o, sds field) {
}
else
if
(
o
->
encoding
==
OBJ_ENCODING_HT
)
{
sds
value
=
hashTypeGetFromHashTable
(
o
,
field
);
if
(
value
==
NULL
)
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
else
addReplyBulkCBuffer
(
c
,
value
,
sdslen
(
value
));
}
else
{
...
...
@@ -675,7 +675,7 @@ static void addHashFieldToReply(client *c, robj *o, sds field) {
void
hgetCommand
(
client
*
c
)
{
robj
*
o
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
bulk
))
==
NULL
||
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
o
,
OBJ_HASH
))
return
;
addHashFieldToReply
(
c
,
o
,
c
->
argv
[
2
]
->
ptr
);
...
...
@@ -693,7 +693,7 @@ void hmgetCommand(client *c) {
return
;
}
addReply
MultiBulk
Len
(
c
,
c
->
argc
-
2
);
addReply
Array
Len
(
c
,
c
->
argc
-
2
);
for
(
i
=
2
;
i
<
c
->
argc
;
i
++
)
{
addHashFieldToReply
(
c
,
o
,
c
->
argv
[
i
]
->
ptr
);
}
...
...
@@ -766,17 +766,19 @@ static void addHashIteratorCursorToReply(client *c, hashTypeIterator *hi, int wh
void
genericHgetallCommand
(
client
*
c
,
int
flags
)
{
robj
*
o
;
hashTypeIterator
*
hi
;
int
multiplier
=
0
;
int
length
,
count
=
0
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
emptymultibulk
))
==
NULL
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
o
,
OBJ_HASH
))
return
;
if
(
flags
&
OBJ_HASH_KEY
)
multiplier
++
;
if
(
flags
&
OBJ_HASH_VALUE
)
multiplier
++
;
length
=
hashTypeLength
(
o
)
*
multiplier
;
addReplyMultiBulkLen
(
c
,
length
);
/* We return a map if the user requested keys and values, like in the
* HGETALL case. Otherwise to use a flat array makes more sense. */
length
=
hashTypeLength
(
o
);
if
(
flags
&
OBJ_HASH_KEY
&&
flags
&
OBJ_HASH_VALUE
)
{
addReplyMapLen
(
c
,
length
);
}
else
{
addReplyArrayLen
(
c
,
length
);
}
hi
=
hashTypeInitIterator
(
o
);
while
(
hashTypeNext
(
hi
)
!=
C_ERR
)
{
...
...
@@ -791,6 +793,9 @@ void genericHgetallCommand(client *c, int flags) {
}
hashTypeReleaseIterator
(
hi
);
/* Make sure we returned the right number of elements. */
if
(
flags
&
OBJ_HASH_KEY
&&
flags
&
OBJ_HASH_VALUE
)
count
/=
2
;
serverAssert
(
count
==
length
);
}
...
...
src/t_list.c
View file @
adfaf548
...
...
@@ -298,7 +298,7 @@ void linsertCommand(client *c) {
server
.
dirty
++
;
}
else
{
/* Notify client of a failed insert */
addReply
(
c
,
shared
.
cnegone
);
addReply
LongLong
(
c
,
-
1
);
return
;
}
...
...
@@ -312,7 +312,7 @@ void llenCommand(client *c) {
}
void
lindexCommand
(
client
*
c
)
{
robj
*
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
bulk
);
robj
*
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]
);
if
(
o
==
NULL
||
checkType
(
c
,
o
,
OBJ_LIST
))
return
;
long
index
;
robj
*
value
=
NULL
;
...
...
@@ -331,7 +331,7 @@ void lindexCommand(client *c) {
addReplyBulk
(
c
,
value
);
decrRefCount
(
value
);
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
}
else
{
serverPanic
(
"Unknown list encoding"
);
...
...
@@ -365,12 +365,12 @@ void lsetCommand(client *c) {
}
void
popGenericCommand
(
client
*
c
,
int
where
)
{
robj
*
o
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
bulk
);
robj
*
o
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]
);
if
(
o
==
NULL
||
checkType
(
c
,
o
,
OBJ_LIST
))
return
;
robj
*
value
=
listTypePop
(
o
,
where
);
if
(
value
==
NULL
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
char
*
event
=
(
where
==
LIST_HEAD
)
?
"lpop"
:
"rpop"
;
...
...
@@ -402,7 +402,7 @@ void lrangeCommand(client *c) {
if
((
getLongFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
start
,
NULL
)
!=
C_OK
)
||
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
3
],
&
end
,
NULL
)
!=
C_OK
))
return
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
emptymultibulk
))
==
NULL
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
o
,
OBJ_LIST
))
return
;
llen
=
listTypeLength
(
o
);
...
...
@@ -414,14 +414,14 @@ void lrangeCommand(client *c) {
/* Invariant: start >= 0, so this test will be true when end < 0.
* The range is empty when start > end or start >= length. */
if
(
start
>
end
||
start
>=
llen
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
return
;
}
if
(
end
>=
llen
)
end
=
llen
-
1
;
rangelen
=
(
end
-
start
)
+
1
;
/* Return the result in form of a multi-bulk reply */
addReply
MultiBulk
Len
(
c
,
rangelen
);
addReply
Array
Len
(
c
,
rangelen
);
if
(
o
->
encoding
==
OBJ_ENCODING_QUICKLIST
)
{
listTypeIterator
*
iter
=
listTypeInitIterator
(
o
,
start
,
LIST_TAIL
);
...
...
@@ -564,13 +564,13 @@ void rpoplpushHandlePush(client *c, robj *dstkey, robj *dstobj, robj *value) {
void
rpoplpushCommand
(
client
*
c
)
{
robj
*
sobj
,
*
value
;
if
((
sobj
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
bulk
))
==
NULL
||
checkType
(
c
,
sobj
,
OBJ_LIST
))
return
;
if
((
sobj
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]))
==
NULL
||
checkType
(
c
,
sobj
,
OBJ_LIST
))
return
;
if
(
listTypeLength
(
sobj
)
==
0
)
{
/* This may only happen after loading very old RDB files. Recent
* versions of Redis delete keys of empty lists. */
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
robj
*
dobj
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
2
]);
robj
*
touchedkey
=
c
->
argv
[
1
];
...
...
@@ -639,7 +639,7 @@ int serveClientBlockedOnList(client *receiver, robj *key, robj *dstkey, redisDb
db
->
id
,
argv
,
2
,
PROPAGATE_AOF
|
PROPAGATE_REPL
);
/* BRPOP/BLPOP */
addReply
MultiBulk
Len
(
receiver
,
2
);
addReply
Array
Len
(
receiver
,
2
);
addReplyBulk
(
receiver
,
key
);
addReplyBulk
(
receiver
,
value
);
...
...
@@ -704,7 +704,7 @@ void blockingPopGenericCommand(client *c, int where) {
robj
*
value
=
listTypePop
(
o
,
where
);
serverAssert
(
value
!=
NULL
);
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
addReplyBulk
(
c
,
c
->
argv
[
j
]);
addReplyBulk
(
c
,
value
);
decrRefCount
(
value
);
...
...
@@ -731,7 +731,7 @@ void blockingPopGenericCommand(client *c, int where) {
/* If we are inside a MULTI/EXEC and the list is empty the only thing
* we can do is treating it as a timeout (even with timeout 0). */
if
(
c
->
flags
&
CLIENT_MULTI
)
{
addReply
(
c
,
shared
.
nullmultibulk
);
addReply
NullArray
(
c
);
return
;
}
...
...
@@ -759,7 +759,7 @@ void brpoplpushCommand(client *c) {
if
(
c
->
flags
&
CLIENT_MULTI
)
{
/* Blocking against an empty list in a multi state
* returns immediately. */
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
/* The list is empty and the client blocks. */
blockForKeys
(
c
,
BLOCKED_LIST
,
c
->
argv
+
1
,
1
,
timeout
,
c
->
argv
[
2
],
NULL
);
...
...
src/t_set.c
View file @
adfaf548
...
...
@@ -415,13 +415,13 @@ void spopWithCountCommand(client *c) {
/* Make sure a key with the name inputted exists, and that it's type is
* indeed a set. Otherwise, return nil */
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
emptymultibulk
))
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
set
,
OBJ_SET
))
return
;
/* If count is zero, serve an empty multibulk ASAP to avoid special
* cases later. */
if
(
count
==
0
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
return
;
}
...
...
@@ -455,7 +455,7 @@ void spopWithCountCommand(client *c) {
robj
*
propargv
[
3
];
propargv
[
0
]
=
createStringObject
(
"SREM"
,
4
);
propargv
[
1
]
=
c
->
argv
[
1
];
addReply
MultiBulk
Len
(
c
,
count
);
addReply
Set
Len
(
c
,
count
);
/* Common iteration vars. */
sds
sdsele
;
...
...
@@ -566,8 +566,8 @@ void spopCommand(client *c) {
/* Make sure a key with the name inputted exists, and that it's type is
* indeed a set */
if
((
set
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
bulk
))
==
NULL
||
checkType
(
c
,
set
,
OBJ_SET
))
return
;
if
((
set
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]))
==
NULL
||
checkType
(
c
,
set
,
OBJ_SET
))
return
;
/* Get a random element from the set */
encoding
=
setTypeRandomElement
(
set
,
&
sdsele
,
&
llele
);
...
...
@@ -632,13 +632,13 @@ void srandmemberWithCountCommand(client *c) {
uniq
=
0
;
}
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
emptymultibulk
))
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
set
,
OBJ_SET
))
return
;
size
=
setTypeSize
(
set
);
/* If count is zero, serve it ASAP to avoid special cases later. */
if
(
count
==
0
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
return
;
}
...
...
@@ -647,7 +647,7 @@ void srandmemberWithCountCommand(client *c) {
* This case is trivial and can be served without auxiliary data
* structures. */
if
(
!
uniq
)
{
addReply
MultiBulk
Len
(
c
,
count
);
addReply
Set
Len
(
c
,
count
);
while
(
count
--
)
{
encoding
=
setTypeRandomElement
(
set
,
&
ele
,
&
llele
);
if
(
encoding
==
OBJ_ENCODING_INTSET
)
{
...
...
@@ -737,7 +737,7 @@ void srandmemberWithCountCommand(client *c) {
dictIterator
*
di
;
dictEntry
*
de
;
addReply
MultiBulk
Len
(
c
,
count
);
addReply
Set
Len
(
c
,
count
);
di
=
dictGetIterator
(
d
);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
addReplyBulk
(
c
,
dictGetKey
(
de
));
...
...
@@ -760,8 +760,8 @@ void srandmemberCommand(client *c) {
return
;
}
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
bulk
))
==
NULL
||
checkType
(
c
,
set
,
OBJ_SET
))
return
;
if
((
set
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]))
==
NULL
||
checkType
(
c
,
set
,
OBJ_SET
))
return
;
encoding
=
setTypeRandomElement
(
set
,
&
ele
,
&
llele
);
if
(
encoding
==
OBJ_ENCODING_INTSET
)
{
...
...
@@ -813,7 +813,7 @@ void sinterGenericCommand(client *c, robj **setkeys,
}
addReply
(
c
,
shared
.
czero
);
}
else
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
}
return
;
}
...
...
@@ -833,7 +833,7 @@ void sinterGenericCommand(client *c, robj **setkeys,
* to the output list and save the pointer to later modify it with the
* right length */
if
(
!
dstkey
)
{
replylen
=
addDeferred
MultiBulkLength
(
c
);
replylen
=
add
Reply
Deferred
Len
(
c
);
}
else
{
/* If we have a target key where to store the resulting set
* create this key with an empty set inside */
...
...
@@ -911,7 +911,7 @@ void sinterGenericCommand(client *c, robj **setkeys,
signalModifiedKey
(
c
->
db
,
dstkey
);
server
.
dirty
++
;
}
else
{
setDeferred
MultiBulkLength
(
c
,
replylen
,
cardinality
);
setDeferred
SetLen
(
c
,
replylen
,
cardinality
);
}
zfree
(
sets
);
}
...
...
@@ -1057,7 +1057,7 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum,
/* Output the content of the resulting set, if not in STORE mode */
if
(
!
dstkey
)
{
addReply
MultiBulk
Len
(
c
,
cardinality
);
addReply
Set
Len
(
c
,
cardinality
);
si
=
setTypeInitIterator
(
dstset
);
while
((
ele
=
setTypeNextObject
(
si
))
!=
NULL
)
{
addReplyBulkCBuffer
(
c
,
ele
,
sdslen
(
ele
));
...
...
src/t_stream.c
View file @
adfaf548
...
...
@@ -914,7 +914,7 @@ size_t streamReplyWithRange(client *c, stream *s, streamID *start, streamID *end
}
if
(
!
(
flags
&
STREAM_RWR_RAWENTRIES
))
arraylen_ptr
=
addDeferred
MultiBulkLength
(
c
);
arraylen_ptr
=
add
Reply
Deferred
Len
(
c
);
streamIteratorStart
(
&
si
,
s
,
start
,
end
,
rev
);
while
(
streamIteratorGetID
(
&
si
,
&
id
,
&
numfields
))
{
/* Update the group last_id if needed. */
...
...
@@ -925,9 +925,10 @@ size_t streamReplyWithRange(client *c, stream *s, streamID *start, streamID *end
/* Emit a two elements array for each item. The first is
* the ID, the second is an array of field-value pairs. */
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
addReplyStreamID
(
c
,
&
id
);
addReplyMultiBulkLen
(
c
,
numfields
*
2
);
addReplyMapLen
(
c
,
numfields
);
/* Emit the field-value pairs. */
while
(
numfields
--
)
{
...
...
@@ -993,7 +994,7 @@ size_t streamReplyWithRange(client *c, stream *s, streamID *start, streamID *end
if
(
count
&&
count
==
arraylen
)
break
;
}
streamIteratorStop
(
&
si
);
if
(
arraylen_ptr
)
setDeferred
MultiBulkLength
(
c
,
arraylen_ptr
,
arraylen
);
if
(
arraylen_ptr
)
setDeferred
ArrayLen
(
c
,
arraylen_ptr
,
arraylen
);
return
arraylen
;
}
...
...
@@ -1018,7 +1019,7 @@ size_t streamReplyWithRangeFromConsumerPEL(client *c, stream *s, streamID *start
if
(
end
)
streamEncodeID
(
endkey
,
end
);
size_t
arraylen
=
0
;
void
*
arraylen_ptr
=
addDeferred
MultiBulkLength
(
c
);
void
*
arraylen_ptr
=
add
Reply
Deferred
Len
(
c
);
raxStart
(
&
ri
,
consumer
->
pel
);
raxSeek
(
&
ri
,
">="
,
startkey
,
sizeof
(
startkey
));
while
(
raxNext
(
&
ri
)
&&
(
!
count
||
arraylen
<
count
))
{
...
...
@@ -1032,11 +1033,11 @@ size_t streamReplyWithRangeFromConsumerPEL(client *c, stream *s, streamID *start
* about a message that's no longer here because was removed
* by the user by other means. In that case we signal it emitting
* the ID but then a NULL entry for the fields. */
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
streamID
id
;
streamDecodeID
(
ri
.
key
,
&
id
);
addReplyStreamID
(
c
,
&
id
);
addReply
(
c
,
shared
.
nullmultibulk
);
addReply
NullArray
(
c
);
}
else
{
streamNACK
*
nack
=
ri
.
data
;
nack
->
delivery_time
=
mstime
();
...
...
@@ -1045,7 +1046,7 @@ size_t streamReplyWithRangeFromConsumerPEL(client *c, stream *s, streamID *start
arraylen
++
;
}
raxStop
(
&
ri
);
setDeferred
MultiBulkLength
(
c
,
arraylen_ptr
,
arraylen
);
setDeferred
ArrayLen
(
c
,
arraylen_ptr
,
arraylen
);
return
arraylen
;
}
...
...
@@ -1286,12 +1287,13 @@ void xrangeGenericCommand(client *c, int rev) {
}
/* Return the specified range to the user. */
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
emptymultibulk
))
==
NULL
||
checkType
(
c
,
o
,
OBJ_STREAM
))
return
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
emptyarray
))
==
NULL
||
checkType
(
c
,
o
,
OBJ_STREAM
))
return
;
s
=
o
->
ptr
;
if
(
count
==
0
)
{
addReply
(
c
,
shared
.
nullmultibulk
);
addReply
NullArray
(
c
);
}
else
{
if
(
count
==
-
1
)
count
=
0
;
streamReplyWithRange
(
c
,
s
,
&
startid
,
&
endid
,
count
,
rev
,
NULL
,
NULL
,
0
,
NULL
);
...
...
@@ -1505,7 +1507,7 @@ void xreadCommand(client *c) {
if
(
serve_synchronously
)
{
arraylen
++
;
if
(
arraylen
==
1
)
arraylen_ptr
=
addDeferred
MultiBulkLength
(
c
);
if
(
arraylen
==
1
)
arraylen_ptr
=
add
Reply
Deferred
Len
(
c
);
/* streamReplyWithRange() handles the 'start' ID as inclusive,
* so start from the next ID, since we want only messages with
* IDs greater than start. */
...
...
@@ -1514,7 +1516,7 @@ void xreadCommand(client *c) {
/* Emit the two elements sub-array consisting of the name
* of the stream and the data we extracted from it. */
addReplyMultiBulk
Len
(
c
,
2
);
if
(
c
->
resp
==
2
)
addReplyArray
Len
(
c
,
2
);
addReplyBulk
(
c
,
c
->
argv
[
streams_arg
+
i
]);
streamConsumer
*
consumer
=
NULL
;
if
(
groups
)
consumer
=
streamLookupConsumer
(
groups
[
i
],
...
...
@@ -1532,7 +1534,10 @@ void xreadCommand(client *c) {
/* We replied synchronously! Set the top array len and return to caller. */
if
(
arraylen
)
{
setDeferredMultiBulkLength
(
c
,
arraylen_ptr
,
arraylen
);
if
(
c
->
resp
==
2
)
setDeferredArrayLen
(
c
,
arraylen_ptr
,
arraylen
);
else
setDeferredMapLen
(
c
,
arraylen_ptr
,
arraylen
);
goto
cleanup
;
}
...
...
@@ -1541,7 +1546,7 @@ void xreadCommand(client *c) {
/* If we are inside a MULTI/EXEC and the list is empty the only thing
* we can do is treating it as a timeout (even with timeout 0). */
if
(
c
->
flags
&
CLIENT_MULTI
)
{
addReply
(
c
,
shared
.
nullmultibulk
);
addReply
NullArray
(
c
);
goto
cleanup
;
}
blockForKeys
(
c
,
BLOCKED_STREAM
,
c
->
argv
+
streams_arg
,
streams_count
,
...
...
@@ -1570,7 +1575,7 @@ void xreadCommand(client *c) {
/* No BLOCK option, nor any stream we can serve. Reply as with a
* timeout happened. */
addReply
(
c
,
shared
.
nullmultibulk
);
addReply
NullArray
(
c
);
/* Continue to cleanup... */
cleanup:
/* Cleanup. */
...
...
@@ -1960,14 +1965,14 @@ void xpendingCommand(client *c) {
/* XPENDING <key> <group> variant. */
if
(
justinfo
)
{
addReply
MultiBulk
Len
(
c
,
4
);
addReply
Array
Len
(
c
,
4
);
/* Total number of messages in the PEL. */
addReplyLongLong
(
c
,
raxSize
(
group
->
pel
));
/* First and last IDs. */
if
(
raxSize
(
group
->
pel
)
==
0
)
{
addReply
(
c
,
shared
.
nullbulk
);
/* Start. */
addReply
(
c
,
shared
.
nullbulk
);
/* End. */
addReply
(
c
,
shared
.
nullmultibulk
);
/* Clients. */
addReply
Null
(
c
);
/* Start. */
addReply
Null
(
c
);
/* End. */
addReply
NullArray
(
c
);
/* Clients. */
}
else
{
/* Start. */
raxIterator
ri
;
...
...
@@ -1987,17 +1992,17 @@ void xpendingCommand(client *c) {
/* Consumers with pending messages. */
raxStart
(
&
ri
,
group
->
consumers
);
raxSeek
(
&
ri
,
"^"
,
NULL
,
0
);
void
*
arraylen_ptr
=
addDeferred
MultiBulkLength
(
c
);
void
*
arraylen_ptr
=
add
Reply
Deferred
Len
(
c
);
size_t
arraylen
=
0
;
while
(
raxNext
(
&
ri
))
{
streamConsumer
*
consumer
=
ri
.
data
;
if
(
raxSize
(
consumer
->
pel
)
==
0
)
continue
;
addReply
MultiBulk
Len
(
c
,
2
);
addReply
Array
Len
(
c
,
2
);
addReplyBulkCBuffer
(
c
,
ri
.
key
,
ri
.
key_len
);
addReplyBulkLongLong
(
c
,
raxSize
(
consumer
->
pel
));
arraylen
++
;
}
setDeferred
MultiBulkLength
(
c
,
arraylen_ptr
,
arraylen
);
setDeferred
ArrayLen
(
c
,
arraylen_ptr
,
arraylen
);
raxStop
(
&
ri
);
}
}
...
...
@@ -2010,7 +2015,7 @@ void xpendingCommand(client *c) {
/* If a consumer name was mentioned but it does not exist, we can
* just return an empty array. */
if
(
consumername
&&
consumer
==
NULL
)
{
addReply
MultiBulk
Len
(
c
,
0
);
addReply
Array
Len
(
c
,
0
);
return
;
}
...
...
@@ -2024,7 +2029,7 @@ void xpendingCommand(client *c) {
streamEncodeID
(
endkey
,
&
endid
);
raxStart
(
&
ri
,
pel
);
raxSeek
(
&
ri
,
">="
,
startkey
,
sizeof
(
startkey
));
void
*
arraylen_ptr
=
addDeferred
MultiBulkLength
(
c
);
void
*
arraylen_ptr
=
add
Reply
Deferred
Len
(
c
);
size_t
arraylen
=
0
;
while
(
count
&&
raxNext
(
&
ri
)
&&
memcmp
(
ri
.
key
,
endkey
,
ri
.
key_len
)
<=
0
)
{
...
...
@@ -2032,7 +2037,7 @@ void xpendingCommand(client *c) {
arraylen
++
;
count
--
;
addReply
MultiBulk
Len
(
c
,
4
);
addReply
Array
Len
(
c
,
4
);
/* Entry ID. */
streamID
id
;
...
...
@@ -2052,7 +2057,7 @@ void xpendingCommand(client *c) {
addReplyLongLong
(
c
,
nack
->
delivery_count
);
}
raxStop
(
&
ri
);
setDeferred
MultiBulkLength
(
c
,
arraylen_ptr
,
arraylen
);
setDeferred
ArrayLen
(
c
,
arraylen_ptr
,
arraylen
);
}
}
...
...
@@ -2221,7 +2226,7 @@ void xclaimCommand(client *c) {
/* Do the actual claiming. */
streamConsumer
*
consumer
=
streamLookupConsumer
(
group
,
c
->
argv
[
3
]
->
ptr
,
1
);
void
*
arraylenptr
=
addDeferred
MultiBulkLength
(
c
);
void
*
arraylenptr
=
add
Reply
Deferred
Len
(
c
);
size_t
arraylen
=
0
;
for
(
int
j
=
5
;
j
<=
last_id_arg
;
j
++
)
{
streamID
id
;
...
...
@@ -2284,7 +2289,7 @@ void xclaimCommand(client *c) {
}
else
{
size_t
emitted
=
streamReplyWithRange
(
c
,
o
->
ptr
,
&
id
,
&
id
,
1
,
0
,
NULL
,
NULL
,
STREAM_RWR_RAWENTRIES
,
NULL
);
if
(
!
emitted
)
addReply
(
c
,
shared
.
nullbulk
);
if
(
!
emitted
)
addReply
Null
(
c
);
}
arraylen
++
;
...
...
@@ -2298,7 +2303,7 @@ void xclaimCommand(client *c) {
streamPropagateGroupID
(
c
,
c
->
argv
[
1
],
group
,
c
->
argv
[
2
]);
server
.
dirty
++
;
}
setDeferred
MultiBulkLength
(
c
,
arraylenptr
,
arraylen
);
setDeferred
ArrayLen
(
c
,
arraylenptr
,
arraylen
);
preventCommandPropagation
(
c
);
}
...
...
@@ -2463,7 +2468,7 @@ NULL
return
;
}
addReply
MultiBulk
Len
(
c
,
raxSize
(
cg
->
consumers
));
addReply
Array
Len
(
c
,
raxSize
(
cg
->
consumers
));
raxIterator
ri
;
raxStart
(
&
ri
,
cg
->
consumers
);
raxSeek
(
&
ri
,
"^"
,
NULL
,
0
);
...
...
@@ -2473,7 +2478,7 @@ NULL
mstime_t
idle
=
now
-
consumer
->
seen_time
;
if
(
idle
<
0
)
idle
=
0
;
addReplyM
ultiBulk
Len
(
c
,
6
);
addReplyM
ap
Len
(
c
,
3
);
addReplyBulkCString
(
c
,
"name"
);
addReplyBulkCBuffer
(
c
,
consumer
->
name
,
sdslen
(
consumer
->
name
));
addReplyBulkCString
(
c
,
"pending"
);
...
...
@@ -2485,17 +2490,17 @@ NULL
}
else
if
(
!
strcasecmp
(
opt
,
"GROUPS"
)
&&
c
->
argc
==
3
)
{
/* XINFO GROUPS <key>. */
if
(
s
->
cgroups
==
NULL
)
{
addReply
MultiBulk
Len
(
c
,
0
);
addReply
Array
Len
(
c
,
0
);
return
;
}
addReply
MultiBulk
Len
(
c
,
raxSize
(
s
->
cgroups
));
addReply
Array
Len
(
c
,
raxSize
(
s
->
cgroups
));
raxIterator
ri
;
raxStart
(
&
ri
,
s
->
cgroups
);
raxSeek
(
&
ri
,
"^"
,
NULL
,
0
);
while
(
raxNext
(
&
ri
))
{
streamCG
*
cg
=
ri
.
data
;
addReplyM
ultiBulk
Len
(
c
,
8
);
addReplyM
ap
Len
(
c
,
4
);
addReplyBulkCString
(
c
,
"name"
);
addReplyBulkCBuffer
(
c
,
ri
.
key
,
ri
.
key_len
);
addReplyBulkCString
(
c
,
"consumers"
);
...
...
@@ -2508,7 +2513,7 @@ NULL
raxStop
(
&
ri
);
}
else
if
(
!
strcasecmp
(
opt
,
"STREAM"
)
&&
c
->
argc
==
3
)
{
/* XINFO STREAM <key> (or the alias XINFO <key>). */
addReplyM
ultiBulk
Len
(
c
,
14
);
addReplyM
ap
Len
(
c
,
7
);
addReplyBulkCString
(
c
,
"length"
);
addReplyLongLong
(
c
,
s
->
length
);
addReplyBulkCString
(
c
,
"radix-tree-keys"
);
...
...
@@ -2529,11 +2534,11 @@ NULL
addReplyBulkCString
(
c
,
"first-entry"
);
count
=
streamReplyWithRange
(
c
,
s
,
&
start
,
&
end
,
1
,
0
,
NULL
,
NULL
,
STREAM_RWR_RAWENTRIES
,
NULL
);
if
(
!
count
)
addReply
(
c
,
shared
.
nullbulk
);
if
(
!
count
)
addReply
Null
(
c
);
addReplyBulkCString
(
c
,
"last-entry"
);
count
=
streamReplyWithRange
(
c
,
s
,
&
start
,
&
end
,
1
,
1
,
NULL
,
NULL
,
STREAM_RWR_RAWENTRIES
,
NULL
);
if
(
!
count
)
addReply
(
c
,
shared
.
nullbulk
);
if
(
!
count
)
addReply
Null
(
c
);
}
else
{
addReplySubcommandSyntaxError
(
c
);
}
...
...
src/t_string.c
View file @
adfaf548
...
...
@@ -80,7 +80,7 @@ void setGenericCommand(client *c, int flags, robj *key, robj *val, robj *expire,
if
((
flags
&
OBJ_SET_NX
&&
lookupKeyWrite
(
c
->
db
,
key
)
!=
NULL
)
||
(
flags
&
OBJ_SET_XX
&&
lookupKeyWrite
(
c
->
db
,
key
)
==
NULL
))
{
addReply
(
c
,
abort_reply
?
abort_reply
:
shared
.
null
bulk
);
addReply
(
c
,
abort_reply
?
abort_reply
:
shared
.
null
[
c
->
resp
]
);
return
;
}
setKey
(
c
->
db
,
key
,
val
);
...
...
@@ -157,7 +157,7 @@ void psetexCommand(client *c) {
int
getGenericCommand
(
client
*
c
)
{
robj
*
o
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
bulk
))
==
NULL
)
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
null
[
c
->
resp
]
))
==
NULL
)
return
C_OK
;
if
(
o
->
type
!=
OBJ_STRING
)
{
...
...
@@ -285,14 +285,14 @@ void getrangeCommand(client *c) {
void
mgetCommand
(
client
*
c
)
{
int
j
;
addReply
MultiBulk
Len
(
c
,
c
->
argc
-
1
);
addReply
Array
Len
(
c
,
c
->
argc
-
1
);
for
(
j
=
1
;
j
<
c
->
argc
;
j
++
)
{
robj
*
o
=
lookupKeyRead
(
c
->
db
,
c
->
argv
[
j
]);
if
(
o
==
NULL
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
if
(
o
->
type
!=
OBJ_STRING
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
addReplyBulk
(
c
,
o
);
}
...
...
src/t_zset.c
View file @
adfaf548
...
...
@@ -1638,7 +1638,7 @@ reply_to_client:
if
(
processed
)
addReplyDouble
(
c
,
score
);
else
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
/* ZADD. */
addReplyLongLong
(
c
,
ch
?
added
+
updated
:
added
);
}
...
...
@@ -2427,7 +2427,7 @@ void zrangeGenericCommand(client *c, int reverse) {
return
;
}
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
emptymultibulk
))
==
NULL
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
zobj
,
OBJ_ZSET
))
return
;
/* Sanitize indexes. */
...
...
@@ -2439,14 +2439,19 @@ void zrangeGenericCommand(client *c, int reverse) {
/* Invariant: start >= 0, so this test will be true when end < 0.
* The range is empty when start > end or start >= length. */
if
(
start
>
end
||
start
>=
llen
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
return
;
}
if
(
end
>=
llen
)
end
=
llen
-
1
;
rangelen
=
(
end
-
start
)
+
1
;
/* Return the result in form of a multi-bulk reply */
addReplyMultiBulkLen
(
c
,
withscores
?
(
rangelen
*
2
)
:
rangelen
);
/* Return the result in form of a multi-bulk reply. RESP3 clients
* will receive sub arrays with score->element, while RESP2 returned
* a flat array. */
if
(
withscores
&&
c
->
resp
==
2
)
addReplyArrayLen
(
c
,
rangelen
*
2
);
else
addReplyArrayLen
(
c
,
rangelen
);
if
(
zobj
->
encoding
==
OBJ_ENCODING_ZIPLIST
)
{
unsigned
char
*
zl
=
zobj
->
ptr
;
...
...
@@ -2466,13 +2471,13 @@ void zrangeGenericCommand(client *c, int reverse) {
while
(
rangelen
--
)
{
serverAssertWithInfo
(
c
,
zobj
,
eptr
!=
NULL
&&
sptr
!=
NULL
);
serverAssertWithInfo
(
c
,
zobj
,
ziplistGet
(
eptr
,
&
vstr
,
&
vlen
,
&
vlong
));
if
(
withscores
&&
c
->
resp
>
2
)
addReplyArrayLen
(
c
,
2
);
if
(
vstr
==
NULL
)
addReplyBulkLongLong
(
c
,
vlong
);
else
addReplyBulkCBuffer
(
c
,
vstr
,
vlen
);
if
(
withscores
)
addReplyDouble
(
c
,
zzlGetScore
(
sptr
));
if
(
withscores
)
addReplyDouble
(
c
,
zzlGetScore
(
sptr
));
if
(
reverse
)
zzlPrev
(
zl
,
&
eptr
,
&
sptr
);
...
...
@@ -2500,9 +2505,9 @@ void zrangeGenericCommand(client *c, int reverse) {
while
(
rangelen
--
)
{
serverAssertWithInfo
(
c
,
zobj
,
ln
!=
NULL
);
ele
=
ln
->
ele
;
if
(
withscores
&&
c
->
resp
>
2
)
addReplyArrayLen
(
c
,
2
);
addReplyBulkCBuffer
(
c
,
ele
,
sdslen
(
ele
));
if
(
withscores
)
addReplyDouble
(
c
,
ln
->
score
);
if
(
withscores
)
addReplyDouble
(
c
,
ln
->
score
);
ln
=
reverse
?
ln
->
backward
:
ln
->
level
[
0
].
forward
;
}
}
else
{
...
...
@@ -2570,7 +2575,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
}
/* Ok, lookup the key and get the range */
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
emptymultibulk
))
==
NULL
||
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
zobj
,
OBJ_ZSET
))
return
;
if
(
zobj
->
encoding
==
OBJ_ENCODING_ZIPLIST
)
{
...
...
@@ -2590,7 +2595,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
/* No "first" element in the specified interval. */
if
(
eptr
==
NULL
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
return
;
}
...
...
@@ -2601,7 +2606,7 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
/* We don't know in advance how many matching elements there are in the
* list, so we push this object that will represent the multi-bulk
* length in the output buffer, and will "fix" it later */
replylen
=
addDeferred
MultiBulkLength
(
c
);
replylen
=
add
Reply
Deferred
Len
(
c
);
/* If there is an offset, just traverse the number of elements without
* checking the score because that is done in the next loop. */
...
...
@@ -2623,19 +2628,18 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
if
(
!
zslValueLteMax
(
score
,
&
range
))
break
;
}
/* We know the element exists, so ziplistGet should always succeed */
/* We know the element exists, so ziplistGet should always
* succeed */
serverAssertWithInfo
(
c
,
zobj
,
ziplistGet
(
eptr
,
&
vstr
,
&
vlen
,
&
vlong
));
rangelen
++
;
if
(
withscores
&&
c
->
resp
>
2
)
addReplyArrayLen
(
c
,
2
);
if
(
vstr
==
NULL
)
{
addReplyBulkLongLong
(
c
,
vlong
);
}
else
{
addReplyBulkCBuffer
(
c
,
vstr
,
vlen
);
}
if
(
withscores
)
{
addReplyDouble
(
c
,
score
);
}
if
(
withscores
)
addReplyDouble
(
c
,
score
);
/* Move to next node */
if
(
reverse
)
{
...
...
@@ -2658,14 +2662,14 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
/* No "first" element in the specified interval. */
if
(
ln
==
NULL
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
return
;
}
/* We don't know in advance how many matching elements there are in the
* list, so we push this object that will represent the multi-bulk
* length in the output buffer, and will "fix" it later */
replylen
=
addDeferred
MultiBulkLength
(
c
);
replylen
=
add
Reply
Deferred
Len
(
c
);
/* If there is an offset, just traverse the number of elements without
* checking the score because that is done in the next loop. */
...
...
@@ -2686,11 +2690,9 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
}
rangelen
++
;
if
(
withscores
&&
c
->
resp
>
2
)
addReplyArrayLen
(
c
,
2
);
addReplyBulkCBuffer
(
c
,
ln
->
ele
,
sdslen
(
ln
->
ele
));
if
(
withscores
)
{
addReplyDouble
(
c
,
ln
->
score
);
}
if
(
withscores
)
addReplyDouble
(
c
,
ln
->
score
);
/* Move to next node */
if
(
reverse
)
{
...
...
@@ -2703,11 +2705,8 @@ void genericZrangebyscoreCommand(client *c, int reverse) {
serverPanic
(
"Unknown sorted set encoding"
);
}
if
(
withscores
)
{
rangelen
*=
2
;
}
setDeferredMultiBulkLength
(
c
,
replylen
,
rangelen
);
if
(
withscores
&&
c
->
resp
==
2
)
rangelen
*=
2
;
setDeferredArrayLen
(
c
,
replylen
,
rangelen
);
}
void
zrangebyscoreCommand
(
client
*
c
)
{
...
...
@@ -2918,7 +2917,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
}
/* Ok, lookup the key and get the range */
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
emptymultibulk
))
==
NULL
||
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
zobj
,
OBJ_ZSET
))
{
zslFreeLexRange
(
&
range
);
...
...
@@ -2941,7 +2940,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
/* No "first" element in the specified interval. */
if
(
eptr
==
NULL
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
zslFreeLexRange
(
&
range
);
return
;
}
...
...
@@ -2953,7 +2952,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
/* We don't know in advance how many matching elements there are in the
* list, so we push this object that will represent the multi-bulk
* length in the output buffer, and will "fix" it later */
replylen
=
addDeferred
MultiBulkLength
(
c
);
replylen
=
add
Reply
Deferred
Len
(
c
);
/* If there is an offset, just traverse the number of elements without
* checking the score because that is done in the next loop. */
...
...
@@ -3005,7 +3004,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
/* No "first" element in the specified interval. */
if
(
ln
==
NULL
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
zslFreeLexRange
(
&
range
);
return
;
}
...
...
@@ -3013,7 +3012,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
/* We don't know in advance how many matching elements there are in the
* list, so we push this object that will represent the multi-bulk
* length in the output buffer, and will "fix" it later */
replylen
=
addDeferred
MultiBulkLength
(
c
);
replylen
=
add
Reply
Deferred
Len
(
c
);
/* If there is an offset, just traverse the number of elements without
* checking the score because that is done in the next loop. */
...
...
@@ -3048,7 +3047,7 @@ void genericZrangebylexCommand(client *c, int reverse) {
}
zslFreeLexRange
(
&
range
);
setDeferred
MultiBulkLength
(
c
,
replylen
,
rangelen
);
setDeferred
ArrayLen
(
c
,
replylen
,
rangelen
);
}
void
zrangebylexCommand
(
client
*
c
)
{
...
...
@@ -3074,11 +3073,11 @@ void zscoreCommand(client *c) {
robj
*
zobj
;
double
score
;
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
null
bulk
))
==
NULL
||
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
zobj
,
OBJ_ZSET
))
return
;
if
(
zsetScore
(
zobj
,
c
->
argv
[
2
]
->
ptr
,
&
score
)
==
C_ERR
)
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
else
{
addReplyDouble
(
c
,
score
);
}
...
...
@@ -3090,7 +3089,7 @@ void zrankGenericCommand(client *c, int reverse) {
robj
*
zobj
;
long
rank
;
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
null
bulk
))
==
NULL
||
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
key
,
shared
.
null
[
c
->
resp
]
))
==
NULL
||
checkType
(
c
,
zobj
,
OBJ_ZSET
))
return
;
serverAssertWithInfo
(
c
,
ele
,
sdsEncodedObject
(
ele
));
...
...
@@ -3098,7 +3097,7 @@ void zrankGenericCommand(client *c, int reverse) {
if
(
rank
>=
0
)
{
addReplyLongLong
(
c
,
rank
);
}
else
{
addReply
(
c
,
shared
.
nullbulk
);
addReply
Null
(
c
);
}
}
...
...
@@ -3156,11 +3155,11 @@ void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey
/* No candidate for zpopping, return empty. */
if
(
!
zobj
)
{
addReply
(
c
,
shared
.
emptymultibulk
);
addReply
Null
(
c
);
return
;
}
void
*
arraylen_ptr
=
addDeferred
MultiBulkLength
(
c
);
void
*
arraylen_ptr
=
add
Reply
Deferred
Len
(
c
);
long
arraylen
=
0
;
/* We emit the key only for the blocking variant. */
...
...
@@ -3227,7 +3226,7 @@ void genericZpopCommand(client *c, robj **keyv, int keyc, int where, int emitkey
}
}
while
(
--
count
);
setDeferred
MultiBulkLength
(
c
,
arraylen_ptr
,
arraylen
+
(
emitkey
!=
0
));
setDeferred
ArrayLen
(
c
,
arraylen_ptr
,
arraylen
+
(
emitkey
!=
0
));
}
/* ZPOPMIN key [<count>] */
...
...
@@ -3282,7 +3281,7 @@ void blockingGenericZpopCommand(client *c, int where) {
/* If we are inside a MULTI/EXEC and the zset is empty the only thing
* we can do is treating it as a timeout (even with timeout 0). */
if
(
c
->
flags
&
CLIENT_MULTI
)
{
addReply
(
c
,
shared
.
nullmultibulk
);
addReply
NullArray
(
c
);
return
;
}
...
...
tests/integration/replication.tcl
View file @
adfaf548
...
...
@@ -275,7 +275,6 @@ start_server {tags {"repl"}} {
start_server
{}
{
test
"Master stream is correctly processed while the replica has a script in -BUSY state"
{
set slave
[
srv 0 client
]
puts
[
srv 0 port
]
$slave config set lua-time-limit 500
$slave slaveof $master_host $master_port
...
...
tests/unit/auth.tcl
View file @
adfaf548
...
...
@@ -2,14 +2,14 @@ start_server {tags {"auth"}} {
test
{
AUTH fails if there is no password configured server side
}
{
catch
{
r auth foo
}
err
set _ $err
}
{
ERR*
no
password*
}
}
{
ERR*
any
password*
}
}
start_server
{
tags
{
"auth"
}
overrides
{
requirepass foobar
}}
{
test
{
AUTH fails when a wrong password is given
}
{
catch
{
r auth wrong!
}
err
set _ $err
}
{
ERR*invalid password
}
}
{
WRONGPASS*
}
test
{
Arbitrary command gives an error when AUTH is required
}
{
catch
{
r set foo bar
}
err
...
...
tests/unit/dump.tcl
View file @
adfaf548
...
...
@@ -362,7 +362,7 @@ start_server {tags {"dump"}} {
r -1 lpush list a b c d
$second config set requirepass foobar2
catch
{
r -1 migrate $second_host $second_port list 9 5000 AUTH foobar
}
err
assert_match
{
*
invalid password
*
}
$err
assert_match
{
*
WRONGPASS
*
}
$err
}
}
}
Prev
1
2
3
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