OceanBase是典型的单进程多线程架构,在每个节点的OBServer进程中会用到很多种线程,例如多租户环境的守护线程MultiTenant和处理请求的TNT类线程。总体上可以把OBServer中的线程分成I/O线程、工作线程和后台线程。
1)I/O线程用在网络子系统中,用于取下MySQL或RPC端口上到达的包,然后包装成内部的请求形式供工作线程消费(详见3.5节),I/O线程及其管理机制在网络子系统初始化时建立。
2)工作线程代表各租户处理各种请求,例如SQL请求和RPC请求(详见3.5节),工作线程及其管理机制在多租户环境初始化时建立。
3)后台线程是各个子系统执行特定任务的代理,例如用于分区的转储、合并、迁移等任务的DAG线程,它们随着各个子系统的初始化而产生。
为了便于操纵线程,OceanBase封装了一个Thread类(oceanbase.lib.Thread),直观来看,一个线程就可以用一个Thread类的实例来表达。Thread属性的关键属性和方法包括:
1)start():启动线程的方法,在这个方法中会调用pthread_create函数创建这个对象所代表的线程,同时将现成的入口函数指向__th_start方法。
2)__th_start():所属线程的入口函数,在其中会通过系统调用获取当前进程的进程ID以及线程ID并保存在pid_和tid_两个属性中,最后会调用runnable_属性中对象的run接口来执行线程的自定义主函数。
3)get_pid():从pid_属性中返回当前线程进程ID的方法。
4)get_tid():从tid_属性中返回当前线程ID的方法。
5)pid_:保存已启动线程所属的进程ID。
6)tid_:保存已启动线程的线程ID。
7)runnable_:用于嵌入一个Runnable对象(也可能是其子类对象),runnable_中的对象可以在Thread对象实例化或者用start方法启动线程时作为参数传入,以实现线程主函数的可定制化。
但事实上,OceanBase中的绝大部分线程都没有直接利用Thread类来表示,而是利用协程化的线程CoKThread类。例如用于处理用户或者RPC请求的工作线程ObThWorker就是从CoKThread继承而来。
CoKThread是CoXThread的别名,而CoXThread又是CoKThreadTemp<CoUserThread>模板类的别名,CoKThreadTemp中会把模板参数(CoUserThread类)当作一种表示线程的类,在自己的create_thread方法中启动线程。CoUserThread又是CoUserThreadTemp<CoSetSched>模板类的别名,CoUserThreadTemp实际上会把模板参数(CoSetSched类)当作其父类。在启动一个CoKThread实例(例如一个ObThWorker)时,其start方法会启动一个CoSetSched实例,它对应一个线程,其执行入口指向CoKThreadTemp对象的run方法,由于这个run方法是一个虚函数(virtual),因此线程实际执行的是CoKThreadTemp类继承对象的run方法,例如ObThWorker的run方法。