das 2.0开发记录

来源:互联网 发布:敏捷网络功能 编辑:程序博客网 时间:2024/06/10 08:00
本文目前是工作过程记录的素材整理,尚未校正。

1.内存对象定义及访问


核心的内存对象描述对应的系统资源,主要包括机构,用户,服务器。
原来本地和平台是2套分别定义的。
本地:
MEM_SVR_DATA定义:common\APBase.h
SERVERINFO,USERINFO,ORGINFO定义:    common\APBase.h    

统一定义到:
 .i_memdata2.h
    文件名字不是很恰当,作用就是服务器端内存系统对象定义及接口。
 .memdata.h
    实现对象类定义
    
原来本地和平台访问内存数据分别通过IAP,IDAP接口。分别由ap,dap插件实现。
    
调整后统一到IMemData接口。
md_xxx是实现IMemData接口的插件统称.
md_bdb和md_mysql分别实现BerkeleyDB和MySQL的IMemData接口。

md_xxx插件的含义提供共享数据的访问,数据一般可以保存在内存中,但不是必须的。
所以,md_xxx理解为share_data_xxx更合适。


dap废除。
ap的作用:作为服务器与外部主动连接的插件,提供内存数据库访问,用户登录处理等。
ap的功能分拆到几个插件中:
。与central server的连接和通信:改为linkto框架和具体的业务插件。
。用户接入功能移到uap.
。内存数据库功能移到md_xxx中
    
可用于das前置机,im本地服务器(目前不实现),平台服务器与交换服务器连接。
可能存在一些差异:
如:das需要在连接后注册,配置中包含机构,服务器信息等。

2.路由框架

不同的服务器路由策略不同。

以bbox为路由模块的基础。
原来向平台发送消息(通过ap_接口来完成),则需要从代码中消除。由link_to提供路由方法。
.bbox:
---本地模式:
   服务器需要与外部服务器主动通信。
   GetDataProc,InquiryData,InquiryData2线程都只有在与外部服务器连接后才执行.
 
   CanSend的含义是是否能与平台通信
---非本地模式:平台模式
   只有本地服务器连接时才主动推送消息
   
linkto_xxx:
.一个主动连接器:代码来自ap,目标可配置,支持代理
.负责与central server(外部服务器)的通信
.连接后逻辑由具体的linkto_xx插件完成,如das的linkto_das,向服务器注册。(linkto框架通过事件与具体的模块通信)


.linkto_das的开发
im需要开发的有
.linkto_im (本地服务器连接平台)---暂时不支持
.linkto_switch:需要开发

bbox作为框架
入口消息路由:
有2种结果:(1)消息由本服务器插件处理 (2)根据消息目标转发,或者存储转发或丢弃

出口消息路由:
.这种消息不会存储,路径选择和入口消息转发处理一致。


多个插件可以登记路由处理器,根据消息的目标进行路由,
一个消息只能有一个路由出口。

多个路由处理器按登记的顺序调用,如果消息被某个路由处理器处理,则结束不再调用后面的路由处理器。
    /// @return 0:未路由 >0:已路由 <0:错误
    virtual int HandleInput(CWrappedMsg<> *pwm,int &action) = 0;

如果一个消息没有被任何路由处理器成功处理,则调用默认的路由处理器。

应用可以定义和登记自己的默认路由处理器。
默认路由处理器最后调用。
    
如果默认路由处理器也未处理,则框架输出丢弃消息的信息。

路由处理
接收路由处理
返回值:
0:由插件处理
非0:不再由插件处理(<0:错误 >0:其它情况)
int CBBoxPlugin::HandleInput(CWrappedMsg<> *pwm,void **pploc,int &action)

发送路由处理
int CBBoxPlugin::HandleSend(CMsg *msg,CWrappedMsg<> **wm)

登记消息检查函数,端点路由函数(如针对特定的类型)

路由是针对目标进行的。可以对端点类型或者具体的目标进行路由,如对机构路由,甚至对某个机构进行路由。
拦截机制:

