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