gyb优化事项(4)

来源:互联网 发布:qt软件架构 编辑:程序博客网 时间:2024/05/16 14:17

dxi_chaneg_log支持同步模式

dxi_change_log支持直接调用dxi_ddd和dd,而不写入tb_change_log后异步处理
----异步方式在DAS中存在多个内部服务器时如何分配,协调tb_change_log记录任务存在问题
假设A,B两个内部服务器,写入tb_change_log后,这些未处理的记录由谁处理?
方案:
----写入者处理:在tb_change_log增加处理者ID信息(如内部服务器ID)
   如果某个内部服务器宕机,则该服务器的记录在其重新启动前无法被处理
----任务协调者:这是一种常见的模式。需要增加一个协调者,在多个工作者协调分配任务。(需要开发,有一定的复杂度)
  ***也许有开源实现!
采用直接调用dxi_ddd的方式,则可避免上述问题。
通常数据库操作的开销较大。
缺点是,如果接收队列太小,则可能导致通信速率降低。

dxi_change_log.conf
增加以下配置
<handle_mode>3</handle_mode> <!-- 处理模式: bit0-1:同步 0-异步 bit1-同步模式下是否写变更日志表.默认:0 -->

dxi_chaneg_log.h
CDxkChangeLog
增加处理模式配置:
    short handle_mode_; ///< 处理模式: bit0-1:同步 0-异步 bit1-同步模式下是否写变更日志表.默认:0

HandleLogRecord增加参数flag
    ///< flag=1直接调用,因没有写入变更日志所以不需要修改状态    int HandleLogRecord(CChangeLogRecord *record,short flag);
  
    
HandleBillAccept中判定handle_mode_,如果是直接调用,则直接生成CChangeLogRecord对象,调用CDxkChangeLog::HandleLogRecord函数.
    
    ////////////////////////////////////////////////////////////////////////////////
int CDxkChangeLog::HandleBillAccept(CBillAcceptEvent *e) {
    GetThisLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CDxkChangeLog::HandleBillAccept...\n");
    ISheetTypeInfo *sti = ibiz_->GetSheetTypeInfo(e->sheet_type_);
    if (sti==0) { ///< 可assert(sti!=0)
        GetThisLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"CDxkChangeLog::HandleBillAccept失败,无效的单据类型%lu.\n",e->sheet_type_);
        return -1;
    }
    GETDBC(pdbor,this->local_dbc_.c_str());
    FAIL_RETURN(pdbor->BeginTrans(),,-1);
    char now[24];
    GetCurSystemTime(now);
    int cnt = sti->get_key_field_num();
    CRowset* row = e->data_->GetRowset(0);
    int rowcnt = row->GetRSMeta(RST_ROW_CNT);
    for(int i = 0; i < rowcnt; i++)
    {
        if(!bcatcherall)
        {
            int j = 0;
            for(; j < catch_rule_.size(); j++)
            {
                CCatchRule *cr = catch_rule_.at(j);
                if (cr->filter_.src_orgid_.size() > 0 && cr->filter_.src_orgid_.find(e->src_orgid_) == cr->filter_.src_orgid_.end() )
                    continue;
                if (cr->filter_.dest_orgid_.size() > 0 && cr->filter_.dest_orgid_.find(e->orgid_) == cr->filter_.dest_orgid_.end() )
                    continue;
                if (cr->filter_.sheet_type_.size() > 0 && cr->filter_.sheet_type_.find(e->sheet_type_) == cr->filter_.sheet_type_.end() )
                    continue;
                ///< 检查单据内容是否满足条件
                if (cr->filter_.cond_.is_valid_) {
                    int ret = cr->filter_.cond_.Check(row,i);
                    if (ret!=1)
                        continue;
                }
                break;
            }
            if(j >= catch_rule_.size())
                continue;
        }
        string app_key = "";
        bool bsrc_orgid = true;
        bool bsheet_id = true;
        if(sti->GetFieldInfo(1,"src_orgid") == NULL)
            bsrc_orgid = false;
        if(sti->GetFieldInfo(1,"sheet_id") == NULL)
            bsheet_id = false;
        for(int j = 0; j < cnt; j++)
        {
            CBillFieldInfo* field = sti->get_key_field(j);    
            if(row->GetFieldInfo(field->name.c_str()) == NULL)
                continue;
            if(stricmp(field->name.c_str(),"src_orgid") == 0)
                bsrc_orgid = false;
            else if(stricmp(field->name.c_str(),"sheet_id") == 0)
                bsheet_id = false;
            char ctype_ = 'C';
            if(field->type.length() > 0)
                ctype_ = field->type[0];
            app_key = app_key + field->name + "=" + fieldtypebyinterfacetype(ctype_) + "[" + row->GetFieldValueByName(i,field->name.c_str()) +"],";

        }
        if(bsrc_orgid) app_key = app_key +  LogMsg("src_orgid=N[%lu],",e->src_orgid_);
        if(bsheet_id) app_key = app_key +  LogMsg("sheet_id=C[%s],",e->sheet_id_.c_str());
        if(app_key.length() > 0) app_key = app_key.substr(0,app_key.length()-1);

        if (handle_mode_&0x01) { ///< 如果是直接调用(不经过变更日志表)
            CChangeLogRecord record;
            record.app_pk_ = app_key;
            record.data_type_ = e->sheet_type_;
            if (HandleLogRecord(&record,1)) {
                return -1;
            }
        }

        if ((handle_mode_&0x01)==0||(handle_mode_&0x02)) {
        ITableHandler *th = CBasePluginModule::db_helper_->NewTableHandler(pdbor,changelog_cfg_.tableConfig._tableName.c_str());
        AUTO_POINTER_NODECLARE(ITableHandler,th);

        if (handle_mode_&0x02) { ///< 如果是直接处理且需要记录变更日志,则需要把logflag置为已处理
            int flag=1;
            th->BindField("logflag",(char**)&flag,sizeof(flag));
        }

        th->BindField("datatype",(char**)&e->sheet_type_,sizeof(e->sheet_type_));
        th->BindField("app_pk",app_key);

        th->BindField("logtime",now);
        if (th->Insert()) {
            GetThisLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_ERROR,"CDxkChangeLog::HandleBillAccept失败.目标orgid=%lu,源orgid=%lu,错误:%s.\n",e->orgid_,e->src_orgid_,pdbor->GetLastError());
            return -1;
        }
        }
    }

    GetThisLogger()->log(LO_STDOUT|LO_FILE,SEVERITY_DEBUG,"CDxkChangeLog::HandleBillAccept ok.\n");

    return 0;
}


