memcached(五)--源码分析,启动

  源码memcached.c中,main入口函数。

第一步,根据memcached的启动参数做校验参数、配置

main函数中,几乎600行代码都是这些参数校验。吐槽一个。

第二步,初始化

  2.1:初始化主线程的libevent。

main_base = event_init();

  2.2:初始化memcached的stats信息。

  在文本协议的memcached中,我们nc/telent后输入stats命令,会很快地输出一些当前memcached的信息的。这些就是stats信息。并不是输入stats的时候才遍历统计出来的。而是已经保存好了这份信息。代码调用在main函数中的:

stats_init();

  具体的统计信息,可以在memcached.h这个文件中找到:

/**
 * Global stats.
 */
struct stats {
    pthread_mutex_t mutex;
    unsigned int  curr_items;
    unsigned int  total_items;
    uint64_t      curr_bytes;
    unsigned int  curr_conns;
    unsigned int  total_conns;
    uint64_t      rejected_conns;
    uint64_t      malloc_fails;
    unsigned int  reserved_fds;
    unsigned int  conn_structs;
    uint64_t      get_cmds;
    uint64_t      set_cmds;
    uint64_t      touch_cmds;
    uint64_t      get_hits;
    uint64_t      get_misses;
    uint64_t      touch_hits;
    uint64_t      touch_misses;
    uint64_t      evictions;
    uint64_t      reclaimed;
    time_t        started;          /* when the process was started */
    bool          accepting_conns;  /* whether we are currently accepting */
    uint64_t      listen_disabled_num;
    unsigned int  hash_power_level; /* Better hope it‘s not over 9000 */
    uint64_t      hash_bytes;       /* size used for hash tables */
    bool          hash_is_expanding; /* If the hash table is being expanded */
    uint64_t      expired_unfetched; /* items reclaimed but never touched */
    uint64_t      evicted_unfetched; /* items evicted but never touched */
    bool          slab_reassign_running; /* slab reassign in progress */
    uint64_t      slabs_moved;       /* times slabs were moved around */
    uint64_t      lru_crawler_starts; /* Number of item crawlers kicked off */
    bool          lru_crawler_running; /* crawl in progress */
    uint64_t      lru_maintainer_juggles; /* number of LRU bg pokes */
};

  2.3:hash桶初始化

  代码main函数中的:

assoc_init(settings.hashpower_init);

  在memcached中,保存着一份hash表用来存放memcached key。默认这个hash表是2^16(65536)个key。后续会根据规则动态扩容这个hash表的。如果希望启动的时候,这个hash表更大,可以-o 参数调节。

  hash表中, memcached key作为key,value是item指针,并不是item value。

  2.4:初始化connection。

conn_init()

  也就是 memcached启动参数中的-c参数,默认1024。

  为了更快地找到connection的fd(文件描述符),实际上申请的connection会比配置的更大一点。

/*
 * Initializes the connections array. We don‘t actually allocate connection
 * structures until they‘re needed, so as to avoid wasting memory when the
 * maximum connection count is much higher than the actual number of
 * connections.
 *
 * This does end up wasting a few pointers‘ worth of memory for FDs that are
 * used for things other than connections, but that‘s worth it in exchange for
 * being able to directly index the conns array by FD.
 */
static void conn_init(void) {
    /* We‘re unlikely to see an FD much higher than maxconns. */
    int next_fd = dup(1);
    int headroom = 10;      /* account for extra unexpected open FDs */
    struct rlimit rl;

    max_fds = settings.maxconns + headroom + next_fd;

    /* But if possible, get the actual highest FD we can possibly ever see. */
    if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
        max_fds = rl.rlim_max;
    } else {
        fprintf(stderr, "Failed to query maximum file descriptor; "
                        "falling back to maxconns\n");
    }

    close(next_fd);

    if ((conns = calloc(max_fds, sizeof(conn *))) == NULL) {
        fprintf(stderr, "Failed to allocate connection structures\n");
        /* This is unrecoverable so bail out early. */
        exit(1);
    }
}

  2.5:初始化slabs。

  在2.3的hash桶中初始化的是key。slabs初始化的是这些key对应的value。下面摘录关键代码:

    while (++i < MAX_NUMBER_OF_SLAB_CLASSES-1 && size <= settings.item_size_max / factor) {
        /* Make sure items are always n-byte aligned */
        if (size % CHUNK_ALIGN_BYTES)
            size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);

        slabclass[i].size = size;
        slabclass[i].perslab = settings.item_size_max / slabclass[i].size;
        size *= factor;
        if (settings.verbose > 1) {
            fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",
                    i, slabclass[i].size, slabclass[i].perslab);
        }
    }

  在初始化slab的时候,下一个slab的size(chunk size)总是大于等于当前slab的size的。

  2.6:初始化worker线程。

memcached_thread_init(settings.num_threads, main_base);

  worker线程和main线程,组成了libevent的reactor模式。

  2.7:定时器

clock_handler(0, 0, 0);

  用于对比对象是否过期。

第三步、libevent主线程监听事件

    /* enter the event loop */
    if (event_base_loop(main_base, 0) != 0) {
        retval = EXIT_FAILURE;
    }

第四步、关闭hash桶线程

  在2.3的初始化步骤中,有线程操作。这里明确关闭这个线程。

