Redis启动总体上可以分为如下几步:
1.初始化全局服务器配置
- 加载配置文件(如果指定了配置文件,否则使用默认配置)
- 初始化服务器
- 加载数据库
- 网络监听
-
redis整个程序的入口函数在server.c中的main函数,函数调用关系如下图1,调用顺序为从上到下,从左至右。
- main——程序入口
- initServerConfig——初始化 server 变量
- populateCommanTable——初始化命令表
- loadServerConfig——根据配置文件和传入的选项,修改 server 变量(服务器配置)
- initServer——初始化Server
- createSharedObjects—— 初始化共享对象
- aeCreateEventLoop——初始化事件状态
- listenToPort——开始网络监听
- aeCreateTimeEvent——初始化时间事件
- aeSetBeforeSleepProc——设置每次事件循环等待前的事件处理
- aeMain——启动服务器循环
时间事件
- 打印一些运行参数。
- 关闭连接超时的客户端(需开启timeout配置项)
- rehash数据库字典,循环1ms,每次rehash100个key(需开启activerehashing配置项)
- 检查BGSAVE或者BGREWRITEAOF是否已经执行完毕
- 集群相关操作。
程序入口
Redis服务器的main函数是在server.c中
//整个程序的入口函数
int main(int argc, char **argv) {
//初始化服务器配置,设置全局对象server的状态
initServerConfig();
/* Store the executable path and arguments in a safe place in order
* to be able to restart the server later. */
//存储运行命令的绝对路径及运行参数
server.executable = getAbsolutePath(argv[0]);
server.exec_argv = zmalloc(sizeof(char*)*(argc+1));
server.exec_argv[argc] = NULL;
for (j = 0; j < argc; j++) server.exec_argv[j] = zstrdup(argv[j]);
if (argc >= 2) {
j = 1; /* First option to parse in argv[] */
sds options = sdsempty();
char *configfile = NULL;
//命令指定了配置文件,对配置文件做处理,配置文件跟在程序名后第一位
/* First argument is the config file name? */
if (argv[j][0] != '-' || argv[j][1] != '-') {
configfile = argv[j];
server.configfile = getAbsolutePath(configfile);
/* Replace the config file in server.exec_argv with
* its absolute path. */
zfree(server.exec_argv[j]);
server.exec_argv[j] = zstrdup(server.configfile);
j++;
}
/* All the other options are parsed and conceptually appended to the
* configuration file. For instance --port 6380 will generate the
* string "port 6380\n" to be parsed after the actual file name
* is parsed, if any. */
while(j != argc) {//解析除配置文件外的其它参数
if (argv[j][0] == '-' && argv[j][1] == '-') {
/* Option name */
if (!strcmp(argv[j], "--check-rdb")) {
/* Argument has no options, need to skip for parsing. */
j++;
continue;
}
if (sdslen(options)) options = sdscat(options,"\n");
options = sdscat(options,argv[j]+2);//去掉参数前面的--
options = sdscat(options," ");//参数对应的值和参数名应" "分隔
} else {
/* Option argument */
options = sdscatrepr(options,argv[j],strlen(argv[j]));
options = sdscat(options," ");
}
j++;
}
//从指定配置文件和命令选项设置服务器对象server参数,覆盖默认配置
loadServerConfig(configfile,options);
}
server.supervised = redisIsSupervised(server.supervised_mode);
int background = server.daemonize && !server.supervised;
if (background) daemonize();//后台进程模式
//初始化服务器功能,包括时间事件1ms调用serverCron,文件事件(套接字可读可写时的处理函数),集群初始化等
initServer();
aeSetBeforeSleepProc(server.el,beforeSleep);//设置beforeSleep事件处理函数
aeSetAfterSleepProc(server.el,afterSleep);//设置aftersleep事件处理函数
aeMain(server.el);//循环,接受客户端连接,处理命令等
aeDeleteEventLoop(server.el);//退出循环,删除事件处理
return 0;
}
初始化服务器配置initServerConfig()
- 初始化redis的16个db。dict是hash table结构,之后统一描述各种数据结构
/*
* 初始化 server 结构
*/
void initServerConfig() {
getRandomHexChars(server.runid,REDIS_RUN_ID_SIZE);
server.runid[REDIS_RUN_ID_SIZE] = '\0';
// 判断架构
server.arch_bits = (sizeof(long) == 8) ? 64 : 32;
// 网络连接相关
server.port = REDIS_SERVERPORT;
server.bindaddr = NULL;
server.unixsocket = NULL;
server.unixsocketperm = 0;
server.ipfd = -1;
server.sofd = -1;
// 数据库个数
server.dbnum = REDIS_DEFAULT_DBNUM;
server.verbosity = REDIS_NOTICE;
server.maxidletime = REDIS_MAXIDLETIME;
// 客户端查询缓存最大长度
server.client_max_querybuf_len = REDIS_MAX_QUERYBUF_LEN;
// 保存 flag
server.saveparams = NULL;
// 是否正在载入数据?
server.loading = 0;
// log
server.logfile = NULL; /* NULL = log on standard output */
server.syslog_enabled = 0;
server.syslog_ident = zstrdup("redis");
server.syslog_facility = LOG_LOCAL0;
// deamon 进程
server.daemonize = 0;
// AOF 状态
server.aof_state = REDIS_AOF_OFF;
server.aof_fsync = AOF_FSYNC_EVERYSEC;
server.aof_no_fsync_on_rewrite = 0;
server.aof_rewrite_perc = REDIS_AOF_REWRITE_PERC;
server.aof_rewrite_min_size = REDIS_AOF_REWRITE_MIN_SIZE;
server.aof_rewrite_base_size = 0;
server.aof_rewrite_scheduled = 0;
server.aof_last_fsync = time(NULL);
server.aof_rewrite_time_last = -1;
server.aof_rewrite_time_start = -1;
server.aof_lastbgrewrite_status = REDIS_OK;
server.aof_delayed_fsync = 0;
server.aof_fd = -1;
server.aof_selected_db = -1; /* Make sure the first time will not match */
server.aof_flush_postponed_start = 0;
// 持久化相关
server.pidfile = zstrdup("/var/run/redis.pid");
server.rdb_filename = zstrdup("dump.rdb");
server.aof_filename = zstrdup("appendonly.aof");
server.requirepass = NULL;
server.rdb_compression = 1;
server.rdb_checksum = 1;
// 开启主动 rehash
server.activerehashing = 1;
// 最大客户端数量
server.maxclients = REDIS_MAX_CLIENTS;
server.bpop_blocked_clients = 0;
// 内存相关
server.maxmemory = 0;
server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU;
server.maxmemory_samples = 3;
// 压缩数据结构实体数量限制
server.hash_max_ziplist_entries = REDIS_HASH_MAX_ZIPLIST_ENTRIES;
server.hash_max_ziplist_value = REDIS_HASH_MAX_ZIPLIST_VALUE;
server.list_max_ziplist_entries = REDIS_LIST_MAX_ZIPLIST_ENTRIES;
server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE;
server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES;
server.zset_max_ziplist_entries = REDIS_ZSET_MAX_ZIPLIST_ENTRIES;
server.zset_max_ziplist_value = REDIS_ZSET_MAX_ZIPLIST_VALUE;
// 关闭指示 flag
server.shutdown_asap = 0;
// REPL
server.repl_ping_slave_period = REDIS_REPL_PING_SLAVE_PERIOD;
server.repl_timeout = REDIS_REPL_TIMEOUT;
// 集群相关
server.cluster_enabled = 0;
server.cluster.configfile = zstrdup("nodes.conf");
// LUA 脚本相关
server.lua_caller = NULL;
server.lua_time_limit = REDIS_LUA_TIME_LIMIT;
server.lua_client = NULL;
server.lua_timedout = 0;
server.migrate_cached_sockets = dictCreate(&migrateCacheDictType,NULL);
updateLRUClock();
resetServerSaveParams();
// 保存相关
appendServerSaveParams(60*60,1); /* save after 1 hour and 1 change */
appendServerSaveParams(300,100); /* save after 5 minutes and 100 changes */
appendServerSaveParams(60,10000); /* save after 1 minute and 10000 changes */
// 复制相关
/* Replication related */
server.masterauth = NULL;
server.masterhost = NULL;
server.masterport = 6379;
server.master = NULL;
server.repl_state = REDIS_REPL_NONE;
server.repl_syncio_timeout = REDIS_REPL_SYNCIO_TIMEOUT;
server.repl_serve_stale_data = 1;
server.repl_slave_ro = 1;
server.repl_down_since = time(NULL);
server.slave_priority = REDIS_DEFAULT_SLAVE_PRIORITY;
// 客户端输出缓存限制
/* Client output buffer limits */
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_NORMAL].hard_limit_bytes = 0;
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_NORMAL].soft_limit_bytes = 0;
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_NORMAL].soft_limit_seconds = 0;
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_SLAVE].hard_limit_bytes = 1024*1024*256;
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_SLAVE].soft_limit_bytes = 1024*1024*64;
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_SLAVE].soft_limit_seconds = 60;
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_PUBSUB].hard_limit_bytes = 1024*1024*32;
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_PUBSUB].soft_limit_bytes = 1024*1024*8;
server.client_obuf_limits[REDIS_CLIENT_LIMIT_CLASS_PUBSUB].soft_limit_seconds = 60;
/* Double constants initialization */
R_Zero = 0.0;
R_PosInf = 1.0/R_Zero;
R_NegInf = -1.0/R_Zero;
R_Nan = R_Zero/R_Zero;
/* Command table -- we intiialize it here as it is part of the
* initial configuration, since command names may be changed via
* redis.conf using the rename-command directive. */
// 命令表
server.commands = dictCreate(&commandTableDictType,NULL);
populateCommandTable();
server.delCommand = lookupCommandByCString("del");
server.multiCommand = lookupCommandByCString("multi");
server.lpushCommand = lookupCommandByCString("lpush");
server.lpopCommand = lookupCommandByCString("lpop");
server.rpopCommand = lookupCommandByCString("rpop");
/* Slow log */
// 慢查询
server.slowlog_log_slower_than = REDIS_SLOWLOG_LOG_SLOWER_THAN;
server.slowlog_max_len = REDIS_SLOWLOG_MAX_LEN;
/* Debugging */
// 调试
server.assert_failed = "<no assertion failed>";
server.assert_file = "<no file>";
server.assert_line = 0;
server.bug_report_start = 0;
server.watchdog_period = 0;
}
初始化服务器initServer()
void initServer() {
int j;
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
setupSignalHandlers();
// LOG
if (server.syslog_enabled) {
openlog(server.syslog_ident, LOG_PID | LOG_NDELAY | LOG_NOWAIT,
server.syslog_facility);
}
// 当前处理的客户端
server.current_client = NULL;
// 所有客户端
server.clients = listCreate();
// 要被关闭的客户端
server.clients_to_close = listCreate();
// 附属节点
server.slaves = listCreate();
// monitor 客户端
server.monitors = listCreate();
// 被取消阻塞的客户端
server.unblocked_clients = listCreate();
// 所有已就绪 key
server.ready_keys = listCreate();
// 初始化共享对象
createSharedObjects();
// 获取最大打开文件数目
adjustOpenFilesLimit();
// 初始化事件状态
server.el = aeCreateEventLoop(server.maxclients+1024);
// 初始化数据库
server.db = zmalloc(sizeof(redisDb)*server.dbnum);
// 初始化网络连接
if (server.port != 0) {
server.ipfd = anetTcpServer(server.neterr,server.port,server.bindaddr);
if (server.ipfd == ANET_ERR) {
redisLog(REDIS_WARNING, "Opening port %d: %s",
server.port, server.neterr);
exit(1);
}
}
if (server.unixsocket != NULL) {
unlink(server.unixsocket); /* don't care if this fails */
server.sofd = anetUnixServer(server.neterr,server.unixsocket,server.unixsocketperm);
if (server.sofd == ANET_ERR) {
redisLog(REDIS_WARNING, "Opening socket: %s", server.neterr);
exit(1);
}
}
if (server.ipfd < 0 && server.sofd < 0) {
redisLog(REDIS_WARNING, "Configured to not listen anywhere, exiting.");
exit(1);
}
// 初始化数据库
for (j = 0; j < server.dbnum; j++) {
// key space
server.db[j].dict = dictCreate(&dbDictType,NULL);
// 过期空间
server.db[j].expires = dictCreate(&keyptrDictType,NULL);
// 被阻塞键
server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
// 可解除阻塞的键
server.db[j].ready_keys = dictCreate(&setDictType,NULL);
// 被 WATCH 命令监视的键
server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
// 数据库 ID
server.db[j].id = j;
}
// pubsub
server.pubsub_channels = dictCreate(&keylistDictType,NULL);
server.pubsub_patterns = listCreate();
listSetFreeMethod(server.pubsub_patterns,freePubsubPattern);
listSetMatchMethod(server.pubsub_patterns,listMatchPubsubPattern);
// CRON 执行计数
server.cronloops = 0;
// BGSAVE 执行指示变量
server.rdb_child_pid = -1;
// BGREWRITEAOF 执行指示变量
server.aof_child_pid = -1;
// 初始化 AOF 重写缓存
aofRewriteBufferReset();
server.aof_buf = sdsempty();
// 最后一次成功保存的时间
server.lastsave = time(NULL);
// 结束 SAVE 的时间
server.rdb_save_time_last = -1;
// 开始 SAVE 的时间
server.rdb_save_time_start = -1;
server.dirty = 0;
// 统计变量
server.stat_numcommands = 0;
server.stat_numconnections = 0;
server.stat_expiredkeys = 0;
server.stat_evictedkeys = 0;
server.stat_starttime = time(NULL);
server.stat_keyspace_misses = 0;
server.stat_keyspace_hits = 0;
server.stat_peak_memory = 0;
server.stat_fork_time = 0;
server.stat_rejected_conn = 0;
memset(server.ops_sec_samples,0,sizeof(server.ops_sec_samples));
server.ops_sec_idx = 0;
server.ops_sec_last_sample_time = mstime();
server.ops_sec_last_sample_ops = 0;
server.unixtime = time(NULL);
server.lastbgsave_status = REDIS_OK;
server.stop_writes_on_bgsave_err = 1;
// 关联 server cron 到时间事件
aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL);
// 关联网络连接事件
if (server.ipfd > 0 && aeCreateFileEvent(server.el,server.ipfd,AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.ipfd file event.");
if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event.");
// 如果 AOF 已打开,那么打开或创建 AOF 文件
if (server.aof_state == REDIS_AOF_ON) {
server.aof_fd = open(server.aof_filename,
O_WRONLY|O_APPEND|O_CREAT,0644);
if (server.aof_fd == -1) {
redisLog(REDIS_WARNING, "Can't open the append-only file: %s",
strerror(errno));
exit(1);
}
}
/* 32 bit instances are limited to 4GB of address space, so if there is
* no explicit limit in the user provided configuration we set a limit
* at 3 GB using maxmemory with 'noeviction' policy'. This avoids
* useless crashes of the Redis instance for out of memory. */
// 设置内存限制
if (server.arch_bits == 32 && server.maxmemory == 0) {
redisLog(REDIS_WARNING,"Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.");
server.maxmemory = 3072LL*(1024*1024); /* 3 GB */
server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION;
}
// 如果集群模式已打开,那么初始化集群
if (server.cluster_enabled) clusterInit();
// 初始化脚本环境
scriptingInit();
// 初始化慢查询
slowlogInit();
// 初始化后台 IO
bioInit();
}
主循环
//处理客户端命令的主函数,由main函数调用,aeEventLoop定义在(ae.h),beforesleep和aftersleep均在服务器启动初始化时设定
void aeMain(aeEventLoop *eventLoop) {
eventLoop->stop = 0;
while (!eventLoop->stop) {
// 如果有需要在事件处理前执行的函数,那么运行它
if (eventLoop->beforesleep != NULL)
eventLoop->beforesleep(eventLoop);
//处理文件时间及时间事件
aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);
}
}
相关结构体
struct redisServer {
/* General */
// 数据库数组
redisDb *db;
// 命令表
dict *commands; /* Command table hash table */
// 事件状态结构
aeEventLoop *el;
// LRU
unsigned lruclock:22; /* Clock incrementing every minute, for LRU */
unsigned lruclock_padding:10;
// 关闭标志
int shutdown_asap; /* SHUTDOWN needed ASAP */
// 主动 rehash
int activerehashing; /* Incremental rehash in serverCron() */
// 密码
char *requirepass; /* Pass for AUTH command, or NULL */
// PID 文件路径
char *pidfile; /* PID file path */
// 宿主架构字长
int arch_bits; /* 32 or 64 depending on sizeof(long) */
// CRON 函数调用的次数
int cronloops; /* Number of times the cron function run */
// 每次调用 exec 时都创建新 ID
char runid[REDIS_RUN_ID_SIZE+1]; /* ID always different at every exec. */
// 如果服务器为 SENTINEL ,那么为真
int sentinel_mode; /* True if this instance is a Sentinel. */
/* Networking */
// 监听端口
int port; /* TCP listening port */
// 绑定地址
char *bindaddr; /* Bind address or NULL */
// 套接字路径
char *unixsocket; /* UNIX socket path */
// 套接字权限
mode_t unixsocketperm; /* UNIX socket permission */
int ipfd; /* TCP socket file descriptor */
int sofd; /* Unix socket file descriptor */
int cfd; /* Cluster bus lisetning socket */
/* 客户端 */
// 所有当前活动的客户端
list *clients; /* List of active clients */
// 所有等待关闭的客户端
list *clients_to_close; /* Clients to close asynchronously */
// 所有附属节点和 MONITOR
list *slaves, *monitors; /* List of slaves and MONITORs */
// 当前客户端,只在创建崩溃报告时使用
redisClient *current_client; /* Current client, only used on crash report */
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;
/* 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 latets fork() */
long long stat_rejected_conn; /* Clients rejected because of maxclients */
// 保存慢查询日志的链表
list *slowlog; /* SLOWLOG list of commands */
// 慢查询日志的当前 id 值
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 */
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 */
/* 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 save succeeede */
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 */
/* Slave specific fields */
char *masterauth; /* AUTH with this password with master */
char *masterhost; /* Hostname of master */
int masterport; /* Port of master */
int repl_ping_slave_period; /* Master pings the slave every N seconds */
int repl_timeout; /* Timeout after N seconds of master idle */
redisClient *master; /* Client that is master for this slave */
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 slave_priority; /* Reported in INFO and used by Sentinel. */
/* 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 evition */
int maxmemory_samples; /* Pricision of random sampling */
/* Blocked clients */
unsigned int bpop_blocked_clients; /* Number of clients blocked by lists */
// 要在下一次事件 lopp 前取消阻塞的所有客户端
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;
/* 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 second. */
/* Pubsub */
// 频道
dict *pubsub_channels; /* Map channels to list of subscribed clients */
// 模式
list *pubsub_patterns; /* A list of pubsub_patterns */
/* Cluster */
int cluster_enabled; /* Is cluster enabled? */
clusterState cluster; /* State of the cluster */
/* 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 */
long long lua_time_limit; /* Script timeout in seconds */
long long lua_time_start; /* Start time of script */
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 reportign */
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 */
};
网友评论