。只要消息被一个拦截器拦截,消息就不需要再经过其它拦截器处理了。

接口定义

class IRouter {public:    ///< 登记一个路由模块    virtual int RegisterRouteHandler(IRouteHandler *handler) = 0;};
实现:

class CBBoxPlugin: public CQQBasePlugin,public IRouter {publci:    int RegisterRouteHandler(IRouteHandler *handler);};

    
。das服务器的路由:
rto_das_server
---入口消息路由
对于目标为(8,8)的消息,交给插件处理。
默认路由处理:
 。对于目标(0,0)的消息,交给插件处理
 。其它的返回未路由信息

---出口消息路由

。das前置机的路由:
rto_das_ws

 3.hotfox优化   

是否支持时序控制可配置.

hotfox.conf增加配置项:  在<Scheduler>节点中增加
<enable_seq_ctrl>false</enable_seq_ctrl> <!--是否支持时序控制,默认:true -->

.直接路由走的消息不需要解析

.ExtAttr的低16位用做时序控制键

4.umx4支持

新特性:
    1.消息头ExtAttr域无法使用问题
    .利用ExtAttr的低12位作为时序键(最大4096)
    可快速分发
 
  2.消息头域的顺序调整,
    版本号(1字节)+消息包长度(4字节)+其它
  先读5个字节的版本号,然后读整个包.
    const unsigned short UMX_INIT_READ_NUM = 5; ///< 初始读的字节数
   
  3.PktHead效率问题:能否做性能优化(未处理)
    int VarToBuffer(char *&base,const char *type_name,int offset);
    int BufferToVar(char *&base,const char *type_name,int offset);
      
 
  4.长度引导方式:(未实现)
  行集列数据长度是按最大可能长度占用空间的,可能存在比较大的浪费.
  每个字节的最高位用来区分是否是最后一个长度字节
 
   
兼容性考虑:
 
 为了兼容现有系统(如在不全面升级的情况下,应用于现有的本地服务器),connector默认仍采用UMX3.
 对于新的系统,可以通过set_prot_version设置connector的协议版本.可以在linkto_xxx中配置.
class IConnector {public:    ///< 设置主动连接器协议版本    virtual void set_prot_version(short version) = 0;};
     

5.全表覆盖支持            

实现单表定时同步,与单个对象处理模式相比有2个优点:1.一次处理多个对象,效率高 2.支持删除的情况
/// 变更类型enum OP_MODE {    OM_UNSPECIFED=0, ///< 未指定:默认按新增处理    OM_NEW=1, ///< 新增    OM_DELETE=2, ///< 删除    OM_OVERWRITE=3, ///< 全量修改    OM_PK_CHANGED=4, ///< 主键修改    OM_INC=5,///< 增量修改    OM_SLIGHT_CHANGE=6, ///< 主表(细微)修改    OM_FULL_SYNC=7, ///< 表同步};
   
virtual int HandleTableChange(CMsg *msg,CSheetDealResult &sdr);  ///< 处理全表更新
改名为:
virtual int HandleFullSync(CMsg *msg,CSheetDealResult &sdr);  ///< 处理全表更新

该变更应用的限制:
1.对于数据汇集的情况,多个源合并到一个目标库中,只能同步源对应的部分数据而不能影响到其它源的数据. (目标库中需要一个区分源的标志字段,源数据包含该源标志,如src_orgid)。
处理方配置为合并模式处理.目前暂不实现,当出现真实应用的要求时再确定方案和实现.
---源端的消息包可以通过消息头确定源机构.

2.语义上的理解:
  从整体角度,这是一种合理的数据同步,分布式环境下的数据一致性。
  有危害的方面是,对于目标方这个行为是由源端决定的。
  当源和目标属于不同的利益体时,这可能引发责任和风险方面的顾虑。


OM_NEW和OM_INC的处理逻辑的差别:
---增量修改时忽略主表主键冲突,适用于新增明细的情况
    
抽取规则属性增加:<ChangeMode>.

f023n_5606字段废弃.对应的成员变量append_mode_也废除。

dd.conf增加<do_cleanup>配置,默认:true    

BillInterface修改:    
v3.7 2014-8-18

int CSheet::ProcessImport(CMsg *msg,CSheetDealResult &sdr)  {    USEDBC(pdbor,this->dbc_name_.c_str());    int result = 0;    switch(op_type_) {        case OM_UNSPECIFED:        case OM_NEW:            result = HandleNew(msg,sdr);            break;        case OM_DELETE:            result = HandleDelete(msg,sdr);            break;        case OM_OVERWRITE:            result = HandleUpdate(msg,sdr);            break;        case OM_PK_CHANGED:            result = HandlePKChange(msg,sdr);            break;        case OM_INC:            result = HandleIncChange(msg,sdr,1);            break;        case OM_SLIGHT_CHANGE:            result = HandleSlightChange(msg,sdr);            break;                    case OM_FULL_SYNC:            result = HandleFullSync(msg,sdr);            break;                }    return result;}

