一、redisServer、redisDB、robj关系

Redis没有表的概念。然而能够用key作标识进行辨别,比方:user:1000作为key值,示意在user表下id为1000的元素,相似于user表的id=1000的行。

Redis逻辑关系: redisServer–>redisDB–>key-redisObject。所以这里次要介绍redisServer、redisDB、redisObject构造。

二、redisServer构造体(在server.h中)

服务端构造体redisServer存储Redis服务器的所有信息,包含但不限于数据库、配置参数、命令表、监听端口与地址、客户端列表、若干统计信息、RDB与AOF长久化相干信息、主从复制相干信息、集群相干信息等。

redis.h/redisServer 构造记录了和服务器相干的所有数据, 这个构造体次要蕴含以下信息:

  • 服务器中的所有数据库是数组指针。
  • 已连贯客户端的信息 list指针。
  • 服务器配置选项:redis.conf中配置的存储。
  • 命令hash表:在执行命令时,依据字符来查找相应命令的实现函数。
  • 服务端的网络信息:套接字地址、端口,以及套接字描述符。
  • 日志(log)和慢查问日志(slowlog)的选项和相干信息。
  • 统计信息:比方键有多少次命令、不命中,服务器的运行工夫,等等。
  • 数据长久化(AOF 和 RDB)的配置和状态。
  • 实现订阅与公布(pub/sub)性能所需的数据结构。
  • Lua 脚本的运行环境及相干选项。
