Mysql源码学习笔记 偷窥线程
安装完Mysql后,使用VS打开源码开开眼,我嘞个去,这代码和想象中怎么差别这么大呢?
感觉代码有些凌乱,注释代码都写的比较随意,好像没有什么统一的规范,不同的文件中代码风格也有差异,可能Mysql经过了很多牛人的手之后,集众牛人之长吧。也可能是我见识比较浅薄,适应了自己的代码风格,井底之蛙了,总之还是怀着敬畏的心情开始咱的源码之旅吧。本人菜鸟,大神轻拍。Mysql可以启动起来了,应该怎么学习呢?总不能从main开始一步一步的看吧,Mysql作为比较底层的大型软件,涉及到数据库实现的方方面面,没有厚实的数据库理论基础和对Mysql各个模块相当的熟悉,从main开始势必会把自己引入某个死胡同啊,什么都看,最后啥也不会,咱伤不起。
经过思考后,我想还是通过客户端来调试服务器,从而学习服务器代码比较现实。也就是通过客户端的动作,看服务器的反应。比如从客户端的登录动作来看SERVER如何进行通信、用户识别、鉴定以及任务分配的,通过CREATE TABLE,来看SERVER如何解析DDL语句以及针对不同的存储引擎采取的不同的物理存储方式,通过INSERT语句,来看SERVER如何进行Btree的操作。通过SELECT语句来看如何进行SQL语句语法树的创建和优化的,通过ROLL BACK,来看SERVER事务是如何实现的。这里主要是通过跟踪代码学习Mysql数据库实现的思想,对于具体的代码不去做过多的追究(主要是我对C++不是很熟悉),好读书,不求甚解,呵呵。
由此,暂时准备了以下几条SQL语句,来有针对的进行SERVER的分析
代码如下:
1、 LOGIN(登录)
mysql.exe –uroot –p
2、 DDL(建表语句)
create table tb_myisam(c1 int, c2 varchar(256)) engine = myisam;
create table tb_innodb(c1 int, c2 varchar(256)) engine = innodb;
3、 INSERT
Insert into tb_myisam values(1 , '寂寞的肥肉');
Insert into tb_innodb values(1 , '寂寞的肥肉');
4、 SELECT
Select c1 from tb_myisam;
Select * from tb_innodb;
5、 ROLLBACK
大家都知道,mysql可以通过多个客户端,进行并发操作,当然也包括登录了。在别人登录的时候,其他的用户可能正在进行一些其它的操作,因此对于登录我们猜测应该有专门的线程负责客户端和服务器的连接的创建,以保证登录的及时性,对于每个连接的用户,应该用一个独立的线程进行任务的执行。
首先介绍下mysql中创建线程的函数,创建线程的函数貌似就是_begin_thread,CreateThread,我们通过VS在整个解决方案中进行查找,bingo!在my_winthread.c中找到了调用_begin_thread的函数pthread_create,在os0thread.c中找到了调用CreateThread的函数os_thread_create,一个系统怎么封装两个系统函数呢??再仔细看下,发现my_winthread.c是在项目mysys下,而os0thread.c是在项目innobase下。innobase!!这不就是innodb的插件式存储引擎么,原来这是存储引擎自己的封装的底层函数,哥心中豁然开朗了。我想Mysql应用范围如此之广,除了开源之外,插件式的存储引擎功不可没啊,用户可以根据自己的实际应用采取不同的存储引擎,对于大公司,估计会开发自己的存储引擎。
下面分析下pthread_create是如何调用_begin_thread的,先粗略看下源码。
代码如下:
int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
pthread_handler func, void *param)
{
HANDLE hThread;
struct pthread_map *map;
DBUG_ENTER("pthread_create");
if (!(map=malloc(sizeof(*map))))
DBUG_RETURN(-1);
map->func=func;
map->param=param;
pthread_mutex_lock(&THR_LOCK_thread);
#ifdef __BORLANDC__
hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map);
#else
hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map);
#endif
DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
*thread_id=map->pthreadself=hThread;
pthread_mutex_unlock(&THR_LOCK_thread);
if (hThread == (HANDLE) -1)
{
int error=errno;
DBUG_PRINT("error",
("Can't create thread to handle request (error %d)",error));
DBUG_RETURN(error ? error : -1);
}
VOID(SetThreadPriority(hThread, attr->priority)) ;
DBUG_RETURN(0);
}
关键的代码是下面三句:
代码如下:
map->func=func;
map->param=param;
_beginthread((void( __cdecl *)(void *)) pthread_start,
attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map);
从这可以看出,创建的新线程的名字是个固定的函数——pthread_start,而我们传进来的想创建的函数func是挂载在了map上了,函数的参数同样的挂载在map上了,这样我们就可以推理出在pthread_start函数中,肯定会出现这样的代码:
map->func(map->param);
mysql没有选择直接_beginthread(func, stack_size, param)的形式,而是进行了一次封装,不知道这样的好处是什么,可能牛人的思想不是我这样小菜鸟能顿悟的,跑题了~~
至此,我们只在pthread_create函数上设置断点,调试启动mysqld,断点停下来,看下系统的线程状况:
我们第一次进入pthread_create,任何线程都没开始创建呢,按理说系统线程应该就只有一个主线程,可现在多了这么多,这些应该是innodb存储引擎创建的线程了(具体是在plugin_init)。根据线程的名称,结合注释,猜测了下这些线程的作用。
Io_handler_thread:从名称可以知道这些是I/O线程,负责进行磁盘I/O。
Svr_error_monitor_thread:应该是服务器出错监控线程。
Svr_lock_timeout_thread:应该是和上锁相关的线程。
Svr_master_thread:
/*************************************************************************
The master thread controlling the server. */
服务器控制线程,应该是具体进行作业的线程。
Svr_monitor_thread:
/*************************************************************************
A thread prints the info output by various InnoDB monitors. */
监控线程,负责打印信息。
淡然飘过吧,不去细究了,我们只关心pthread_create创建的线程。根据调试,发现多了几个线程同名的线程_threadstart,如下所示:
创建者:调用pthread_create进行创建线程的函数。
应该是处理连接的线程了,从顺序上看,也应该是这样,只有系统中所有的其他必须的线程创建完毕后,才能创建监听线程(连接线程),即监听线程应该是系统最后创建的。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

