I. Overview
1, DIY database using a multi-process and multi-threading server model. Each process acts as a node instance and listens on one port, and each user connection has a proxy thread corresponding to it in the DB node instance.
2, in addition to the main thread, there is an EDU (process scheduling unit, also known as the Thread control block), and each system thread type has only one thread entity (there is only one system thread, that is, the listener thread, the main thread is not in thread management pool)
3, the agent thread is specialized in processing user requests, created by the listener thread
4, the thread pool to schedule, by passing in different types, internal calls different functions to execute the corresponding request
5. edu can be assigned to other tasks after returning to the pool
Execution queue: The Edu (that is, the thread control block) of all threads that get the task is in the execution queue
Wait queue: The client exits after the agent thread pool is dissatisfied and is placed in the idle thread queue
Thread class (that is, thread control block (EDU))
#ifndef pmdedu_hpp__#define pmdedu_hpp__#include "core.hpp" #include "pmdeduevent.hpp" #include "ossqueue.hpp" # Include "OSSSOCKET.HPP" #define PMD_INVALID_EDUID 0//illegal edu_id#define pmd_is_edu_creating (x) (pmd_edu_creating = = x)//Line process is creating a # define Pmd_is_edu_running (x) (pmd_edu_running = = x)//Run Status # pmd_is_edu_waiting (x) (pmd_edu_waiting = = x)//wait state (for the agent thread, which indicates that it is waiting for the response of the client being proxied) #define PMD_IS_EDU_IDLE (x) (Pmd_edu_idle = = x)//idle state (already back to the pool) #define Pmd_i S_edu_destroy (x) (Pmd_edu_destroy = = x)//Destroy state typedef unsigned long long eduid; enum edu_types//thread type {//System E DU Type listener Thread Edu_type_tcplistener = 0,//Agent EDU TYPE handles thread edu_type_agent, edu_type_unknown,//for later expansion edu_type_m Aximum = Edu_type_unknown}; enum edu_status//the state of the thread {pmd_edu_creating = 0, pmd_edu_running, pmd_edu_waiting, PMD_ED U_idle, Pmd_edu_destroy, pmd_edu_unknown, pmd_edu_status_maximum = Pmd_edu_unknown}; class pmdedumgr;//thread pool declaration class P mdeducb//Thread control block {PUBLIC:PMDEDUCB (Pmdedumgr *mgr, edu_types type);//Gets the thread of the specified type from the specified thread pool inline eduid GetID ()//thread ID {return _id; The inline void postevent (pmdeduevent const &DATA)//sends the event {_queue.push (data);//actually presses the message into the message queue, and each edu has a Queue} bool Waitevent (Pmdeduevent &data, Long long millsec)//millsec<0 means infinite wait {//millsec less than 0 wireless wait BOOL waitmsg = false; if (pmd_edu_idle! = _status) {_status = pmd_edu_waiting; } if (0 > Millsec) {_queue.wait_and_pop (data);//infinite wait waitmsg = true; } else {waitmsg = _queue.timed_wait_and_pop (data, millsec);//Timeout wait} if (waitmsg) { if (Data._eventtype = = pmd_edu_event_term)//End event: Want to end EDU {_isdisconnected = true; } else {_status = pmd_edu_running;//Go Back to execute}} return waitmsg; The inline Void Force ()//forcibly stops the current thread {_isforced = true; } inlinevoid disconnect ()//Disconnect {_isdisconnected = true; } inline Edu_types GetType ()//Gets the current thread type {return _type; } inline Edu_status GetStatus ()//Gets the current thread state {return _status; } inline void SetType (edu_types type)//Set Thread type {_type = type; } inline void SetID (EDUID ID)//Set the current id {_id = ID; } inline void SetStatus (Edu_status status)//set current thread's state {_status = status; } inline bool Isforced () {return _isforced; } inline Pmdedumgr *getedumgr ()//Gets the thread pool {return _mgr corresponding to the current threads; }private:edu_types _type;//thread type pmdedumgr *_mgr;//which thread pool to belong to Edu_status _status;//thread state eduid _id;//Thread Ed UID bool _isforced;//whether to turn off thread bool _isdisconnected;//whether to disconnect ossqueue<pmdeduevent> _queue;//Message queue, per Edu has a message queue}; typedef int (*pmdentrypoint) (PMDEDUCB *, void *);//type of thread entry function, function pointer pmdentrypoint getentryfuncbytype (EDU _types type);//get the corresponding entry function int pmdagententrypoint by thread type (PMDEDUCB*CB, void *arg);//proxy type function pointer int pmdtcplistenerentrypoint (PMDEDUCB *cb, void *arg);//listener type function pointer int pmdeduentrypoint (E Du_types type, PMDEDUCB *cb, void *arg);//thread entry function int pmdrecv (char *pbuffer, int recvsize, Osssocket *sock , PMDEDUCB *CB);//tcp receive int pmdsend (const char *pbuffer, int sendsize, Osssocket *sock, PMDEDUCB *CB);// TCP Send #endif
1) DIY Database thread class structure is clear, and the function is more complete. We begin by analyzing his attributes.
Edu_types _type;//Thread Type
There are two main types of threading in Diydb, one is the listener thread and the other is the agent thread. The listener thread is responsible for listening to the port and establishing a connection with the client, and then taking a proxy thread from the thread pool to the client that is connected to the request. One is the agent thread, and all interactions with the client are performed in the agent thread.
Pmdedumgr thread pool to which *_mgr;//threads belong
Each database instance has a thread pool that can grow dynamically. This thread pool manages all the threads in this DB instance.
Edustadus _stadus;//Thread State
Each thread is in a finite state machine, there are five states of threads, and when a thread receives a message, it transitions between five states.
Eduid id;//thread's edu ID
bool _isforced;//Whether the thread is closed, normally set to true by line pool
bool _isdisconnected;//Whether to disconnect, set this property to True after the agent thread receives the client's disconnect command
Ossqueue<pmdeduevent> _queue;//Message Queuing, each EDU has a message queue
2) The entry function of the thread
typedef int (*pmdentrypoint) (PMDEDUCB *, void *);//Thread entry function type, function pointer .
Pmdentrypoint getentryfuncbytype (edu_types type);//get the corresponding entry function by thread type
int Pmdagententrypoint (PMDEDUCB *cb, void *arg);//function pointer of proxy type
int Pmdtcplistenerentrypoint (PMDEDUCB *cb, void *arg);//listener type function pointer
int Pmdeduentrypoint (edu_types type, PMDEDUCB *cb, void *arg);//The entry function of the thread , in fact, the corresponding thread entry function is called according to the type parameter in the function body
Iii. message classes for communication between threads
#ifndef pmdeduevent_hpp__#define pmdeduevent_hpp__#include "core.hpp" enum pmdedueventtypes//message type { PMD_EDU_ Event_none = 0,//Empty message pmd_edu_event_term, //End message pmd_edu_event_msg, pmd_edu_event_resume // Wake-Up message}; class Pmdeduevent{public: pmdeduevent (): _eventtype (Pmd_edu_event_none), _release (false), _data (NULL) { } pmdeduevent (pmdedueventtypes type): _eventtype (type), _release (false), _data (NULL) { } pmdeduevent (pmdedueventtypes type, bool release, void *data): _eventtype (Type), _ Release, _data (Data) { } void Reset ()//empty { _eventtype = Pmd_edu_event_ NONE; _release = false; _data = NULL; } Pmdedueventtypes _eventtype;//Event Type bool _release;//release void *_data;//data}; #endif
We can see a total of four types of messages, _release indicates whether the thread receiving the message immediately releases the data that the data pointer in the message refers to, _data is a pointer to the data address that represents the data in the message, which is primarily for inter-thread communication.
Iv. thread Pool
#ifndef pmdedumgr_hpp__#define pmdedumgr_hpp__#include "core.hpp" #include "pmdedu.hpp" #include "osslatch.hpp" # Include "OSSUTIL.HPP" #define Edu_system 0x01//system level edu#define edu_user 0x02//user-level edu#define Edu_all (edu_sy STEM | Edu_user) class pmdedumgr//thread pool {private:std::map<eduid, pmdeducb*> _runqueue;//Running Threads queue Std::map<eduid, PmdE Ducb*> _idlequeue;//idle thread queue std::map<unsigned int, eduid> _tid_eduid_map;//thread pool all thread IDs and their Edu mappings Ossslatch _mu Tex;//read-write lock required to access thread queue Eduid _eduid;//new the next edu-assigned ID std::map<unsigned int, eduid> _mapsystemedus;/System edu Mapping between type and eduid bool _isquiesced;//identifies if the database is suspended, and the thread pool does not accept requests when the database is suspended, suspending the database so that DBAs can perform special operations on the database bool _isdestroyed; Whether the thread pool is destroyed public:pmdedumgr (): _eduid (1), _isquiesced (false), _isdestroyed (false) {} ~pmdedumgr () { Reset (); } void Reset () {_destroyall ();//delete all threads in thread pool} unsigned int size ()//Get the number of all threads {unsigned int num = 0; _mutex.get_shared ();//shared lock because it is read num = (unsigned int) _runqueue.size () + (unsigned int) _idlequeue.size (); _mutex.release_shared (); return num; } unsigned int sizerun ()//Gets the length of the run queue {unsigned int num = 0; _mutex.get_shared (); num = (unsigned int) _runqueue.size (); _mutex.release_shared (); return num; } unsigned int sizeidle () {unsigned int num = 0; _mutex.get_shared (); num = (unsigned int) _idlequeue.size (); _mutex.release_shared (); return num; } unsigned int sizesystem ()//system edu number {unsigned int num = 0; _mutex.get_shared (); num = _mapsystemedus.size (); _mutex.release_shared (); return num; } eduid getsystemedu (edu_types edu)//By the system Edu type to get its corresponding eduid {eduid eduid = Pmd_invalid_eduid; _mutex.get_shared (); std::map<unsigned int, Eduid>::iterator it = _mapsystemedus.find (edu); if (It! = _mapsystemedus.end () {eduid = It->second; } _mutex.release_shared (); return eduid; } bool Issystemedu (Eduid eduid) {bool Issys = false; _mutex.get_shared (); Issys = _issystemedu (Eduid); _mutex.release_shared (); return Issys; } void regsystemedu (Edu_types edu, eduid eduid)//Register a system edu {_mutex.get (); _mapsystemedus[edu] = eduid; _mutex.release (); } bool Isquiesced () {return _isquiesced; } void setquiesced (bool b) {_isquiesced = b; } bool Isdestroyed () {return _isdestroyed; } static bool Ispoolable (edu_types type)//thread-edu-type corresponding thread can be recycled to the thread pool, currently only the agent thread of Edu can be recycled, because the listener thread is normally not exited {Retu RN (edu_type_agent = = TYPE); }private:int _createnewedu (edu_types type, void *arg, Eduid *eduid);//When no EDU is idle, create a new edu int _destroyall ();//Destroy the Some of the threads int _forceedus (int property = Edu_all);//Kill some type of EDU unsigned int _geteducount (int property = Edu_all); void _setdestroyed (bool b) {_isdestroyed = b; } bool _issystemedu (Eduid eduid) {std::map<unsigned int, eduid>::iterator it = _mapsystemedus.begin (); while (It! = _mapsystemedus.end ()) {if (Eduid = = It->second) {return true; } ++it; } return false; } int _destroyedu (Eduid eduid);//Destroy a specific Edu int _deactivateedu (eduid eduid);//Put an edu back into the thread pool public:/* * ED U Status Transition Table * c:creating * r:running * w:waiting * i:idle * D:destroy * function * C:CR eatenewedu * a:activateedu * d:destroyedu * w:waitedu * t:deactivateedu * C R w I D <--- from * C c * R--A A-<---creating/idle/waiting status can move to Running status * w W- --<---Running status move to Waiting * I--t--<---creating/waiting status move to Idle * D d-d D-<---creating/waiting/idle can destroyed * ^ to */int activateedu (Eduid eduid);//Waiting and I Dle thread activated into running thread int waitedu (Eduid eduid);//enable EDU to transition from execution state to wait state int startedu (edu_types type, void* arg, Eduid *edu ID);//You can create an edu and create the appropriate thread. If a proxy is created, and there are idle threads in the thread pool, it is picked up from the thread pools and the corresponding Edu is placed from the idle queue to the run queue int postedupost (eduid eduid, pmdedueventtypes type, BOOL release = False, void *pdata = NULL);//sends a message to a queue of a specified thread that activates the thread int waitedupost (Eduid eduid) that is blocked waiting for messages in the message queue. pmdeduevent& event, long long millsecond);//wait for the specified EDU events int returnedu (Eduid eduid, bool fo RCE, bool* destroyed);//The EDU is destroyed or returned to the pool int forceuseredu (Eduid eduid); PMDEDUCB *getedu (unsigned int tid);//Get Edu PMDEDUCB *getedu () by thread ID;//get current edu pmdeducb *getedubyid (eduid Edui D); void setedu (unsigned int tid, eduid eduid);} ; #endif
Analysis
1. EDU State Migration Diagram
* c:creating
* r:running
* w:waiting
* I:idle
* D:destroy
* function
* c:createnewedu
* a:activateedu
* d:destroyedu
* w:waitedu
* t:deactivateedu
* C R W I D <---from
* C C
* R--A A-<---idle/waiting status can move to Running status
* W w W---<---creating/running status move to Waiting
* I t-t--<---Waiting status move to Idle
* D d-d D-<---creating/waiting/idle can be destroyed
2, CREATING, RUNNING, waiting these three states of the thread's Edu store in the running thread queue, the idle thread is placed in the idle thread queue, the destroy thread's edu is not in any thread queue (because when the state of a thread is destroyed state, His thread management block has been removed from the queue of two threads by the thread pool, and when the threading entity detects its state as destroy, the thread entity returns from the thread execution function, which actually ends the thread
Five, Summary:
1, this paper mainly analyzes the threading module of Diydb, is actually a relatively perfect thread pool model
2, the thread pool is mainly implemented by the following types:
Thread control blocks: primarily encapsulation of thread entities. Each thread control block entity corresponds to a thread entity that contains the state of the thread, its type, its corresponding thread pool, and the message queue for that thread.
Message: Message entities are used to pass information between threads that can pass normal data or control the state of the thread that receives the message
Thread Management classes: There is only one instance of the thread management class in the entire diydb, she is the core of the thread pool, which manages two queues, one running thread queue and one idle thread queue (the only agent thread in the idle thread queue). She controls the state of all threads to maintain the thread pool.
3. The threads in this thread pool are divided into system threads (there are only listener threads) and user threads (there are only agent threads), and each system thread type corresponds to only one thread entity, while threads for each user thread type correspond to multiple thread entities.
4, only the state of the agent thread may be an idle thread, so in a sense the thread pool is actually only beneficial to the efficiency of the agent thread, although the system thread's EDU is also running the thread queue, and its state is controlled by the thread management class.
5. The idle threads in the thread pool are not created at the time of system startup, but are returned to the idle thread queue (that is, if the user disconnects) after the user request is processed by the created agent thread (the precondition is that the number of idle threads is less than Maxpool, which is the upper limit of idle threads).
6, the size of the thread pool is controlled by a parameter (Maxpool), when the number of idle threads in the thread pool equals Maxpool, the thread that is running is not allowed back to the pool.
7. When idle threads in the thread pool are exhausted, a new agent thread is created to handle the user's task if a new user request comes in. So, the number of threads in this thread pool can change dynamically.
DIY Database (vii)--Threading control block, message, thread pool