xml增删改操作的回滚实现

类似数据库回滚,定义一系列的原子操作,定义每种操作的逆操作,在底层监控所有操作、纪录操作,回滚时执行每个原子操作的逆操作。

实现过程中,存在编译问题,具体原因不记得了,大概是两个类互相依赖问题。采用cpp的模板类可以解决这个问题。c语言下实现的话,估计需要用到函数指针解决。

原子操作的类型(非xml原子操作已删除,例如跨文件、数据库)

    kEXAT_att_add, /**< 属性添加,逆操作是属性删除*/
    kEXAT_att_delete, /**< 属性删除,逆操作是属性添加*/
    kEXAT_att_change, /**< 属性变更,逆操作是属性变更*/
    kEXAT_node_add, /**< 添加的逆操作是移除,不释放内存*/
    kEXAT_node_delete, /**< 删除节点,  释放内存。逆操作是添加*/
    kEXAT_node_remove, /**< 移除节点,不释放内存。逆操作时添加*/
    //移除操作需要根据后续操作才知道对应逆操作.移除非原子操作,移除是半原子操作。
    //XmlObject的移除子节点+添加子节点两个操作需要变为单个移动函数才方便实现逆操作。
    //采用移动节点概念替代移除节点。
    //kEXAT_node_move, /**< 移动节点,不释放内存。对应其它基本操作*/
    kEXAT_node_change, /**< 节点变更、此操作无效*/
    kEXAT_father_change, /**< 变更父节点指针*/
    kEXAT_text_change, /**< 变更xml节点中间的text内容*/

原子操作类的定义示例

/** @brief 各种XML内存操作信息,属性的增删改,节点的增删改
           新增词条的增删改。
           新增key、desc数据库的增删改。*/
template<class XmlNodeT, class DicT/*, class KeyDbT*/>
class XmlAction
{
public:
    //friend class XmlObjectRollBackManager;
public:    //各种操作的构造函数
    /** @brief 属性增:ver_id、修改类型、XmlNodeT * obj 、属性名
    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] obj 属性变更的节点指针
    @param [in] att_name 属性名
    @return 无
    */
    XmlAction(const EnumXmlActionType type_temp, const int vid,
        XmlNodeT *obj, const XBaseString &att_name)
        :vid_(kInvalidVersionId), type_(type_temp),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {
        if (type_temp != kEXAT_att_add      //属性增
            || vid <= kInvalidVersionId
            || obj == NULL
            || att_name.length() == 0)
        {
            type_ = kEXAT_unkown;
            return;
        }
        type_ = type_temp;
        vid_ = vid;
        obj_ = obj;
        att_name_ = att_name;
        value_from_ = kInvalidString;
        value_to_ = kInvalidString;
        father_ = NULL;
        obj_index_ = kInvalidIndex;
    }

    /** @brief 属性改:ver_id、修改类型、XmlNodeT *obj 、属性名、修改前的属性值、修改后的属性值
    kEXAT_text_change 此属性特殊处理
    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] obj 属性变更的节点指针
    @param [in] att_name 属性名
    @param [in] value_from 属性修改前的值
    @param [in] value_to 属性修改后的值
    @return 无
    */
    XmlAction(const EnumXmlActionType type_temp, const int vid,
        XmlNodeT *obj, const XBaseString &att_name,
        const XBaseString &value_from, const XBaseString &value_to)
        :vid_(kInvalidVersionId), type_(type_temp),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {
        if ((type_temp != kEXAT_att_change && type_temp != kEXAT_text_change)      //属性改
            || vid <= kInvalidVersionId
            || obj == NULL
            || att_name.length() == 0)
        {
            type_ = kEXAT_unkown;
            return;
        }
        if (type_temp == kEXAT_text_change && att_name != kXmlTextAttName)
        {
            type_ = kEXAT_unkown;
            return;
        }
        type_ = type_temp;
        vid_ = vid;
        obj_ = obj;
        att_name_ = att_name;
        value_from_ = value_from;
        value_to_ = value_to;
        father_ = NULL;
        obj_index_ = kInvalidIndex;
    }

    /** @brief 
    词条变更,key变更、value变更、key-value的增删改(没有remove)
    key变更,value_from_,value_to_,          ver_id、修改类型、DicT *dic
    value变更,value_from_,value_to_,        ver_id、修改类型、DicT *dic
    key-value增,att_name_,value_to_,       ver_id、修改类型、DicT *dic
    删,id,att_name_,value_from_,              ver_id、修改类型、DicT *dic
    改,att_name_,value_from_,value_to_,    ver_id、修改类型、DicT *dic

    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] dic 词条管理对象
    @param [in] att_name 属性名(不同操作含义不同)
    @param [in] value_from 属性修改前的值(不同操作含义不同)
    @param [in] value_to 属性修改后的值(不同操作含义不同)
    @param [in] id_temp 词条id
    @return 无
    */
    XmlAction(const EnumXmlActionType type_temp, const int vid,
        DicT *dic, const XBaseString &att_name,
        const XBaseString &value_from, const XBaseString &value_to, const int id_temp)
        :vid_(kInvalidVersionId), type_(type_temp),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {
        if ((type_temp != kEXAT_word_key_change && type_temp != kEXAT_word_value_change
            && type_temp != kEXAT_word_add && type_temp != kEXAT_word_delete
            && type_temp != kEXAT_word_change)      //词条相关变更
            || vid <= kInvalidVersionId
            || dic == NULL)
        {
            type_ = kEXAT_unkown;
            return;
        }
        type_ = type_temp;
        vid_ = vid;
        obj_ = NULL;
        att_name_ = att_name;
        value_from_ = value_from;
        value_to_ = value_to;
        father_ = NULL;
        obj_index_ = id_temp;//词条的id
        dic_ = dic;//词条相关变更
    }

