Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto-generate the command table from JSON files #9656

Merged
merged 63 commits into from Dec 15, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
11193cd
WIP gen command table
guybe7 Sep 15, 2021
bd3730b
refactor
guybe7 Oct 27, 2021
38a3805
cont
guybe7 Oct 29, 2021
f7d288d
minimise preprocessor usage
guybe7 Oct 29, 2021
827719e
restore help.h (for now)
guybe7 Oct 29, 2021
d3ab327
cont
guybe7 Nov 3, 2021
31f13dd
Merge remote-tracking branch 'origin/unstable' into gen_command_code
guybe7 Nov 3, 2021
6739408
cont
guybe7 Nov 3, 2021
49c29bc
cont 2
guybe7 Nov 10, 2021
f25f3e8
typo
guybe7 Nov 10, 2021
8e7c5ef
Merge remote-tracking branch 'origin/unstable' into gen_command_code
guybe7 Nov 10, 2021
c49c859
some fixes
guybe7 Nov 10, 2021
da1605b
cont 3
guybe7 Nov 11, 2021
1111ba3
cont 4
guybe7 Nov 17, 2021
0df1448
cont 5
guybe7 Nov 17, 2021
873aa25
fix module tests
guybe7 Nov 17, 2021
6173023
fix eval
guybe7 Nov 17, 2021
60e8ad1
cont
guybe7 Nov 17, 2021
71c5af6
cont 2
guybe7 Nov 22, 2021
038d858
cont 3
guybe7 Nov 22, 2021
3206d33
almost done
guybe7 Nov 24, 2021
1b918a7
Merge remote-tracking branch 'origin/unstable' into gen_command_code
guybe7 Nov 24, 2021
16a8595
almost done 2
guybe7 Nov 24, 2021
3e999cb
remove return_type for the moment
guybe7 Nov 24, 2021
a693243
typo
guybe7 Nov 24, 2021
bb267a5
mostly refactoring in module, add history API
guybe7 Nov 24, 2021
3ba6d81
more APIs
guybe7 Nov 24, 2021
436ef4b
add args API
guybe7 Nov 28, 2021
fc4002d
some more fixes
guybe7 Nov 28, 2021
b2d81c8
Merge remote-tracking branch 'origin/unstable' into gen_command_code
guybe7 Nov 28, 2021
b493b7a
remove lcsGetKeys
guybe7 Nov 28, 2021
dfc5383
fix memleak
guybe7 Nov 28, 2021
1ab3f34
CR fixes 1
guybe7 Nov 30, 2021
d12c769
fix ACL test
guybe7 Nov 30, 2021
3f924b8
CR fixes 2
guybe7 Dec 1, 2021
eb31e91
Merge remote-tracking branch 'origin/unstable' into gen_command_code
guybe7 Dec 1, 2021
d317b53
fix CONFIG SET arity
guybe7 Dec 1, 2021
2e467b8
re-gen commands.c
guybe7 Dec 1, 2021
a235623
fix addACLLogEntry
guybe7 Dec 1, 2021
3d268a3
literals uppercase, placeholders lowercase
guybe7 Dec 1, 2021
0e6832d
reference key arg to key-spec
guybe7 Dec 1, 2021
8341d27
Merge remote-tracking branch 'origin/unstable' into gen_command_code
guybe7 Dec 3, 2021
b436bc9
CR fixes 2
guybe7 Dec 3, 2021
707931e
update jsons with new Redis functions
guybe7 Dec 3, 2021
59fa55b
fix test
guybe7 Dec 3, 2021
87a4f7f
COMMAND LIST args + cleanup of non-optional pure-tokens
guybe7 Dec 6, 2021
fd58bc6
move function command declarations to server.h
guybe7 Dec 6, 2021
87f3218
apply module API doc standards
guybe7 Dec 6, 2021
4070176
more fixes
guybe7 Dec 8, 2021
49b148f
cont
guybe7 Dec 8, 2021
dfcf81b
Merge remote-tracking branch 'origin/unstable' into gen_command_code
guybe7 Dec 8, 2021
31ec2f3
remove unused arg from moduleAPI
guybe7 Dec 15, 2021
58bc08e
add CMD_MODULE to COMMAND INFO
guybe7 Dec 15, 2021
be1989e
Yossi's comments
guybe7 Dec 15, 2021
6264460
add args where needed
guybe7 Dec 15, 2021
ba79b5f
use uppercase flag/categories in jsons + use command flags, not string
guybe7 Dec 15, 2021
faa270b
remove module API
guybe7 Dec 15, 2021
eb968b8
split flags and ACL categories
guybe7 Dec 15, 2021
adb40d0
fix ACL tests
guybe7 Dec 15, 2021
7269e47
add missing information
guybe7 Dec 15, 2021
1036f93
fix complexity
guybe7 Dec 15, 2021
2d6b7fb
final fix
guybe7 Dec 15, 2021
ebd9216
final fix 2
guybe7 Dec 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/Makefile
Expand Up @@ -288,7 +288,7 @@ endif

