服务器:
一、服务器结构体 redisServer:
struct redisServer {
char *configfile;
int hz;
int dbnum;
redisDb *db;
dict *commands;
aeEventLoop *el;
int port;
char *bindaddr[CONFIG_BINDADDR_MAX];
int bindaddr_count;
int ipfd[REDIS_BINDADDR_MAX]; /* TCP socket file descriptors */
int ipfd_count; /* Used slots in ipfd[] */
list *clients;
int maxidletime;
/* 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. */
}
-
L15、L16:redis可以配置在多个网卡上,所以配置多个socket fd;
在config.c中可以看到,服务器启动加载配置文件时,如果配置文件中有bind项,才会有多个ipfd;
if (!strcasecmp(argv[0],"bind") && argc >= 2) { int j, addresses = argc-1; if (addresses > REDIS_BINDADDR_MAX) { err = "Too many bind addresses specified"; goto loaderr; } for (j = 0; j < addresses; j++) server.bindaddr[j] = zstrdup(argv[j+1]); server.bindaddr_count = addresses; }
-
L6:服务器中的数据库:
typedef struct redisDb { dict *dict; /* The keyspace for this DB */ dict *expires; /* Timeout of keys with a timeout set */ int id; long long avg_ttl; /* Average TTL, just for stats */ } redisDb;
-
L2: 这个字典称作 键空间 key space,就是用户所见到的数据库;
所有对数据库的操作(添加或删除数据库),都是对这个键空间字典的操作;
-
L2:键的过期字典;
-
二、服务器的启动与初始化:
1、启动服务器:
Redis服务器启动后,首先执行main函数:
int main(int argc, char **argv) {
// ...
initServer();
// ...
// 解析参数,加载配置文件等
// ...
aeMain(server.el);
aeDeleteEventLoop(server.el);
return 0;
}
- 服务器首先进行初始化 L3,接着就进入事件循环[2] L7;
2、初始化服务器:
接着看服务器初始化需要哪些步骤:
void initServer() {
// ...
/* 创建事件循环和数据库 */
server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
server.db = zmalloc(sizeof(redisDb)*server.dbnum);
// ...
/* Create the serverCron() time event, that's our main way to process
* background operations. */
if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
redisPanic("Can't create the serverCron time event.");
exit(1);
}
/* Create the Redis databases, and initialize other internal state. */
for (j = 0; j < server.dbnum; j++) {
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);
server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
server.db[j].id = j;
server.db[j].avg_ttl = 0;
}
// ...
/* 为每个bind的端口开一个socket用来处理连接 */
for (j = 0; j < server.ipfd_count; j++) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR)
{
redisPanic(
"Unrecoverable error creating server.ipfd file event.");
}
}
// ...
}
-
L3:在事件循环中加入对时间事件serverCron的监听 //todo;
-
L29:此时绑定了port和地址的socket fd正在listen;创建监听可读事件,回调acceptTcpHandler accept客户端连接,创建客户端;
void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) { int cport, cfd; char cip[REDIS_IP_STR_LEN]; REDIS_NOTUSED(el); REDIS_NOTUSED(mask); REDIS_NOTUSED(privdata); /* 进行accept */ cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport); if (cfd == AE_ERR) { redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr); return; } redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport); /* 会调用createClient创建客户端 */ acceptCommonHandler(cfd,0); }
-
L4~L6:学习一下,避免编译器报Warning:
/* Anti-warning macro... */ #define REDIS_NOTUSED(V) ((void) V)
-