diff --git a/src/acl.c b/src/acl.c index 30fdc8e07..aa3ed197f 100644 --- a/src/acl.c +++ b/src/acl.c @@ -1115,8 +1115,9 @@ int ACLCheckCommandPerm(client *c, int *keyidxptr) { if (!(c->user->flags & USER_FLAG_ALLKEYS) && (c->cmd->getkeys_proc || c->cmd->firstkey)) { - int numkeys; - int *keyidx = getKeysFromCommand(c->cmd,c->argv,c->argc,&numkeys); + getKeysResult result = GETKEYS_RESULT_INIT; + int numkeys = getKeysFromCommand(c->cmd,c->argv,c->argc,&result); + int *keyidx = result.keys; for (int j = 0; j < numkeys; j++) { listIter li; listNode *ln; @@ -1137,11 +1138,11 @@ int ACLCheckCommandPerm(client *c, int *keyidxptr) { } if (!match) { if (keyidxptr) *keyidxptr = keyidx[j]; - getKeysFreeResult(keyidx); + getKeysFreeResult(&result); return ACL_DENIED_KEY; } } - getKeysFreeResult(keyidx); + getKeysFreeResult(&result); } /* If we survived all the above checks, the user can execute the diff --git a/src/cluster.c b/src/cluster.c index f7f033ba3..248d5c17d 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -5644,7 +5644,10 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in margc = ms->commands[i].argc; margv = ms->commands[i].argv; - keyindex = getKeysFromCommand(mcmd,margv,margc,&numkeys); + getKeysResult result = GETKEYS_RESULT_INIT; + numkeys = getKeysFromCommand(mcmd,margv,margc,&result); + keyindex = result.keys; + for (j = 0; j < numkeys; j++) { robj *thiskey = margv[keyindex[j]]; int thisslot = keyHashSlot((char*)thiskey->ptr, @@ -5662,7 +5665,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in * not trapped earlier in processCommand(). Report the same * error to the client. */ if (n == NULL) { - getKeysFreeResult(keyindex); + getKeysFreeResult(&result); if (error_code) *error_code = CLUSTER_REDIR_DOWN_UNBOUND; return NULL; @@ -5686,7 +5689,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in if (!equalStringObjects(firstkey,thiskey)) { if (slot != thisslot) { /* Error: multiple keys from different slots. */ - getKeysFreeResult(keyindex); + getKeysFreeResult(&result); if (error_code) *error_code = CLUSTER_REDIR_CROSS_SLOT; return NULL; @@ -5705,7 +5708,7 @@ clusterNode *getNodeByQuery(client *c, struct redisCommand *cmd, robj **argv, in missing_keys++; } } - getKeysFreeResult(keyindex); + getKeysFreeResult(&result); } /* No key at all in command? then we can serve the request diff --git a/src/db.c b/src/db.c index c004468d8..d30956c9a 100644 --- a/src/db.c +++ b/src/db.c @@ -1314,27 +1314,54 @@ int expireIfNeeded(redisDb *db, robj *key) { /* ----------------------------------------------------------------------------- * API to get key arguments from commands * ---------------------------------------------------------------------------*/ -#define MAX_KEYS_BUFFER 256 -static int getKeysTempBuffer[MAX_KEYS_BUFFER]; + +/* Prepare the getKeysResult struct to hold numkeys, either by using the + * pre-allocated keysbuf or by allocating a new array on the heap. + * + * This function must be called at least once before starting to populate + * the result, and can be called repeatedly to enlarge the result array. + */ +int *getKeysPrepareResult(getKeysResult *result, int numkeys) { + /* GETKEYS_RESULT_INIT initializes keys to NULL, point it to the pre-allocated stack + * buffer here. */ + if (!result->keys) { + serverAssert(!result->numkeys); + result->keys = result->keysbuf; + } + + /* Resize if necessary */ + if (numkeys > result->size) { + if (result->keys != result->keysbuf) { + /* We're not using a static buffer, just (re)alloc */ + result->keys = zrealloc(result->keys, numkeys * sizeof(int)); + } else { + /* We are using a static buffer, copy its contents */ + result->keys = zmalloc(numkeys * sizeof(int)); + if (result->numkeys) + memcpy(result->keys, result->keysbuf, result->numkeys * sizeof(int)); + } + result->size = numkeys; + } + + return result->keys; +} /* The base case is to use the keys position as given in the command table * (firstkey, lastkey, step). */ -int *getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, int *numkeys) { +int getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, getKeysResult *result) { int j, i = 0, last, *keys; UNUSED(argv); if (cmd->firstkey == 0) { - *numkeys = 0; - return NULL; + result->numkeys = 0; + return 0; } last = cmd->lastkey; if (last < 0) last = argc+last; int count = ((last - cmd->firstkey)+1); - keys = getKeysTempBuffer; - if (count > MAX_KEYS_BUFFER) - keys = zmalloc(sizeof(int)*count); + keys = getKeysPrepareResult(result, count); for (j = cmd->firstkey; j <= last; j += cmd->keystep) { if (j >= argc) { @@ -1345,17 +1372,17 @@ int *getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, in * return no keys and expect the command implementation to report * an arity or syntax error. */ if (cmd->flags & CMD_MODULE || cmd->arity < 0) { - getKeysFreeResult(keys); - *numkeys = 0; - return NULL; + getKeysFreeResult(result); + result->numkeys = 0; + return 0; } else { serverPanic("Redis built-in command declared keys positions not matching the arity requirements."); } } keys[i++] = j; } - *numkeys = i; - return keys; + result->numkeys = i; + return i; } /* Return all the arguments that are keys in the command passed via argc / argv. @@ -1369,20 +1396,20 @@ int *getKeysUsingCommandTable(struct redisCommand *cmd,robj **argv, int argc, in * * This function uses the command table if a command-specific helper function * is not required, otherwise it calls the command-specific function. */ -int *getKeysFromCommand(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int getKeysFromCommand(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { if (cmd->flags & CMD_MODULE_GETKEYS) { - return moduleGetCommandKeysViaAPI(cmd,argv,argc,numkeys); + return moduleGetCommandKeysViaAPI(cmd,argv,argc,result); } else if (!(cmd->flags & CMD_MODULE) && cmd->getkeys_proc) { - return cmd->getkeys_proc(cmd,argv,argc,numkeys); + return cmd->getkeys_proc(cmd,argv,argc,result); } else { - return getKeysUsingCommandTable(cmd,argv,argc,numkeys); + return getKeysUsingCommandTable(cmd,argv,argc,result); } } /* Free the result of getKeysFromCommand. */ -void getKeysFreeResult(int *result) { - if (result != getKeysTempBuffer) - zfree(result); +void getKeysFreeResult(getKeysResult *result) { + if (result && result->keys != result->keysbuf) + zfree(result->keys); } /* Helper function to extract keys from following commands: @@ -1397,43 +1424,42 @@ void getKeysFreeResult(int *result) { * 'firstKeyOfs': firstkey index. * 'keyStep': the interval of each key, usually this value is 1. * */ -int *genericGetKeys(int storeKeyOfs, int keyCountOfs, int firstKeyOfs, int keyStep, - robj **argv, int argc, int *numkeys) { +int genericGetKeys(int storeKeyOfs, int keyCountOfs, int firstKeyOfs, int keyStep, + robj **argv, int argc, getKeysResult *result) { int i, num, *keys; num = atoi(argv[keyCountOfs]->ptr); /* Sanity check. Don't return any key if the command is going to * reply with syntax error. (no input keys). */ if (num < 1 || num > (argc - firstKeyOfs)/keyStep) { - *numkeys = 0; - return NULL; + result->numkeys = 0; + return 0; } - keys = getKeysTempBuffer; - *numkeys = storeKeyOfs ? num + 1 : num; - if (*numkeys > MAX_KEYS_BUFFER) - keys = zmalloc(sizeof(int)*(*numkeys)); + int numkeys = storeKeyOfs ? num + 1 : num; + keys = getKeysPrepareResult(result, numkeys); + result->numkeys = numkeys; /* Add all key positions for argv[firstKeyOfs...n] to keys[] */ for (i = 0; i < num; i++) keys[i] = firstKeyOfs+(i*keyStep); if (storeKeyOfs) keys[num] = storeKeyOfs; - return keys; + return result->numkeys; } -int *zunionInterStoreGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int zunionInterStoreGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { UNUSED(cmd); - return genericGetKeys(1, 2, 3, 1, argv, argc, numkeys); + return genericGetKeys(1, 2, 3, 1, argv, argc, result); } -int *zunionInterGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int zunionInterGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { UNUSED(cmd); - return genericGetKeys(0, 1, 2, 1, argv, argc, numkeys); + return genericGetKeys(0, 1, 2, 1, argv, argc, result); } -int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { UNUSED(cmd); - return genericGetKeys(0, 2, 3, 1, argv, argc, numkeys); + return genericGetKeys(0, 2, 3, 1, argv, argc, result); } /* Helper function to extract keys from the SORT command. @@ -1443,13 +1469,12 @@ int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) * The first argument of SORT is always a key, however a list of options * follow in SQL-alike style. Here we parse just the minimum in order to * correctly identify keys in the "STORE" option. */ -int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { int i, j, num, *keys, found_store = 0; UNUSED(cmd); num = 0; - keys = getKeysTempBuffer; /* Alloc 2 places for the worst case. */ - + keys = getKeysPrepareResult(result, 2); /* Alloc 2 places for the worst case. */ keys[num++] = 1; /* is always present. */ /* Search for STORE option. By default we consider options to don't @@ -1481,11 +1506,11 @@ int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) } } } - *numkeys = num + found_store; - return keys; + result->numkeys = num + found_store; + return result->numkeys; } -int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { int i, num, first, *keys; UNUSED(cmd); @@ -1506,20 +1531,17 @@ int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkey } } - keys = getKeysTempBuffer; - if (num>MAX_KEYS_BUFFER) - keys = zmalloc(sizeof(int)*num); - + keys = getKeysPrepareResult(result, num); for (i = 0; i < num; i++) keys[i] = first+i; - *numkeys = num; - return keys; + result->numkeys = num; + return num; } /* Helper function to extract keys from following commands: * GEORADIUS key x y radius unit [WITHDIST] [WITHHASH] [WITHCOORD] [ASC|DESC] * [COUNT count] [STORE key] [STOREDIST key] * GEORADIUSBYMEMBER key member radius unit ... options ... */ -int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { int i, num, *keys; UNUSED(cmd); @@ -1542,24 +1564,21 @@ int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numk * argv[1] = key, * argv[5...n] = stored key if present */ - keys = getKeysTempBuffer; - if (num>MAX_KEYS_BUFFER) - keys = zmalloc(sizeof(int) * num); + keys = getKeysPrepareResult(result, num); /* Add all key positions to keys[] */ keys[0] = 1; if(num > 1) { keys[1] = stored_key; } - *numkeys = num; - return keys; + result->numkeys = num; + return num; } /* LCS ... [KEYS ] ... */ -int *lcsGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) -{ +int lcsGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { int i; - int *keys = getKeysTempBuffer; + int *keys = getKeysPrepareResult(result, 2); UNUSED(cmd); /* We need to parse the options of the command in order to check for the @@ -1573,33 +1592,32 @@ int *lcsGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) } else if (!strcasecmp(arg, "keys") && moreargs >= 2) { keys[0] = i+1; keys[1] = i+2; - *numkeys = 2; - return keys; + result->numkeys = 2; + return result->numkeys; } } - *numkeys = 0; - return keys; + result->numkeys = 0; + return result->numkeys; } /* Helper function to extract keys from memory command. * MEMORY USAGE */ -int *memoryGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { - int *keys; +int memoryGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { UNUSED(cmd); + getKeysPrepareResult(result, 1); if (argc >= 3 && !strcasecmp(argv[1]->ptr,"usage")) { - keys = getKeysTempBuffer; - keys[0] = 2; - *numkeys = 1; - return keys; + result->keys[0] = 2; + result->numkeys = 1; + return result->numkeys; } - *numkeys = 0; - return NULL; + result->numkeys = 0; + return 0; } /* XREAD [BLOCK ] [COUNT ] [GROUP ] * STREAMS key_1 key_2 ... key_N ID_1 ID_2 ... ID_N */ -int *xreadGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int xreadGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { int i, num = 0, *keys; UNUSED(cmd); @@ -1629,19 +1647,16 @@ int *xreadGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) /* Syntax error. */ if (streams_pos == -1 || num == 0 || num % 2 != 0) { - *numkeys = 0; - return NULL; + result->numkeys = 0; + return 0; } num /= 2; /* We have half the keys as there are arguments because there are also the IDs, one per key. */ - keys = getKeysTempBuffer; - if (num>MAX_KEYS_BUFFER) - keys = zmalloc(sizeof(int) * num); - + keys = getKeysPrepareResult(result, num); for (i = streams_pos+1; i < argc-num; i++) keys[i-streams_pos-1] = i; - *numkeys = num; - return keys; + result->numkeys = num; + return num; } /* Slot to Key API. This is used by Redis Cluster in order to obtain in diff --git a/src/module.c b/src/module.c index 3f3d92aea..a48780be9 100644 --- a/src/module.c +++ b/src/module.c @@ -147,8 +147,7 @@ struct RedisModuleCtx { on keys. */ /* Used if there is the REDISMODULE_CTX_KEYS_POS_REQUEST flag set. */ - int *keys_pos; - int keys_count; + getKeysResult *keys_result; struct RedisModulePoolAllocBlock *pa_head; redisOpArray saved_oparray; /* When propagating commands in a callback @@ -158,7 +157,7 @@ struct RedisModuleCtx { }; typedef struct RedisModuleCtx RedisModuleCtx; -#define REDISMODULE_CTX_INIT {(void*)(unsigned long)&RM_GetApi, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, 0, NULL, {0}} +#define REDISMODULE_CTX_INIT {(void*)(unsigned long)&RM_GetApi, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL, {0}} #define REDISMODULE_CTX_MULTI_EMITTED (1<<0) #define REDISMODULE_CTX_AUTO_MEMORY (1<<1) #define REDISMODULE_CTX_KEYS_POS_REQUEST (1<<2) @@ -665,18 +664,24 @@ void RedisModuleCommandDispatcher(client *c) { * In order to accomplish its work, the module command is called, flagging * the context in a way that the command can recognize this is a special * "get keys" call by calling RedisModule_IsKeysPositionRequest(ctx). */ -int *moduleGetCommandKeysViaAPI(struct redisCommand *cmd, robj **argv, int argc, int *numkeys) { +int moduleGetCommandKeysViaAPI(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result) { RedisModuleCommandProxy *cp = (void*)(unsigned long)cmd->getkeys_proc; RedisModuleCtx ctx = REDISMODULE_CTX_INIT; ctx.module = cp->module; ctx.client = NULL; ctx.flags |= REDISMODULE_CTX_KEYS_POS_REQUEST; + + /* Initialize getKeysResult */ + getKeysPrepareResult(result, MAX_KEYS_BUFFER); + ctx.keys_result = result; + cp->func(&ctx,(void**)argv,argc); - int *res = ctx.keys_pos; - if (numkeys) *numkeys = ctx.keys_count; + /* We currently always use the array allocated by RM_KeyAtPos() and don't try + * to optimize for the pre-allocated buffer. + */ moduleFreeContext(&ctx); - return res; + return result->numkeys; } /* Return non-zero if a module command, that was declared with the @@ -701,10 +706,18 @@ int RM_IsKeysPositionRequest(RedisModuleCtx *ctx) { * keys are at fixed positions. This interface is only used for commands * with a more complex structure. */ void RM_KeyAtPos(RedisModuleCtx *ctx, int pos) { - if (!(ctx->flags & REDISMODULE_CTX_KEYS_POS_REQUEST)) return; + if (!(ctx->flags & REDISMODULE_CTX_KEYS_POS_REQUEST) || !ctx->keys_result) return; if (pos <= 0) return; - ctx->keys_pos = zrealloc(ctx->keys_pos,sizeof(int)*(ctx->keys_count+1)); - ctx->keys_pos[ctx->keys_count++] = pos; + + getKeysResult *res = ctx->keys_result; + + /* Check overflow */ + if (res->numkeys == res->size) { + int newsize = res->size + (res->size > 8192 ? 8192 : res->size); + getKeysPrepareResult(res, newsize); + } + + res->keys[res->numkeys++] = pos; } /* Helper for RM_CreateCommand(). Turns a string representing command diff --git a/src/server.c b/src/server.c index ef40b4fff..6ae7037af 100644 --- a/src/server.c +++ b/src/server.c @@ -3273,7 +3273,7 @@ struct redisCommand *lookupCommand(sds name) { return dictFetchValue(server.commands, name); } -struct redisCommand *lookupCommandByCString(char *s) { +struct redisCommand *lookupCommandByCString(const char *s) { struct redisCommand *cmd; sds name = sdsnew(s); @@ -4142,7 +4142,8 @@ NULL addReplyLongLong(c, dictSize(server.commands)); } else if (!strcasecmp(c->argv[1]->ptr,"getkeys") && c->argc >= 3) { struct redisCommand *cmd = lookupCommand(c->argv[2]->ptr); - int *keys, numkeys, j; + getKeysResult result = GETKEYS_RESULT_INIT; + int j; if (!cmd) { addReplyError(c,"Invalid command specified"); @@ -4157,14 +4158,13 @@ NULL return; } - keys = getKeysFromCommand(cmd,c->argv+2,c->argc-2,&numkeys); - if (!keys) { + if (!getKeysFromCommand(cmd,c->argv+2,c->argc-2,&result)) { addReplyError(c,"Invalid arguments specified for command"); } else { - addReplyArrayLen(c,numkeys); - for (j = 0; j < numkeys; j++) addReplyBulk(c,c->argv[keys[j]+2]); - getKeysFreeResult(keys); + addReplyArrayLen(c,result.numkeys); + for (j = 0; j < result.numkeys; j++) addReplyBulk(c,c->argv[result.keys[j]+2]); } + getKeysFreeResult(&result); } else { addReplySubcommandSyntaxError(c); } diff --git a/src/server.h b/src/server.h index 50083652e..a5881e9a2 100644 --- a/src/server.h +++ b/src/server.h @@ -1497,8 +1497,21 @@ typedef struct pubsubPattern { robj *pattern; } pubsubPattern; +#define MAX_KEYS_BUFFER 256 + +/* A result structure for the various getkeys function calls. It lists the + * keys as indices to the provided argv. + */ +typedef struct { + int keysbuf[MAX_KEYS_BUFFER]; /* Pre-allocated buffer, to save heap allocations */ + int *keys; /* Key indices array, points to keysbuf or heap */ + int numkeys; /* Number of key indices return */ + int size; /* Available array size */ +} getKeysResult; +#define GETKEYS_RESULT_INIT { {0}, NULL, 0, MAX_KEYS_BUFFER } + typedef void redisCommandProc(client *c); -typedef int *redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); +typedef int redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); struct redisCommand { char *name; redisCommandProc *proc; @@ -1608,7 +1621,7 @@ void moduleInitModulesSystem(void); void moduleInitModulesSystemLast(void); int moduleLoad(const char *path, void **argv, int argc); void moduleLoadFromQueue(void); -int *moduleGetCommandKeysViaAPI(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); +int moduleGetCommandKeysViaAPI(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); moduleType *moduleTypeLookupModuleByID(uint64_t id); void moduleTypeNameByID(char *name, uint64_t moduleid); void moduleFreeContext(struct RedisModuleCtx *ctx); @@ -2020,7 +2033,7 @@ int processCommand(client *c); void setupSignalHandlers(void); void removeSignalHandlers(void); struct redisCommand *lookupCommand(sds name); -struct redisCommand *lookupCommandByCString(char *s); +struct redisCommand *lookupCommandByCString(const char *s); struct redisCommand *lookupCommandOrOriginal(sds name); void call(client *c, int flags); void propagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, int flags); @@ -2181,17 +2194,18 @@ size_t lazyfreeGetPendingObjectsCount(void); void freeObjAsync(robj *o); /* API to get key arguments from commands */ -int *getKeysFromCommand(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); -void getKeysFreeResult(int *result); -int *zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys); -int *zunionInterStoreGetKeys(struct redisCommand *cmd,robj **argv, int argc, int *numkeys); -int *evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); -int *sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); -int *migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); -int *georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); -int *xreadGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); -int *memoryGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); -int *lcsGetKeys(struct redisCommand *cmd, robj **argv, int argc, int *numkeys); +int *getKeysPrepareResult(getKeysResult *result, int numkeys); +int getKeysFromCommand(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); +void getKeysFreeResult(getKeysResult *result); +int zunionInterGetKeys(struct redisCommand *cmd,robj **argv, int argc, getKeysResult *result); +int zunionInterStoreGetKeys(struct redisCommand *cmd,robj **argv, int argc, getKeysResult *result); +int evalGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); +int sortGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); +int migrateGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); +int georadiusGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); +int xreadGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); +int memoryGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); +int lcsGetKeys(struct redisCommand *cmd, robj **argv, int argc, getKeysResult *result); /* Cluster */ void clusterInit(void); diff --git a/src/tracking.c b/src/tracking.c index 3737f6859..913577eab 100644 --- a/src/tracking.c +++ b/src/tracking.c @@ -171,9 +171,14 @@ void trackingRememberKeys(client *c) { uint64_t caching_given = c->flags & CLIENT_TRACKING_CACHING; if ((optin && !caching_given) || (optout && caching_given)) return; - int numkeys; - int *keys = getKeysFromCommand(c->cmd,c->argv,c->argc,&numkeys); - if (keys == NULL) return; + getKeysResult result = GETKEYS_RESULT_INIT; + int numkeys = getKeysFromCommand(c->cmd,c->argv,c->argc,&result); + if (!numkeys) { + getKeysFreeResult(&result); + return; + } + + int *keys = result.keys; for(int j = 0; j < numkeys; j++) { int idx = keys[j]; @@ -188,7 +193,7 @@ void trackingRememberKeys(client *c) { if (raxTryInsert(ids,(unsigned char*)&c->id,sizeof(c->id),NULL,NULL)) TrackingTableTotalItems++; } - getKeysFreeResult(keys); + getKeysFreeResult(&result); } /* Given a key name, this function sends an invalidation message in the