共计 17271 个字符,预计需要花费 44 分钟才能阅读完成。
一、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 位的零碎中:short
与 int
占两个字节,long
占四个字节,long long
占八个字节;
在 64 位的零碎中:short
占两个字节,int
与 long
占四个字节,long long
占八个字节。
C short/int/long/long long 等数据类型大小
C 的规范并没有规定每种类型占多少位,只是说“sizeof(long)>=sizeof(int)>=sizeof(short)”,所以具体的字节数都是依据编译器来确定的
数据类型 | 字节大小 | 数值范畴 |
---|---|---|
char | 1 字节 | -128 到 127 或 0 到 255 |
unsigned char | 1 字节 | 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 示意的是对应的数据结构。
type | encoding-simple | encoding | 形容 |
---|---|---|---|
string | int | REDIS_ENCODING_INT(整数) | value 为纯数字时 |
embstr | REDIS_ENCODING_EMBSTR(embstr 编码的简略动静字符串(SDS)) | value 为小字符串,长度 小于 44(OBJ_ENCODING_EMBSTR_SIZE_LIMIT)个字节 | |
raw | REDIS_ENCODING_RAW(简略动静字符串) | value 为大字符串,长度 大于 44(OBJ_ENCODING_EMBSTR_SIZE_LIMIT)个字节 | |
list | quicklist | REDIS_ENCODING_QUICKLIST(疾速列表) | |
set | intset | REDIS_ENCODING_INTSET(整数汇合) | 当 Redis 汇合类型的所有元素均是整数并且都处在 64 位有符号整数范畴内。 |
dict | REDIS_ENCODING_HT(字典) | 当 Redis 汇合类型的元素是非整数或蕴含处在 64 位有符号整数范畴外元素。 | |
zset | ziplist | REDIS_ENCODING_ZIPLIST(压缩列表) | 当元素的个数比拟少,且元素都是小整数或短字符串时。 |
skiplist | REDIS_ENCODING_SKIPLIST(跳表) | 当元素的个数比拟多或元素不是小整数或短字符串时。 | |
hash | ziplist | REDIS_ENCODING_ZIPLIST(压缩列表) | 当散列表元素的个数比拟少,且元素都是小整数或短字符串时。 |
dict | REDIS_ENCODING_HT(字典) | 当散列表元素的个数比拟多或元素不是小整数或短字符串时。 | |
stream | ziplist | OBJ_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 即可计算出该命令的均匀解决工夫,用于统计。