某托管服务器崩溃产生了crash,经惠礼分析定位到missive插件中处理消息执行下面的调用时返回NULL,后续对th的访问导致崩溃:
ITableHandler *th = CBasePluginModule::db_helper_->NewTableHandler(pdbor,"tb_6016");
使用IDbHelper接口NewTableHandler创建表处理器对象,用来操纵数据库.避免编写SQL.
GETDBC(pdbor,this->local_dbc_.c_str());
ITableHandler *th = CBasePluginModule::db_helper_->NewTableHandler(pdbor,"tb_6016");
AUTO_POINTER_NODECLARE(ITableHandler,th);
th->BindField("missive_id",(char*)strmissive_id.c_str(),0);
th->BindField("missive_name",(char*)strmissive_name.c_str(),0);
NewTableHandler实现代码如下:
ITableHandler* HTX_DB_Helper::NewTableHandler(CDbAccessor *pdbor,const char *tbl_name) {
CTableInfo *tbl;
string s = StringToUpper(tbl_name);
tbl = this->FindTable(s.c_str());
if (tbl==NULL)
tbl = this->OpenTable(pdbor,s.c_str());
CTableHandler *th = 0;
if (tbl) {
th = new CTableHandler;
th->Attach(tbl);
th->SetDbAccessor(pdbor);
}
return th;
}
在执行OpenTable时,如果出现数据库访问故障(如网络或者数据库系统原因),就可能导致返回的th为NULL.
此问题以前从发现过。采用的方式是在服务器启动时预先执行,初始化后再出现数据库访问故障不会导致问题,,因为表的模式信息已被缓存。
如bbox插件的处理如下:
int CBBoxPlugin::CheckValid()
{
parent::CheckValid();
InitTableHandler("tb_0032");
InitTableHandler(REDO_TABLE_NAME);
return 0;
}
int CBBoxPlugin::InitTableHandler(const char *tbl_name) {
do {
GETDBC(pdbor,this->local_dbc_.c_str());
ITableHandler *th = db_helper_->NewTableHandler(pdbor,tbl_name);
AUTO_POINTER_NODECLARE(ITableHandler,th);
if (th)
break;
ACE_OS::sleep(1);
}while(1);
return 0;
}
以上是一种处理问题的方法。
更简单和彻底的解决办法是修改NewTableHandler的实现,升级hotfox。
修改后的代码如下:
<p>ITableHandler* HTX_DB_Helper::NewTableHandler(CDbAccessor *pdbor,const char *tbl_name) {
CTableInfo *tbl;
string s = StringToUpper(tbl_name);
tbl = this->FindTable(s.c_str());
if (tbl==NULL) {
CDbAccessor2 *p = dynamic_cast<CDbAccessor2*>(pdbor);
const char *dbc_name = p->GetPool()->dbcc_->name.c_str();
do {
CDbAccessor *new_pdbor = HTX_DBPOOL::instance()->GetDbConnection(dbc_name,-1,true,true);
tbl = this->OpenTable(new_pdbor,s.c_str());
HTX_DBPOOL::instance()->ReleaseDbConnection(new_pdbor);
}while(tbl==0);
}
CTableHandler *th = 0;
if (tbl) {
th = new CTableHandler;
th->Attach(tbl);
th->SetDbAccessor(pdbor);
}</p><p> return th;
}</p>