void stop_assoc_maintenance_thread() {
    mutex_lock(&maintenance_lock);
    do_run_maintenance_thread = 0;
    pthread_cond_signal(&maintenance_cond);
    mutex_unlock(&maintenance_lock);

    /* Wait for the maintenance thread to stop */
    pthread_join(maintenance_tid, NULL);
}

  memcached启动的主要流程就是这些了。

  源码github上有,见:https://github.com/memcached/memcached/blob/master/memcached.c  文件有点大,可能浏览器卡顿一下。这里肯定就不贴出来了^_^

时间: 2024-10-11 18:22:24

memcached(五)--源码分析,启动的相关文章

TOMCAT源码分析(启动框架)

建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, 是不那么容易掌握TOMCAT的框架的. 所以得实践.实践.再实践. 建议下载一份TOMCAT的源码, 调试通过, 然后单步跟踪其启动过程. 如果有不明白的地方, 再来查阅本文, 看是否能得到帮助. 我相信这样效果以及学习速度都会好很多! 1. Tomcat的整体框架结构 Tomcat的基本框架, 分为4个层次. Top Level Elements: Server Service Connector HTTP AJP Conta

Zookeeper 源码分析-启动

Zookeeper 源码分析-启动 博客分类: Zookeeper 本文主要介绍了zookeeper启动的过程 运行zkServer.sh start命令可以启动zookeeper.入口的main函数在类中QuorumPeerMain. main函数主要调用了runFromConfig函数,创建了QuorumPeer对象,并且调用了start函数,从而启动了zookeeper. Java代码   public class QuorumPeerMain { protected QuorumPeer

基于TCP网络通信的自动升级程序源码分析-启动升级文件下载程序

升级程序启动后,首先会连接服务器 private void Connect() { try { int port = int.Parse(System.Configuration.ConfigurationManager.AppSettings["Port"]); connnectionInfo = new ConnectionInfo(IPAddress, port); connection = TCPConnection.GetConnection(connnectionInfo)

Symfoy2源码分析——启动过程2

上一篇分析Symfony2框架源码,探究Symfony2如何完成一个请求的前半部分,前半部分可以理解为Symfony2框架为处理请求做准备工作,包括container生成.缓存.bundls初始化等一些列准备工作(Symfoy2源码分析——启动过程1).而这一篇讲的是Symfony2如何根据请求的数据生成Response对象,向客户端返回响应数据. 在分析前需要了解Symfony2的事件驱动机制:Symfony2事件驱动. 言归正传,Symfony2请求的工作流程其实是Symfony2内核的事件

Tomcat7.0源码分析——启动与停止服务

前言 熟悉Tomcat的工程师们,肯定都知道Tomcat是如何启动与停止的.对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处理命令,大家一定知道改如何使用它,但是它们究竟是如何实现的,尤其是shutdown.sh脚本(或者shutdown.bat)究竟是如何和Tomcat进程通信的呢?本文将通过对Tomcat7.0的源码阅读,深入剖析这一过程. 由于在生产环境中,Tomcat一般部署在Linux系统下,所以本文将以startup.s

Tomcat7.0源码分析——启动与停止服务原理

前言 熟悉Tomcat的工程师们,肯定都知道Tomcat是如何启动与停止的.对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处理命令,大家一定知道改如何使用它,但是它们究竟是如何实现的,尤其是shutdown.sh脚本(或者shutdown.bat)究竟是如何和Tomcat进程通信的呢?本文将通过对Tomcat7.0的源码阅读,深入剖析这一过程. 由于在生产环境中,Tomcat一般部署在Linux系统下,所以本文将以startup.s

Tomcat源码分析——启动与停止服务

前言 熟悉Tomcat的工程师们,肯定都知道Tomcat是如何启动与停止的.对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处理命令,大家一定知道改如何使用它,但是它们究竟是如何实现的,尤其是shutdown.sh脚本(或者shutdown.bat)究竟是如何和Tomcat进程通信的呢?本文将通过对Tomcat7.0的源码阅读,深入剖析这一过程. 由于在生产环境中,Tomcat一般部署在Linux系统下,所以本文将以startup.s

Tomcat源码分析--启动过程

一直使用Tomcat确不知道它的运行原理.看了源码后对它的启动过程有了一定的了解,特来记录一下. 首先先介绍一下Tomcat的架构图: Tomcat主要有两个核心的组件,一个是Connector(连接器)和容器.所谓连接器就是当有HTTP请求到来时,连接器负责接收这个请求,然后将该请求转发到容器.容器有Engine,Host,Context,Wrapper.Engine:表示整个Catalina servlet引擎:Host:表示包含一个或多个Context容器的虚拟主机:Context:表示一

【转】Android 4.0 Launcher2源码分析——启动过程分析

Android的应用程序的入口定义在AndroidManifest.xml文件中可以找出:[html] <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.launcher">  <original-package android:name="com.android.launcher2" /> .

junit4.12源码分析-启动到选择runner

第一次写源代码分析,介绍运行流程和其中重要的类和接口! JUnitCore JUnitCore采用门面模式,可以启动junit4,junit3测试,也可以测试指定class.JUnitCore声明RunNotifier类,该类采用观察者模式实现事件管理.RunListener为测试事件基类,有测试开始结束失败等事件,如果想自定义事件可以继承该类.默认增加了两个RunListener,一个是TextListener,另一个是Result类函数createListener构造的Listener用于记