   是否存在多表的同步要求呢?
   .常见的应用场景是零售商端向目标同步门店或商品资料等单表信息。
   单据交换是基于数据对象的,对象分为单表对象和多表对象,多表对象对应的是多个由树形结构关系的表。
   对表对象每次交换一个对象,对于单表对象为了提交处理效率,支持多个对象的组合传输与处理。
   dd模式:一次批量扫描处理多个单表对象
   dxi_change_log模式:app_key只能对应到一个对象,如果为空则表示表的所有对象(记录)。
   dxi_change_log跟踪记录单个对象的变化,额外支持单表的全量覆盖。
   
   这些信息是关于多个对象的。
   
   对于单表,

   dd扫描时不带任何条件,定时抽取,实现表之间的定时同步。  

5.多零售商异构数据支持

。das 1.0中没有合作机构的概念,也没有使用供应商机构ID。

零售商提供的单据信息中包含供应商的MIS编号信息。
das平台内部服务器负责把零售商机构ID转换为jxj的客户编码。
jxj金融平台自己处理mis编号到客户编号的转换。
(所依赖的编码表由jxj组织和维护)
    

.das服务端对来自零售商的数据中的供应商MIS编号,查表确定供应商的机构ID。
在gyb2中供应商是以此机构ID访问系统的。
das 可以需要也可以不需要做此MIS编号到供应宝机构ID的转换。
对于gyb2需要,对于独立部署的das则不需要,如das 1.0的应用场合

.das 2.0服务端对数据库的支持:
---对于gyb2,需要全面支持PostgreSQL
---支持mysql(考虑支持sql server:应该是可以的,需要验证)

.动态根据单据的源机构输出到对应的数据库(仅包含业务数据的数据源)
规划部署时服务端数据库的种类不限定只有一种,这是考虑未来迁移的可能,考虑可能同时出现两种类型的数据库。

驱动采用非DSN方式,避免服务器本地对各个数据源配置DSN。
lm.conf中配置数据库驱动,连接串模板。
因这些数据库仅限于单据处理


不同实例的数据库名字相同。
<!-- 是否映射目标接收机构,默认:false--><map_vender_orgid>true</map_vender_orgid><!-- 多数据源模式(不同的源机构的数据存储在不同的数据库中) 0:单数据源 1:多数据源.默认: 0 --><multi_ds>1</multi_ds>    <!--数据源连接串模板 --><ds_connstr_template><database>gyb_platform_2_9_1</database><item><ds_name>mysql5.1</ds_name><connstr_template>{MySQL ODBC 3.51 Driver};SERVER=@server;port=@port;DATABASE=@database;USER=@user;PASSWORD=@password;OPTION=3;charset=gbk</connstr_template><db_ext>mysql_ext.dll</db_ext> <!--数据库扩展 --></item></ds_connstr_template>

其中,@server,@port,@user,@password运行时根据机构ID从tb_8021中获取.

机构数据源信息在服务器内存中缓存,访问后缓存,而不是初始全部加载.
tb_8021增加一个数值字段表示版本,初始为1。每次变更递增。
对于长期不使用的项予以释放。
这些机制保证了效率,资源以及动态加入,运行时调整需要的兼顾。
这种机制同样适用于tb_8022.

DRIVER={MySQL ODBC 3.51 Driver};SERVER=172.23.2.56;port=3308;DATABASE=gyb_platform_2_9_1;USER=root;PASSWORD=Admin_123;OPTION=3;charset=gbk
das对业务单据全部采用通用单据处理。
CSheet.OnReceive是接收单据的处理入口

orgid--->dbpool---->从中取得一个连接(如果没有缓存连接则创建)

hotfox提供新的接口方法:
.指定连接串,连接名(连接池名称),数据库扩展模块名创建连接对象

---连接池名称不能与hotfox中配置的冲突,采用格式:用机构ID作为连接池名称.


零售商数量不是很大时,可以简化实现,不需要回收连接对象及连接配置信息所占资源.

.动态创建和管理连接对象:


das前置机与服务器的区别:
。lm:
  ----<mulit_ds>为0:不需要tb_8021,tb_8022,tb_1068表

数据库表:
.mis-机构ID对照表(tb_1068)
.数据源信息(tb_8021)
.机构数据源信息(tb_8022)    

