diff options
Diffstat (limited to 'command.c')
| -rw-r--r-- | command.c | 1700 |
1 files changed, 1700 insertions, 0 deletions
diff --git a/command.c b/command.c new file mode 100644 index 0000000..e32091b --- /dev/null +++ b/command.c @@ -0,0 +1,1700 @@ +#include <ctype.h> +#include <errno.h> + +#include "command.h" +#include "hiutil.h" +#include "hiarray.h" + + +static uint64_t cmd_id = 0; /* command id counter */ + + +/* + * Return true, if the redis command take no key, otherwise + * return false + */ +static int +redis_argz(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_PING: + case CMD_REQ_REDIS_QUIT: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts no arguments, otherwise + * return false + */ +static int +redis_arg0(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_EXISTS: + case CMD_REQ_REDIS_PERSIST: + case CMD_REQ_REDIS_PTTL: + case CMD_REQ_REDIS_SORT: + case CMD_REQ_REDIS_TTL: + case CMD_REQ_REDIS_TYPE: + case CMD_REQ_REDIS_DUMP: + + case CMD_REQ_REDIS_DECR: + case CMD_REQ_REDIS_GET: + case CMD_REQ_REDIS_INCR: + case CMD_REQ_REDIS_STRLEN: + + case CMD_REQ_REDIS_HGETALL: + case CMD_REQ_REDIS_HKEYS: + case CMD_REQ_REDIS_HLEN: + case CMD_REQ_REDIS_HVALS: + + case CMD_REQ_REDIS_LLEN: + case CMD_REQ_REDIS_LPOP: + case CMD_REQ_REDIS_RPOP: + + case CMD_REQ_REDIS_SCARD: + case CMD_REQ_REDIS_SMEMBERS: + case CMD_REQ_REDIS_SPOP: + + case CMD_REQ_REDIS_ZCARD: + case CMD_REQ_REDIS_PFCOUNT: + case CMD_REQ_REDIS_AUTH: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts exactly 1 argument, otherwise + * return false + */ +static int +redis_arg1(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_EXPIRE: + case CMD_REQ_REDIS_EXPIREAT: + case CMD_REQ_REDIS_PEXPIRE: + case CMD_REQ_REDIS_PEXPIREAT: + + case CMD_REQ_REDIS_APPEND: + case CMD_REQ_REDIS_DECRBY: + case CMD_REQ_REDIS_GETBIT: + case CMD_REQ_REDIS_GETSET: + case CMD_REQ_REDIS_INCRBY: + case CMD_REQ_REDIS_INCRBYFLOAT: + case CMD_REQ_REDIS_SETNX: + + case CMD_REQ_REDIS_HEXISTS: + case CMD_REQ_REDIS_HGET: + + case CMD_REQ_REDIS_LINDEX: + case CMD_REQ_REDIS_LPUSHX: + case CMD_REQ_REDIS_RPOPLPUSH: + case CMD_REQ_REDIS_RPUSHX: + + case CMD_REQ_REDIS_SISMEMBER: + + case CMD_REQ_REDIS_ZRANK: + case CMD_REQ_REDIS_ZREVRANK: + case CMD_REQ_REDIS_ZSCORE: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts exactly 2 arguments, otherwise + * return false + */ +static int +redis_arg2(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_GETRANGE: + case CMD_REQ_REDIS_PSETEX: + case CMD_REQ_REDIS_SETBIT: + case CMD_REQ_REDIS_SETEX: + case CMD_REQ_REDIS_SETRANGE: + + case CMD_REQ_REDIS_HINCRBY: + case CMD_REQ_REDIS_HINCRBYFLOAT: + case CMD_REQ_REDIS_HSET: + case CMD_REQ_REDIS_HSETNX: + + case CMD_REQ_REDIS_LRANGE: + case CMD_REQ_REDIS_LREM: + case CMD_REQ_REDIS_LSET: + case CMD_REQ_REDIS_LTRIM: + + case CMD_REQ_REDIS_SMOVE: + + case CMD_REQ_REDIS_ZCOUNT: + case CMD_REQ_REDIS_ZLEXCOUNT: + case CMD_REQ_REDIS_ZINCRBY: + case CMD_REQ_REDIS_ZREMRANGEBYLEX: + case CMD_REQ_REDIS_ZREMRANGEBYRANK: + case CMD_REQ_REDIS_ZREMRANGEBYSCORE: + + case CMD_REQ_REDIS_RESTORE: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts exactly 3 arguments, otherwise + * return false + */ +static int +redis_arg3(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_LINSERT: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command accepts 0 or more arguments, otherwise + * return false + */ +static int +redis_argn(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_BITCOUNT: + + case CMD_REQ_REDIS_SET: + case CMD_REQ_REDIS_HDEL: + case CMD_REQ_REDIS_HMGET: + case CMD_REQ_REDIS_HMSET: + case CMD_REQ_REDIS_HSCAN: + + case CMD_REQ_REDIS_LPUSH: + case CMD_REQ_REDIS_RPUSH: + + case CMD_REQ_REDIS_SADD: + case CMD_REQ_REDIS_SDIFF: + case CMD_REQ_REDIS_SDIFFSTORE: + case CMD_REQ_REDIS_SINTER: + case CMD_REQ_REDIS_SINTERSTORE: + case CMD_REQ_REDIS_SREM: + case CMD_REQ_REDIS_SUNION: + case CMD_REQ_REDIS_SUNIONSTORE: + case CMD_REQ_REDIS_SRANDMEMBER: + case CMD_REQ_REDIS_SSCAN: + + case CMD_REQ_REDIS_PFADD: + case CMD_REQ_REDIS_PFMERGE: + + case CMD_REQ_REDIS_ZADD: + case CMD_REQ_REDIS_ZINTERSTORE: + case CMD_REQ_REDIS_ZRANGE: + case CMD_REQ_REDIS_ZRANGEBYSCORE: + case CMD_REQ_REDIS_ZREM: + case CMD_REQ_REDIS_ZREVRANGE: + case CMD_REQ_REDIS_ZRANGEBYLEX: + case CMD_REQ_REDIS_ZREVRANGEBYSCORE: + case CMD_REQ_REDIS_ZUNIONSTORE: + case CMD_REQ_REDIS_ZSCAN: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command is a vector command accepting one or + * more keys, otherwise return false + */ +static int +redis_argx(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_MGET: + case CMD_REQ_REDIS_DEL: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command is a vector command accepting one or + * more key-value pairs, otherwise return false + */ +static int +redis_argkvx(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_MSET: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Return true, if the redis command is either EVAL or EVALSHA. These commands + * have a special format with exactly 2 arguments, followed by one or more keys, + * followed by zero or more arguments (the documentation online seems to suggest + * that at least one argument is required, but that shouldn't be the case). + */ +static int +redis_argeval(struct cmd *r) +{ + switch (r->type) { + case CMD_REQ_REDIS_EVAL: + case CMD_REQ_REDIS_EVALSHA: + return 1; + + default: + break; + } + + return 0; +} + +/* + * Reference: http://redis.io/topics/protocol + * + * Redis >= 1.2 uses the unified protocol to send requests to the Redis + * server. In the unified protocol all the arguments sent to the server + * are binary safe and every request has the following general form: + * + * *<number of arguments> CR LF + * $<number of bytes of argument 1> CR LF + * <argument data> CR LF + * ... + * $<number of bytes of argument N> CR LF + * <argument data> CR LF + * + * Before the unified request protocol, redis protocol for requests supported + * the following commands + * 1). Inline commands: simple commands where arguments are just space + * separated strings. No binary safeness is possible. + * 2). Bulk commands: bulk commands are exactly like inline commands, but + * the last argument is handled in a special way in order to allow for + * a binary-safe last argument. + * + * only supports the Redis unified protocol for requests. + */ +void +redis_parse_cmd(struct cmd *r) +{ + int len; + char *p, *m, *token = NULL; + char *cmd_end; + char ch; + uint32_t rlen = 0; /* running length in parsing fsa */ + uint32_t rnarg = 0; /* running # arg used by parsing fsa */ + enum { + SW_START, + SW_NARG, + SW_NARG_LF, + SW_REQ_TYPE_LEN, + SW_REQ_TYPE_LEN_LF, + SW_REQ_TYPE, + SW_REQ_TYPE_LF, + SW_KEY_LEN, + SW_KEY_LEN_LF, + SW_KEY, + SW_KEY_LF, + SW_ARG1_LEN, + SW_ARG1_LEN_LF, + SW_ARG1, + SW_ARG1_LF, + SW_ARG2_LEN, + SW_ARG2_LEN_LF, + SW_ARG2, + SW_ARG2_LF, + SW_ARG3_LEN, + SW_ARG3_LEN_LF, + SW_ARG3, + SW_ARG3_LF, + SW_ARGN_LEN, + SW_ARGN_LEN_LF, + SW_ARGN, + SW_ARGN_LF, + SW_SENTINEL + } state; + + state = SW_START; + cmd_end = r->cmd + r->clen; + + ASSERT(state >= SW_START && state < SW_SENTINEL); + ASSERT(r->cmd != NULL && r->clen > 0); + + for (p = r->cmd; p < cmd_end; p++) { + ch = *p; + + switch (state) { + + case SW_START: + case SW_NARG: + if (token == NULL) { + if (ch != '*') { + goto error; + } + token = p; + /* req_start <- p */ + r->narg_start = p; + rnarg = 0; + state = SW_NARG; + } else if (isdigit(ch)) { + rnarg = rnarg * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if (rnarg == 0) { + goto error; + } + r->narg = rnarg; + r->narg_end = p; + token = NULL; + state = SW_NARG_LF; + } else { + goto error; + } + + break; + + case SW_NARG_LF: + switch (ch) { + case LF: + state = SW_REQ_TYPE_LEN; + break; + + default: + goto error; + } + + break; + + case SW_REQ_TYPE_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + token = p; + rlen = 0; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if (rlen == 0 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_REQ_TYPE_LEN_LF; + } else { + goto error; + } + + break; + + case SW_REQ_TYPE_LEN_LF: + switch (ch) { + case LF: + state = SW_REQ_TYPE; + break; + + default: + goto error; + } + + break; + + case SW_REQ_TYPE: + if (token == NULL) { + token = p; + } + + m = token + rlen; + if (m >= cmd_end) { + //m = cmd_end - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + m = token; + token = NULL; + r->type = CMD_UNKNOWN; + + switch (p - m) { + + case 3: + if (str3icmp(m, 'g', 'e', 't')) { + r->type = CMD_REQ_REDIS_GET; + break; + } + + if (str3icmp(m, 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_SET; + break; + } + + if (str3icmp(m, 't', 't', 'l')) { + r->type = CMD_REQ_REDIS_TTL; + break; + } + + if (str3icmp(m, 'd', 'e', 'l')) { + r->type = CMD_REQ_REDIS_DEL; + break; + } + + break; + + case 4: + if (str4icmp(m, 'p', 't', 't', 'l')) { + r->type = CMD_REQ_REDIS_PTTL; + break; + } + + if (str4icmp(m, 'd', 'e', 'c', 'r')) { + r->type = CMD_REQ_REDIS_DECR; + break; + } + + if (str4icmp(m, 'd', 'u', 'm', 'p')) { + r->type = CMD_REQ_REDIS_DUMP; + break; + } + + if (str4icmp(m, 'h', 'd', 'e', 'l')) { + r->type = CMD_REQ_REDIS_HDEL; + break; + } + + if (str4icmp(m, 'h', 'g', 'e', 't')) { + r->type = CMD_REQ_REDIS_HGET; + break; + } + + if (str4icmp(m, 'h', 'l', 'e', 'n')) { + r->type = CMD_REQ_REDIS_HLEN; + break; + } + + if (str4icmp(m, 'h', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_HSET; + break; + } + + if (str4icmp(m, 'i', 'n', 'c', 'r')) { + r->type = CMD_REQ_REDIS_INCR; + break; + } + + if (str4icmp(m, 'l', 'l', 'e', 'n')) { + r->type = CMD_REQ_REDIS_LLEN; + break; + } + + if (str4icmp(m, 'l', 'p', 'o', 'p')) { + r->type = CMD_REQ_REDIS_LPOP; + break; + } + + if (str4icmp(m, 'l', 'r', 'e', 'm')) { + r->type = CMD_REQ_REDIS_LREM; + break; + } + + if (str4icmp(m, 'l', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_LSET; + break; + } + + if (str4icmp(m, 'r', 'p', 'o', 'p')) { + r->type = CMD_REQ_REDIS_RPOP; + break; + } + + if (str4icmp(m, 's', 'a', 'd', 'd')) { + r->type = CMD_REQ_REDIS_SADD; + break; + } + + if (str4icmp(m, 's', 'p', 'o', 'p')) { + r->type = CMD_REQ_REDIS_SPOP; + break; + } + + if (str4icmp(m, 's', 'r', 'e', 'm')) { + r->type = CMD_REQ_REDIS_SREM; + break; + } + + if (str4icmp(m, 't', 'y', 'p', 'e')) { + r->type = CMD_REQ_REDIS_TYPE; + break; + } + + if (str4icmp(m, 'm', 'g', 'e', 't')) { + r->type = CMD_REQ_REDIS_MGET; + break; + } + if (str4icmp(m, 'm', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_MSET; + break; + } + + if (str4icmp(m, 'z', 'a', 'd', 'd')) { + r->type = CMD_REQ_REDIS_ZADD; + break; + } + + if (str4icmp(m, 'z', 'r', 'e', 'm')) { + r->type = CMD_REQ_REDIS_ZREM; + break; + } + + if (str4icmp(m, 'e', 'v', 'a', 'l')) { + r->type = CMD_REQ_REDIS_EVAL; + break; + } + + if (str4icmp(m, 's', 'o', 'r', 't')) { + r->type = CMD_REQ_REDIS_SORT; + break; + } + + if (str4icmp(m, 'p', 'i', 'n', 'g')) { + r->type = CMD_REQ_REDIS_PING; + r->noforward = 1; + break; + } + + if (str4icmp(m, 'q', 'u', 'i', 't')) { + r->type = CMD_REQ_REDIS_QUIT; + r->quit = 1; + break; + } + + if (str4icmp(m, 'a', 'u', 't', 'h')) { + r->type = CMD_REQ_REDIS_AUTH; + r->noforward = 1; + break; + } + + break; + + case 5: + if (str5icmp(m, 'h', 'k', 'e', 'y', 's')) { + r->type = CMD_REQ_REDIS_HKEYS; + break; + } + + if (str5icmp(m, 'h', 'm', 'g', 'e', 't')) { + r->type = CMD_REQ_REDIS_HMGET; + break; + } + + if (str5icmp(m, 'h', 'm', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_HMSET; + break; + } + + if (str5icmp(m, 'h', 'v', 'a', 'l', 's')) { + r->type = CMD_REQ_REDIS_HVALS; + break; + } + + if (str5icmp(m, 'h', 's', 'c', 'a', 'n')) { + r->type = CMD_REQ_REDIS_HSCAN; + break; + } + + if (str5icmp(m, 'l', 'p', 'u', 's', 'h')) { + r->type = CMD_REQ_REDIS_LPUSH; + break; + } + + if (str5icmp(m, 'l', 't', 'r', 'i', 'm')) { + r->type = CMD_REQ_REDIS_LTRIM; + break; + } + + if (str5icmp(m, 'r', 'p', 'u', 's', 'h')) { + r->type = CMD_REQ_REDIS_RPUSH; + break; + } + + if (str5icmp(m, 's', 'c', 'a', 'r', 'd')) { + r->type = CMD_REQ_REDIS_SCARD; + break; + } + + if (str5icmp(m, 's', 'd', 'i', 'f', 'f')) { + r->type = CMD_REQ_REDIS_SDIFF; + break; + } + + if (str5icmp(m, 's', 'e', 't', 'e', 'x')) { + r->type = CMD_REQ_REDIS_SETEX; + break; + } + + if (str5icmp(m, 's', 'e', 't', 'n', 'x')) { + r->type = CMD_REQ_REDIS_SETNX; + break; + } + + if (str5icmp(m, 's', 'm', 'o', 'v', 'e')) { + r->type = CMD_REQ_REDIS_SMOVE; + break; + } + + if (str5icmp(m, 's', 's', 'c', 'a', 'n')) { + r->type = CMD_REQ_REDIS_SSCAN; + break; + } + + if (str5icmp(m, 'z', 'c', 'a', 'r', 'd')) { + r->type = CMD_REQ_REDIS_ZCARD; + break; + } + + if (str5icmp(m, 'z', 'r', 'a', 'n', 'k')) { + r->type = CMD_REQ_REDIS_ZRANK; + break; + } + + if (str5icmp(m, 'z', 's', 'c', 'a', 'n')) { + r->type = CMD_REQ_REDIS_ZSCAN; + break; + } + + if (str5icmp(m, 'p', 'f', 'a', 'd', 'd')) { + r->type = CMD_REQ_REDIS_PFADD; + break; + } + + break; + + case 6: + if (str6icmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) { + r->type = CMD_REQ_REDIS_APPEND; + break; + } + + if (str6icmp(m, 'd', 'e', 'c', 'r', 'b', 'y')) { + r->type = CMD_REQ_REDIS_DECRBY; + break; + } + + if (str6icmp(m, 'e', 'x', 'i', 's', 't', 's')) { + r->type = CMD_REQ_REDIS_EXISTS; + break; + } + + if (str6icmp(m, 'e', 'x', 'p', 'i', 'r', 'e')) { + r->type = CMD_REQ_REDIS_EXPIRE; + break; + } + + if (str6icmp(m, 'g', 'e', 't', 'b', 'i', 't')) { + r->type = CMD_REQ_REDIS_GETBIT; + break; + } + + if (str6icmp(m, 'g', 'e', 't', 's', 'e', 't')) { + r->type = CMD_REQ_REDIS_GETSET; + break; + } + + if (str6icmp(m, 'p', 's', 'e', 't', 'e', 'x')) { + r->type = CMD_REQ_REDIS_PSETEX; + break; + } + + if (str6icmp(m, 'h', 's', 'e', 't', 'n', 'x')) { + r->type = CMD_REQ_REDIS_HSETNX; + break; + } + + if (str6icmp(m, 'i', 'n', 'c', 'r', 'b', 'y')) { + r->type = CMD_REQ_REDIS_INCRBY; + break; + } + + if (str6icmp(m, 'l', 'i', 'n', 'd', 'e', 'x')) { + r->type = CMD_REQ_REDIS_LINDEX; + break; + } + + if (str6icmp(m, 'l', 'p', 'u', 's', 'h', 'x')) { + r->type = CMD_REQ_REDIS_LPUSHX; + break; + } + + if (str6icmp(m, 'l', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_LRANGE; + break; + } + + if (str6icmp(m, 'r', 'p', 'u', 's', 'h', 'x')) { + r->type = CMD_REQ_REDIS_RPUSHX; + break; + } + + if (str6icmp(m, 's', 'e', 't', 'b', 'i', 't')) { + r->type = CMD_REQ_REDIS_SETBIT; + break; + } + + if (str6icmp(m, 's', 'i', 'n', 't', 'e', 'r')) { + r->type = CMD_REQ_REDIS_SINTER; + break; + } + + if (str6icmp(m, 's', 't', 'r', 'l', 'e', 'n')) { + r->type = CMD_REQ_REDIS_STRLEN; + break; + } + + if (str6icmp(m, 's', 'u', 'n', 'i', 'o', 'n')) { + r->type = CMD_REQ_REDIS_SUNION; + break; + } + + if (str6icmp(m, 'z', 'c', 'o', 'u', 'n', 't')) { + r->type = CMD_REQ_REDIS_ZCOUNT; + break; + } + + if (str6icmp(m, 'z', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_ZRANGE; + break; + } + + if (str6icmp(m, 'z', 's', 'c', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZSCORE; + break; + } + + break; + + case 7: + if (str7icmp(m, 'p', 'e', 'r', 's', 'i', 's', 't')) { + r->type = CMD_REQ_REDIS_PERSIST; + break; + } + + if (str7icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e')) { + r->type = CMD_REQ_REDIS_PEXPIRE; + break; + } + + if (str7icmp(m, 'h', 'e', 'x', 'i', 's', 't', 's')) { + r->type = CMD_REQ_REDIS_HEXISTS; + break; + } + + if (str7icmp(m, 'h', 'g', 'e', 't', 'a', 'l', 'l')) { + r->type = CMD_REQ_REDIS_HGETALL; + break; + } + + if (str7icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y')) { + r->type = CMD_REQ_REDIS_HINCRBY; + break; + } + + if (str7icmp(m, 'l', 'i', 'n', 's', 'e', 'r', 't')) { + r->type = CMD_REQ_REDIS_LINSERT; + break; + } + + if (str7icmp(m, 'z', 'i', 'n', 'c', 'r', 'b', 'y')) { + r->type = CMD_REQ_REDIS_ZINCRBY; + break; + } + + if (str7icmp(m, 'e', 'v', 'a', 'l', 's', 'h', 'a')) { + r->type = CMD_REQ_REDIS_EVALSHA; + break; + } + + if (str7icmp(m, 'r', 'e', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_RESTORE; + break; + } + + if (str7icmp(m, 'p', 'f', 'c', 'o', 'u', 'n', 't')) { + r->type = CMD_REQ_REDIS_PFCOUNT; + break; + } + + if (str7icmp(m, 'p', 'f', 'm', 'e', 'r', 'g', 'e')) { + r->type = CMD_REQ_REDIS_PFMERGE; + break; + } + + break; + + case 8: + if (str8icmp(m, 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) { + r->type = CMD_REQ_REDIS_EXPIREAT; + break; + } + + if (str8icmp(m, 'b', 'i', 't', 'c', 'o', 'u', 'n', 't')) { + r->type = CMD_REQ_REDIS_BITCOUNT; + break; + } + + if (str8icmp(m, 'g', 'e', 't', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_GETRANGE; + break; + } + + if (str8icmp(m, 's', 'e', 't', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_SETRANGE; + break; + } + + if (str8icmp(m, 's', 'm', 'e', 'm', 'b', 'e', 'r', 's')) { + r->type = CMD_REQ_REDIS_SMEMBERS; + break; + } + + if (str8icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'k')) { + r->type = CMD_REQ_REDIS_ZREVRANK; + break; + } + + break; + + case 9: + if (str9icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) { + r->type = CMD_REQ_REDIS_PEXPIREAT; + break; + } + + if (str9icmp(m, 'r', 'p', 'o', 'p', 'l', 'p', 'u', 's', 'h')) { + r->type = CMD_REQ_REDIS_RPOPLPUSH; + break; + } + + if (str9icmp(m, 's', 'i', 's', 'm', 'e', 'm', 'b', 'e', 'r')) { + r->type = CMD_REQ_REDIS_SISMEMBER; + break; + } + + if (str9icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e')) { + r->type = CMD_REQ_REDIS_ZREVRANGE; + break; + } + + if (str9icmp(m, 'z', 'l', 'e', 'x', 'c', 'o', 'u', 'n', 't')) { + r->type = CMD_REQ_REDIS_ZLEXCOUNT; + break; + } + + break; + + case 10: + if (str10icmp(m, 's', 'd', 'i', 'f', 'f', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_SDIFFSTORE; + break; + } + + case 11: + if (str11icmp(m, 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) { + r->type = CMD_REQ_REDIS_INCRBYFLOAT; + break; + } + + if (str11icmp(m, 's', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_SINTERSTORE; + break; + } + + if (str11icmp(m, 's', 'r', 'a', 'n', 'd', 'm', 'e', 'm', 'b', 'e', 'r')) { + r->type = CMD_REQ_REDIS_SRANDMEMBER; + break; + } + + if (str11icmp(m, 's', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_SUNIONSTORE; + break; + } + + if (str11icmp(m, 'z', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZINTERSTORE; + break; + } + + if (str11icmp(m, 'z', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZUNIONSTORE; + break; + } + + if (str11icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'l', 'e', 'x')) { + r->type = CMD_REQ_REDIS_ZRANGEBYLEX; + break; + } + + break; + + case 12: + if (str12icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) { + r->type = CMD_REQ_REDIS_HINCRBYFLOAT; + break; + } + + + break; + + case 13: + if (str13icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZRANGEBYSCORE; + break; + } + + break; + + case 14: + if (str14icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'l', 'e', 'x')) { + r->type = CMD_REQ_REDIS_ZREMRANGEBYLEX; + break; + } + + break; + + case 15: + if (str15icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'r', 'a', 'n', 'k')) { + r->type = CMD_REQ_REDIS_ZREMRANGEBYRANK; + break; + } + + break; + + case 16: + if (str16icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZREMRANGEBYSCORE; + break; + } + + if (str16icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { + r->type = CMD_REQ_REDIS_ZREVRANGEBYSCORE; + break; + } + + break; + + default: + break; + } + + if (r->type == CMD_UNKNOWN) { + goto error; + } + + state = SW_REQ_TYPE_LF; + break; + + case SW_REQ_TYPE_LF: + switch (ch) { + case LF: + if (redis_argz(r)) { + goto done; + } else if (redis_argeval(r)) { + state = SW_ARG1_LEN; + } else { + state = SW_KEY_LEN; + } + break; + + default: + goto error; + } + + break; + + case SW_KEY_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + token = p; + rlen = 0; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + + if (rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_KEY_LEN_LF; + } else { + goto error; + } + + break; + + case SW_KEY_LEN_LF: + switch (ch) { + case LF: + state = SW_KEY; + break; + + default: + goto error; + } + + break; + + case SW_KEY: + if (token == NULL) { + token = p; + } + + m = token + rlen; + if (m >= cmd_end) { + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } else { /* got a key */ + struct keypos *kpos; + + p = m; /* move forward by rlen bytes */ + rlen = 0; + m = token; + token = NULL; + + kpos = hiarray_push(r->keys); + if (kpos == NULL) { + goto enomem; + } + kpos->start = m; + kpos->end = p; + //kpos->v_len = 0; + + state = SW_KEY_LF; + } + + break; + + case SW_KEY_LF: + switch (ch) { + case LF: + if (redis_arg0(r)) { + if (rnarg != 0) { + goto error; + } + goto done; + } else if (redis_arg1(r)) { + if (rnarg != 1) { + goto error; + } + state = SW_ARG1_LEN; + } else if (redis_arg2(r)) { + if (rnarg != 2) { + goto error; + } + state = SW_ARG1_LEN; + } else if (redis_arg3(r)) { + if (rnarg != 3) { + goto error; + } + state = SW_ARG1_LEN; + } else if (redis_argn(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARG1_LEN; + } else if (redis_argx(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_KEY_LEN; + } else if (redis_argkvx(r)) { + if (rnarg == 0) { + goto done; + } + if (r->narg % 2 == 0) { + goto error; + } + state = SW_ARG1_LEN; + } else if (redis_argeval(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_ARG1_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + rlen = 0; + token = p; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if ((p - token) <= 1 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + + /* + //for mset value length + if(redis_argkvx(r)) + { + struct keypos *kpos; + uint32_t array_len = array_n(r->keys); + if(array_len == 0) + { + goto error; + } + + kpos = array_n(r->keys, array_len-1); + if (kpos == NULL || kpos->v_len != 0) { + goto error; + } + + kpos->v_len = rlen; + } + */ + state = SW_ARG1_LEN_LF; + } else { + goto error; + } + + break; + + case SW_ARG1_LEN_LF: + switch (ch) { + case LF: + state = SW_ARG1; + break; + + default: + goto error; + } + + break; + + case SW_ARG1: + m = p + rlen; + if (m >= cmd_end) { + //rlen -= (uint32_t)(b->last - p); + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + + state = SW_ARG1_LF; + + break; + + case SW_ARG1_LF: + switch (ch) { + case LF: + if (redis_arg1(r)) { + if (rnarg != 0) { + goto error; + } + goto done; + } else if (redis_arg2(r)) { + if (rnarg != 1) { + goto error; + } + state = SW_ARG2_LEN; + } else if (redis_arg3(r)) { + if (rnarg != 2) { + goto error; + } + state = SW_ARG2_LEN; + } else if (redis_argn(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else if (redis_argeval(r)) { + if (rnarg < 2) { + goto error; + } + state = SW_ARG2_LEN; + } else if (redis_argkvx(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_KEY_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_ARG2_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + rlen = 0; + token = p; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if ((p - token) <= 1 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_ARG2_LEN_LF; + } else { + goto error; + } + + break; + + case SW_ARG2_LEN_LF: + switch (ch) { + case LF: + state = SW_ARG2; + break; + + default: + goto error; + } + + break; + + case SW_ARG2: + if (token == NULL && redis_argeval(r)) { + /* + * For EVAL/EVALSHA, ARG2 represents the # key/arg pairs which must + * be tokenized and stored in contiguous memory. + */ + token = p; + } + + m = p + rlen; + if (m >= cmd_end) { + //rlen -= (uint32_t)(b->last - p); + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + + if (redis_argeval(r)) { + uint32_t nkey; + char *chp; + + /* + * For EVAL/EVALSHA, we need to find the integer value of this + * argument. It tells us the number of keys in the script, and + * we need to error out if number of keys is 0. At this point, + * both p and m point to the end of the argument and r->token + * points to the start. + */ + if (p - token < 1) { + goto error; + } + + for (nkey = 0, chp = token; chp < p; chp++) { + if (isdigit(*chp)) { + nkey = nkey * 10 + (uint32_t)(*chp - '0'); + } else { + goto error; + } + } + if (nkey == 0) { + goto error; + } + + token = NULL; + } + + state = SW_ARG2_LF; + + break; + + case SW_ARG2_LF: + switch (ch) { + case LF: + if (redis_arg2(r)) { + if (rnarg != 0) { + goto error; + } + goto done; + } else if (redis_arg3(r)) { + if (rnarg != 1) { + goto error; + } + state = SW_ARG3_LEN; + } else if (redis_argn(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else if (redis_argeval(r)) { + if (rnarg < 1) { + goto error; + } + state = SW_KEY_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_ARG3_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + rlen = 0; + token = p; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if ((p - token) <= 1 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_ARG3_LEN_LF; + } else { + goto error; + } + + break; + + case SW_ARG3_LEN_LF: + switch (ch) { + case LF: + state = SW_ARG3; + break; + + default: + goto error; + } + + break; + + case SW_ARG3: + m = p + rlen; + if (m >= cmd_end) { + //rlen -= (uint32_t)(b->last - p); + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + state = SW_ARG3_LF; + + break; + + case SW_ARG3_LF: + switch (ch) { + case LF: + if (redis_arg3(r)) { + if (rnarg != 0) { + goto error; + } + goto done; + } else if (redis_argn(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_ARGN_LEN: + if (token == NULL) { + if (ch != '$') { + goto error; + } + rlen = 0; + token = p; + } else if (isdigit(ch)) { + rlen = rlen * 10 + (uint32_t)(ch - '0'); + } else if (ch == CR) { + if ((p - token) <= 1 || rnarg == 0) { + goto error; + } + rnarg--; + token = NULL; + state = SW_ARGN_LEN_LF; + } else { + goto error; + } + + break; + + case SW_ARGN_LEN_LF: + switch (ch) { + case LF: + state = SW_ARGN; + break; + + default: + goto error; + } + + break; + + case SW_ARGN: + m = p + rlen; + if (m >= cmd_end) { + //rlen -= (uint32_t)(b->last - p); + //m = b->last - 1; + //p = m; + //break; + goto error; + } + + if (*m != CR) { + goto error; + } + + p = m; /* move forward by rlen bytes */ + rlen = 0; + state = SW_ARGN_LF; + + break; + + case SW_ARGN_LF: + switch (ch) { + case LF: + if (redis_argn(r) || redis_argeval(r)) { + if (rnarg == 0) { + goto done; + } + state = SW_ARGN_LEN; + } else { + goto error; + } + + break; + + default: + goto error; + } + + break; + + case SW_SENTINEL: + default: + NOT_REACHED(); + break; + } + } + + ASSERT(p == cmd_end); + + return; + +done: + + ASSERT(r->type > CMD_UNKNOWN && r->type < CMD_SENTINEL); + + r->result = CMD_PARSE_OK; + + return; + +enomem: + + r->result = CMD_PARSE_ENOMEM; + + return; + +error: + + r->result = CMD_PARSE_ERROR; + errno = EINVAL; + if(r->errstr == NULL){ + r->errstr = hi_alloc(100*sizeof(*r->errstr)); + } + + len = _scnprintf(r->errstr, 100, "Parse command error. Cmd type: %d, state: %d, break position: %d.", + r->type, state, (int)(p - r->cmd)); + r->errstr[len] = '\0'; +} + +struct cmd *command_get() +{ + struct cmd *command; + command = hi_alloc(sizeof(struct cmd)); + if(command == NULL) + { + return NULL; + } + + command->id = ++cmd_id; + command->result = CMD_PARSE_OK; + command->errstr = NULL; + command->type = CMD_UNKNOWN; + command->cmd = NULL; + command->clen = 0; + command->keys = NULL; + command->narg_start = NULL; + command->narg_end = NULL; + command->narg = 0; + command->quit = 0; + command->noforward = 0; + command->slot_num = -1; + command->frag_seq = NULL; + command->reply = NULL; + command->sub_commands = NULL; + + command->keys = hiarray_create(1, sizeof(struct keypos)); + if (command->keys == NULL) + { + hi_free(command); + return NULL; + } + + return command; +} + +void command_destroy(struct cmd *command) +{ + if(command == NULL) + { + return; + } + + if(command->cmd != NULL) + { + free(command->cmd); + } + + if(command->errstr != NULL){ + hi_free(command->errstr); + } + + if(command->keys != NULL) + { + command->keys->nelem = 0; + hiarray_destroy(command->keys); + } + + if(command->frag_seq != NULL) + { + hi_free(command->frag_seq); + command->frag_seq = NULL; + } + + if(command->reply != NULL) + { + freeReplyObject(command->reply); + } + + if(command->sub_commands != NULL) + { + listRelease(command->sub_commands); + } + + hi_free(command); +} + + |