MySQL是一種開源的關係型數據庫管理系統,主要用於快速、可靠地存儲和檢索數據。其工作原理包括客戶端請求、查詢解析、執行查詢和返回結果。使用示例包括創建表、插入和查詢數據,以及高級功能如JOIN操作。常見錯誤涉及SQL語法、數據類型和權限問題,優化建議包括使用索引、優化查詢和分錶分區。

Apache 連接數據庫需要以下步驟:安裝數據庫驅動程序。配置 web.xml 文件以創建連接池。創建 JDBC 數據源,指定連接設置。從 Java 代碼中使用 JDBC API 訪問數據庫,包括獲取連接、創建語句、綁定參數、執行查詢或更新以及處理結果。

MySQL在數據庫和編程中的地位非常重要,它是一個開源的關係型數據庫管理系統,廣泛應用於各種應用場景。 1)MySQL提供高效的數據存儲、組織和檢索功能,支持Web、移動和企業級系統。 2)它使用客戶端-服務器架構,支持多種存儲引擎和索引優化。 3)基本用法包括創建表和插入數據,高級用法涉及多表JOIN和復雜查詢。 4)常見問題如SQL語法錯誤和性能問題可以通過EXPLAIN命令和慢查詢日誌調試。 5)性能優化方法包括合理使用索引、優化查詢和使用緩存,最佳實踐包括使用事務和PreparedStatemen

選擇MySQL的原因是其性能、可靠性、易用性和社區支持。 1.MySQL提供高效的數據存儲和檢索功能,支持多種數據類型和高級查詢操作。 2.採用客戶端-服務器架構和多種存儲引擎,支持事務和查詢優化。 3.易於使用,支持多種操作系統和編程語言。 4.擁有強大的社區支持,提供豐富的資源和解決方案。

MySQL在Web應用中的主要作用是存儲和管理數據。 1.MySQL高效處理用戶信息、產品目錄和交易記錄等數據。 2.通過SQL查詢,開發者能從數據庫提取信息生成動態內容。 3.MySQL基於客戶端-服務器模型工作,確保查詢速度可接受。

在 Docker 中啟動 MySQL 的過程包含以下步驟:拉取 MySQL 鏡像創建並啟動容器,設置根用戶密碼並映射端口驗證連接創建數據庫和用戶授予對數據庫的所有權限

Laravel 是一款 PHP 框架,用於輕鬆構建 Web 應用程序。它提供一系列強大的功能,包括:安裝: 使用 Composer 全局安裝 Laravel CLI,並在項目目錄中創建應用程序。路由: 在 routes/web.php 中定義 URL 和處理函數之間的關係。視圖: 在 resources/views 中創建視圖以呈現應用程序的界面。數據庫集成: 提供與 MySQL 等數據庫的開箱即用集成,並使用遷移來創建和修改表。模型和控制器: 模型表示數據庫實體,控制器處理 HTTP 請求。

在開發一個小型應用時,我遇到了一個棘手的問題:需要快速集成一個輕量級的數據庫操作庫。嘗試了多個庫後,我發現它們要么功能過多,要么兼容性不佳。最終,我找到了minii/db,這是一個基於Yii2的簡化版本,完美地解決了我的問題。