    /** @brief 
    db变更,key desc的增删改
    增,att_name_,value_to_,                 ver_id、修改类型、KeyDbT *db、父节点xpath
    删,att_name_,value_from_,               ver_id、修改类型、KeyDbT *db、父节点xpath
    改,att_name_,value_from_,value_to_,    ver_id、修改类型、KeyDbT *db、父节点xpath

    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] db 数据库管理对象
    @param [in] att_name 属性名
    @param [in] value_from 属性修改前的值
    @param [in] value_to 属性修改后的值
    @param [in] father_xpath 父节点的路径
    @return 无
    */
    //XmlAction(const EnumXmlActionType type_temp, const int vid,
    //    KeyDbT *db, const XBaseString &att_name,
    //    const XBaseString &value_from, const XBaseString &value_to,
    //    const XBaseString &father_xpath)
    //    :vid_(kInvalidVersionId), type_(type_temp),
    //    father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
    //    att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
    //    father_from_(NULL), father_to_(NULL),
    //    dic_(NULL), db_(NULL), father_xpath_(kInvalidString)
    //{
    //    if ((type_temp != kEXAT_db_key_desc_add 
    //        && type_temp != kEXAT_db_key_desc_delete
    //        && type_temp != kEXAT_db_key_desc_change)
    //        || vid <= kInvalidVersionId
    //        || db == NULL)
    //    {
    //        type_ = kEXAT_unkown;
    //        return;
    //    }
    //    type_ = type_temp;
    //    vid_ = vid;
    //    att_name_ = att_name;
    //    value_from_ = value_from;
    //    value_to_ = value_to;
    //    db_ = db;
    //    father_xpath_ = father_xpath;
    //}
    
    /** @brief kEXAT_father_change 父节点变更
    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] obj 属性变更的节点指针
    @param [in] father_from 变更前父节点
    @param [in] father_to 变更后父节点
    @return 无
    */
    XmlAction(const EnumXmlActionType type_temp, const int vid,
        XmlNodeT *obj, XmlNodeT *father_from, XmlNodeT *father_to)
        :vid_(kInvalidVersionId), type_(type_temp),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {
        if ((type_temp != kEXAT_father_change)      //父节点改
            || vid <= kInvalidVersionId
            || obj == NULL)
        {
            type_ = kEXAT_unkown;
            return;
        }
        type_ = type_temp;
        vid_ = vid;
        obj_ = obj;
        att_name_ = kInvalidString;
        father_from_ = father_from;
        father_to_ = father_to;
        father_ = NULL;
        obj_index_ = kInvalidIndex;
    }
        
    /** @brief 属性删,实际可能没有此需求:ver_id、修改类型、XmlNodeT * obj 、属性名、属性值
    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] att_name 属性名
    @param [in] obj 属性变更的节点指针
    @param [in] value_from 变更前属性值
    @return 无
    */
    XmlAction(const EnumXmlActionType type_temp, const int vid,
        XmlNodeT *obj, const XBaseString &att_name,
        const XBaseString &value_from)
        :vid_(kInvalidVersionId), type_(type_temp),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {
        if (type_temp != kEXAT_att_delete      //属性删
            || vid <= kInvalidVersionId
            || obj == NULL
            || att_name.length() == 0)
        {
            type_ = kEXAT_unkown;
            return;
        }
        type_ = type_temp;
        vid_ = vid;
        obj_ = obj;
        att_name_ = att_name;
        value_from_ = value_from;
        value_to_ = kInvalidString;
        father_ = NULL;
        obj_index_ = kInvalidIndex;
    }

    /** @brief 
    节点改:实际无此需求,等价于属性变更、子节点增删
    节点增:ver_id、修改类型、XmlNodeT *father、child_index、XmlNodeT *child
    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] father 父节点
    @param [in] child_index 子节点在父节点中的序号
    @param [in] child 子节点
    @return 无
    */
    XmlAction(const EnumXmlActionType type_temp, const int vid,
        XmlNodeT *father, const int obj_index,
        XmlNodeT *obj)
        :vid_(kInvalidVersionId), type_(type_temp),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {
        if (type_temp != kEXAT_node_add
            || vid <= kInvalidVersionId
            || obj == NULL
            || father == NULL
            || obj_index < 0
            /*|| obj_index >= father->Size()*/)
        {
            type_ = kEXAT_unkown;
            return;
        }
        type_ = type_temp;
        vid_ = vid;
        obj_ = obj;
        att_name_ = kInvalidString;
        value_from_ = kInvalidString;
        value_to_ = kInvalidString;
        father_ = father;
        obj_index_ = obj_index;
    }

