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

来源:互联网 发布:mac如何卸载opera 编辑:程序博客网 时间:2024/05/22 17:27
一、主流程,直接从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个链表,每一个链表都存放了相同大小的itemstatic 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中的一些机制







0 0
原创粉丝点击