REDIS_SERVER_NAME=redis-server$(PROG_SUFFIX)
REDIS_SENTINEL_NAME=redis-sentinel$(PROG_SUFFIX)
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o connection.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o
REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o commands.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crcspeed.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o connection.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o
REDIS_CLI_NAME=redis-cli$(PROG_SUFFIX)
REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o redisassert.o crcspeed.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o
REDIS_BENCHMARK_NAME=redis-benchmark$(PROG_SUFFIX)
Expand Down Expand Up @@ -430,9 +430,6 @@ valgrind:
helgrind:
$(MAKE) OPTIMIZATION="-O0" MALLOC="libc" CFLAGS="-D__ATOMIC_VAR_FORCE_SYNC_MACROS" REDIS_CFLAGS="-I/usr/local/include" REDIS_LDFLAGS="-L/usr/local/lib"

src/help.h:
@../utils/generate-command-help.rb > help.h

install: all
@mkdir -p $(INSTALL_BIN)
$(call MAKE_INSTALL,$(REDIS_SERVER_NAME),$(INSTALL_BIN))
Expand Down
363 changes: 363 additions & 0 deletions src/commands.c
@@ -0,0 +1,363 @@
/* Automatically generated by generate-command-code.py, do not edit. */

#include "server.h"

/* Our command table.
*
* (See comment above sturct redisCommand)
*
* Command flags are expressed using space separated strings, that are turned
* into actual flags by the populateCommandTable() function.
*
* This is the meaning of the flags:
*
* write: Write command (may modify the key space).
*
* read-only: Commands just reading from keys without changing the content.
* Note that commands that don't read from the keyspace such as
* TIME, SELECT, INFO, administrative commands, and connection
* or transaction related commands (multi, exec, discard, ...)
* are not flagged as read-only commands, since they affect the
* server or the connection in other ways.
*
* use-memory: May increase memory usage once called. Don't allow if out
* of memory.
*
* admin: Administrative command, like SAVE or SHUTDOWN.
*
* pub-sub: Pub/Sub related command.
*
* no-script: Command not allowed in scripts.
*
* random: Random command. Command is not deterministic, that is, the same
* command with the same arguments, with the same key space, may
* have different results. For instance SPOP and RANDOMKEY are
* two random commands.
*
* to-sort: Sort command output array if called from script, so that the
* output is deterministic. When this flag is used (not always
* possible), then the "random" flag is not needed.
*
* ok-loading: Allow the command while loading the database.
*
* ok-stale: Allow the command while a slave has stale data but is not
* allowed to serve this data. Normally no command is accepted
* in this condition but just a few.
*
* no-monitor: Do not automatically propagate the command on MONITOR.
*
* no-slowlog: Do not automatically propagate the command to the slowlog.
*
* cluster-asking: Perform an implicit ASKING for this command, so the
* command will be accepted in cluster mode if the slot is marked
* as 'importing'.
*
* fast: Fast command: O(1) or O(log(N)) command that should never
* delay its execution as long as the kernel scheduler is giving
* us time. Note that commands that may trigger a DEL as a side
* effect (like SET) are not fast commands.
*
* may-replicate: Command may produce replication traffic, but should be
* allowed under circumstances where write commands are disallowed.
* Examples include PUBLISH, which replicates pubsub messages,and
* EVAL, which may execute write commands, which are replicated,
* or may just execute read commands. A command can not be marked
* both "write" and "may-replicate"
*
* sentinel: This command is present in sentinel mode too.
*
* sentinel-only: This command is present only when in sentinel mode.
*
* The following additional flags are only used in order to put commands
* in a specific ACL category. Commands can have multiple ACL categories.
* See redis.conf for the exact meaning of each.
*
* @keyspace, @read, @write, @set, @sortedset, @list, @hash, @string, @bitmap,
* @hyperloglog, @stream, @admin, @fast, @slow, @pubsub, @blocking, @dangerous,
* @connection, @transaction, @scripting, @geo.
*
* Note that:
*
* 1) The read-only flag implies the @read ACL category.
* 2) The write flag implies the @write ACL category.
* 3) The fast flag implies the @fast ACL category.
* 4) The admin flag implies the @admin and @dangerous ACL category.
* 5) The pub-sub flag implies the @pubsub ACL category.
* 6) The lack of fast flag implies the @slow ACL category.
* 7) The non obvious "keyspace" category includes the commands
* that interact with keys without having anything to do with
* specific data structures, such as: DEL, RENAME, MOVE, SELECT,
* TYPE, EXPIRE*, PEXPIRE*, TTL, PTTL, ...
*/