    /** @brief
    节点删:ver_id、修改类型、XmlNodeT *father、child_index、XmlNodeT *child
    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] father 父节点
    @param [in] obj_index 子节点在父节点中的序号
    @param [in] obj 子节点
    @return 无
    */
    XmlAction(const EnumXmlActionType type_temp, const int vid,
        XmlNodeT *father, XmlNodeT *obj, const int obj_index)//交换obj和obj_index的位置避免构造函数歧义
        :vid_(kInvalidVersionId), type_(type_temp),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {
        if (type_temp != kEXAT_node_delete
            || vid <= kInvalidVersionId
            || obj == NULL
            || father == NULL
            || obj_index < 0
            /*|| obj_index > father->Size()*/)
        {
            type_ = kEXAT_unkown;
            return;
        }
        type_ = type_temp;
        vid_ = vid;
        obj_ = obj;
        att_name_ = kInvalidString;
        value_from_ = kInvalidString;
        value_to_ = kInvalidString;
        father_ = father;
        obj_index_ = obj_index;
    }

    /** @brief
    节点移除:ver_id、修改类型、XmlNodeT *father、child_index、XmlNodeT *child
    @param [in] type_temp 修改类型
    @param [in] vid 版本id
    @param [in] father 父节点
    @param [in] obj_index 子节点在父节点中的序号
    @param [in] obj 子节点
    @return 无
    */
    XmlAction(const EnumXmlActionType type_temp, const int vid,
        const int obj_index, XmlNodeT *father, XmlNodeT *obj)//交换参数位置避免构造函数歧义
        :vid_(kInvalidVersionId), type_(type_temp),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {
        if (type_temp != kEXAT_node_remove
            || vid <= kInvalidVersionId
            || obj == NULL
            || father == NULL
            || obj_index < 0
            /*|| obj_index > father->Size()*/)
        {
            type_ = kEXAT_unkown;
            return;
        }
        type_ = type_temp;
        vid_ = vid;
        obj_ = obj;
        att_name_ = kInvalidString;
        value_from_ = kInvalidString;
        value_to_ = kInvalidString;
        father_ = father;
        obj_index_ = obj_index;
    }
public:
    /** @brief 默认构造函数
    @return 无
    */
    XmlAction()
        :vid_(kInvalidVersionId), type_(kEXAT_unkown),
        father_(NULL), obj_index_(kInvalidIndex), obj_(NULL),
        att_name_(kInvalidString), value_from_(kInvalidString), value_to_(kInvalidString),
        father_from_(NULL), father_to_(NULL),
        dic_(NULL)/*, db_(NULL)*/, father_xpath_(kInvalidString)
    {}

    /** @brief 默认析构函数
    @return 无
    */
    ~XmlAction()
    {
        //如果采用析构函数实现回滚,就没有返回值
    }

    /** @brief 拷贝构造函数
    @return 无
    */
    XmlAction(const XmlAction &t)
        :vid_(t.vid_), type_(t.type_),
        father_(t.father_), obj_index_(t.obj_index_), obj_(t.obj_),
        att_name_(t.att_name_), value_from_(t.value_from_), value_to_(t.value_to_),
        father_from_(t.father_from_), father_to_(t.father_to_),
        dic_(t.dic_)/*, db_(t.db_)*/, father_xpath_(t.father_xpath_)
    {}

    /** @brief 拷贝赋值函数
    @return 无
    */
    XmlAction &operator=(const XmlAction &t)
    {
        if (this == &t)
        {
            return *this;
        }
        vid_ = t.vid_;
        type_ = t.type_;
        father_ = t.father_;
        obj_index_ = t.obj_index_;
        obj_ = t.obj_;
        att_name_ = t.att_name_;
        value_from_ = t.value_from_;
        value_to_ = t.value_to_;
        father_from_ = t.father_from_;
        father_to_ = t.father_to_;
        dic_ = t.dic_;
        //db_ = t.db_;
        father_xpath_ = t.father_xpath_;
        return *this;
    }

    /** @brief 大小比较
    @return 是否小于
    */
    bool operator<(const XmlAction &t)const
    {
        return vid_ < t.vid_;
    }
public:
    /** @brief 单个操作的回滚 */
    bool RollBack()
    {
        if (vid_ == kInvalidVersionId)
        {
            return false;
        }
        switch (type_)
        {
        case kEXAT_unkown:            return false;
        case kEXAT_att_add:           return RollBackAttAdd();
        case kEXAT_att_delete:        return RollBackAttDelete();
        case kEXAT_att_change:        return RollBackAttChange();
        case kEXAT_node_add:          return RollBackNodeAdd();
        case kEXAT_node_delete:       return RollBackNodeDelete();
        case kEXAT_node_remove:       return RollBackNodeRemove();
        case kEXAT_node_change:       return RollBackNodeChange();
        case kEXAT_text_change:       return RollBackTextChange();
        case kEXAT_father_change:     return RollBackFatherChange();
            //
        case kEXAT_word_key_change:   return RollBackWordKeyChange();
        case kEXAT_word_value_change: return RollBackWordValueChange();
        case kEXAT_word_add:          return RollBackWordAdd();
        case kEXAT_word_delete:       return RollBackWordDelete();
        case kEXAT_word_change:       return RollBackWordChange();
            //
        //case kEXAT_db_key_desc_add:   return RollBackDbAdd();
        //case kEXAT_db_key_desc_delete:return RollBackDbDelete();
        //case kEXAT_db_key_desc_change:return RollBackDbChange();
            //
        default:                      return false;
        }
    }
private:
    //db key desc的回滚
    /** @brief db key desc变更的回滚:增 */
    //bool RollBackDbAdd()
    //{
    //    if (db_ == NULL)
    //    {
    //        return false;
    //    }
    //    if (att_name_ == kXmlKeyAttName)
    //    {
    //        return db_->DeleteKey(value_to_, father_xpath_);
    //    }
    //    if (att_name_ == kXmlDescAttName)
    //    {
    //        return db_->DeleteDesc(value_to_, father_xpath_);
    //    }
    //    return false;
    //}
    /** @brief db key desc变更的回滚:删 */
    //bool RollBackDbDelete()
    //{
    //    if (db_ == NULL)
    //    {
    //        return false;
    //    }
    //    if (att_name_ == kXmlKeyAttName)
    //    {
    //        return db_->AddKey(value_from_, father_xpath_);
    //    }
    //    if (att_name_ == kXmlDescAttName)
    //    {
    //        return db_->AddDesc(value_from_, father_xpath_);
    //    }
    //    return false;
    //}
    /** @brief db key desc变更的回滚:改 */
    //bool RollBackDbChange()
    //{
    //    if (db_ == NULL)
    //    {
    //        return false;
    //    }
    //    if (att_name_ == kXmlKeyAttName)
    //    {
    //        return db_->ChangeKey(value_to_, value_from_, father_xpath_);
    //    }
    //    if (att_name_ == kXmlDescAttName)
    //    {
    //        return db_->ChangeDesc(value_to_, value_from_, father_xpath_);
    //    }
    //    return false;
    //}

private:
    /** @brief 语言变更的回滚 */
    bool RollBackWordKeyChange()
    {
        if (dic_ == NULL)
        {
            return false;
        }
        //dic_->set_key_name(value_from_);//与RollBackWordValueChange合并
        return false;
    }

