Chinaunix首页 | 论坛 | 博客
  • 博客访问: 110785
  • 博文数量: 12
  • 博客积分: 226
  • 博客等级: 二等列兵
  • 技术积分: 221
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-10 23:15
文章分类

全部博文(12)

分类: Mysql/postgreSQL

2012-12-01 23:40:13

Oracle MySQL只公开了前两种源码,企业版中线程池以插件的形式实现提供,Mariadb提供了三种线程调度方法:

one_thread_scheduler_functions:
由main函数处理连接,连接断开后,等待处理其他连接

one_thread_per_connection_scheduler_functions
为每个连接创建一个处理线程,连接断开后,处理线程被释放

tp_scheduler_functions
线程池处理连接,由一定数量的work thread共同处理接入的连接

线程调度是由一组函数接口规定的,server层通过回调这些函数来处理连接

点击(此处)折叠或打开

  1. struct scheduler_functions
  2. {
  3.   uint max_threads, *connection_count;
  4.   ulong *max_connections;
  5.   bool (*init)(void);
  6.   bool (*init_new_connection_thread)(void);
  7.   void (*add_connection)(THD *thd);
  8.   void (*thd_wait_begin)(THD *thd, int wait_type);
  9.   void (*thd_wait_end)(THD *thd);
  10.   void (*post_kill_notification)(THD *thd);
  11.   bool (*end_thread)(THD *thd, bool cache_thread);
  12.   void (*end)(void);
  13. };

三种具体的线程调度方案,函数指针初始化如下:
由main函数处理连接

点击(此处)折叠或打开

  1. static scheduler_functions one_thread_scheduler_functions=
  2. {
  3.   1,  // max_threads
  4.   &connection_count,
  5.   &max_connections,
  6.   NULL,  // init
  7.   init_new_connection_handler_thread,  // init_new_connection_thread
  8.   handle_connection_in_main_thread,  // add_connection
  9.   NULL,  // add_connection
  10.   NULL,  // thd_wait_begin
  11.   NULL,  // thd_wait_end
  12.   NULL,  // post_kill_notification
  13.   no_threads_end,  // end_thread
  14.   NULL,  // end
  15. };

单线程调度通过handle_connection_in_main_thread调用do_handle_one_connection来做,它会首先回调init_new_connection_handler_thread做一些初始化工作,之后进入一个for(;;)循环,之后就看到了熟悉的do_command函数了,通过它就可以进入mysql执行查询了,其end函数指针被初始化no_threads_end,做的事情比较简单,清理了连接对应的thd,之后继续接受下一个连接

一个连接一个处理线程

点击(此处)折叠或打开

  1. static scheduler_functions one_thread_per_connection_scheduler_functions=
  2. {
  3.   0,  // max_threads
  4.   &connection_count,
  5.   &max_connections,
  6.   NULL,  // init
  7.   init_new_connection_handler_thread,  // init_new_connection_thread
  8.   create_thread_to_handle_connection,  // add_connection
  9.   NULL,  // thd_wait_begin
  10.   NULL,  // thd_wait_end
  11.   NULL,  // post_kill_notification
  12.   one_thread_per_connection_end,  // end_thread
  13.   NULL,  // end
  14. };

每来一个连接都会在create_thread_to_handle_connection中获得线程,它首先会在这thread_cache中找,找到了就唤醒work thread,找不到才创建线程,对应的线程函数为handle_one_connection,与单线程调度类似,最终通过调用do_handle_one_connection函数来进入do_command的for(;;)循环,与单线程调度不同的是,其end函数指针为one_thread_per_connection_end,连接退出后做的事情会多一些,如果put_in_cache被设置,work thread会被cache起来,否则会通过my_thread_end清理线程资源

线程池处理连接:(将在下篇博客中介绍)

点击(此处)折叠或打开

  1. static scheduler_functions tp_scheduler_functions=
  2. {
  3.   0,  // max_threads
  4.   NULL,
  5.   NULL,
  6.   tp_init,  // init
  7.   NULL,  // init_new_connection_thread
  8.   tp_add_connection,  // add_connection
  9.   tp_wait_begin,  // thd_wait_begin
  10.   tp_wait_end,  // thd_wait_end
  11.   tp_post_kill_notification,  // post_kill_notification
  12.   NULL,  // end_thread
  13.   tp_end  // end
  14. };

线程回调函数接口在server层被调用的地方:
main线程中,读取配置信息,决定具体采用的thread scheduler,接着初始化网络,调用init接口完成线程调度初始化工作,之后server接受client连接,通过调用add_connection接口处理请求

点击(此处)折叠或打开

  1. mysqld_main
  2.   ...
  3.   |->init_common_variables
  4.     |->get_options
  5.       |->
  6.          if (thread_handling <= SCHEDULER_ONE_THREAD_PER_CONNECTION)
  7.             one_thread_per_connection_scheduler(thread_scheduler);
  8.           else if (thread_handling == SCHEDULER_NO_THREADS)
  9.             one_thread_scheduler(thread_scheduler);
  10.           else 
  11.             pool_of_threads_scheduler(thread_scheduler)
  12.   ...

  13.   |->network_init(void)
  14.     |->MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0)
  15.   ...

  16.   |->handle_connections_sockets
  17.     |->create_new_thread // 会对连接数进行判断
  18.       |->MYSQL_CALLBACK(thread_scheduler, add_connection, (thd))
  19.   ...

server在退出时,会回调post_kill_notification接口通知线程

点击(此处)折叠或打开

  1. mysqld_exit
  2.   |->
  3.      I_List_iterator<THD> it(threads);
  4.       while (it++)
  5.         MYSQL_CALLBACK(thread_scheduler, post_kill_notification, it)

线程等待回调:

点击(此处)折叠或打开

  1. thd_wait_begin
  2.   |->MYSQL_CALLBACK(thd->scheduler, thd_wait_begin, (thd, wait_type))

  3. thd_wait_end
  4.   |->MYSQL_CALLBACK(thd->scheduler, thd_wait_end, (thd))
连接中断,退出,错误处理

点击(此处)折叠或打开

  1. |->MYSQL_CALLBACK_ELSE(thd->scheduler, end_thread, (thd, 1), 0)

由于线程调度的接口的定义比较清晰,线程调度方案的具有很好的扩展性,而mariadb的线程池处理连接的实现就是通过实现了scheduler_functions线程调度接口来扩展的,代码写得比较优雅,接下来几天将抽空总结一下~
阅读(2915) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~