在前面三篇,bingxi和alex聊了關于innodb的hash、list、以及動態數組的實現方法,這三個結構比較常用。講完前9篇內容,本篇會描述在windows環境下debug mysql的方法,強烈建議通過debug的方式進行學習。在本篇里,bingxi和alex會聊到windows下常用的調試mysql代碼的方法,僅供參考。
## 1)在windows和linux下調試的異同?
Bingxi:“alex,咱們看myslq代碼的方法,是通過windows看好呢,還是linux/unix下看呢,兩者之間最大的差異是什么?”
Alex:“在mysql 5.1的高版本開始,windows環境與linux環境使用同一套代碼。我電腦里面正好有兩個版本的代碼,我們看下mysql-6.0.4-alpha目錄下的INSTALL-WIN-SOURCE文件,其中有這么一段:
To? build MySQL on Windows from source, you must satisfy the
?following system, compiler, and resource requirements:
?? * Windows 2000, Windows XP, or newer version. Windows Vista is
???? not supported until Microsoft certifies Visual Studio 2005 on
???? Vista.
?? * CMake, which can be downloaded from http://www.cmake.org.
???? After? installing, modify your path to include the cmake
???? binary.
?? * Microsoft Visual C++ 2005 Express Edition, Visual Studio .Net
???? 2003 (7.1), or Visual Studio 2005 (8.0) compiler system.
?? * If you are using Visual C++ 2005 Express Edition, you must
???? also install an appropriate Platform SDK. More information and
???? links to downloads for various Windows platforms is available
???? from http://msdn.microsoft.com/platformsdk/.
?? * If you are compiling from a BitKeeper tree or making changes
???? to? the parser, you need bison for Windows, which can be
???? downloaded from
???? http://gnuwin32.sourceforge.net/packages/bison.htm.Download
???? the package labeled "Complete package, excluding sources".
???? After installing the package, modify your path to include the
???? bison binary and ensure that this binary is accessible from
???? Visual Studio.
?? * Cygwin might be necessary if you want to run the test script
???? or package the compiled binaries and support files into a Zip
???? archive.? (Cygwin? is needed only to test or package the
???? distribution, not to build it.) Cygwin is available from
???? http://cygwin.com.
?? * 3GB to 5GB of disk space.
可以通過這樣的方式來生成一份代碼,然后用vs2005或者更高版本來調試。
”
Bingxi:“alex,你電腦里面的另外一個軟件包是mysql-5.1.7的吧。”
Alex:“嗯,這個版本是mysql5.1.7代碼剛出來的時候進行下載的。這個版本的代碼直接解壓縮之后,可以直接用vs2003進行編譯調試。對innodb而言,用這個版本的就可以了,innodb的變化不大,如果需要理解查詢引擎,則需要使用更新的版本進行學習。”
Bingxi:“mysql-5.1.7-beta-win-src.zip,這個軟件包的內容,我們學了之后,會不會和linux下不一樣,有人會有這樣的疑問,畢竟在很多公司里面,mysql是運行在linux/unix環境的。我們知道windows與linux/unix的差異還是存在的,尤其是底層的系統函數。”
Alex:“嗯,這個是很多人的疑問。其實mysql進行了代碼的封裝,比如在5.1.7的windows版本的代碼中,也是可以看到系統函數的封裝。比如event semaphore。看下對應的代碼:
~~~
/*************************************************************
Creates an event semaphore, i.e., a semaphore which may just have two
states: signaled and nonsignaled. The created event is manual reset: it
must be reset explicitly by calling sync_os_reset_event. */
os_event_t
os_event_create(
/*============*/
??????????????????????????? /* out: the event handle */
?????? const char*??? name)???? /* in: the name of the event, if NULL
??????????????????????????? the event is created without a name */
{
#ifdef __WIN__
??????? os_event_t event;
?????? event = ut_malloc(sizeof(struct os_event_struct));
?????? event->handle = CreateEvent(NULL,/* No security attributes */
???????????????????? TRUE,?????????? /* Manual reset */
???????????????????? FALSE,????????? /* Initial state nonsignaled */
???????????????????? (LPCTSTR) name);
?????? if (!event->handle) {
?????? ??????? fprintf(stderr,
"InnoDB: Could not create a Windows event semaphore; Windows error %lu/n",
????????????? ? (ulong) GetLastError());
?????? }
#else /* Unix */
?????? os_event_t????? event;
?????? UT_NOT_USED(name);
?????? event = ut_malloc(sizeof(struct os_event_struct));
?????? os_fast_mutex_init(&(event->os_mutex));
#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
?????? ut_a(0 == pthread_cond_init(&(event->cond_var),
?????????????????????????????????? pthread_condattr_default));
#else
?????? ut_a(0 == pthread_cond_init(&(event->cond_var), NULL));
#endif
?????? event->is_set = FALSE;
?????? event->signal_count = 0;
#endif /* __WIN__ */
??????? /* Put to the list of events */
?????? os_mutex_enter(os_sync_mutex);
?????? UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
?????? os_event_count++;
?????? os_mutex_exit(os_sync_mutex);
?????? return(event);
}
~~~
在os_event_create函數體,屏蔽了系統的差異性。開發人員在開發時,需要創建event,只需要os_event_create就行了。
”
Bingxi:“alex,那么按照這個思路,是不是可以獲得兩個信息:1)如果需要debug系統封裝函數,還是建議在linux/unix下也調試下,2)對我們查看非系統函數,在windows與linux/unix下調試,兩者都是可以的。”
Alex:“嗯,用哪種調試方法都是可以的。用哪個版本的也是可以的,本系列以描述innodb存儲為主,因此使用5.1.7就可以了。”
## 2)搭建windows環境下的mysql5.1.7的調試環境
Bingxi:“好吧,那我們就開始搭建環境吧。”
Alex:“ok,我們先將代碼找一個目錄進行解壓縮,本文中的解壓縮位置為d:/。使用vs2003打開D:/bin-mysql-5.1.7-beta/mysql.sln項目文件。?