/********** CONFIG SET ********************/

/* CONFIG SET return info */
commandReturnInfo CONFIG_SET_ReturnInfo[] = {
{"Command succeeded","+OK",RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_SIMPLE_STRING},
{0}
};

/* CONFIG SET history */
#define CONFIG_SET_History NULL

/* CONFIG SET argument table */
struct redisCommandArg CONFIG_SET_Args[] = {
{"parameter",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="parameter"},
{"value",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="value"},
{0}
};

/* CONFIG command table */
struct redisCommand CONFIG_Subcommands[] = {
{"SET","Set a configuration parameter to the given value",NULL,"2.0.0",COMMAND_GROUP_GENERIC,CONFIG_SET_ReturnInfo,CONFIG_SET_History,configSetCommand,4,"admin no-script",.args=CONFIG_SET_Args},
{0}
};

/********** CONFIG ********************/

/* CONFIG return info */
#define CONFIG_ReturnInfo NULL

/* CONFIG history */
#define CONFIG_History NULL

/********** MIGRATE ********************/

/* MIGRATE return info */
commandReturnInfo MIGRATE_ReturnInfo[] = {
{"Command succeeded","+OK",RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_SIMPLE_STRING},
{"Key(s) was not in found in source","+NOKEY",RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_SIMPLE_STRING},
{0}
};

/* MIGRATE history */
commandHistory MIGRATE_History[] = {
{"3.0.0","Added the `COPY` and `REPLACE` options."},
{"3.0.6","Added the `KEYS` option."},
{"4.0.7","Added the `AUTH` option."},
{"6.0.0","Added the `AUTH2` option."},
{0}
};

