项目数据库逻辑

项目数据库逻辑
数据库主要逻辑模块分为asynDBCenter,DBNet,DBSvr
asynDBCenter与DBNet之间通过共享内存通信(缓存进程为了防止GS崩溃导致玩家数据丢失,并且在DBNet里面可以做定时存储)
这里的共享内存有点复杂
1.发包类型的,就是跟GS与Net之间的相似带回收类型的
2.不带回收的,每个玩家独占一个小块,只有玩家独占,当服务器蹦了玩家数据可以存储数据库
3.对于道具由于玩家身上的道具数量众多,不可能有那么多内存分给,当玩家装备属性发生变化时将其放到共享内存中
而且有一个tick,过了这个tick直接归还,防止不常更新的道具长期占据共享内存
4.帮会,拍卖行也一行给他分配共享内存
共享内存GS这边创建DBNet那边读取

游戏过程中哪个属性发生变化,设置脏标记
DBNet根据脏标记发送差异更新包到DBSvr
问题:其实我们这个DBSvr没必要,我们现在是直接发差异更新包到DBSvr然后DBSvr访问数据库,其实可以再DBNet这一端直接访问mongo的api,就这个问题我问过经理
经理说其实是在DBNet这一段去访问数据库,不是在DBSvr,DBSvr不跟数据库打交道,DBSvr的作用是同步在各个服务器的表,服务器直接访问数据库,我也是醉了一地

听说类似memcached和redis缓冲东西应用到数据库不错,我问过经理,经理说在web上应用的比较多,在游戏中直接同步到共享内存中,在换从进程中进行定时存储,不用这个memcached机制
但貌似不是这样的,应该能用的上

举个例子吧
/*
设置玩家等级
*/
inline void    ShuiHu::ActorInfoEx::SetLevel(int nLevel)
{
    __COMPARE_START(m_actInfo.m_nLevel, nLevel)
    
    SetDBEnumAttrDirty(eCharDBAttr_Level);
    
    __COMPARE_END
}

void SetDBEnumAttrDirty(CharDBAttr eCharDBAttr)
{
    char cUseState = m_pActSM->GetUseStateSafe();//获取保存状态
    if (DB::GetbIsState(cUseState, SM_USE_SAVED))//数据库已保存清除上一次脏标记
    {
        m_attrFlag.ClearFlag();
    }
    m_attrFlag.SetBitFlag(eCharDBAttr);//将当前标记设置成脏比较
    UpdateActSMInfo(eCharDBAttr);//拷贝对于的数据到共享内存中
}

DBNet每次遍历所有的脏标记,如果是脏的话,拷贝数据出来拼相关BSON

bool DBNet::NormalDBModifyOpt(int nIndex)
{
    SM_Data<ShuiHu::ActorInfoEx>* pSMData = m_spSMDataActEx->GetSMData(nIndex);
    char cUseState = pSMData->GetUseStateFast();
    static ShuiHu::ActorInfoEx InfoEx;

    if (DB::GetbIsState(cUseState, SM_USE_READYSAVE)) //判断是否处于待保存状态
    {
        char cOpt = 0;
        pSMData->GetDBOptSafe(cOpt);

        size_t nCurSaveTime = pSMData->GetSaveTimeFast();
        //每个共享内存头部保存一个tick,每次循环根据tick定时保存数据库,正式根据这个tick和脏比较减少数据库压力
        if(!IsCanSaveDB(cOpt, cUseState, nCurSaveTime))
            return false;
    //...
}

在看个玩家下线
void asynDBCenter::SetActorInfoEx(guid_t actorID,const ShuiHu::ActorInfoEx& info)
{
    SMDataInfo<ShuiHu::ActorInfoEx>& smInfo = m_mapSMAct[actorID];
    smInfo.GetSMData()->CopyDataIn(&info);
    smInfo.GetSMData()->AddDBOpt(DB::eSM_DB_Update);
    smInfo.GetSMData()->AddUseState(SM_USE_READYSAVE);
    smInfo.GetSMData()->AddUseState(SM_USE_OFFLINE);
    //将玩家放到回收队列中,如果DBNet还没有将玩家数据保存并把玩家共享内存设置成已保存状态,这边回收队列中还有玩家的数据
    //玩家再次上线可以直接从共享内存中获取数据不用访问数据库
    if (!smInfo.GetbInRec())
    {
        smInfo.SetbInRec(true);
        m_spActorInfoExRecMgr->Push(&smInfo);
    }
}

DBNet那边
if(DB::GetbIsState(cOpt, DB::eSM_DB_Del) || DB::GetbIsState(cUseState, SM_USE_OFFLINE))
    pSMData->SetUseState(SM_USE_READYREC);//将内存设置成待回收状态
else
{
    pSMData->SetUseState(SM_USE_SAVED);
}

GS这边
if (DB::GetbIsState(cOpt, SM_USE_READYREC))//待回收状态
{
    pData->SetUseState(SM_USE_FREE); //设置为可利用状态
    m_pSmPoolMgr->Push(pData);//将这块内存放到可用队列中,下次还是从可用队列中分配一块出来
    m_pAsynDBCenter->DelSMData(pData);
    it = m_recycleDeq.erase(it);    
}

 

posted @ 2015-03-28 23:33  zzyoucan  阅读(305)  评论(0编辑  收藏  举报