Bingxi,打開之后會有46個project,我們要編譯其中哪些工具呢??

”
Bingxi:“ok,至少要包含下面三個內容:1)服務端程序,2)客戶端程序,3)mysqladmin工具(用于退出調試時使用,直接使用中斷調試太暴力了)。順著這個思路,我們一步步來編譯。
首先編譯服務端程序,也就是編譯mysqld項目。這里有三個建議,1)因為本系列主要調試mysqld的代碼,因此需要將mysqld設置為啟動項目,2)設置啟動方式為console方法,這樣可以在console窗口中看到打印信息,3)將D:/bin-mysql-5.1.7-beta下的data文件夾進行壓縮保存,這樣,我們需要恢復到原始的數據,直接用保存的data進行覆蓋就可以了。
設置為啟動項目:

設置為console啟動方式:?

根據個人習慣,決定是否將data進行壓縮保存。
接著,我們編譯mysqld項目、mysql項目、mysqladmin項目。編譯產生的工具在D:/mysql-5.1.7-beta/client_debug目錄。
設置斷點,比如查詢的總入口是handle_select函數(在sql_select.cpp文件中)。使用“進入單步執行新實例”進行調試。如圖:?

執行時,停止在main函數開始處(可以一步步看看mysql是如何啟動的),我們按F5,程序會直接執行,如果斷點被執行,那么就會停在斷點處,因為我們此處設置的是查詢函數,所以沒有被執行。因此,我們需要通過客戶端執行一條語句,來觸發斷點對應的代碼被執行。?

執行show databases命令之后,我們可以看到斷點生效了。?

這樣我們通過F10/F11/F5/shift+F11等常用的快捷鍵進行調試了。如果需要退出調試狀態,則使用mysqladmin,如圖(圖中打印的一行錯誤信息不用理它,是系統的一個bug):?

”
## 3)調試的技巧
Alex:“bingxi,這個我理解了,有沒有一些常用的技巧。Alex常用的是通過快速監控,見下面的兩圖。?


這樣,我們可以看到變量的值。但是,遇到想測試函數,或者看宏的值就有點麻煩了。Bingxi,你給我講講。
”
Bingxi:“最常用的方法是直接分析算法,如果有些確實不太明白,可以通過自己寫測試函數的方法進行調試。如果我想知道某一頁屬于哪個簇描述符,可以在fsp0fsp.c的文件尾加上我們自己的測試函數,同時設置斷點:

接著在該文件的文件頭(添加內容為紅色選中處),聲明定義:?

接著找一個函數,進行調用函數test_bingxi,這里我們選擇fsp_get_space_header函數,因為這個函數在同一個文件,并且啟動的時候會被執行。添加調用,添加內容為紅色選中處。?

然后,我們啟動調試,按F5進入斷點。通過j值就可以知道UNIV_PAGE_SIZE的值,如果是多個宏計算后的值,也是一樣的方法。通過i1值就可以知道xdes_calc_descriptor_page(0)的返回值。?

類似這樣的方法,我們可以通過添加測試代碼,將疑問的地方進行測試。今天調試的就說到這兒吧。
”
Alex:“ok,說完調試,開始正式進入innodb存儲了。咱們也是初學者,需要多debug來解惑。今天不說晚安了,馬上6點了,早安。”
Bingxi:“早安。”