    /** @brief 语言变更的回滚 */
    bool RollBackWordValueChange()
    {
        if (dic_ == NULL)
        {
            return false;
        }
        dic_->SetCurrentLanguage(value_from_);
        return true;
    }

    /** @brief 词条添加的回滚 */
    bool RollBackWordAdd()
    {
        if (dic_ == NULL)
        {
            return false;
        }
        dic_->DeleteGuid(att_name_);//att_name_是guid的值
        return true;
    }

    /** @brief 词条删除的回滚 */
    bool RollBackWordDelete()
    {
        if (dic_ == NULL)
        {
            return false;
        }
        dic_->AddStringByGuid(att_name_, value_from_, obj_index_); //TODO 回滚时未考虑GUID重复问题
        return true;
    }

    /** @brief 词条变更的回滚 */
    bool RollBackWordChange()
    {
        if (dic_ == NULL)
        {
            return false;
        }
        dic_->ChangeStringByGuid(att_name_, value_from_);
        return true;
    }

private:
    /** @brief 属性添加的回滚 */
    bool RollBackAttAdd()
    {
        if (obj_ == NULL)
        {
            return false;
        }
        obj_->DeleteProperty(att_name_);//TODO 派生类属性是否处理?
        return true;
    }

    /** @brief 属性删除的回滚 */
    bool RollBackAttDelete()
    {
        if (obj_ == NULL)
        {
            return false;
        }
        obj_->SetProperty(att_name_, value_from_);//TODO 派生类属性是否处理?
        return true;
    }

    /** @brief 属性变更的回滚 */
    bool RollBackAttChange()
    {
        if (obj_ == NULL)
        {
            return false;
        }
        obj_->SetProperty(att_name_, value_from_);//TODO 派生类属性是否处理?
        return true;
    }

    /** @brief text变更的回滚 */
    bool RollBackTextChange()
    {
        if (obj_ == NULL)
        {
            return false;
        }
        obj_->set_text(value_from_);//TODO 派生类属性是否处理?
        return true;
    }

    /** @brief 父节点变更的回滚 */
    bool RollBackFatherChange()
    {
        if (obj_ == NULL)
        {
            return false;
        }
        obj_->set_xml_parent(father_from_);//TODO 派生类属性是否处理?
        return true;
    }

    /** @brief 子节点添加的回滚 */
    bool RollBackNodeAdd()
    {
        if (father_ == NULL)
        {
            return false;
        }
        //bool b = father_->DeleteChild(obj_);
        bool b = father_->RemoveChild(obj_);//存在移除操作,此处无法分辨是否该释放内存
        obj_ = NULL;//TODO 支持回滚后,此处应该delete
        return b;
    }

    /** @brief 子节点删除的回滚 */
    bool RollBackNodeDelete()
    {
        if (father_ == NULL)
        {
            return false;
        }
        bool b = father_->AddChild(obj_index_, obj_);
        obj_index_ = kInvalidIndex;
        obj_ = NULL;
        return b;
    }

    /** @brief 子节点移除的回滚 */
    bool RollBackNodeRemove()
    {
        if (father_ == NULL)
        {
            return false;
        }
        bool b = father_->AddChild(obj_index_, obj_);
        obj_index_ = kInvalidIndex;
        obj_ = NULL;
        return b;
    }

    /** @brief 子节点变更的回滚 */
    bool RollBackNodeChange()
    {
        if (father_ == NULL)
        {
            return false;
        }
        return false;//本函数没有实际意义
    }

public:
    /** @brief 获得操作类型 */
    EnumXmlActionType GetActionType()const
    {
        return type_;
    }
    
    /** @brief 获得当前操作对象的指针 */
    XmlNodeT* GetObj()
    {
        return obj_;
    }

private:
    int vid_; /**< 版本id*/
    EnumXmlActionType type_; /**< 操作类型*/
    XmlNodeT *father_; /**< 父节点,仅当增删节点时有用*/
    int obj_index_; /**< 当前节点在父节点中的序号,从0开始,仅当增删节点时有用*/
    XmlNodeT *obj_; /**< 当前变更的节点*/
    XBaseString att_name_; /**< 属性名*/
    XBaseString value_from_; /**< 修改前的属性值*/
    XBaseString value_to_; /**< 修改后的属性值*/
    //仅在父节点变更时有效
    XmlNodeT *father_from_; /**< 修改父节点时,存储修改前的父节点指针*/
    XmlNodeT *father_to_; /**< 修改父节点时,存储修改后的父节点指针*/

    //词条变更,key变更、value变更、key-value的增删改(没有remove)
    //key变更,value_from_,value_to_,ver_id、修改类型、DicT *dic
    //value变更,value_from_,value_to_,ver_id、修改类型、DicT *dic
    //key-value增,att_name_,value_to_,ver_id、修改类型、DicT *dic
    //删,att_name_,value_from_,ver_id、修改类型、DicT *dic
    //改,att_name_,value_from_,value_to_,ver_id、修改类型、DicT *dic
    DicT *dic_; /**< 词条变更相关的DictionaryClass类对象,其它信息存储重用其它变量*/
    //
    //KeyDbT *db_; /**< key desc DB对象*/
    XBaseString father_xpath_; /**< 数据库增删改时需要给出父节点路径*/
};

回滚控制类


/** @brief 回滚管理类。
内存中的xml文件回滚,基于XmlNodeT实现。
加入词条回滚。
保存到文件后不支持回滚。
*/
template<class XmlNodeT, class DicT/*, class KeyDbT*/>
class XmlObjectRollBackManager
{
public:
    typedef std::set<XmlNodeT*> XmlObjectPointSet;
    typedef XmlAction<XmlObject, DicT/*, KeyDbT*/> MyXmlAction;
    typedef std::vector<MyXmlAction *> XmlActionVector;
public:
    /** @brief 默认构造函数 */
    XmlObjectRollBackManager()
    {
        remember_action_ = false;
        //version_id_ = kInValidVersionId;
        action_vector_ = new XmlActionVector;
        obj_set_ = new XmlObjectPointSet;
    }

    /** @brief 默认析构函数 */
    ~XmlObjectRollBackManager()
    {
        if (this == NULL)
        {
            return;
        }
        if (action_vector_)
        {
            ClearVersionData();
            delete action_vector_;
            action_vector_ = NULL;
        }
        if (obj_set_)
        {
            ClearObjSet();
            delete obj_set_;
            obj_set_ = NULL;
        }
        //version_id_ = kInValidVersionId;
    }

private:
    /** @brief 清空删除节点时临时保存的子节点。外部目前没有此接口需求 */
    void ClearObjSet()
    {
        if (this == NULL)
        {
            return;
        }
        for (XmlObjectPointSet::iterator i = obj_set_->begin();
            i != obj_set_->end(); ++i)
        {
            XmlNodeT *p = *i;
            delete p;
        }
        obj_set_->clear();
    }

public:
    /** @brief db key desc添加
    @param [in] db 数据库管理对象
    @param [in] att_name 属性名
    @param [in] value_to 添加的属性值
    @param [in] father_xpath 父节点的xpath
    @return 是否成功监控
    */
    //bool DbKeyDescAdd(KeyDbT *db, const XBaseString &att_name,
    //    const XBaseString &value_to, const XBaseString &father_xpath)
    //{
    //    if (this == NULL)
    //    {
    //        return false;
    //    }
    //    if (remember_action_ == false)
    //    {
    //        return true;
    //    }
    //    int vid = GetCurrentVersionId() + 1;
    //    if (action_vector_)
    //    {
    //        action_vector_->push_back(new MyXmlAction(kEXAT_db_key_desc_add, vid, db, att_name, "", value_to, father_xpath));
    //        return true;
    //    }
    //    return false;
    //}

    /** @brief db key desc删除
    @param [in] db 数据库管理对象
    @param [in] att_name 属性名
    @param [in] value_from 删除的属性值
    @param [in] father_xpath 父节点的xpath
    @return 是否成功监控
    */
    //bool DbKeyDescDelete(KeyDbT *db, const XBaseString &att_name,
    //    const XBaseString &value_from, const XBaseString &father_xpath)
    //{
    //    if (this == NULL)
    //    {
    //        return false;
    //    }
    //    if (remember_action_ == false)
    //    {
    //        return true;
    //    }
    //    int vid = GetCurrentVersionId() + 1;
    //    if (action_vector_)
    //    {
    //        action_vector_->push_back(new MyXmlAction(kEXAT_db_key_desc_delete, vid, db, att_name, value_from, "", father_xpath));
    //        return true;
    //    }
    //    return false;
    //}

