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
cc1cb7e5
Commit
cc1cb7e5
authored
Mar 29, 2011
by
antirez
Browse files
Merge remote branch 'origin/getkeys' into unstable
parents
e360e3bb
a07bc926
Changes
4
Show whitespace changes
Inline
Side-by-side
src/db.c
View file @
cc1cb7e5
...
...
@@ -616,3 +616,76 @@ void persistCommand(redisClient *c) {
}
}
}
/* -----------------------------------------------------------------------------
* API to get key arguments from commands
* ---------------------------------------------------------------------------*/
int
*
getKeysUsingCommandTable
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
)
{
int
j
,
i
=
0
,
last
,
*
keys
;
REDIS_NOTUSED
(
argv
);
if
(
cmd
->
firstkey
==
0
)
{
*
numkeys
=
0
;
return
NULL
;
}
last
=
cmd
->
lastkey
;
if
(
last
<
0
)
last
=
argc
+
last
;
keys
=
zmalloc
(
sizeof
(
int
)
*
((
last
-
cmd
->
firstkey
)
+
1
));
for
(
j
=
cmd
->
firstkey
;
j
<=
last
;
j
+=
cmd
->
keystep
)
{
redisAssert
(
j
<
argc
);
keys
[
i
++
]
=
j
;
}
*
numkeys
=
i
;
return
keys
;
}
int
*
getKeysFromCommand
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
)
{
if
(
cmd
->
getkeys_proc
)
{
return
cmd
->
getkeys_proc
(
cmd
,
argv
,
argc
,
numkeys
,
flags
);
}
else
{
return
getKeysUsingCommandTable
(
cmd
,
argv
,
argc
,
numkeys
);
}
}
void
getKeysFreeResult
(
int
*
result
)
{
zfree
(
result
);
}
int
*
noPreloadGetKeys
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
)
{
if
(
flags
&
REDIS_GETKEYS_PRELOAD
)
{
*
numkeys
=
0
;
return
NULL
;
}
else
{
return
getKeysUsingCommandTable
(
cmd
,
argv
,
argc
,
numkeys
);
}
}
int
*
renameGetKeys
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
)
{
if
(
flags
&
REDIS_GETKEYS_PRELOAD
)
{
int
*
keys
=
zmalloc
(
sizeof
(
int
));
*
numkeys
=
1
;
keys
[
0
]
=
1
;
return
keys
;
}
else
{
return
getKeysUsingCommandTable
(
cmd
,
argv
,
argc
,
numkeys
);
}
}
int
*
zunionInterGetKeys
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
)
{
int
i
,
num
,
*
keys
;
REDIS_NOTUSED
(
cmd
);
REDIS_NOTUSED
(
flags
);
num
=
atoi
(
argv
[
2
]
->
ptr
);
/* Sanity check. Don't return any key if the command is going to
* reply with syntax error. */
if
(
num
>
(
argc
-
3
))
{
*
numkeys
=
0
;
return
NULL
;
}
keys
=
zmalloc
(
sizeof
(
int
)
*
num
);
for
(
i
=
0
;
i
<
num
;
i
++
)
keys
[
i
]
=
3
+
i
;
*
numkeys
=
num
;
return
keys
;
}
src/dscache.c
View file @
cc1cb7e5
...
...
@@ -903,59 +903,6 @@ int waitForSwappedKey(redisClient *c, robj *key) {
return
1
;
}
/* Preload keys for any command with first, last and step values for
* the command keys prototype, as defined in the command table. */
void
waitForMultipleSwappedKeys
(
redisClient
*
c
,
struct
redisCommand
*
cmd
,
int
argc
,
robj
**
argv
)
{
int
j
,
last
;
if
(
cmd
->
vm_firstkey
==
0
)
return
;
last
=
cmd
->
vm_lastkey
;
if
(
last
<
0
)
last
=
argc
+
last
;
for
(
j
=
cmd
->
vm_firstkey
;
j
<=
last
;
j
+=
cmd
->
vm_keystep
)
{
redisAssert
(
j
<
argc
);
waitForSwappedKey
(
c
,
argv
[
j
]);
}
}
/* Preload keys needed for the ZUNIONSTORE and ZINTERSTORE commands.
* Note that the number of keys to preload is user-defined, so we need to
* apply a sanity check against argc. */
void
zunionInterBlockClientOnSwappedKeys
(
redisClient
*
c
,
struct
redisCommand
*
cmd
,
int
argc
,
robj
**
argv
)
{
int
i
,
num
;
REDIS_NOTUSED
(
cmd
);
num
=
atoi
(
argv
[
2
]
->
ptr
);
if
(
num
>
(
argc
-
3
))
return
;
for
(
i
=
0
;
i
<
num
;
i
++
)
{
waitForSwappedKey
(
c
,
argv
[
3
+
i
]);
}
}
/* Preload keys needed to execute the entire MULTI/EXEC block.
*
* This function is called by blockClientOnSwappedKeys when EXEC is issued,
* and will block the client when any command requires a swapped out value. */
void
execBlockClientOnSwappedKeys
(
redisClient
*
c
,
struct
redisCommand
*
cmd
,
int
argc
,
robj
**
argv
)
{
int
i
,
margc
;
struct
redisCommand
*
mcmd
;
robj
**
margv
;
REDIS_NOTUSED
(
cmd
);
REDIS_NOTUSED
(
argc
);
REDIS_NOTUSED
(
argv
);
if
(
!
(
c
->
flags
&
REDIS_MULTI
))
return
;
for
(
i
=
0
;
i
<
c
->
mstate
.
count
;
i
++
)
{
mcmd
=
c
->
mstate
.
commands
[
i
].
cmd
;
margc
=
c
->
mstate
.
commands
[
i
].
argc
;
margv
=
c
->
mstate
.
commands
[
i
].
argv
;
if
(
mcmd
->
vm_preload_proc
!=
NULL
)
{
mcmd
->
vm_preload_proc
(
c
,
mcmd
,
margc
,
margv
);
}
else
{
waitForMultipleSwappedKeys
(
c
,
mcmd
,
margc
,
margv
);
}
}
}
/* Is this client attempting to run a command against swapped keys?
* If so, block it ASAP, load the keys in background, then resume it.
*
...
...
@@ -967,10 +914,39 @@ void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int
* Return 1 if the client is marked as blocked, 0 if the client can
* continue as the keys it is going to access appear to be in memory. */
int
blockClientOnSwappedKeys
(
redisClient
*
c
,
struct
redisCommand
*
cmd
)
{
if
(
cmd
->
vm_preload_proc
!=
NULL
)
{
cmd
->
vm_preload_proc
(
c
,
cmd
,
c
->
argc
,
c
->
argv
);
int
*
keyindex
,
numkeys
,
j
,
i
;
/* EXEC is a special case, we need to preload all the commands
* queued into the transaction */
if
(
cmd
->
proc
==
execCommand
)
{
struct
redisCommand
*
mcmd
;
robj
**
margv
;
int
margc
;
if
(
!
(
c
->
flags
&
REDIS_MULTI
))
return
0
;
for
(
i
=
0
;
i
<
c
->
mstate
.
count
;
i
++
)
{
mcmd
=
c
->
mstate
.
commands
[
i
].
cmd
;
margc
=
c
->
mstate
.
commands
[
i
].
argc
;
margv
=
c
->
mstate
.
commands
[
i
].
argv
;
keyindex
=
getKeysFromCommand
(
mcmd
,
margv
,
margc
,
&
numkeys
,
REDIS_GETKEYS_PRELOAD
);
for
(
j
=
0
;
j
<
numkeys
;
j
++
)
{
redisLog
(
REDIS_DEBUG
,
"Preloading %s"
,
(
char
*
)
margv
[
keyindex
[
j
]]
->
ptr
);
waitForSwappedKey
(
c
,
margv
[
keyindex
[
j
]]);
}
getKeysFreeResult
(
keyindex
);
}
}
else
{
waitForMultipleSwappedKeys
(
c
,
cmd
,
c
->
argc
,
c
->
argv
);
keyindex
=
getKeysFromCommand
(
cmd
,
c
->
argv
,
c
->
argc
,
&
numkeys
,
REDIS_GETKEYS_PRELOAD
);
for
(
j
=
0
;
j
<
numkeys
;
j
++
)
{
redisLog
(
REDIS_DEBUG
,
"Preloading %s"
,
(
char
*
)
c
->
argv
[
keyindex
[
j
]]
->
ptr
);
waitForSwappedKey
(
c
,
c
->
argv
[
keyindex
[
j
]]);
}
getKeysFreeResult
(
keyindex
);
}
/* If the client was blocked for at least one key, mark it as blocked. */
...
...
src/redis.c
View file @
cc1cb7e5
...
...
@@ -70,12 +70,12 @@ struct redisServer server; /* server global state */
struct
redisCommand
*
commandTable
;
struct
redisCommand
redisCommandTable
[]
=
{
{
"get"
,
getCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"set"
,
setCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"setnx"
,
setnxCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"setex"
,
setexCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"set"
,
setCommand
,
3
,
REDIS_CMD_DENYOOM
,
noPreloadGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"setnx"
,
setnxCommand
,
3
,
REDIS_CMD_DENYOOM
,
noPreloadGetKeys
,
1
,
1
,
1
,
0
,
0
},
{
"setex"
,
setexCommand
,
4
,
REDIS_CMD_DENYOOM
,
noPreloadGetKeys
,
2
,
2
,
1
,
0
,
0
},
{
"append"
,
appendCommand
,
3
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"strlen"
,
strlenCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"del"
,
delCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"del"
,
delCommand
,
-
2
,
0
,
noPreloadGetKeys
,
1
,
-
1
,
1
,
0
,
0
},
{
"exists"
,
existsCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"setbit"
,
setbitCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"getbit"
,
getbitCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
...
...
@@ -94,7 +94,7 @@ struct redisCommand redisCommandTable[] = {
{
"lpop"
,
lpopCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"brpop"
,
brpopCommand
,
-
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"brpoplpush"
,
brpoplpushCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
2
,
1
,
0
,
0
},
{
"blpop"
,
blpopCommand
,
-
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"blpop"
,
blpopCommand
,
-
3
,
0
,
NULL
,
1
,
-
2
,
1
,
0
,
0
},
{
"llen"
,
llenCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lindex"
,
lindexCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"lset"
,
lsetCommand
,
4
,
REDIS_CMD_DENYOOM
,
NULL
,
1
,
1
,
1
,
0
,
0
},
...
...
@@ -121,8 +121,8 @@ struct redisCommand redisCommandTable[] = {
{
"zrem"
,
zremCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zremrangebyscore"
,
zremrangebyscoreCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zremrangebyrank"
,
zremrangebyrankCommand
,
4
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zunionstore"
,
zunionstoreCommand
,
-
4
,
REDIS_CMD_DENYOOM
,
zunionInter
BlockClientOnSwapped
Keys
,
0
,
0
,
0
,
0
,
0
},
{
"zinterstore"
,
zinterstoreCommand
,
-
4
,
REDIS_CMD_DENYOOM
,
zunionInter
BlockClientOnSwapped
Keys
,
0
,
0
,
0
,
0
,
0
},
{
"zunionstore"
,
zunionstoreCommand
,
-
4
,
REDIS_CMD_DENYOOM
,
zunionInter
Get
Keys
,
0
,
0
,
0
,
0
,
0
},
{
"zinterstore"
,
zinterstoreCommand
,
-
4
,
REDIS_CMD_DENYOOM
,
zunionInter
Get
Keys
,
0
,
0
,
0
,
0
,
0
},
{
"zrange"
,
zrangeCommand
,
-
4
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrangebyscore"
,
zrangebyscoreCommand
,
-
4
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"zrevrangebyscore"
,
zrevrangebyscoreCommand
,
-
4
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
...
...
@@ -152,10 +152,10 @@ struct redisCommand redisCommandTable[] = {
{
"randomkey"
,
randomkeyCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"select"
,
selectCommand
,
2
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"move"
,
moveCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"rename"
,
renameCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"renamenx"
,
renamenxCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"expire"
,
expireCommand
,
3
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"expireat"
,
expireatCommand
,
3
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"rename"
,
renameCommand
,
3
,
0
,
renameGetKeys
,
1
,
2
,
1
,
0
,
0
},
{
"renamenx"
,
renamenxCommand
,
3
,
0
,
renameGetKeys
,
1
,
2
,
1
,
0
,
0
},
{
"expire"
,
expireCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"expireat"
,
expireatCommand
,
3
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"keys"
,
keysCommand
,
2
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"dbsize"
,
dbsizeCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"auth"
,
authCommand
,
2
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
...
...
@@ -168,7 +168,7 @@ struct redisCommand redisCommandTable[] = {
{
"lastsave"
,
lastsaveCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"type"
,
typeCommand
,
2
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"multi"
,
multiCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"exec"
,
execCommand
,
1
,
REDIS_CMD_DENYOOM
,
execBlockClientOnSwappedKeys
,
0
,
0
,
0
,
0
,
0
},
{
"exec"
,
execCommand
,
1
,
REDIS_CMD_DENYOOM
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"discard"
,
discardCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"sync"
,
syncCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"flushdb"
,
flushdbCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
...
...
@@ -186,7 +186,7 @@ struct redisCommand redisCommandTable[] = {
{
"psubscribe"
,
psubscribeCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"punsubscribe"
,
punsubscribeCommand
,
-
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
REDIS_CMD_FORCE_REPLICATION
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
0
,
noPreloadGetKeys
,
1
,
-
1
,
1
,
0
,
0
},
{
"unwatch"
,
unwatchCommand
,
1
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
}
};
...
...
src/redis.h
View file @
cc1cb7e5
...
...
@@ -507,20 +507,19 @@ typedef struct pubsubPattern {
}
pubsubPattern
;
typedef
void
redisCommandProc
(
redisClient
*
c
);
typedef
void
redisVmPreloadProc
(
redisClient
*
c
,
struct
redisCommand
*
cmd
,
int
argc
,
robj
**
argv
);
typedef
int
*
redisGetKeysProc
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
);
struct
redisCommand
{
char
*
name
;
redisCommandProc
*
proc
;
int
arity
;
int
flags
;
/* Use a function to determine which keys need to be loaded
* in the background prior to executing this command. Takes precedence
* over vm_firstkey and others, ignored when NULL */
redisVmPreloadProc
*
vm_preload_proc
;
/* Use a function to determine keys arguments in a command line.
* Used both for diskstore preloading and Redis Cluster. */
redisGetKeysProc
*
getkeys_proc
;
/* What keys should be loaded in background when calling this command? */
int
vm_
firstkey
;
/* The first argument that's a key (0 = no keys) */
int
vm_
lastkey
;
/* THe last argument that's a key */
int
vm_
keystep
;
/* The step between first and last key */
int
firstkey
;
/* The first argument that's a key (0 = no keys) */
int
lastkey
;
/* THe last argument that's a key */
int
keystep
;
/* The step between first and last key */
long
long
microseconds
,
calls
;
};
...
...
@@ -829,8 +828,6 @@ void freeIOJob(iojob *j);
void
queueIOJob
(
iojob
*
j
);
void
waitEmptyIOJobsQueue
(
void
);
void
processAllPendingIOJobs
(
void
);
void
zunionInterBlockClientOnSwappedKeys
(
redisClient
*
c
,
struct
redisCommand
*
cmd
,
int
argc
,
robj
**
argv
);
void
execBlockClientOnSwappedKeys
(
redisClient
*
c
,
struct
redisCommand
*
cmd
,
int
argc
,
robj
**
argv
);
int
blockClientOnSwappedKeys
(
redisClient
*
c
,
struct
redisCommand
*
cmd
);
int
dontWaitForSwappedKey
(
redisClient
*
c
,
robj
*
key
);
void
handleClientsBlockedOnSwappedKey
(
redisDb
*
db
,
robj
*
key
);
...
...
@@ -917,6 +914,15 @@ int selectDb(redisClient *c, int id);
void
signalModifiedKey
(
redisDb
*
db
,
robj
*
key
);
void
signalFlushedDb
(
int
dbid
);
/* API to get key arguments from commands */
#define REDIS_GETKEYS_ALL 0
#define REDIS_GETKEYS_PRELOAD 1
int
*
getKeysFromCommand
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
);
void
getKeysFreeResult
(
int
*
result
);
int
*
noPreloadGetKeys
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
);
int
*
renameGetKeys
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
);
int
*
zunionInterGetKeys
(
struct
redisCommand
*
cmd
,
robj
**
argv
,
int
argc
,
int
*
numkeys
,
int
flags
);
/* Git SHA1 */
char
*
redisGitSHA1
(
void
);
char
*
redisGitDirty
(
void
);
...
...
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