您的位置:首页 > 其它

memched1.0源码阅读(3)——运行流程

2016-05-30 20:38 316 查看
一、主流程,直接从main函数开始入手。
1、调用settings_init函数,初始化全局变量settings,这个全局变量存放了memched的环境设置。
2、解析输入的参数,设置全局变量setting相关参数。
3、调用item_init函数,进行内存对象(item)的相关设置。
4、调用event_init函数,初始libevent框架。
5、调用stats_init函数,初始化memched的状态。
6、调用assoc_init函数,初始化关联数组(是一个hashmap,用于快速查找内存对象)
7、调用conn_init函数,初始化套接字会话的数组。
8、调用slabs_init函数,初始化slabs内存分配器。
9、如果以守护进程的模式运行,那么进行守护进程的相关设置
10、如果需要,就锁定进程当前的内存页
11、调用server_socket函数,创建监听套接字,并绑定到地址上
12、调用conn_new函数,根据监听套接字以及其他的相关参数,创建一个监听套接字会话。
13、分配一个数组,用于存放被删除的对象。
14、调用delete_handler函数,添加删除事件以及相应的回调函数到libevent中(libevent框架的需要)。
15、调用event_loop函数(libevent的接口),进入循环,等待各种事件的发生

int main (int argc, char **argv) {
int c;
int l_socket;
// 监听者
conn *l_conn;
struct in_addr addr;
int lock_memory = 0;
int daemonize = 0;

/* init settings */
settings_init();

/* process arguments */
while ((c = getopt(argc, argv, "p:s:m:c:khvdl:")) != -1) {
switch (c) {
case 'p':
settings.port = atoi(optarg);
break;
case 's':
settings.maxitems = atoi(optarg);
break;
case 'm':
settings.maxbytes = atoi(optarg)*1024*1024;
break;
case 'c':
settings.maxconns = atoi(optarg);
break;
case 'h':
usage();
exit(0);
case 'k':
lock_memory = 1;
break;
case 'v':
settings.verbose = 1;
break;
case 'l':
if (!inet_aton(optarg, &addr)) {
fprintf(stderr, "Illegal address: %s\n", optarg);
return 1;
} else {
settings.interface = addr;
}
break;
case 'd':
daemonize = 1;
break;
default:
fprintf(stderr, "Illegal argument \"%c\"\n", c);
return 1;
}
}

/* initialize other stuff stuff */
// 对象列表初始化
item_init();
// 监听事件处理器初始化,这是libevent中的函数
event_init();
// 状态初始化
stats_init();
// 关联数组的初始化
assoc_init();
// 连接数组的初始化
conn_init();
// slabs内存分配器初始化
slabs_init(settings.maxbytes);

// 是否作为守护进程运行
if (daemonize) {
int res;
res = daemon(0, 0);
if (res == -1) {
fprintf(stderr, "failed to fork() in order to daemonize\n");
return 1;
}
}

/* lock paged memory if needed */
// 如果需要,那么锁定当前内存页
if (lock_memory) {
mlockall(MCL_CURRENT | MCL_FUTURE);
}

/* create the listening socket and bind it */
// 创建监听套接字
l_socket = server_socket(settings.port);
if (l_socket == -1) {
fprintf(stderr, "failed to listen\n");
exit(1);
}

/* create the initial listening connection */
// 创建监听者
if (!(l_conn = conn_new(l_socket, conn_listening, EV_READ | EV_PERSIST))) {
fprintf(stderr, "failed to create listening connection");
exit(1);
}

/* initialise deletion array and timer event */
// 创建删除数组,被删除的对象放在这里,当超过指定的时间之后就删除
deltotal = 200; delcurr = 0;
todelete = malloc(sizeof(item *)*deltotal);
delete_handler(0,0,0); /* sets up the event */

/* enter the loop */
event_loop(0);

return;
}


下面讲解一些初始化的函数,他们都在main函数中被调用,对memched进行相关的初始化
二、环境的初始化
void settings_init(void) {
// 监听端口
settings.port = 11211;
// 在任何一个地址监听
settings.interface.s_addr = htonl(INADDR_ANY);
// 使用的内存的最大数量
settings.maxbytes = 64*1024*1024; /* default is 64MB */
// 最大的项目的数量
settings.maxitems = 0;            /* no limit on no. of items by default */
// 最大的连接的数量
settings.maxconns = 1024;         /* to limit connections-related memory to about 5MB */
settings.verbose = 0;
}

三、对象数组的初始化
memched中定义了三个全局变量,存放了32个链表,然后再初始化这32个链表
<span style="font-family: Arial, Helvetica, sans-serif;">// 0~31的链表id,每一个链表对应一个id,id对应存放了大小为(2^id)的内存块的链表</span>

#define LARGEST_ID 32
// 定义32个链表,每一个链表都存放了相同大小的item
static item *heads[LARGEST_ID];
// 指向32链表的尾部
static item *tails[LARGEST_ID];
// 存放了32个链表的长度
unsigned int sizes[LARGEST_ID];
// 对象链表的初始化
void item_init(void) {
int i;
for(i=0; i<LARGEST_ID; i++) {
heads[i]=0;
tails[i]=0;
sizes[i]=0;
}
}
四、memched状态初始化
// 状态初始化
void stats_init(void) {
// 当前对象的数量
stats.curr_items = stats.total_items = stats.curr_conns = stats.total_conns = stats.conn_structs = 0;
// 命令的数量
stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses = 0;
// 读写字节数量的初始化
stats.curr_bytes = stats.bytes_read = stats.bytes_written = 0;
// 设置启动的时间
stats.started = time(0);
}

五、关联数组的初始化(使用了第三方库)
// 关联数组的初始化
void assoc_init(void) {
return;
}

六、空闲套接字会话数组的初始化
// 空闲的套接字会话的初始化
void conn_init(void) {
freetotal = 200;
freecurr = 0;
freeconns = (conn **)malloc(sizeof (conn *)*freetotal);
return;
}

七、slabs内存分配器的初始化
// 初始化一个slabs内存分配器
/*
* 全局数组slabclass中的每一个元素都有一个链表
* 如果元素的下标是i,那么它对应的链表就存储着大小为(2的i次方)内存块
*/
void slabs_init(unsigned int limit) {
int i;
int size=1;

mem_limit = limit;

// 初始化每一个类型的slabs
for(i=0; i<=POWER_LARGEST; i++, size*=2) {
slabclass[i].size = size;
// 当前链表中可以存放多少个内存块
slabclass[i].perslab = POWER_BLOCK / size;
slabclass[i].slots = 0;
slabclass[i].sl_curr = slabclass[i].sl_total = slabclass[i].slabs = 0;
}
}
下一章讲解套接字创建以及libevent中的一些机制
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: