1.tb_0030增加在f003v_0030上的唯一索引
a.目的:
关于发送端消息记录的Ack记录可能在目标接收方因多次传输可能出现多条记录。
这种重复是不必要,而且导致在故障检查时双方消息数的不一致而不利于排查问题。
CREATE UNIQUE NONCLUSTERED INDEX [ui_0030_2] ON [dbo].[tb_0030]
(
[f003v_0030] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = OFF) ON [PRIMARY]
b.代码修改:
修改semq.cpp文件的内容.
int QueryValue(CDbAccessor *pdbor,const char *sql,_variant_t *v) {
AUTO_QUERY_RECORDSET(CRecordset,prs,pdbor);
prs = pdbor->Query(adCmdText,sql);
if (prs==0) {
return -1;
}
if (prs->IsEof()) {
return -2;
}
int fld_cnt = prs->GetFieldCount();
for (int i=0;i<fld_cnt;i++) {
_variant_t vtVal;
if (!prs->GetFieldValue(i,vtVal))
return -3;
v[i] = vtVal;
}
return 0;
}
int CSEMQ::SaveAck(SEMQ_ACK_HELPER *ak) {
USEDBC(pdbor,ack_queue_dbc_.c_str());
ITableHandler *th = CBasePlugInModule::db_helper_->NewTableHandler(pdbor,"tb_0030");
AUTO_POINTER_NODECLARE(ITableHandler,th);
pdbor->BeginTrans();
unsigned short num = ak->loc_keys_.size();
for (unsigned short i=0;i<num;i++) {
MQ_LOC_KEY *lk = ak->loc_keys_[i];
char key[128];
sprintf(key,"%d,%d,%d,%d,%I64d",lk->node_type_,lk->node_id_,lk->mq_id_,lk->mq_db_id_,lk->record_id_);
th->BindField("f003v_0030",key);
char date[32];
CDateTime::GetDateTime(date);
th->BindField("src_type",(char**)&ak->src_.type_,sizeof(ak->src_.type_));
th->BindField("src_id",(char**)&ak->src_.id_,sizeof(ak->src_.id_));
th->BindField("dest_type",(char**)&ak->dest_.type_,sizeof(ak->dest_.type_));
th->BindField("dest_id",(char**)&ak->dest_.id_,sizeof(ak->dest_.id_));
th->BindField("f005d_0030",date);
bool dup_key_error = false;
if (th->Insert()) {
dup_key_error = pdbor->GetDBExt()->IsDuplicateKeyError(pdbor->GetLastErrorCode());
if (!dup_key_error) {
return -1;
}
}
unsigned __int64 record_id;
if (!dup_key_error) {
if (pdbor->GetDBExt()->GetLastID(record_id,1,"tb_0030")) {
return -2;
}
}
else {
string sql = LogMsg("select object_id from tb_0030 where f003v_0030='%s'",key);
_variant_t v;
if (QueryValue(pdbor,sql.c_str(),&v)) {
return -3;
}
string sVal = ExVariantToString(v);
record_id = a2Li(sVal.c_str());
}
ak->src_record_ids_.push_back(record_id); ///< 保存写入的待确认记录的记录编号
}
FAIL_RETURN(pdbor->CommitTrans(),,-1);
return 0;
}
2.多内部服务器时异步处理模式的实现
a.背景
之前的版本引入了对dxi_change_log同步方式的支持.见http://blog.csdn.net/wherwh/article/details/26482279
目的是在多个内部服务器时避免对异步任务的分配.带来好处的同时,存在一个缺陷:由于接收消息时立即处理,如果数据库处理效率低下或者开销大,可能导致通信接收的堵塞现象。
另外,系统还遗留一个失败重做时任务由谁承担的问题,当时的计划是配置一个服务器可以执行失败重做任务,这引入了单点问题。
鉴于测试的效果,需要对于异步任务方式的完全支持。
实现策略为:
在异步模式下,谁接收谁负责处理.接收者写入tb_change_log时记录处理者ID.即服务器ID.
失败重做也采用同样机制.
b.脚本
以下为前置机和内部服务器数据库的SQL Server升级脚本:
.tb_0033增加处理者ID字段
alter table tb_0033 add f016n_0033 int;
.tb_change_log增加处理者ID字段:
alter table tb_jxj_job add handler int;
***表名对应具体的配置
c.代码修改
.dxi_change_log默认采用异步方式:
<handle_mode>3</handle_mode> <!-- 处理模式: bit0-1:同步 0-异步 bit1-同步模式下是否写变更日志表.默认:1 -->
.bbox
int CRedoar::Save(CMsg *msg,const char *text,const char *seq_ctrl_key,const char *app_key);
int CRedoar::RedoProc();
.dxi_change_log
ACE_THR_FUNC_RETURN ChangeLogScanProc(void *arg);
int CDxkChangeLog::HandleBillAccept(CBillAcceptEvent *e)