From 9791f0f8ceb18e2e3c297a8c479307b7af0f9830 Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 23 Mar 2011 18:09:17 +0100 Subject: [PATCH] new preloading implemented, still EXEC not handled correctly, everything to test --- src/db.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/dscache.c | 14 ++++++---- src/redis.c | 2 +- src/redis.h | 26 ++++++++++++------- 4 files changed, 98 insertions(+), 16 deletions(-) diff --git a/src/db.c b/src/db.c index 9daa5ddb..9bc299ca 100644 --- a/src/db.c +++ b/src/db.c @@ -616,3 +616,75 @@ 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; + } + 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 NULL; + } 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(num); + for (i = 0; i < num; i++) keys[i] = 3+i; + *numkeys = num; + return keys; +} diff --git a/src/dscache.c b/src/dscache.c index cbe9bb01..5813052e 100644 --- a/src/dscache.c +++ b/src/dscache.c @@ -903,6 +903,7 @@ int waitForSwappedKey(redisClient *c, robj *key) { return 1; } +#if 0 /* 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) { @@ -955,6 +956,7 @@ void execBlockClientOnSwappedKeys(redisClient *c, struct redisCommand *cmd, int } } } +#endif /* 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,11 +969,13 @@ 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); - } else { - waitForMultipleSwappedKeys(c,cmd,c->argc,c->argv); - } + int *keyindex, numkeys, j; + + keyindex = getKeysFromCommand(cmd,c->argv,c->argc,&numkeys,REDIS_GETKEYS_PRELOAD); + for (j = 0; j < numkeys; j++) waitForSwappedKey(c,c->argv[keyindex[j]]); + getKeysFreeResult(keyindex); + +#warning "Handle EXEC here" /* If the client was blocked for at least one key, mark it as blocked. */ if (listLength(c->io_keys)) { diff --git a/src/redis.c b/src/redis.c index 51e58f58..19fd912c 100644 --- a/src/redis.c +++ b/src/redis.c @@ -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,execGetKeys,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}, diff --git a/src/redis.h b/src/redis.h index cdddb601..b5188330 100644 --- a/src/redis.h +++ b/src/redis.h @@ -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); -- GitLab