/* MIGRATE keyornone argument table */
struct redisCommandArg MIGRATE_keyornone_Subargs[] = {
{"key",ARG_TYPE_KEY,NULL,NULL,NULL,0,0,.value.string="key"},
{"nokey",ARG_TYPE_NULL,"""",NULL,NULL,0,0},
{0}
};

/* MIGRATE auth2 argument table */
struct redisCommandArg MIGRATE_auth2_Subargs[] = {
{"username",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="username"},
{"password",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="password"},
{0}
};

/* MIGRATE argument table */
struct redisCommandArg MIGRATE_Args[] = {
{"host",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="host"},
{"port",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="port"},
{"keyornone",ARG_TYPE_ONEOF,NULL,NULL,NULL,0,0,.value.subargs=MIGRATE_keyornone_Subargs},
{"destination-db",ARG_TYPE_INTEGER,NULL,NULL,NULL,0,0,.value.string="destination-db"},
{"timeout",ARG_TYPE_INTEGER,NULL,NULL,NULL,0,0,.value.string="timeout"},
{"copy",ARG_TYPE_NULL,"COPY",NULL,NULL,1,0},
{"replace",ARG_TYPE_NULL,"REPLACE",NULL,NULL,1,0},
{"auth",ARG_TYPE_STRING,"AUTH",NULL,NULL,1,0,.value.string="password"},
{"auth2",ARG_TYPE_BLOCK,"AUTH2",NULL,NULL,1,0,.value.subargs=MIGRATE_auth2_Subargs},
{"keys",ARG_TYPE_KEY,"KEYS",NULL,NULL,1,1,.value.string="key"},
{0}
};

/********** COMMAND COUNT ********************/

/* COMMAND COUNT return info */
commandReturnInfo COMMAND_COUNT_ReturnInfo[] = {
{"Number of commands",NULL,RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_INTEGER},
{0}
};

/* COMMAND COUNT history */
#define COMMAND_COUNT_History NULL

/********** COMMAND GETKEYS ********************/

/* COMMAND GETKEYS return info */
commandReturnInfo COMMAND_GETKEYS_ReturnInfo[] = {
{"The list of keys from your command",NULL,RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_ARRAY},
{0}
};

/* COMMAND GETKEYS history */
#define COMMAND_GETKEYS_History NULL

/* COMMAND command table */
struct redisCommand COMMAND_Subcommands[] = {
{"COUNT","Get total number of Redis commands","O(1)","2.8.13",COMMAND_GROUP_SERVER,COMMAND_COUNT_ReturnInfo,COMMAND_COUNT_History,commandCountCommand,2,"ok-loading ok-stale @connection"},
{"GETKEYS","Extract keys given a full Redis command","O(N) where N is the number of arguments to the command","2.8.13",COMMAND_GROUP_SERVER,COMMAND_GETKEYS_ReturnInfo,COMMAND_GETKEYS_History,commandGetKeysCommand,-4,"ok-loading ok-stale @connection"},
{0}
};

/********** COMMAND ********************/

/* COMMAND return info */
commandReturnInfo COMMAND_ReturnInfo[] = {
{"Nested list of command details",NULL,RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_ARRAY},
{0}
};

/* COMMAND history */
#define COMMAND_History NULL

/********** ZUNIONSTORE ********************/

/* ZUNIONSTORE return info */
commandReturnInfo ZUNIONSTORE_ReturnInfo[] = {
{"Cardinality of the result",NULL,RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_INTEGER},
{0}
};

/* ZUNIONSTORE history */
#define ZUNIONSTORE_History NULL

/* ZUNIONSTORE aggregate argument table */
struct redisCommandArg ZUNIONSTORE_aggregate_Subargs[] = {
{"sum",ARG_TYPE_NULL,"SUM",NULL,NULL,0,0},
{"min",ARG_TYPE_NULL,"MIN",NULL,NULL,0,0},
{"max",ARG_TYPE_NULL,"MAX",NULL,NULL,0,0},
{0}
};

/* ZUNIONSTORE argument table */
struct redisCommandArg ZUNIONSTORE_Args[] = {
{"destination",ARG_TYPE_KEY,NULL,NULL,NULL,0,0,.value.string="destination"},
{"numkeys",ARG_TYPE_INTEGER,NULL,NULL,NULL,0,0,.value.string="numkeys"},
{"key",ARG_TYPE_KEY,NULL,NULL,NULL,0,1,.value.string="key"},
{"weights",ARG_TYPE_INTEGER,"WEIGHTS",NULL,NULL,1,1,.value.string="weight"},
{"aggregate",ARG_TYPE_ONEOF,"AGGREGATE",NULL,NULL,1,0,.value.subargs=ZUNIONSTORE_aggregate_Subargs},
{0}
};

/********** XADD ********************/

/* XADD return info */
commandReturnInfo XADD_ReturnInfo[] = {
{"ID of the added entry",NULL,RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_BULK_STRING},
{"Stream doesn't exist and NOMKSTREAN was given",NULL,RETURN_TYPE_RESP2_3_DIFFER,.type.unique={RESP2_NULL_BULK_STRING,RESP3_NULL}},
{0}
};

/* XADD history */
commandHistory XADD_History[] = {
{"6.2","Added the `NOMKSTREAM` option, `MINID` trimming strategy and the `LIMIT` option."},
{0}
};

/* XADD trimming strategy argument table */
struct redisCommandArg XADD_trimming_strategy_Subargs[] = {
{"maxlen",ARG_TYPE_NULL,"MAXLEN",NULL,NULL,0,0},
{"minid",ARG_TYPE_NULL,"MINID",NULL,"6.2.0",0,0},
{0}
};

/* XADD trimming operator argument table */
struct redisCommandArg XADD_trimming_operator_Subargs[] = {
{"exact",ARG_TYPE_NULL,"=",NULL,NULL,0,0},
{"inexact",ARG_TYPE_NULL,"~",NULL,NULL,0,0},
{0}
};

/* XADD trimming argument table */
struct redisCommandArg XADD_trimming_Subargs[] = {
{"strategy",ARG_TYPE_ONEOF,NULL,NULL,NULL,0,0,.value.subargs=XADD_trimming_strategy_Subargs},
{"operator",ARG_TYPE_ONEOF,NULL,NULL,NULL,1,0,.value.subargs=XADD_trimming_operator_Subargs},
{"threshold",ARG_TYPE_INTEGER,NULL,NULL,NULL,0,0,.value.string="threshold"},
{"limit",ARG_TYPE_INTEGER,"LIMIT",NULL,"6.2.0",1,0,.value.string="limit"},
{0}
};

/* XADD id argument table */
struct redisCommandArg XADD_id_Subargs[] = {
{"auto",ARG_TYPE_NULL,"*",NULL,NULL,0,0},
{"specific",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="ID"},
{0}
};

/* XADD fieldandvalues argument table */
struct redisCommandArg XADD_fieldandvalues_Subargs[] = {
{"field",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="field"},
{"value",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="value"},
{0}
};

/* XADD argument table */
struct redisCommandArg XADD_Args[] = {
{"key",ARG_TYPE_KEY,NULL,NULL,NULL,0,0,.value.string="key"},
{"trimming",ARG_TYPE_BLOCK,NULL,NULL,NULL,1,0,.value.subargs=XADD_trimming_Subargs},
{"nomakestream",ARG_TYPE_NULL,"NOMKSTREAM",NULL,"6.2.0",1,0},
{"id",ARG_TYPE_ONEOF,NULL,NULL,NULL,0,0,.value.subargs=XADD_id_Subargs},
{"fieldandvalues",ARG_TYPE_BLOCK,NULL,NULL,NULL,0,1,.value.subargs=XADD_fieldandvalues_Subargs},
{0}
};

/********** SET ********************/

/* SET return info */
commandReturnInfo SET_ReturnInfo[] = {
{"Command succeeded","+OK",RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_SIMPLE_STRING},
{"Old value if `GET` was given",NULL,RETURN_TYPE_RESP2_3_SAME,.type.global=RESP2_BULK_STRING},
{"Either `SET` failed (with `NX` or `XX`), or `GET` was given and key didn't exist",NULL,RETURN_TYPE_RESP2_3_DIFFER,.type.unique={RESP2_NULL_BULK_STRING,RESP3_NULL}},
{0}
};

/* SET history */
commandHistory SET_History[] = {
{"2.6.12","Added the `EX`, `PX`, `NX` and `XX` options."},
{"6.0","Added the `KEEPTTL` option."},
{"6.2","Added the `GET`, `EXAT` and `PXAT` option."},
{"7.0","Allowed the `NX` and `GET` options to be used together."},
{0}
};

/* SET expire argument table */
struct redisCommandArg SET_expire_Subargs[] = {
{"ex",ARG_TYPE_INTEGER,"EX",NULL,"2.6.12",0,0,.value.string="seconds"},
{"px",ARG_TYPE_INTEGER,"PX",NULL,"2.6.12",0,0,.value.string="milliseconds"},
{"exat",ARG_TYPE_UNIX_TIME,"EXAT",NULL,"6.2.0",0,0,.value.string="timestamp"},
{"pxat",ARG_TYPE_UNIX_TIME,"PXAT",NULL,"6.2.0",0,0,.value.string="milliseconds-timestamp"},
{"keepttl",ARG_TYPE_NULL,"KEEPTTL",NULL,"6.0.0",0,0},
{0}
};

/* SET existence argument table */
struct redisCommandArg SET_existence_Subargs[] = {
{"nx",ARG_TYPE_NULL,"NX",NULL,NULL,0,0},
{"xx",ARG_TYPE_NULL,"XX",NULL,NULL,0,0},
{0}
};

/* SET argument table */
struct redisCommandArg SET_Args[] = {
{"key",ARG_TYPE_KEY,NULL,NULL,NULL,0,0,.value.string="key"},
{"value",ARG_TYPE_STRING,NULL,NULL,NULL,0,0,.value.string="value"},
{"expire",ARG_TYPE_ONEOF,NULL,NULL,NULL,1,0,.value.subargs=SET_expire_Subargs},
{"existence",ARG_TYPE_ONEOF,NULL,NULL,NULL,1,0,.value.subargs=SET_existence_Subargs},
{"get",ARG_TYPE_NULL,"GET",NULL,"6.2.0",1,0},
{0}
};

/* Main command table */
struct redisCommand redisCommandTable[] = {
/* generic */
{"CONFIG",NULL,NULL,NULL,COMMAND_GROUP_GENERIC,CONFIG_ReturnInfo,CONFIG_History,NULL,-2,"",.subcommands=CONFIG_Subcommands},
{"MIGRATE","Atomically transfer a key from a Redis instance to another one.","This command actually executes a DUMP+DEL in the source instance, and a RESTORE in the target instance. See the pages of these commands for time complexity. Also an O(N) data transfer between the two instances is performed.","2.6.0",COMMAND_GROUP_GENERIC,MIGRATE_ReturnInfo,MIGRATE_History,migrateCommand,-6,"write random @keyspace @dangerous @write @slow",{{"write",KSPEC_BS_INDEX,.bs.index={3},KSPEC_FK_RANGE,.fk.range={0,1,0}},{"write incomplete",KSPEC_BS_KEYWORD,.bs.keyword={"KEYS",-2},KSPEC_FK_RANGE,.fk.range={-1,1,0}}},migrateGetKeys,.args=MIGRATE_Args},
/* server */
{"COMMAND","Get array of Redis command details","O(N) where N is the total number of Redis commands","2.8.13",COMMAND_GROUP_SERVER,COMMAND_ReturnInfo,COMMAND_History,commandCommand,-1,"ok-loading ok-stale @connection",.subcommands=COMMAND_Subcommands},
/* sorted-set */
{"ZUNIONSTORE","Add multiple sorted sets and store the resulting sorted set in a new key","O(N)+O(M log(M)) with N being the sum of the sizes of the input sorted sets, and M being the number of elements in the resulting sorted set.","2.0.0",COMMAND_GROUP_SORTED_SET,ZUNIONSTORE_ReturnInfo,ZUNIONSTORE_History,zunionstoreCommand,-4,"write use-memory @sortedset @write @slow",{{"write",KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}},{"read",KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.keynum={0,1,1}}},zunionInterDiffStoreGetKeys,.args=ZUNIONSTORE_Args},
/* stream */
{"XADD","Appends a new entry to a stream","O(1) when adding a new entry, O(N) when trimming where N being the number of entries evicted.","5.0.0",COMMAND_GROUP_STREAM,XADD_ReturnInfo,XADD_History,xaddCommand,-5,"write use-memory fast random @stream @write @slow",{{"write",KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=XADD_Args},
/* string */
{"SET","Set the string value of a key","O(1)","1.0.0",COMMAND_GROUP_STRING,SET_ReturnInfo,SET_History,setCommand,-3,"write use-memory @string @write @slow",{{"write",KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=SET_Args},
{0}
};