设为首页 收藏本站
查看: 1423|回复: 0

[经验分享] memcached源码阅读笔记一

[复制链接]

尚未签到

发表于 2015-9-1 14:07:16 | 显示全部楼层 |阅读模式
  
  从main函数开始,位于memcached.c
  



1 int main (int argc, char **argv) {
2     //.......................
3     //.......................
4     //.......................
5     
6     
7     /* handle SIGINT 注册信号处理函数,目前sig_handler是空函数*/
8     signal(SIGINT, sig_handler);
9     
10     settings_init();
11     /* init settings
12          初始化默认设置,其中
13          settings.port = 11211;                     默认端口
14          settings.maxbytes = 64 * 1024 * 1024;      默认使用64MB内存
15          settings.num_threads = 4;                  默认启动4个工作线程
16          settings.item_size_max = 1024 * 1024;      默认每对 key value的value最大1MB
17      */
18     
19     
20     //.......................
21     //.......................
22     //.......................
23     
24     
25     /* 初始化主线程的libevent实例 */
26     main_base = event_init();
27     
28     
29     //.......................
30     //.......................
31     //.......................
32     
33     
34     /* 启动工作线程 */
35     thread_init(settings.num_threads, main_base);
36     /*
37          // 主线程是分配线程,分配工作给工作线程
38          dispatcher_thread.base = main_base;
39          dispatcher_thread.thread_id = pthread_self();
40          //设置工作线程的属性以及它们各自的libevent实例初始化
41          for (i = 0; i < nthreads; i++) {
42          int fds[2];
43          pipe(fds)
44          threads.notify_receive_fd = fds[0];
45          threads.notify_send_fd = fds[1];
46          setup_thread(&threads);
47          }
48          //启动线程,线程处理函数为worker_libevent, 每个线程有各自的event_base_loop
49          for (i = 0; i < nthreads; i++) {
50          create_worker(worker_libevent, &threads);
51          }
52     */
53     
54     
55     //.......................
56     //.......................
57     //.......................
58     
59     
60     /* 创建服务端的socket */
61     server_sockets(settings.port, tcp_transport, portnumber_file))
62     
63     //.......................
64     //.......................
65     //.......................
66     
67     
68     /* 主线程的libevent消息循环 */
69     if (event_base_loop(main_base, 0) != 0) {
70         retval = EXIT_FAILURE;
71     }
72     
73     
74     //.......................
75     //.......................
76     //.......................
77     
78     
79     return retval;
80 }
  
  主线程



1 server_sockets(settings.port, tcp_transport, portnumber_file)
2 --->
3 server_socket(settings.inter, port, transport, portnumber_file);
4 --->
5 listen(sfd, settings.backlog)
6 listen_conn_add = conn_new(sfd, conn_listening, EV_READ | EV_PERSIST, 1, transport, main_base)
7 --->   
8 //设置sfd的消息响应函数event_handler
9 event_set(&c->event, sfd, event_flags, event_handler, (void *)c);
10 event_base_set(base, &c->event);
11 --->
12 void event_handler(const int fd, const short which, void *arg) {
13     conn *c;
14     c = (conn *)arg;
15     
16     //.......................
17     //.......................
18     //.......................
19     
20     drive_machine(c);
21     
22     return;
23 }
24 --->
25 //drive_machine
26 sfd = accept(c->sfd, (struct sockaddr *)&addr, &addrlen)
27 dispatch_conn_new(sfd, conn_new_cmd, EV_READ | EV_PERSIST,
28                   DATA_BUFFER_SIZE, tcp_transport);
29
30 --->
31 void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags,
32                        int read_buffer_size, enum network_transport transport) {
33     char buf[1];
34     int tid = (last_thread + 1) % settings.num_threads;
35     
36     LIBEVENT_THREAD *thread = threads + tid;
37     
38     //往其中一个worker线程的管道写,分配这个链接给worker
39     buf[0] = 'c';
40     if (write(thread->notify_send_fd, buf, 1) != 1) {
41         perror("Writing to thread notify pipe");
42     }
43 }
  
  
  函数补充:



