Transactions: Implementation of the IF command

This commit is contained in:
antirez 2015-03-06 10:35:40 -08:00
parent 509a6cc1e8
commit 2bf27c3361
4 changed files with 46 additions and 2 deletions

View File

@ -62,7 +62,7 @@ robj *lookupKeyRead(redisDb *db, robj *key) {
if (expireIfNeeded(db,key) == 1) {
/* Key expired. If we are in the context of a master, expireIfNeeded()
* returns 0 only when the key does not exist at all, so it's save
* returns 0 only when the key does not exist at all, so it's safe
* to return NULL ASAP. */
if (server.masterhost == NULL) return NULL;

View File

@ -304,6 +304,9 @@ void touchWatchedKeysOnFlush(int dbid) {
}
}
/* WATCH key key key ...
* Add keys to the set of watched keys. If those keys are modified
* before the next transaction is executed, the transaction aborts. */
void watchCommand(redisClient *c) {
int j;
@ -316,8 +319,47 @@ void watchCommand(redisClient *c) {
addReply(c,shared.ok);
}
/* UNWATCH
* Flush the set of watched keys. */
void unwatchCommand(redisClient *c) {
unwatchAllKeys(c);
c->flags &= (~REDIS_DIRTY_CAS);
addReply(c,shared.ok);
}
/* IF XX key key key ...
* IF NX key key key ...
* Abort transaction if condition is not met. */
void ifCommand(redisClient *c) {
int j;
int xx = 0, nx = 0;
if (!(c->flags & REDIS_MULTI)) {
addReplyError(c,"IF outside MULTI is not allowed");
return;
}
/* Check if it's xx or nx option, trying to do it reasonably fast. */
char *a = c->argv[1]->ptr;
if ((a[0] == 'n' || a[0] == 'N') &&
(a[1] == 'x' || a[1] == 'X') && a[2] == '\0')
{
nx = 1;
} else if ((a[0] == 'x' || a[0] == 'X') &&
(a[1] == 'x' || a[1] == 'X') && a[2] == '\0')
{
xx = 1;
} else {
addReply(c,shared.syntaxerr);
return;
}
/* Check if keys exist / don't exist, and flag the transaction if
* at least one key fails the test according to NX / XX option. */
for (j = 2; j < c->argc; j++) {
robj *o = lookupKeyRead(c->db,c->argv[j]);
if ((o != NULL && nx) || (o == NULL && xx))
c->flags |= REDIS_DIRTY_CAS;
}
addReply(c,shared.ok);
}

View File

@ -261,6 +261,7 @@ struct redisCommand redisCommandTable[] = {
{"pubsub",pubsubCommand,-2,"pltrR",0,NULL,0,0,0,0,0},
{"watch",watchCommand,-2,"rsF",0,NULL,1,-1,1,0,0},
{"unwatch",unwatchCommand,1,"rsF",0,NULL,0,0,0,0,0},
{"if",ifCommand,-2,"rsF",0,NULL,2,-1,1,0,0},
{"cluster",clusterCommand,-2,"ar",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},
@ -2336,7 +2337,7 @@ int processCommand(redisClient *c) {
/* Exec the command */
if (c->flags & REDIS_MULTI &&
c->cmd->proc != execCommand && c->cmd->proc != discardCommand &&
c->cmd->proc != execCommand && c->cmd->proc != ifCommand &&
c->cmd->proc != multiCommand && c->cmd->proc != watchCommand)
{
queueMultiCommand(c);

View File

@ -1561,6 +1561,7 @@ void pfcountCommand(redisClient *c);
void pfmergeCommand(redisClient *c);
void pfdebugCommand(redisClient *c);
void latencyCommand(redisClient *c);
void ifCommand(redisClient *c);
#if defined(__GNUC__)
void *calloc(size_t count, size_t size) __attribute__ ((deprecated));