关闭

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

标签: memched分布式内存存储
315人阅读 评论(0) 收藏 举报
分类:
一、主流程,直接从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中的一些机制







0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:264249次
    • 积分:6035
    • 等级:
    • 排名:第4710名
    • 原创:328篇
    • 转载:32篇
    • 译文:0篇
    • 评论:62条
    最新评论