FooServer啓動後,在處理行情請求時,報告錯誤:node
./quz.lua:119: attempt to index global 'Bar' (a nil value)
經過代碼檢索,發現Bar對象是 libluabar.so 註冊到lua中的。在運行環境中, libluabar.so 位於 luamodule 目錄下,沒有配置文件指向這個目錄。 使用 grep -a 檢查程序文件和庫文件,發現 luamodule 目錄名硬編碼在 libFooService.so 中。 這個庫的源代碼和二進制文件版本管理混亂,我不能肯定拿到的代碼和二進制文件是否匹配,因此決定參考源代碼和反彙編代碼,嘗試定位問題。 檢索 libFooService.so 的代碼,發現加載 libluabar.so 的代碼以下:服務器
void FooService::LoadModules() { // ... CBARUtils::getFullPath("luamodule", pszFullPath, 256); // 取luamodule目錄下全部文件. CFileInfo::BuildFileArray(pszFullPath, &fileArray, NULL); size_t nSize = fileArray.size(); CFileInfo* pFileInfo; size_t nIndex = 0; FooModuleInfo ldi; while (nIndex < nSize) { pFileInfo = (CFileInfo*)fileArray[nIndex]; if (pFileInfo->EndWith("so") && strnicmp(pFileInfo->pFileName,"liblua",6) == 0) { // 多加一個判斷,去掉luaxxx_bak等. if (isAvailModule(pFileInfo->pFileName)) { // OK,try loadlib. strcpy(pszFile,pszFullPath); strcat(pszFile,"/"); strcat(pszFile,pFileInfo->pFileName); hLib = ACE_OS::dlopen(pszFile); if (hLib != NULL) { ldi.handler = hLib; strcpy(ldi.fileName,pFileInfo->pFileName); m_daModules.append(ldi); } else { BAR_LOG((ERROR,"load %s error:%s", pszFile, ACE_OS::dlerror())); } } } nIndex++; } CFileInfo::clearFileArray(&fileArray); }
進入 FooService::LoadModules 後,在 strnicmp 處下斷點,執行 finish 命令,斷點沒有觸發。由此判斷 BuildFileArray 讀取的文件數爲0。 檢查源代碼:app
bool CFileInfo::BuildFileArray (char* pstrPathName, DynArray<CFileInfo*>* pFileInfoArray ,char* pDir) { struct dirent* ent = NULL; DIR* pDirent; CFileInfo* pFileInfo = NULL; if ((pDirent=opendir(pstrPathName)) == NULL) { return false; } while ((ent=readdir(pDirent)) != NULL) { if (ent->d_type == DT_REG) { pFileInfo = new CFileInfo(); if (pDir != NULL) { strcpy(pFileInfo->pFileName,pDir); strcat(pFileInfo->pFileName,"/"); strcat(pFileInfo->pFileName, ent->d_name); } else { strcpy (pFileInfo->pFileName, ent->d_name); } pFileInfo->nDataLen = ent->d_reclen; pFileInfoArray->append(pFileInfo); } } closedir(pDirent); return true; }
在 readdir 處下斷點,單步執行,發現判斷 DT_REG 的地方老是失敗。查看 readdir 手冊,發現這樣一段:函數
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* not an offset; see NOTES */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all file system types */ char d_name[256]; /* filename */ };
上網找了一些資料,發現CentOS 7把文件系統換成了 XFS,猜想是這個變動致使 DT_REG 判斷失敗。編寫程序驗證:ui
#include <stdio.h> #include <dirent.h> int main() { DIR *dir; struct dirent *entry; dir = opendir("."); if (dir == NULL) { perror("opendir"); exit(0); } while ((entry = readdir(dir)) != NULL) { printf("name: %s type: %d equal DT_REG: %d\n", entry->d_name, entry->d_type, (entry->d_type == DT_REG)); } return 0; }
在兩臺服務器上運行,CentOS 7上輸出的 type 是 0,而 6.5 輸出的是 8 。由此判定 CentOS 7 的文件系統變動是致使 FooServer 出現異常的緣由。this