struct redisServer {        /* General */        //配置文件门路        char *configfile;           /* Absolute config file path, or NULL */        //serverCron()调用频率        int hz;                     /* serverCron() calls frequency in hertz */        //数据库对象数组指针        redisDb *db;        //反对的命令列表        dict *commands;             /* Command table */        //没有转化的命令        dict *orig_commands;        /* Command table before command renaming. */        //事件        aeEventLoop *el;        //每分钟减少一次        unsigned lruclock:22;       /* Clock incrementing every minute, for LRU */        unsigned lruclock_padding:10;        int shutdown_asap;          /* SHUTDOWN needed ASAP */        int activerehashing;        /* Incremental rehash in serverCron() */        //验证明码        char *requirepass;          /* Pass for AUTH command, or NULL */        char *pidfile;              /* PID file path */        int arch_bits;              /* 32 or 64 depending on sizeof(long) */        int cronloops;              /* Number of times the cron function run */        char runid[REDIS_RUN_ID_SIZE+1];  /* ID always different at every exec. */        int sentinel_mode;          /* True if this instance is a Sentinel. */        /* Networking */        int port;                   /* TCP listening port */        int tcp_backlog;            /* TCP listen() backlog */        char *bindaddr[REDIS_BINDADDR_MAX]; /* Addresses we should bind to */        int bindaddr_count;         /* Number of addresses in server.bindaddr[] */        char *unixsocket;           /* UNIX socket path */        mode_t unixsocketperm;      /* UNIX socket permission */        int ipfd[REDIS_BINDADDR_MAX]; /* TCP socket file descriptors */        int ipfd_count;             /* Used slots in ipfd[] */        int sofd;                   /* Unix socket file descriptor */        int cfd[REDIS_BINDADDR_MAX];/* Cluster bus listening socket */        int cfd_count;              /* Used slots in cfd[] */                // 连贯的客户端        list *clients;              /* List of active clients */        list *clients_to_close;     /* Clients to close asynchronously */        list *slaves, *monitors;    /* List of slaves and MONITORs */        redisClient *current_client; /* Current client, only used on crash report */        int clients_paused;         /* True if clients are currently paused */        mstime_t clients_pause_end_time; /* Time when we undo clients_paused */        char neterr[ANET_ERR_LEN];   /* Error buffer for anet.c */        dict *migrate_cached_sockets;/* MIGRATE cached sockets */        /* RDB / AOF loading information */        int loading;                /* We are loading data from disk if true */        off_t loading_total_bytes;        off_t loading_loaded_bytes;        time_t loading_start_time;        off_t loading_process_events_interval_bytes;        /* Fast pointers to often looked up command */        struct redisCommand *delCommand, *multiCommand, *lpushCommand, *lpopCommand,        *rpopCommand;        /* Fields used only for stats */        time_t stat_starttime;          /* Server start time */        long long stat_numcommands;     /* Number of processed commands */        long long stat_numconnections;  /* Number of connections received */        long long stat_expiredkeys;     /* Number of expired keys */        long long stat_evictedkeys;     /* Number of evicted keys (maxmemory) */        long long stat_keyspace_hits;   /* Number of successful lookups of keys */        long long stat_keyspace_misses; /* Number of failed lookups of keys */        size_t stat_peak_memory;        /* Max used memory record */        long long stat_fork_time;       /* Time needed to perform latest fork() */        long long stat_rejected_conn;   /* Clients rejected because of maxclients */        long long stat_sync_full;       /* Number of full resyncs with slaves. */        long long stat_sync_partial_ok; /* Number of accepted PSYNC requests. */        long long stat_sync_partial_err;/* Number of unaccepted PSYNC requests. */        //保留慢日志命令        list *slowlog;                  /* SLOWLOG list of commands */        long long slowlog_entry_id;     /* SLOWLOG current entry ID */        long long slowlog_log_slower_than; /* SLOWLOG time limit (to get logged) */        unsigned long slowlog_max_len;     /* SLOWLOG max number of items logged */        /* The following two are used to track instantaneous "load" in terms        * of operations per second. */        long long ops_sec_last_sample_time; /* Timestamp of last sample (in ms) */        long long ops_sec_last_sample_ops;  /* numcommands in last sample */        long long ops_sec_samples[REDIS_OPS_SEC_SAMPLES];        int ops_sec_idx;        /* Configuration */        int verbosity;                  /* Loglevel in redis.conf */        int maxidletime;                /* Client timeout in seconds */        int tcpkeepalive;               /* Set SO_KEEPALIVE if non-zero. */        int active_expire_enabled;      /* Can be disabled for testing purposes. */        size_t client_max_querybuf_len; /* Limit for client query buffer length */        int dbnum;                      /* Total number of configured DBs */        int daemonize;                  /* True if running as a daemon */        clientBufferLimitsConfig client_obuf_limits[REDIS_CLIENT_LIMIT_NUM_CLASSES];        /* AOF persistence */        int aof_state;                  /* REDIS_AOF_(ON|OFF|WAIT_REWRITE) */        int aof_fsync;                  /* Kind of fsync() policy */        char *aof_filename;             /* Name of the AOF file */        int aof_no_fsync_on_rewrite;    /* Don't fsync if a rewrite is in prog. */        int aof_rewrite_perc;           /* Rewrite AOF if % growth is > M and... */        off_t aof_rewrite_min_size;     /* the AOF file is at least N bytes. */        off_t aof_rewrite_base_size;    /* AOF size on latest startup or rewrite. */        off_t aof_current_size;         /* AOF current size. */        int aof_rewrite_scheduled;      /* Rewrite once BGSAVE terminates. */        pid_t aof_child_pid;            /* PID if rewriting process */        list *aof_rewrite_buf_blocks;   /* Hold changes during an AOF rewrite. */        sds aof_buf;      /* AOF buffer, written before entering the event loop */        int aof_fd;       /* File descriptor of currently selected AOF file */        int aof_selected_db; /* Currently selected DB in AOF */        time_t aof_flush_postponed_start; /* UNIX time of postponed AOF flush */        time_t aof_last_fsync;            /* UNIX time of last fsync() */        time_t aof_rewrite_time_last;   /* Time used by last AOF rewrite run. */        time_t aof_rewrite_time_start;  /* Current AOF rewrite start time. */        int aof_lastbgrewrite_status;   /* REDIS_OK or REDIS_ERR */        unsigned long aof_delayed_fsync;  /* delayed AOF fsync() counter */        int aof_rewrite_incremental_fsync;/* fsync incrementally while rewriting? */        int aof_last_write_status;      /* REDIS_OK or REDIS_ERR */        int aof_last_write_errno;       /* Valid if aof_last_write_status is ERR */        /* RDB persistence */        long long dirty;                /* Changes to DB from the last save */        long long dirty_before_bgsave;  /* Used to restore dirty on failed BGSAVE */        pid_t rdb_child_pid;            /* PID of RDB saving child */        struct saveparam *saveparams;   /* Save points array for RDB */        int saveparamslen;              /* Number of saving points */        char *rdb_filename;             /* Name of RDB file */        int rdb_compression;            /* Use compression in RDB? */        int rdb_checksum;               /* Use RDB checksum? */        time_t lastsave;                /* Unix time of last successful save */        time_t lastbgsave_try;          /* Unix time of last attempted bgsave */        time_t rdb_save_time_last;      /* Time used by last RDB save run. */        time_t rdb_save_time_start;     /* Current RDB save start time. */        int lastbgsave_status;          /* REDIS_OK or REDIS_ERR */        int stop_writes_on_bgsave_err;  /* Don't allow writes if can't BGSAVE */        /* Propagation of commands in AOF / replication */        redisOpArray also_propagate;    /* Additional command to propagate. */        /* Logging */        char *logfile;                  /* Path of log file */        int syslog_enabled;             /* Is syslog enabled? */        char *syslog_ident;             /* Syslog ident */        int syslog_facility;            /* Syslog facility */        /* Replication (master) */        int slaveseldb;                 /* Last SELECTed DB in replication output */        long long master_repl_offset;   /* Global replication offset */        int repl_ping_slave_period;     /* Master pings the slave every N seconds */        char *repl_backlog;             /* Replication backlog for partial syncs */        long long repl_backlog_size;    /* Backlog circular buffer size */        long long repl_backlog_histlen; /* Backlog actual data length */        long long repl_backlog_idx;     /* Backlog circular buffer current offset */        long long repl_backlog_off;     /* Replication offset of first byte in the        backlog buffer. */        time_t repl_backlog_time_limit; /* Time without slaves after the backlog        gets released. */        time_t repl_no_slaves_since;    /* We have no slaves since that time.        Only valid if server.slaves len is 0. */        int repl_min_slaves_to_write;   /* Min number of slaves to write. */        int repl_min_slaves_max_lag;    /* Max lag of <count> slaves to write. */        int repl_good_slaves_count;     /* Number of slaves with lag <= max_lag. */        /* Replication (slave) */        char *masterauth;               /* AUTH with this password with master */        char *masterhost;               /* Hostname of master */        int masterport;                 /* Port of master */        int repl_timeout;               /* Timeout after N seconds of master idle */        redisClient *master;     /* Client that is master for this slave */        redisClient *cached_master; /* Cached master to be reused for PSYNC. */        int repl_syncio_timeout; /* Timeout for synchronous I/O calls */        int repl_state;          /* Replication status if the instance is a slave */        off_t repl_transfer_size; /* Size of RDB to read from master during sync. */        off_t repl_transfer_read; /* Amount of RDB read from master during sync. */        off_t repl_transfer_last_fsync_off; /* Offset when we fsync-ed last time. */        int repl_transfer_s;     /* Slave -> Master SYNC socket */        int repl_transfer_fd;    /* Slave -> Master SYNC temp file descriptor */        char *repl_transfer_tmpfile; /* Slave-> master SYNC temp file name */        time_t repl_transfer_lastio; /* Unix time of the latest read, for timeout */        int repl_serve_stale_data; /* Serve stale data when link is down? */        int repl_slave_ro;          /* Slave is read only? */        time_t repl_down_since; /* Unix time at which link with master went down */        int repl_disable_tcp_nodelay;   /* Disable TCP_NODELAY after SYNC? */        int slave_priority;             /* Reported in INFO and used by Sentinel. */        char repl_master_runid[REDIS_RUN_ID_SIZE+1];  /* Master run id for PSYNC. */        long long repl_master_initial_offset;         /* Master PSYNC offset. */        /* Replication script cache. */        dict *repl_scriptcache_dict;        /* SHA1 all slaves are aware of. */        list *repl_scriptcache_fifo;        /* First in, first out LRU eviction. */        int repl_scriptcache_size;          /* Max number of elements. */        /* Synchronous replication. */        list *clients_waiting_acks;         /* Clients waiting in WAIT command. */        int get_ack_from_slaves;            /* If true we send REPLCONF GETACK. */        /* Limits */        unsigned int maxclients;        /* Max number of simultaneous clients */        unsigned long long maxmemory;   /* Max number of memory bytes to use */        int maxmemory_policy;           /* Policy for key eviction */        int maxmemory_samples;          /* Pricision of random sampling */        /* Blocked clients */        unsigned int bpop_blocked_clients; /* Number of clients blocked by lists */        list *unblocked_clients; /* list of clients to unblock before next loop */        list *ready_keys;        /* List of readyList structures for BLPOP & co */        /* Sort parameters - qsort_r() is only available under BSD so we        * have to take this state global, in order to pass it to sortCompare() */        int sort_desc;        int sort_alpha;        int sort_bypattern;        int sort_store;        /* Zip structure config, see redis.conf for more information  */        size_t hash_max_ziplist_entries;        size_t hash_max_ziplist_value;        size_t list_max_ziplist_entries;        size_t list_max_ziplist_value;        size_t set_max_intset_entries;        size_t zset_max_ziplist_entries;        size_t zset_max_ziplist_value;        time_t unixtime;        /* Unix time sampled every cron cycle. */        long long mstime;       /* Like 'unixtime' but with milliseconds resolution. */        /* Pubsub */        dict *pubsub_channels;  /* Map channels to list of subscribed clients */        list *pubsub_patterns;  /* A list of pubsub_patterns */        int notify_keyspace_events; /* Events to propagate via Pub/Sub. This is an        xor of REDIS_NOTIFY... flags. */        /* Cluster */        int cluster_enabled;      /* Is cluster enabled? */        mstime_t cluster_node_timeout; /* Cluster node timeout. */        char *cluster_configfile; /* Cluster auto-generated config file name. */        struct clusterState *cluster;  /* State of the cluster */        int cluster_migration_barrier; /* Cluster replicas migration barrier. */        /* Scripting */        lua_State *lua; /* The Lua interpreter. We use just one for all clients */        redisClient *lua_client;   /* The "fake client" to query Redis from Lua */        redisClient *lua_caller;   /* The client running EVAL right now, or NULL */        dict *lua_scripts;         /* A dictionary of SHA1 -> Lua scripts */        mstime_t lua_time_limit;  /* Script timeout in milliseconds */        mstime_t lua_time_start;  /* Start time of script, milliseconds time */        int lua_write_dirty;  /* True if a write command was called during the        execution of the current script. */        int lua_random_dirty; /* True if a random command was called during the        execution of the current script. */        int lua_timedout;     /* True if we reached the time limit for script        execution. */        int lua_kill;         /* Kill the script if true. */        /* Assert & bug reporting */        char *assert_failed;        char *assert_file;        int assert_line;        int bug_report_start; /* True if bug report header was already logged. */        int watchdog_period;  /* Software watchdog period in ms. 0 = off */};

三、redisDB构造体(在server.h中)

typedef struct redisDb {    int id;                     /* id是本数据库的序号,为0-15(默认Redis有16个数据库) */    dict *dict;                 /* 存储数据库所有的key-value */    dict *expires;              /* 键的过期工夫,字典的键为键,字典的值为过期 UNIX 工夫戳 */    dict *blocking_keys;        /* blpop 存储阻塞key和客户端对象 */    dict *ready_keys;           /* 阻塞后push 响应阻塞客户端 存储阻塞后push的key和客户端对象 */    dict *watched_keys;         /* 存储watch监控的的key和客户端对象 */    long long avg_ttl;          /* 存储的数据库对象的均匀ttl(time to live),用于统计 */    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */} redisDb;
  • long long 类型

在32位的零碎中: shortint占两个字节, long 占四个字节, long long 占八个字节;

在64位的零碎中: short占两个字节, intlong 占四个字节, long long 占八个字节。

C short/int/long/long long 等数据类型大小

C的规范并没有规定每种类型占多少位,只是说 “sizeof(long)>=sizeof(int)>=sizeof(short)”,所以具体的字节数都是依据编译器来确定的

数据类型字节大小数值范畴
char1 字节-128 到 127 或 0 到 255
unsigned char1 字节0 到 255
short int (短整型)2 字节-32 768 〜+32 767(2^15 - 1)
unsigned short int (无符号短整型)2 字节0 〜+65 535(2^16 - 1)
int (整型)2或4 字节4字节:-2 147 483 648 〜+2 147 483 647(2^31 - 1)
unsigned int (无符号整型)2或4字节4字节:0 〜4 294 967 295 (2^32 - 1)
long int (长整型)4 字节-2 147 483 648 〜+2 147 483 647(2^31 - 1)
unsigned long int (无符号长整型)4 字节0 〜4 294 967 295(2^32 - 1)
long long int (超长整型)8字节-9 223 372 036 854 775 808~9 223 372 036 854 775 807 (2^63 - 1)
unsigned long long int (无符号超长整型)8字节048 446 744 073 709 551 615 (2^64 - 1)

unsigned、signed、short、long润饰int,int能够省略

四、robj构造体(server.h)

typedef struct redisObject {    // 类型 0-string 1-list 2-set 3-zset 4-hash,在宏中定义。    unsigned type:4; // :4 是位域(位段),示意只占用4bit,2^4 ,http://c.biancheng.net/view/2037.html    // 对象编码。某些类型的对象(如字符串和哈希)能够通过多种形式在外部示意。ENCODING表明示意形式。    unsigned encoding:4;      // LRU_BITS = 24,共24位,高16位存储一个分钟数级别的工夫戳,低8位存储拜访计数(lfu : 最近拜访次数)    unsigned lru:LRU_BITS;     // 援用次数    int refcount;    // 指针指向具体数据,void * 类型,从而能够执行那六大数据结构    void *ptr;} robj;

4.1 type(server.h)

别离对应着5种根底数据类型(非数据结构类型)

/* The actual Redis Object */#define OBJ_STRING 0    /* String object. */#define OBJ_LIST 1      /* List object. */#define OBJ_SET 2       /* Set object. */#define OBJ_ZSET 3      /* Sorted set object. */#define OBJ_HASH 4      /* Hash object. */

4.2 encoding(server.h)

对象编码(数据结构类型)。某些类型的对象(如字符串和哈希)能够通过多种形式在外部示意。ENCODING表明示意形式。

#define OBJ_ENCODING_RAW 0          // 编码为字符串 c语言类型#define OBJ_ENCODING_INT 1          // 编码为整数#define OBJ_ENCODING_HT 2           // 编码为哈希表#define OBJ_ENCODING_ZIPMAP 3       // 编码为 zipmap#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */#define OBJ_ENCODING_ZIPLIST 5      // 编码为压缩列表#define OBJ_ENCODING_INTSET 6       // 编码为整数汇合#define OBJ_ENCODING_SKIPLIST 7  // 编码为跳跃表#define OBJ_ENCODING_EMBSTR 8       // 编码为SDS字符串#define OBJ_ENCODING_QUICKLIST 9 /* 疾速列表 压缩列表+链表 */#define OBJ_ENCODING_STREAM 10      /* Encoded as a radix tree of listpacks */

4.3 lru(Least frequently used)

lru 记录的是对象最初一次被命令程序拜访的工夫,( 4.0 以上版本占 24 位,2.6 版本占 22 位)。高16位存储一个分钟数级别的工夫戳,低8位存储拜访计数(lfu : 最近拜访次数) 。

  • lru----> 高16位: 最初被拜访的工夫,工夫戳秒级十进制是19位,所以分钟级别的是16位。
  • lfu-----> 低8位: 最近拜访次数

4.4 refcount

refcount 记录的是该对象被援用的次数,类型为整型。refcount 的作用,次要在于对象的援用计数和内存回收。

当对象的refcount>1时,称为共享对象,Redis 为了节俭内存,当有一些对象反复呈现时(例如常常返回的"OK"字符串),新的程序不会创立新的对象,而是依然应用原来的对象。

4.5 ptr

ptr 指针指向具体的数据,比方:set hello world,ptr 指向蕴含字符串 world 的 SDS。

4.6 encoding与type组合关系

当然是为了谋求速度,不同数据类型应用不同的数据结构速度才得以晋升。每种数据类型都有一种或者多种数据结构来撑持,底层数据结构有 6 种。

type与encoding有固定的搭配,encoding示意的是对应的数据结构。

typeencoding-simpleencoding形容
stringintREDIS_ENCODING_INT(整数)value为纯数字时
embstrREDIS_ENCODING_EMBSTR(embstr 编码的简略动静字符串(SDS))value为小字符串,长度 小于 44(OBJ_ENCODING_EMBSTR_SIZE_LIMIT)个字节
rawREDIS_ENCODING_RAW(简略动静字符串)value为大字符串,长度 大于 44(OBJ_ENCODING_EMBSTR_SIZE_LIMIT)个字节
listquicklistREDIS_ENCODING_QUICKLIST(疾速列表)
setintsetREDIS_ENCODING_INTSET(整数汇合)当Redis汇合类型的所有元素均是整数并且都处在64位有符号整数范畴内。
dictREDIS_ENCODING_HT(字典)当Redis汇合类型的元素是非整数或蕴含处在64位有符号整数范畴外元素。
zsetziplistREDIS_ENCODING_ZIPLIST(压缩列表)当元素的个数比拟少,且元素都是小整数或短字符串时。
skiplistREDIS_ENCODING_SKIPLIST(跳表)当元素的个数比拟多或元素不是小整数或短字符串时。
hashziplistREDIS_ENCODING_ZIPLIST(压缩列表)当散列表元素的个数比拟少,且元素都是小整数或短字符串时。
dictREDIS_ENCODING_HT(字典)当散列表元素的个数比拟多或元素不是小整数或短字符串时。
streamziplistOBJ_ENCODING_STREAM(流)相似音讯队列

五、client构造体(server.h)

Redis是典型的客户端/服务器(C/S)构造,客户端通过socket与服务端建设网络连接并发送命令申请,服务端解决命令申请并回复。Redis应用构造体client存储客户端连贯的所有信息。包含但不限于客户端的名称、客户端连贯的套接字描述符、客户端以后抉择的数据库ID、客户端的输出缓冲区与输入缓冲区等。构造体client字段较多,此处只介绍命令解决主流程所需的关键字段。

typedef struct client {   uint64_t id;     // 客户端惟一ID,通过全局变量server.next_client_id实现。   int fd;                 // socket的文件描述符。   redisDb *db;     // select命令抉择的数据库对象   robj *name;         // 客户端名称,能够应用命令CLIENT SETNAME设置。   time_t lastinteraction // 客户端上次与服务器交互的工夫,以此实现客户端的超时解决。   sds querybuf;  //输出缓冲区,recv函数接管的客户端命令申请会临时缓存在此缓冲区。   int argc;   robj **argv;   struct redisCommand *cmd;   list *reply;   unsigned long long reply_bytes;   size_t sentlen;   char buf[PROTO_REPLY_CHUNK_BYTES];   int bufpos;} client;
  • id为客户端惟一ID,通过全局变量server.next_client_id实现。
  • fd为客户端socket的文件描述符。
  • db为客户端应用select命令抉择的数据库对象。
  • name:客户端名称,能够应用命令CLIENT SETNAME设置。
  • lastinteraction:客户端上次与服务器交互的工夫,以此实现客户端的超时解决。
  • querybuf:输出缓冲区,recv函数接管的客户端命令申请会临时缓存在此缓冲区。
  • argc:输出缓冲区的命令申请是依照Redis协定格局编码字符串,须要解析出命令申请的所有参数,参数个数存储在argc字段,参数内容被解析为robj对象,存储在argv数组。
  • cmd:待执行的客户端命令;解析命令申请后,会依据命令名称查找该命令对应的命令对象,存储在客户端cmd字段,能够看到其类型为struct redisCommand。
  • reply:输入链表,存储待返回给客户端的命令回复数据。链表节点存储的值类型为clientReplyBlock,定义如下:
typedef struct clientReplyBlock { size_t size, used; char buf[];} clientReplyBlock;

能够看到链表节点实质上就是一个缓冲区(buffffer),其中size示意缓冲区空间总大小,used示意缓冲区已应用空间大小。

  • reply_bytes:示意输入链表中所有节点的存储空间总和;
  • sentlen:示意已返回给客户端的字节数;
  • buf:输入缓冲区,存储待返回给客户端的命令回复数据,
  • bufpos示意输入缓冲区中数据的最大字节地位,显然sentlen~bufpos区间的数据都是须要返回给客户端的。能够看到reply和buf都用于缓存待返回给客户端的命令回复数据,为什么同时须要reply和buf的存在呢?其实二者只是用于返回不同的数据类型而已,将在前面解说。

六、redisCommand构造体(server.h)

redis反对的所有命令初始都存储在全局变量redisCommandTable中,类型为redisCommand。

struct redisCommand redisCommandTable[] = {    {"module",moduleCommand,-2,"as",0,NULL,0,0,0,0,0},    {"get",getCommand,2,"rF",0,NULL,1,1,1,0,0},    {"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},      // ……疏忽局部代码……};

redisCommand构造也非常简单:

struct redisCommand {    char *name;    redisCommandProc *proc;    int arity;    char *sflags; /* Flags as string representation, one char per flag. */    int flags;    /* The actual flags, obtained from the 'sflags' field. */    /* Use a function to determine keys arguments in a command line.     * Used for Redis Cluster redirect. */    redisGetKeysProc *getkeys_proc;    /* What keys should be loaded in background when calling this command? */    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;};
  • name:命令名称。
  • proc:命令处理函数。
  • arity:命令参数数目,用于校验命令申请格局是否正确;当arity小于0时,表示命令参数数目大于等于arity;当arity大于0时,表示命令参数数目必须为arity;留神命令申请中,命令的名称自身也是一个参数,如get命令的参数数目为2,命令申请格局为get key。
  • sflags:命令标记,例如标识命令时读命令还是写命令,详情参见表9-2;留神到sflags的类型为字符串,此处只是为了良好的可读性。

  • flags:命令的二进制标记,服务器启动时解析sflags字段生成。
  • calls:从服务器启动至今命令执行的次数,用于统计。
  • microseconds:从服务器启动至今命令总的执行工夫,
  • microseconds/calls即可计算出该命令的均匀解决工夫,用于统计。