Unverified Commit eedec155 authored by guybe7's avatar guybe7 Committed by GitHub
Browse files

Add key-specs notes (#10193)

Add optional `notes` to keyspecs.

Other changes:

1. Remove the "incomplete" flag from SORT and SORT_RO: it is misleading since "incomplete" means "this spec may not return all the keys it describes" but SORT and SORT_RO's specs (except the input key) do not return any keys at all.
So basically:
If a spec's begin_search is "unknown" you should not use it at all, you must use COMMAND KEYS;
if a spec itself is "incomplete", you can use it to get a partial list of keys, but if you want all of them you must use COMMAND GETKEYS;
otherwise, the spec will return all the keys

2. `getKeysUsingKeySpecs` handles incomplete specs internally
parent be0d2933
This diff is collapsed.
......@@ -16,6 +16,7 @@
],
"key_specs": [
{
"notes": "This command allows both access and modification of the key",
"flags": [
"RW",
"UPDATE",
......
......@@ -19,6 +19,7 @@
],
"key_specs": [
{
"notes": "We cannot tell how the keys will be used so we assume the worst, RW and UPDATE",
"flags": [
"RW",
"ACCESS",
......
......@@ -18,6 +18,7 @@
],
"key_specs": [
{
"notes": "We cannot tell how the keys will be used so we assume the worst, RO and ACCESS",
"flags": [
"RO",
"ACCESS"
......
......@@ -19,6 +19,7 @@
],
"key_specs": [
{
"notes": "We cannot tell how the keys will be used so we assume the worst, RW and UPDATE",
"flags": [
"RW",
"ACCESS",
......
......@@ -18,6 +18,7 @@
],
"key_specs": [
{
"notes": "We cannot tell how the keys will be used so we assume the worst, RO and ACCESS",
"flags": [
"RO",
"ACCESS"
......
......@@ -15,6 +15,7 @@
],
"key_specs": [
{
"notes": "RW and UPDATE because it changes the TTL",
"flags": [
"RW",
"ACCESS",
......
......@@ -15,6 +15,7 @@
],
"key_specs": [
{
"notes": "RW because it may change the internal representation of the key, and propagate to replicas",
"flags": [
"RW",
"ACCESS"
......
......@@ -34,6 +34,7 @@
],
"key_specs": [
{
"notes": "RW and ACCESS due to the optional `GET` argument",
"flags": [
"RW",
"ACCESS",
......
......@@ -37,10 +37,10 @@
}
},
{
"notes": "For the optional BY/GET keyword. It is marked 'unknown' because the key names derive from the content of the key we sort",
"flags": [
"RO",
"ACCESS",
"INCOMPLETE"
"ACCESS"
],
"begin_search": {
"unknown": null
......@@ -50,10 +50,10 @@
}
},
{
"notes": "For the optional STORE keyword. It is marked 'unknown' because the keyword can appear anywhere in the argument array",
"flags": [
"OW",
"UPDATE",
"INCOMPLETE"
"UPDATE"
],
"begin_search": {
"unknown": null
......@@ -73,6 +73,7 @@
"token": "BY",
"name": "pattern",
"type": "pattern",
"key_spec_index": 1,
"optional": true
},
{
......@@ -94,6 +95,7 @@
{
"token": "GET",
"name": "pattern",
"key_spec_index": 1,
"type": "string",
"optional": true,
"multiple": true,
......@@ -126,7 +128,7 @@
"token": "STORE",
"name": "destination",
"type": "key",
"key_spec_index": 1,
"key_spec_index": 2,
"optional": true
}
]
......
......@@ -36,10 +36,10 @@
}
},
{
"notes": "For the optional BY/GET keyword. It is marked 'unknown' because the key names derive from the content of the key we sort",
"flags": [
"RO",
"ACCESS",
"INCOMPLETE"
"ACCESS"
],
"begin_search": {
"unknown": null
......@@ -59,6 +59,7 @@
"token": "BY",
"name": "pattern",
"type": "pattern",
"key_spec_index": 1,
"optional": true
},
{
......@@ -80,6 +81,7 @@
{
"token": "GET",
"name": "pattern",
"key_spec_index": 1,
"type": "string",
"optional": true,
"multiple": true,
......
......@@ -29,6 +29,7 @@
],
"key_specs": [
{
"notes": "UPDATE instead of INSERT because of the optional trimming feature",
"flags": [
"RW",
"UPDATE"
......
......@@ -1704,7 +1704,7 @@ int getKeysUsingKeySpecs(struct redisCommand *cmd, robj **argv, int argc, int se
keySpec *spec = cmd->key_specs + j;
serverAssert(spec->begin_search_type != KSPEC_BS_INVALID);
/* Skip specs that represent channels instead of keys */
if (spec->flags & (CMD_KEY_CHANNEL) && !(search_flags & GET_KEYSPEC_INCLUDE_CHANNELS)) {
if ((spec->flags & CMD_KEY_CHANNEL) && !(search_flags & GET_KEYSPEC_INCLUDE_CHANNELS)) {
continue;
}
......@@ -1788,6 +1788,12 @@ int getKeysUsingKeySpecs(struct redisCommand *cmd, robj **argv, int argc, int se
keys[k++].flags = spec->flags;
}
/* Handle incomplete specs (only after we added the current spec
* to `keys`, just in case GET_KEYSPEC_RETURN_PARTIAL was given) */
if (spec->flags & CMD_KEY_INCOMPLETE) {
goto invalid_spec;
}
/* Done with this spec */
continue;
......@@ -1824,7 +1830,7 @@ int getKeysFromCommandWithSpecs(struct redisCommand *cmd, robj **argv, int argc,
if (cmd->flags & CMD_MODULE_GETKEYS) {
return moduleGetCommandKeysViaAPI(cmd,argv,argc,result);
} else {
if (!(getAllKeySpecsFlags(cmd, 0) & (CMD_KEY_INCOMPLETE|CMD_KEY_VARIABLE_FLAGS))) {
if (!(getAllKeySpecsFlags(cmd, 0) & CMD_KEY_VARIABLE_FLAGS)) {
int ret = getKeysUsingKeySpecs(cmd,argv,argc,search_flags,result);
if (ret >= 0)
return ret;
......
......@@ -4181,7 +4181,7 @@ void addReplyCommandArgList(client *c, struct redisCommandArg *args, int num_arg
for (int j = 0; j<num_args; j++) {
/* Count our reply len so we don't have to use deferred reply. */
long maplen = 2;
if (args[j].type == ARG_TYPE_KEY) maplen++;
if (args[j].key_spec_index != -1) maplen++;
if (args[j].token) maplen++;
if (args[j].summary) maplen++;
if (args[j].since) maplen++;
......@@ -4196,7 +4196,7 @@ void addReplyCommandArgList(client *c, struct redisCommandArg *args, int num_arg
addReplyBulkCString(c, "type");
addReplyBulkCString(c, ARG_TYPE_STR[args[j].type]);
if (args[j].type == ARG_TYPE_KEY) {
if (args[j].key_spec_index != -1) {
addReplyBulkCString(c, "key_spec_index");
addReplyLongLong(c, args[j].key_spec_index);
}
......@@ -4267,7 +4267,15 @@ void addReplyCommandTips(client *c, struct redisCommand *cmd) {
void addReplyCommandKeySpecs(client *c, struct redisCommand *cmd) {
addReplySetLen(c, cmd->key_specs_num);
for (int i = 0; i < cmd->key_specs_num; i++) {
addReplyMapLen(c, 3);
int maplen = 3;
if (cmd->key_specs[i].notes) maplen++;
addReplyMapLen(c, maplen);
if (cmd->key_specs[i].notes) {
addReplyBulkCString(c, "notes");
addReplyBulkCString(c,cmd->key_specs[i].notes);
}
addReplyBulkCString(c, "flags");
addReplyFlagsForKeyArgs(c,cmd->key_specs[i].flags);
......
......@@ -1946,6 +1946,7 @@ typedef enum {
typedef struct {
/* Declarative data */
const char *notes;
uint64_t flags;
kspec_bs_type begin_search_type;
union {
......@@ -1997,7 +1998,7 @@ typedef enum {
ARG_TYPE_STRING,
ARG_TYPE_INTEGER,
ARG_TYPE_DOUBLE,
ARG_TYPE_KEY,
ARG_TYPE_KEY, /* A string, but represents a keyname */
ARG_TYPE_PATTERN,
ARG_TYPE_UNIX_TIME,
ARG_TYPE_PURE_TOKEN,
......
......@@ -119,7 +119,8 @@ class KeySpec(object):
print("Invalid find_keys! value=%s" % self.spec["find_keys"])
exit(1)
return "%s,%s,%s" % (
return "%s,%s,%s,%s" % (
get_optional_desc_string(self.spec, "notes"),
_flags_code(),
_begin_search_code(),
_find_keys_code()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment