zoukankan      html  css  js  c++  java
  • 差异更新

    #include <iostream>
    //下面说的是在服务器差异脏标记,不管在想客户端还是在数据库中经常用到的一种方法
    //由于其实直接拿为进行操作,所以速度是非常快的,也许刚开始不太好理解,但只要熟悉之后就非常好用
    //对于包而言如果Update包只改变一项你把整个结构体都发过去会大大增加网络带快,现在基本都走差异更新
    enum UpdateAtt
    {
        eUpdate1,
        eUpdate2,
        eUpdate3,
        eUpdate4,
        eUpdate5,
        eUpdate6,
        eUpdate7,
        eUpdateMax
    };
    #define Update_Att_Max_Num ((eUpdateMax >> 3) + 1)
    
    /**
     *@brief 脏标记类,关键理解此类
     */
    struct UserAttrFlag
    {
        bool IsUpdated(int nAttr) const
        {
            if(m_Flags[nAttr/8] & (1<<(nAttr%8)))
                return true;
            return false;
        }
        void SetBitFlag(int nAttr)
        {
            m_Flags[nAttr/8] |= (1<<(nAttr%8));
        }
        void ClearBitFlag()
        {
            memset(m_Flags, 0, Update_Att_Max_Num);
        }
        char m_Flags[Update_Att_Max_Num];
    };
    
    struct UserReg
    {
        unsigned char    m_AttrOffset[eUpdateMax];        ///< 角色属性偏移量,距离首地址的偏移位置
        unsigned char    m_AttrSize[eUpdateMax];            ///< 角色属性大小
    };
    
    struct Update
    {
    private://需要将此类的所有数据成员设置成私有,针对没个成员提供set/get接口
        int nUpdate1;
        int nUpdate2;
        int nUpdate3;
        int nUpdate4;
        int nUpdate5;
        int nUpdate6;
        int nUpdate7;
    public:
        void SetUpdate1(int nData)
        {
            if(nUpdate1 != nData)
            {
                nUpdate1 = nData;
                SetDBEnumAttrDirty(eUpdate1);
            }
        }
        void SetUpdate7(int nData)
        {
            if(nUpdate7 != nData)
            {
                nUpdate7 = nData;
                SetDBEnumAttrDirty(eUpdate7);
            }
        }
        int GetUpdate1(){return nUpdate1;}
        int GetUpdate7(){return nUpdate7;}
        Update()
        {
            RegisterAttributes();
            memset(&m_attrFlag, 0, sizeof(m_attrFlag));
        }
        void RegisterAttributes();//注册标记
    
        void _RegAttr(UpdateAtt eAtt, int nOffset, int nSize)
        {
            /// 角色属性偏移量,距离首地址的偏移位置,之前看到天龙代码直接存的是变量的地址,这种只适合单线程使用,多线程会发生内存拷贝
            /// 所以用偏移量更合适
            m_attReg.m_AttrOffset[eAtt] = nOffset;
            m_attReg.m_AttrSize[eAtt] = nSize;
        }
        void SetDBEnumAttrDirty(UpdateAtt eUpdateAttr)
        {
            m_attrFlag.SetBitFlag(eUpdateAttr);
        }
        UserAttrFlag m_attrFlag;//属相脏标记
        UserReg         m_attReg;//属相注册
    public:
        const UserAttrFlag* GetAttrFlag() const  {return &m_attrFlag;} 
        const UserReg*  GetAttrReg() const {return &m_attReg;}
    };
    
    void Update::RegisterAttributes()
    {
        #define REG_DB_ATTR(type,var) _RegAttr(type, ((int)&(var) - (int)this), sizeof(var));
        REG_DB_ATTR(eUpdate1, nUpdate1)
        REG_DB_ATTR(eUpdate2, nUpdate2)
        REG_DB_ATTR(eUpdate3, nUpdate3)
        REG_DB_ATTR(eUpdate4, nUpdate4)
        REG_DB_ATTR(eUpdate5, nUpdate5)
        REG_DB_ATTR(eUpdate6, nUpdate6)
        REG_DB_ATTR(eUpdate7, nUpdate7)
    }
    
    int main()
    {
        Update update;
        update.SetUpdate1(12);
        update.SetUpdate7(120);
        char* buff = new char[1024];//拼buff
        //拼包操作
        int nOffset = 0;
        for (int i = 0; i < eUpdateMax; i++)
        {
            if (update.GetAttrFlag()->IsUpdated(i))//判断其是否为脏
            {
                memcpy(buff + nOffset, &i, sizeof(int));
                nOffset += sizeof(int);
                memcpy(buff + nOffset, &update + update.GetAttrReg()->m_AttrOffset[i], update.GetAttrReg()->m_AttrSize[i]);
                nOffset += update.GetAttrReg()->m_AttrSize[i];
            }
        }
        getchar();
        return 0;
    }
    
    //现在简单解释一下脏标记的处理
    /*
    #define Update_Att_Max_Num ((eUpdateMax >> 3) + 1)
    定义的宏,根据此宏就知道定义多大的char数组,他是吧将8个枚举作为一个char,而一个char正好是8位,+1是为了不足8位,也为其分配一个char
    
    void SetBitFlag(int nAttr)
    {
        m_Flags[nAttr/8] |= (1<<(nAttr%8));
    }
    m_Flags[nAttr/8]是定位其在那个char上,如0,肯定是char[0],如果是9就是char[1]
    (1<<(nAttr%8))表示其在某个char的哪个位上,如9,(1<<(nAttr%8))就是第二个char[1]&10,这样就正确的设置到对应的位上了
    其实将char[..]看出1011111这样位,而此种方法方法就是能更方便的操作,c++没有对应的位的类型,stl里面好像有个bitset,但复杂类型在某些场合不适用的
    |=或操作正好将其设置成1
    
    bool IsUpdated(int nAttr) const
    {
    if(m_Flags[nAttr/8] & (1<<(nAttr%8)))
        return true;
    return false;
    }
    上面那个理解了,这个就好理解了
    m_Flags[nAttr/8]也是定位哪个char,(1<<(nAttr%8)))也是对应char那个位置
    &操作获取对应为是0,还是1
    
    对于其他的大小和偏移量,为了打包更好获取其地址和大小,更快的打包而设置的,好理解
    
    */
    
    /*
    额外补充
    对于DBSvr怎么解析,是根绝实现定义好的function,然后根据类型直接调用,那个类型里面关于数据类型都是写死的,个人觉得不是太好
    客户端我问了,他是根绝枚举,硬猜是哪个包,已醉
    */
  • 相关阅读:
    mac修改brew源
    分屏工具xpanes
    MySQL自增id不连续问题
    Ubuntu16.04安装zkui
    antlr解析hive语句
    Elasticsearch学习笔记——索引模板
    Elasticsearch6.2.1安装elasticsearch-sq插件
    多用户同时操作一条Mysql记录问题
    Nexus上传npm包
    Nginx请求转发
  • 原文地址:https://www.cnblogs.com/zzyoucan/p/4278148.html
Copyright © 2011-2022 走看看