 ///< @note 对于业务数据分库存储的情况,不能保证事务的完整性
 ----接收单据处理时,本地库的操作,事件机制产生的其它操作等如果跨数据库可能存在问题。 -----事件机制应用的场合也是有限制的。

    ***本地库上可能有写待办事宜的操作: 这种事务不一致的错误不严重的话是可以接受的。    

6.其他 

6.1 ICentralServer

接口原来是本地连接平台并通信的接口。
抽象为本地与外部通信的接口。仍然用此名称。
定义转移到common\i_centralserver.h文件中。
struct CCentralServer : public ICentralServer
转移到common\centralserver.h文件中。


6.2CMemDataBDB::GetAllServer

int CMemDataBDB::GetAllServer(vector<CQQ_SERVERID>& vecServer)
        if(svr_data->svr_id_ != self_->GetServerID())
GetAllServer需要排除服务器自身

增加参数:except_server排除的服务器(可带多个)
int CMemDataBDB::GetAllServer(vector<CQQ_SERVERID>& vecServer,CQQ_SERVERID *except_server)

6.3 self_


self_对于本地和平台都存在此对象,表示服务器本身.
self_用IMemData的GetLocalServer代替

6.4服务器证书

用途
(1)与客户端通信时加密密码等安全信息
(2)解密会话密钥
使用的插件有:linkto_das,uap.

证书由md_xxx加载,作为共享数据访问。

7.软件包版本

原来的软件包版本编号的结构如下: 软件包分类编号组成: 包类型编号(1)+行业编码(3)+节点编码(2)

程序通过下列宏访问软件包组成信息项:
#define PKG_TYPE(v) (v/100000)                ///< 包类型编号#define PKG_DOMAIN(v) ((v%100000)/100)        ///< 行业编码#define PKG_LEVEL(v) (v%100)                ///< 供应链节点编号#define PKG_DOMAIN_LEVEL(v) (v%100000)        ///< 行业编码(3)+节点编码(2)

简单的顺序编码就可以满足需要,不可能推出很多软件包.

沿用原来的编码也未尝不可!但编码方式仅用于阅读,不用于程序处理。

8.数据库

ALTER TABLE tb_0033 ADD COLUMN f016n_0033 INT DEFAULT 0;
f016n_0033为失败重做记录的服务器ID.每个服务器只处理本服务器的失败重做记录.


9.插件工程选项

General|Output Directory:..\..\..\bin\output\debug
C++|General\Addtional Directories:..\..\common\hotfox\include;..\..\source\include;..\..\common;
Linker|Output File: ..\..\..\bin\server\debug\md_bdb.dll
Linker|Debugging|Generate Programm Database File:..\..\..\bin\output\debug\md_bdb.pdb

从工程编译选项中去掉原平台的以下宏
CQQ_PLATFORM,BCQ_DEBUG,SEPSDK_AS_STATIC_LIB

10.文件增删


10.1新增文件

common\i_centralserver.h
common\centralserver.h
common\i_routehandler.h

10.2删除文件

common\i_ap.h
common\i_dap.h
common\CQQRSPBase.cpp
coomon\CQQRSPBase.h
common\APBase.cpp
common\APBase.h
common\i_apbase.cpp
common\i_apbase.h


11.todo

?UMX4:压缩特性测试(检查压缩解压是否正常)
?bool CAPBase::IsLocalOrg_(CQQ_ORGID orgid)
重新实现。利用内存数据库中机构的属性信息来区分.
原型:int IsLocalOrg(CQQ_ORGID orgid);
返回值可以区分失败.
1:是0:否 -1:失败

? tb_8021的密码(f007v_8021)是明文

? lm:
GetCoOrg优化,支持缓存.

?本地支持多SEMQ实例(从平台RTO引入)

? 升级支持:涉及uap,

?uap支持Windows域验证: m_piADAdapter (限于本地部署的IM服务器)----可暂时不实现

?uap:
//    ans->AddRowset(getcoserver()); ///< @todo 不支持分离服务器
---gyb2无此场景.
(代码与gyb1统一存在此兼容性问题!!!)

? lm不支持移动应用(如移动供应链)
GetUserSvcPubList方法被屏蔽

? 原ap提供的EVENT_REACTOR可以用框架的事件反应器替代,目前使用的地方不多,产生用户下线事件由其它插件响应处理

? dd清理:
---对于集群部署,清理不能由每个服务器去执行,只能由单一的服务器承担。
  对于专用的单个服务器,允许服务器自行完成清理。
  清理实际上可以由清理插件完成。
 