    /** @brief db key desc修改
    @param [in] db 数据库管理对象
    @param [in] att_name 属性名
    @param [in] value_from 修改前的属性值
    @param [in] value_to 修改后的属性值
    @param [in] father_xpath 父节点的xpath
    @return 是否成功监控
    */
    //bool DbKeyDescChange(KeyDbT *db, const XBaseString &att_name,
    //    const XBaseString &value_from, const XBaseString &value_to, const XBaseString &father_xpath)
    //{
    //    if (this == NULL)
    //    {
    //        return false;
    //    }
    //    if (remember_action_ == false)
    //    {
    //        return true;
    //    }
    //    int vid = GetCurrentVersionId() + 1;
    //    if (action_vector_)
    //    {
    //        action_vector_->push_back(new MyXmlAction(kEXAT_db_key_desc_change, vid, db, att_name, value_from, value_to, father_xpath));
    //        return true;
    //    }
    //    return false;
    //}
private:
    /** @brief 词条key变更,此函数不应该被调用 */
    bool WordKeyChange(DicT *dic, const XBaseString &unuse1,
        const XBaseString &unuse2, const XBaseString &unuse3, const int id_temp = kInvalidId)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        return false;//20171222 此函数不应该被调用。词条key变更是指guid变更,应该用其它方式替代。
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_word_key_change, vid, dic, unuse1, unuse2, unuse3, id_temp));
            return true;
        }
        return false;
    }

public:
    /** @brief 语言变更
    @param [in] dic 词条管理对象
    @param [in] guid_name 关键字,一般固定为guid
    @param [in] lan_from 切换前的语言
    @param [in] lan_to 切换后的语言
    @param [in] id_temp 词条id,此处无用
    @return 是否成功监控
    */
    bool WordValueChange(DicT *dic, const XBaseString &guid_name,
        const XBaseString &lan_from, const XBaseString &lan_to, const int id_temp = kInvalidId)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        if (lan_from == lan_to)
        {
            return true;//20171222 减少无效回滚记录,降低内存。
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_word_value_change, vid, dic, guid_name, lan_from, lan_to, id_temp));
            return true;
        }
        return false;
    }

    /** @brief 词条添加
    @param [in] dic 词条管理对象
    @param [in] guid_name 关键字,一般固定为guid
    @param [in] str_from 修改前的词条
    @param [in] str_to 修改后的词条
    @param [in] id_temp 词条id,此处无用
    @return 是否成功监控
    */
    bool WordAdd(DicT *dic, const XBaseString &guid_temp,
        const XBaseString &str_from, const XBaseString &str_to, const int id_temp = kInvalidId)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_word_add, vid, dic, guid_temp, str_from, str_to, id_temp));
            return true;
        }
        return false;
    }

    //词条变更,key变更、value变更、key-value的增删改(没有remove)
    //key变更,          ver_id、修改类型、DicT *dic
    //value变更,att_name_(key),value_from_,value_to_,        ver_id、修改类型、DicT *dic
    //key-value增,att_name_,value_to_,       ver_id、修改类型、DicT *dic
    //删,id,att_name_,value_from_,              ver_id、修改类型、DicT *dic
    //改,att_name_,value_from_,value_to_,    ver_id、修改类型、DicT *dic
    //const EnumXmlActionType type_temp, const int vid,
    //    DicT *dic, const XBaseString &att_name,
    //    const XBaseString &value_from, const XBaseString &value_to, const int id_temp
    /** @brief 词条删除
    @param [in] dic 词条管理对象
    @param [in] guid_name 关键字,一般固定为guid
    @param [in] str_from 修改前的词条
    @param [in] str_to 修改后的词条
    @param [in] id_temp 词条id,回复时需要指定id
    @return 是否成功监控
    */
    bool WordDelete(DicT *dic, const XBaseString &guid_temp,
        const XBaseString &str_from, const XBaseString &str_to, const int id_temp)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_word_delete, vid, dic, guid_temp, str_from, str_to, id_temp));
            return true;
        }
        return false;
    }

    /** @brief 词条修改
    @param [in] dic 词条管理对象
    @param [in] guid_name 关键字,一般固定为guid
    @param [in] str_from 修改前的词条
    @param [in] str_to 修改后的词条
    @param [in] id_temp 词条id,回复时需要指定id
    @return 是否成功监控
    */
    bool WordChange(DicT *dic, const XBaseString &guid_temp,
        const XBaseString &str_from, const XBaseString &str_to, const int id_temp = kInvalidId)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        if (str_from == str_to)
        {
            return true;//20171222 减少无效回滚记录,降低内存。
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_word_change, vid, dic, guid_temp, str_from, str_to, id_temp));
            return true;
        }
        return false;
    }