////////////////////////////////////////////////////////////////////////////////
int CDxkChangeLog::HandleLogRecord(CChangeLogRecord *record,short flag) {
    CQQ_BILLTYPE bill_type = record->data_type_;
    CHANGELOG_CFG::BILLTYPE_MAP *pBILLTYPE_MAP = changelog_cfg_.Find(bill_type);
    assert(pBILLTYPE_MAP!=0);

    GetThisLogger()->log(LO_FILE|LO_STDOUT,SEVERITY_DEBUG,"HandleLogRecord正在处理:sheet_type=%d,rule_id=%d,app_pk=%s...\n",bill_type,pBILLTYPE_MAP->rule_id_,record->app_pk_.c_str());
    RESULT vecResult;
    try
    {
        vecResult = PKParser(record->app_pk_.c_str());
    }
    catch(PKPException Err)
    {
        GetThisLogger()->log(LO_FILE|LO_STDOUT,SEVERITY_ERROR,"记录ID:%I64d、业务主键:%s、单据类型:%d、机构编码:%s的单据中获取%d规则对象失败,错误原因:.\n",
            record->id_,record->app_pk_.c_str(),bill_type,record->mis_no_.c_str(),pBILLTYPE_MAP->rule_id_,Err.GetError().c_str());
        return -2;                    
    }

    string update_sql;
    int handle_status = 0;
    { ///< @note 此括号有些怪异.它的作用是确保下面操作使用的连接能被释放,有机会在连接中断后继续完成log_flag的修改.见函数尾部的说明
    int ret = 0;
    USEDBC(pdbor,dd_src_.c_str());
    if (pBILLTYPE_MAP->handle_mode_==1) {
        IRule *rule = changelog_tss_->NewRule(pBILLTYPE_MAP->rule_->GetID());
        if (rule==0)
            return -1;

        string strWhere;
        string alias;
        alias = rule->GetMasterTableAliasName();
        if (!alias.empty()) {
            alias +=".";
        }

        for (unsigned long k=0; k<vecResult.size(); k++)
        {
            PKVal &pk_val = vecResult[k];
            string key_field = alias+pk_val.PKName;
            rule->AddKey(pk_val.PKName.c_str(),pk_val.PKValue.c_str());
            switch(vecResult[k].PKType[0]) {
                    case 'N':
                    case 'I':
                        strWhere += LogMsg("%s=%s and ",key_field.c_str(),pk_val.PKValue.c_str());
                        break;
                    case 'D':
                        //strWhere += LogMsg("%s=%s and ",key_field.c_str(), pdbor->GetDBExt()->ToDate(pk_val.PKValue.c_str(),1).c_str());
                        //break;
                    case 'S':
                        strWhere += LogMsg("(%s>=%s and %s<%s) and ",
                            key_field.c_str(),
                            pdbor->GetDBExt()->ToDate(pk_val.PKValue.c_str(),1).c_str(),
                            key_field.c_str(),
                            pdbor->GetDBExt()->Date_Add(pdbor->GetDBExt()->ToDate(pk_val.PKValue.c_str(),1).c_str(), 1,DP_DAY).c_str());
                        break;
                    case 'T':
                        strWhere += LogMsg("%s=%s and ",key_field.c_str(), pdbor->GetDBExt()->ToTime(pk_val.PKValue.c_str(),1).c_str());
                        break;
                    default:
                        strWhere += LogMsg("%s='%s' and ",key_field.c_str(),pk_val.PKValue.c_str());
                        break;
            }
        }
        if (!strWhere.empty()) {
            strWhere.erase(strWhere.length()-5,5);
        }


        if (!record->mis_no_.empty())
            rule->SetProvider(record->mis_no_.c_str());
        else
            rule->SetSpecProvider(false);

        rule->SetOpType(record->op_type_);
        if (record->op_type_==0||record->op_type_==1||record->op_type_==3||record->op_type_==5||record->op_type_==6) { ///< 新增,全量修改,增量修改
            ///< @note 对于主表修改,按理只需要查和取变化的字段.为了简化,取所有字段
            rule->SetQryCond(strWhere.c_str());
            unsigned long count = 0;
            ret = rule->Run(&count);
        }
    
        else if ( record->op_type_== 2) {  /// 删除
            ret = rule->HandleDelete();
        }
        else {
            ////< 无效的变更类型
            handle_status = 51;
            ret = -1;
        }
    }
    else if (pBILLTYPE_MAP->handle_mode_==2) {
        dxi_ddd_ns::ITask *task = iddd_->NewTask(pBILLTYPE_MAP->rule_id_);
        for (unsigned long k=0; k<vecResult.size(); k++) {
            PKVal &pk_val = vecResult[k];
            task->SetKeyValue(pk_val.PKName.c_str(),pk_val.PKValue.c_str());
        }
        ret = task->Run(handle_status);
        task->Release();
    }
    if (flag==0) {
        char now[32];
        sens::CDateTime::GetDateTime(now);
        if (ret)  {///< 处理失败
            update_sql = LogMsg("update %s set logflag=0,try_times=try_times+1,handle_time=%s,handle_status=%d where logid=%I64d",changelog_cfg_.tableConfig._tableName.c_str(),
                pdbor->GetDBExt()->ToDateTime(now,1).c_str(),handle_status,record->id_);    
            GetThisLogger()->log(LO_FILE|LO_STDOUT,SEVERITY_ERROR,"记录ID:%I64d、业务主键:%s、单据类型:%d、机构编码:%s的单据中执行抽取%d规则失败.\n",
                record->id_,record->app_pk_.c_str(),bill_type,record->mis_no_.c_str(),pBILLTYPE_MAP->rule_id_);
        }
        else {
            update_sql = LogMsg("update %s set logflag=1,try_times=try_times+1,handle_time=%s,handle_status=%d where logid=%I64d",changelog_cfg_.tableConfig._tableName.c_str(),
                pdbor->GetDBExt()->ToDateTime(now,1).c_str(),handle_status,record->id_);    
        }

        if (pdbor->Execute(adCmdText,update_sql.c_str()))
            return 0;
    }

    } ///< 离开此作用域,pdbor已经被释放.否则,如果由于当前连接已断开导致update始终失败,而不会重新连接.


    if (flag==0) {

        ///< 如果上面的update失败,则反复执行直到成功.可以处理连接中断的情形.
        while(1) {
            USEDBC(pdbor,dd_src_.c_str());
            if (pdbor->Execute(adCmdText,update_sql.c_str()))
                break;
            ACE_OS::sleep(1);
        };
    }

    return 0;
}
0 0
原创粉丝点击