  ---dd的清理代码注释掉!!
 
?trunk的dd代码的一个小错误:CDd::GetDataProc名字错误
int CDd::OnActivate() {

            IDeamonTask *task = CBasePluginModule::deamon_mgr_->add(cleanup_proc,"CDd::GetDataProc",this);
            task->set_timer_strategy(60);

    
?md_mysql    ,md_bdb接口差异:
目前仍不能彼此替换,没有完全覆盖到所有方法。
接口方法的含义有差异
。md_bdb:取版本只有本地的2个包,md_mysql则包含所有包的版本信息

?linkto_das:提取基类lintobase,在此基础上可以派生出linkto_switch,linkto_im.

! 387协议

    return -1; ///< @note 不再支持组件包

12.测试环境备忘

CREATE TABLE tb_jxjorgcode(  orgid INT PRIMARY KEY,  bizcode VARCHAR(20) NOT NULL) ENGINE=INNODB DEFAULT CHARSET=gbk;ALTER TABLE tb_0033 ADD COLUMN f016n_0033 INT DEFAULT 0;

---tb_0044配置错误 (172.23.2.80 etl库)
<?xml version="1.0" encoding="gb2312" standalone="yes" ?><content><tables><table><name>tb_1116</name><cname>tb_1116</cname></table><table><name>tb_1106</name>     tb_1106 错误的!<cname>tb_1106</cname></table></tables><relations><relation>tb_1116.src_orgid=tb_1118.src_orgid</relation><relation>tb_1116.sheet_id=tb_1118.sheet_id</relation></relations></content    


13.平台插件代码修改方法

//#include "CQQRSPBase.h"#include "CQQBase.h"//class CPSMPlugin : public CCQQRSPBase class CPSMPlugin : public CQQBasePlugin //typedef CCQQRSPBaseparent;typedef CQQBasePluginparent;//IDAP*m_piDap;// 使用m_piDap的地方替换为mem_data_//#pragma comment(lib,"sepsdk.lib")#pragma comment(lib,"lssdk.lib")//USERINFO *user = dynamic_cast<USERINFO*>(this->m_piDap->GetUser(UserSerial));IUSERINFO *user = dynamic_cast<IUSERINFO*>(this->mem_data_->GetUser(UserSerial));

0 0
原创粉丝点击