public:
    /** @brief 属性增:XmlNodeT * obj 、属性名
    @param [in] obj 属性变更的节点指针
    @param [in] att_name 属性名
    @return 是否成功监控
    */
    bool AddAtt(XmlNodeT *obj, const XBaseString &att_name)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_att_add, vid, obj, att_name));
            return true;
        }
        return false;
    }

    /** @brief 属性改:XmlNodeT *obj 、属性名、修改前的属性值、修改后的属性值
    @param [in] obj 属性变更的节点指针
    @param [in] att_name 属性名
    @param [in] value_from 属性修改前的值
    @param [in] value_to 属性修改后的值
    @return 是否成功监控
    */
    bool ChangeAtt(XmlNodeT *obj, const XBaseString &att_name,
        const XBaseString &value_from, const XBaseString &value_to)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        if (value_from == value_to)
        {
            return true;//20171222 减少无效回滚记录,降低内存。
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_att_change, vid, obj, att_name, value_from, value_to));
            return true;
        }
        return false;
    }
    
    /** @brief 属性text改:XmlNodeT *obj 、属性名、修改前的属性值、修改后的属性值
    @param [in] obj 属性变更的节点指针
    @param [in] att_name 属性名
    @param [in] value_from 属性修改前的值
    @param [in] value_to 属性修改后的值
    @return 是否成功监控
    */
    bool ChangeText(XmlNodeT *obj, const XBaseString &value_from, const XBaseString &value_to)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        if (value_from == value_to)
        {
            return true;//20171222 减少无效回滚记录,降低内存。
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_text_change, vid, obj, kXmlTextAttName, value_from, value_to));
            return true;
        }
        return false;
    }
    
    /** @brief father改:XmlNodeT *obj 、修改前的father、修改后的father
    @param [in] obj 属性变更的节点指针
    @param [in] father_from 变更前父节点
    @param [in] father_to 变更后父节点
    @return 是否成功监控
    */
    bool ChangeFather(XmlNodeT *obj, XmlNodeT *father_from, XmlNodeT *father_to)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        if (father_from == father_to)
        {
            return true;//20171222 减少无效回滚记录,降低内存。
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_father_change, vid, obj, father_from, father_to));
            return true;
        }
        return false;
    }

    /** @brief 属性删:XmlNodeT * obj 、属性名、属性值
    @param [in] obj 属性变更的节点指针
    @param [in] att_name 属性名
    @param [in] value_from 变更前属性值
    @return 是否成功监控
    */
    bool DeleteAtt(XmlNodeT *obj, const XBaseString &att_name,
        const XBaseString &value_from)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_att_delete, vid, obj, att_name, value_from));
            return true;
        }
        return false;
    }

    /** @brief 
    节点改:实际无此需求,等价于属性变更、子节点增删
    节点增:XmlNodeT *father、child_index、XmlNodeT *child
    @param [in] father 父节点
    @param [in] obj_index 子节点在父节点中的序号
    @param [in] obj 子节点
    @return 是否成功监控
    */
    bool AddNode(XmlNodeT *father, const int obj_index, XmlNodeT *obj)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_node_add, vid, father, obj_index, obj));
            XmlObjectPointSet::iterator iter_temp = obj_set_->find(obj);
            if (iter_temp != obj_set_->end())
            {
                obj_set_->erase(iter_temp);
            }
            return true;
        }
        return false;
    }

    /** @brief 节点删:XmlNodeT *father、child_index、XmlNodeT *child
    @param [in] father 父节点
    @param [in] obj_index 子节点在父节点中的序号
    @param [in] obj 子节点
    @return 是否成功监控
    */
    bool DeleteNode(XmlNodeT *father, const int obj_index, XmlNodeT *obj)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_node_delete, vid, father, obj, obj_index));
            obj_set_->insert(obj);
            return true;
        }
        return false;
    }

    /** @brief 节点移除:XmlNodeT *father、child_index、XmlNodeT *child
    @param [in] father 父节点
    @param [in] obj_index 子节点在父节点中的序号
    @param [in] obj 子节点
    @return 是否成功监控
    */
    bool RemoveNode(XmlNodeT *father, const int obj_index, XmlNodeT *obj)
    {
        if (this == NULL)
        {
            return false;
        }
        if (gOpenCurrentRollBack == false)
        {
            return false;
        }
        if (remember_action_ == false)
        {
            return true;
        }
        int vid = GetCurrentVersionId() + 1;
        if (action_vector_)
        {
            action_vector_->push_back(new MyXmlAction(kEXAT_node_remove, vid, obj_index, father, obj));
            obj_set_->insert(obj);
            return true;
        }
        return false;
    }
