源码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;}

  主线程启动堆栈:

server_sockets——>
server_socket——>
conn_new——>
event_handler——>
drive_machine——>
try_read_command(这里会判定,是文本协议还是二进制协议)

第四步、关闭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启动的主要流程就是这些了。

  最后来个图片,描述一下启动后的memcached结构。

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

转载于:https://www.cnblogs.com/ELMND/p/4581729.html

memcached(五)--源码分析,启动相关推荐

  1. golang源码分析-启动过程概述

    golang源码分析-启动过程概述 golang语言作为根据CSP模型实现的一种强类型的语言,本文主要就是通过简单的实例来分析一下golang语言的启动流程,为深入了解与学习做铺垫. golang代码 ...

  2. springboot集成mybatis源码分析-启动加载mybatis过程(二)

    springboot集成mybatis源码分析-启动加载mybatis过程(二) 1.springboot项目最核心的就是自动加载配置,该功能则依赖的是一个注解@SpringBootApplicati ...

  3. 嵌入式之uboot源码分析-启动第二阶段学习笔记(下篇)

    接上部分---->嵌入式之uboot源码分析-启动第二阶段学习笔记(上篇) 注:如下内容来自朱老师物联网大讲堂uboot课件 3.2.14 CFG_NO_FLASH (1)虽然NandFlash ...

  4. 【Android 插件化】VirtualApp 源码分析 ( 启动应用源码分析 | HomePresenterImpl 启动应用方法 | VirtualCore 启动插件应用最终方法 )

    文章目录 一.启动应用源码分析 1.HomeActivity 启动应用点击方法 2.HomePresenterImpl 启动应用方法 3.VirtualCore 启动插件应用最终方法 一.启动应用源码 ...

  5. SRS(simple-rtmp-server)流媒体服务器源码分析--启动

    SRS(simple-rtmp-server)流媒体服务器源码分析--系统启动 一.前言 小卒最近看SRS源码,随手写下博客,其一为了整理思路,其二也是为日后翻看方便.如果不足之处,请指教! 首先总结 ...

  6. python3.5源码分析-启动与虚拟机

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3启动流程概述 本文基于python3分析其基本的 ...

  7. uboot源码分析-启动第一阶段

    注:基于九鼎x210 uboot 在SourceInsight软件下 一.start.S引入 1.u-boot.lds中找到start.S入口 (1)在C语言中整个项目的入口就是main函数(这是C语 ...

  8. 嵌入式之uboot源码分析-启动第一阶段学习笔记

    注: 以下的内容来自朱老师物联网大讲堂uboot部分课件 Uboot启动第一阶段start.S执行步骤 1.头文件包含 <config.h>(x210的各种宏定义) <version ...

  9. uboot 2021.10源码分析(启动流程)

    uboot版本:2021.10 平台:armv8  rk3399  eMMC 16G  LPDDR4 4G 本文主要基于uboot的执行流程进行分析而忽略了相关细节,从uboot的基本框架结构着手,新 ...

  10. Nginx源码分析-启动初始化过程(一)

    Nginx的启动初始化在src/core/nginx.c的main函数中完成,当然main函数是整个Nginx的入口,除了完成启动初始化任务以外,也必定是所有功能模块的入口之处.Nginx的初始化工作 ...

最新文章

  1. Alibaba代码规范插件、FindBugs插件安装及详解,IDEA插件安装,代码规范,代码查错,代码格式规范
  2. python有哪些常用的package_python package相关机制总结
  3. 基于GNN,强于GNN:胶囊图神经网络的PyTorch实现 | ICLR 2019
  4. 【Android 逆向】ART 脱壳 ( InMemoryDexClassLoader 脱壳 | BaseDexClassLoader 构造函数 | DexPathList 构造函数及后续调用 )
  5. linux用冒泡排序程序,利用双向走动法改进冒泡排序算法C语言源代码[黑盟核心成员]...
  6. MYSQL中只知表名查询属于哪个SCHEMA
  7. 添加include文件路径_-isystem以及include_next的副作用
  8. [EntLib]UAB(Updater Application Block)下载
  9. iar c语言单片机指针,51单片机IAR编程示例
  10. 虚拟现实中用到的五种定位追踪技术
  11. CQI的解释(完整版)
  12. 阳春三月,正是樱花绽放时,借此机会给午饭献上鲜艳艳的视觉盛宴!
  13. 成语答题赚小程序安装教程
  14. 代码实现判断主机字节序(大端 or小端 )-- 面试题
  15. SQL 为什么动不动就 N 百行以 K 计
  16. 一个字等于几个字节,怎么确定机器是16/32/64位机器
  17. 机械与计算机大一学的一样吗,机械设计制造及其自动化专业各校大一新生学的课程一样吗...
  18. 盛大网络董事长陈天桥 三十年河东三十年河西
  19. 【毕业设计】深度学习人体语义分割在弹幕防遮挡上的实现 - python
  20. IDEA 运行maven项目时出错:Error java:错误: 不支持发行版本 XXX 5,12,14等

热门文章

  1. iOS开发之三方分享(shareSDK)
  2. Set A Light 3D Studio 2.0 for Mac(3D摄影棚布光软件)
  3. mac自带录屏截图功能怎么使用?好用吗?
  4. js将一篇文章中多个连续的br标签替换成两个连续的br标签
  5. Contest-hunter 暑假送温暖 SRM08
  6. DigitalRealty公司在达拉斯新建一个数据中心
  7. linux系统命令 回顾2
  8. pp to write
  9. WPF-14:绑定中数据模型必须为public问题
  10. idea license 20200104