1 static void setup_thread(LIBEVENT_THREAD *me) {
2     me->base = event_init();
3     if (! me->base) {
4         fprintf(stderr, "Can't allocate event base\n");
5         exit(1);
6     }
7     
8     // 把管道的读事件注册到libevent对象中
9     // 分配线程会往工作线程的 notify_send_fd 写数据,然后触发工作线程的 notify_receive_fd 的读事件
10     event_set(&me->notify_event, me->notify_receive_fd,
11               EV_READ | EV_PERSIST, thread_libevent_process, me);
12     event_base_set(me->base, &me->notify_event);
13     
14     if (event_add(&me->notify_event, 0) == -1) {
15         fprintf(stderr, "Can't monitor libevent notify pipe\n");
16         exit(1);
17     }
18     
19     //.......................
20     //.......................
21     //.......................
22 }
  
  工作线程
  thread_libevent_process -> conn_new -> event_set(&c->event, sfd, event_flags, event_handler, (void *)c);event_base_set(base, &c->event);
  ->event_handler -> drive_machine
  工作线程的消息libevent事件处理就由drive_machine负责
  
  尝试去理解它的工作流程
  drive_machine
  -->
  case conn_read:
  case READ_DATA_RECEIVED:
    conn_set_state(c, conn_parse_cmd);
  -->
  case conn_parse_cmd :
    if (try_read_command(c) == 0) {
  -->
  static int try_read_command(conn *c) {
  //..............
  if (c->protocol == binary_prot) {
  }
  else {
  //............
  process_command(c, c->rcurr);
  }
  -->
  static void process_command(conn *c, char *command) {
  //假设是set   
  } else if ((ntokens == 6 || ntokens == 7) &&
                 ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) ||
                  (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) ||
                  (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)) ||
                  (strcmp(tokens[COMMAND_TOKEN].value, "prepend") == 0 && (comm = NREAD_PREPEND)) ||
                  (strcmp(tokens[COMMAND_TOKEN].value, "append") == 0 && (comm = NREAD_APPEND)) )) {
  process_update_command(c, tokens, ntokens, comm, false);
  -->
  process_update_command(c, tokens, ntokens, comm, false);
{
  //...........
         //其实我不懂为什么要分配一个出来
         it = item_alloc(key, nkey, flags, realtime(exptime), vlen);
         //................
         conn_set_state(c, conn_nread);
}
  -->
  //drive_machine
case conn_nread:
          if (c->rlbytes == 0) {
                complete_nread(c);
  -->
  complete_nread_ascii(c);
{
      ret = store_item(it, comm, c);
}
  
  不知道理解得对不对
  
  
  -----------------------------------------------------------------------------------------------------------------
  用户连接memcached成功后,主要逻辑在drive_machine这个函数
  我尝试打日志,理解它的流程

  A:表示memcached  B:表示用户
  A:   ./memcached -m 512 -p 14444 -vv
B:   telnet 127.0.0.1 14444
  
A:   ##############################  state = conn_listening  
B:   add id 1 0 4
A:   
##############################  state = conn_new_cmd
##############################  state = conn_waiting
##############################  state = conn_read
##############################  state = conn_parse_cmd
32: Client using the ascii protocol
<32 add id 1 0 4
##############################  state = conn_nread

B:  1234
A:
##############################  state = conn_nread
##############################  state = conn_nread
>32 STORED
##############################  state = conn_write
##############################  state = conn_mwrite
##############################  state = conn_write
##############################  state = conn_mwrite
##############################  state = conn_new_cmd
##############################  state = conn_waiting
B: 收到
STORED  
  
  B: get id
  A:
  ############################## state = conn_read
##############################  state = conn_parse_cmd
<32 get id
>32 sending key id
>32 END
##############################  state = conn_mwrite
##############################  state = conn_mwrite
##############################  state = conn_new_cmd
##############################  state = conn_waiting
  B: 收到
  VALUE id 1 4
1234
END
  
  B: quit
  A:
  ############################## state = conn_read
##############################  state = conn_parse_cmd
<32 quit
##############################  state = conn_closing
<32 connection closed.
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-108415-1-1.html 上篇帖子: Memcached-高性能的分布式内存缓存服务器 下篇帖子: Memcached学习笔记——windows上初步使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表