public:
    /** @brief 回滚到指定版本号(不含)
    @param [in] version_id 指定版本号
    @return 是否成功回滚
    */
    bool RollbackTo(const int version_id)
    {
        if (this == NULL)
        {
            return false;
        }
        if (version_id < -1 || version_id >= (int)(action_vector_->size()))
        {
            return false;//版本号取值范围为[0, action_vector_->size() - 1]
        }
        bool b = remember_action();
        set_remember_action(false); //回滚时必须关闭操作记录
        for (int i = (int)(action_vector_->size() - 1); i > version_id; --i)
        {
            //倒序回滚
            MyXmlAction *p = action_vector_->at(i);
            if (p)
            {
                EnumXmlActionType type_temp = p->GetActionType();
                XmlNodeT *pobj = p->GetObj();
                p->RollBack();
                switch (type_temp)
                {
                case kEXAT_node_add:
                    obj_set_->insert(pobj);
                    break;
                case kEXAT_node_delete:
                case kEXAT_node_remove:
                {
                    XmlObjectPointSet::iterator iter_temp = obj_set_->find(pobj);
                    if (iter_temp != obj_set_->end())
                    {
                        obj_set_->erase(iter_temp);
                    }
                    //obj_set_->erase(obj_set_->find(pobj));
                    break;
                }
                default:
                    break;
                }
                delete p;
            }
            else
            {
                return false;//TODO log
            }
        }
        set_remember_action(b);
        if (action_vector_->size() > 0)
        {
            int off_temp = version_id + 1;
            if (off_temp >= 0 && off_temp < (int)action_vector_->size())
            {
                action_vector_->erase(action_vector_->begin() + off_temp, action_vector_->end());
                //action_vector_->erase(action_vector_->begin() + version_id + 1, action_vector_->end());
            }
        }
        return true;
    }

    /** @brief 回滚所有操作
    @return 是否成功回滚
    */
    bool RollbackAll()
    {
        if (this == NULL)
        {
            return false;
        }
        return RollbackTo(kInvalidVersionId);
    }

    /** @brief 获得当前版本号
    @return 当前版本号
    */
    int GetCurrentVersionId()
    {
        if (this == NULL)
        {
            return kInvalidVersionId;
        }
        //return version_id_;
        return ((int)(action_vector_->size())) - 1;
    }

    /** @brief 清空部分操作记录
    @param [in] version_id 指定版本号
    @return 是否成功
    */
    bool ClearVersionDataFromVersion(const int version_id)
    {
        if (this == NULL)
        {
            return false;
        }
        //清空范围(version_id, action_vector_->size()),首尾均不包含
        if (version_id < -1 || version_id >= (int)(action_vector_->size()))
        {
            return false;//版本号取值范围为[0, action_vector_->size() - 1]
        }
        for (int i = ((int)(action_vector_->size())) - 1; i > version_id; --i)
        {
            //倒序清空
            MyXmlAction *p = action_vector_->at(i);
            if (p)
            {
                switch (p->GetActionType())
                {
                case kEXAT_node_delete:
                {
                    XmlNodeT *pobj = p->GetObj();
                    delete pobj;
                    XmlObjectPointSet::iterator iter_temp = obj_set_->find(pobj);
                    if (iter_temp != obj_set_->end())
                    {
                        obj_set_->erase(iter_temp);
                    }
                    //obj_set_->erase(obj_set_->find(pobj));
                    break; //内存此时释放
                }
                case kEXAT_node_remove:
                {
                    XmlNodeT *pobj = p->GetObj();
                    XmlObjectPointSet::iterator iter_temp = obj_set_->find(pobj);
                    if (iter_temp != obj_set_->end())
                    {
                        obj_set_->erase(iter_temp);
                    }
                    //obj_set_->erase(obj_set_->find(pobj));
                    break; //内存此时释放
                }
                default:                    break;
                }
                delete p;
            }
            else
            {
                return false;//TODO log
            }
        }
        if (action_vector_->size() > 0)
        {
            int off_temp = version_id + 1;
            if (off_temp >= 0 && off_temp < (int)action_vector_->size())
            {
                action_vector_->erase(action_vector_->begin() + off_temp, action_vector_->end());
                //action_vector_->erase(action_vector_->begin() + version_id + 1, action_vector_->end());
            }
        }
        return true;
    }

    /** @brief 清空所有记录
    @return 是否成功
    */
    bool ClearVersionData() /**< 清空所有记录*/
    {
        if (this == NULL)
        {
            return false;
        }
        return ClearVersionDataFromVersion(kInvalidVersionId);
    }
public:
    /** @brief 设置是否监控
    @param [in] remember_action 是否监控
    @return 无
    */
    void set_remember_action(const bool remember_action = true)
    {
        if (this == NULL)
        {
            return;
        }
        remember_action_ = remember_action;
    }

    /** @brief 返回当前是否正在监控
    @return 是否正在监控
    */
    bool remember_action()const
    {
        if (this == NULL)
        {
            return false;
        }
        return remember_action_;
    }
protected:
private:
    //int version_id_; /**< 版本号*/
    bool remember_action_; /**< 是否记录操作,一般读取sdc文件时都不记录*/
    XmlActionVector *action_vector_; /**< 操作序列*/
    XmlObjectPointSet *obj_set_; /**< 移除删除添加节点操作时临时保存指针,处理内存泄露问题*/
private:
    std::stack<int> step_stack_; /**< step栈,方便外部按复合操作回滚。一个复合操作可能对应几十个原子操作。*/
public:
    /** @brief step栈是否为空
    @return 是否为空
    */
    bool IsStepStackEmpty()const
    {
        return step_stack_.empty();
    }
    /** @brief 保存当前步骤的版本号
    @return 当前版本号
    */
    int PushStep()
    {
        int ver_id_temp = GetCurrentVersionId();
        step_stack_.push(ver_id_temp);
        return ver_id_temp;
    }
    /** @brief 回滚一个复合操作
    @return 是否成功
    */
    bool PopStep()
    {
        if (IsStepStackEmpty())
        {
            return false;//step栈为空
        }
        int ver_id_temp = step_stack_.top();
        step_stack_.pop();
        return RollbackTo(ver_id_temp);
    }
};

控制进程内全局唯一对象的方法
头文件

typedef XmlObjectRollBackManager<XmlObject, DictionaryClass> XmlNodeRBM;
extern X_EXPORT XmlNodeRBM *gCurrentRollBack; /**< 内存操作监控、词条增删改监控*/
extern X_EXPORT bool gOpenCurrentRollBack/* = false*/; /**< 简化关闭全局回滚模块,大量代码需要快速关闭快速打开*/

cpp中定义

/* 内存操作监控、词条增删改监控。
   进程内唯一对象指针,多个XmlParse对象时,在一个时刻只能指向一个。*/
//CAXB_EXPORT XmlObjectRollBackManager<XmlObject, DictionaryClass/*, KeyManager*/> *gCurrentRollBack = NULL;
X_EXPORT XmlNodeRBM *gCurrentRollBack = NULL;
X_EXPORT bool gOpenCurrentRollBack = false; 

以上未考虑多文件,加入支持多文件应该类似,在xml节点中存储回滚管理类对象指针。

猜你喜欢

转载自blog.csdn.net/weixin_43172531/article/details/103769628