Refactor persist_context to correct subnamespace crash and avoid holding stale config references in general.
This commit is contained in:
parent
70902724a6
commit
c6da4fcbd0
2 changed files with 92 additions and 119 deletions
|
@ -53,30 +53,29 @@ persist_file_context::persist_file_context(const std::string &name_space)
|
|||
: persist_context(name_space)
|
||||
{
|
||||
load();
|
||||
root_node_.init();
|
||||
active_ = &(root_node_.child(namespace_.next()));
|
||||
}
|
||||
|
||||
bool persist_file_context::clear_var(const std::string &global, bool immediate)
|
||||
{
|
||||
// if (cfg_.empty()) {
|
||||
// load_persist_data(namespace_.root(),cfg_);
|
||||
// }
|
||||
|
||||
config bak;
|
||||
config bactive;
|
||||
if (immediate) {
|
||||
bak = cfg_;
|
||||
bactive = active_->cfg_.child_or_add("variables");
|
||||
config *node = get_node(bak, namespace_);
|
||||
if (node)
|
||||
bactive = node->child_or_add("variables");
|
||||
load();
|
||||
root_node_.init();
|
||||
}
|
||||
config &cfg = active_->cfg_.child_or_add("variables");
|
||||
bool ret(cfg);
|
||||
config *active = get_node(cfg_, namespace_);
|
||||
if (active == NULL)
|
||||
return false;
|
||||
|
||||
bool ret = active->has_child("variables");
|
||||
if (ret) {
|
||||
config &cfg = active->child("variables");
|
||||
bool exists = cfg.has_attribute(global);
|
||||
if (!exists) {
|
||||
if (cfg.child(global)) {
|
||||
if (cfg.has_child(global)) {
|
||||
exists = true;
|
||||
std::string::const_iterator index_start = std::find(global.begin(),global.end(),'[');
|
||||
if (index_start != global.end())
|
||||
|
@ -96,52 +95,69 @@ bool persist_file_context::clear_var(const std::string &global, bool immediate)
|
|||
cfg.remove_attribute(global);
|
||||
if (immediate) bactive.remove_attribute(global);
|
||||
if (cfg.empty()) {
|
||||
active_->cfg_.clear_children("variables");
|
||||
active_->cfg_.remove_attribute("variables");
|
||||
while ((active_->cfg_.empty()) && (active_->parent_ != NULL)) {
|
||||
active_ = active_->parent_;
|
||||
active_->remove_child(namespace_.node_);
|
||||
namespace_ = namespace_.prev();
|
||||
active->clear_children("variables");
|
||||
active->remove_attribute("variables");
|
||||
name_space working = namespace_;
|
||||
while ((active->empty()) && (!working.lineage_.empty())) {
|
||||
name_space prev = working.prev();
|
||||
active = get_node(cfg_, prev);
|
||||
active->clear_children(working.node_);
|
||||
if (active->has_child("variables") && active->child("variables").empty()) {
|
||||
active->clear_children("variables");
|
||||
active->remove_attribute("variables");
|
||||
}
|
||||
working = prev;
|
||||
}
|
||||
}
|
||||
// dirty_ = true;
|
||||
|
||||
if (!in_transaction_)
|
||||
ret = save_context();
|
||||
else if (immediate) {
|
||||
ret = save_context();
|
||||
cfg_ = bak;
|
||||
root_node_.init();
|
||||
active_->cfg_.clear_children("variables");
|
||||
active_->cfg_.remove_attribute("variables");
|
||||
active_->cfg_.add_child("variables",bactive);
|
||||
config &cfg = active_->cfg_.child("variables");
|
||||
if (cfg.empty()) {
|
||||
active_->cfg_.clear_children("variables");
|
||||
active_->cfg_.remove_attribute("variables");
|
||||
while ((active_->cfg_.empty()) && (active_->parent_ != NULL)) {
|
||||
active_ = active_->parent_;
|
||||
active_->remove_child(namespace_.node_);
|
||||
namespace_ = namespace_.prev();
|
||||
}
|
||||
active = get_node(cfg_, namespace_);
|
||||
if (active != NULL) {
|
||||
active->clear_children("variables");
|
||||
active->remove_attribute("variables");
|
||||
if (!bactive.empty())
|
||||
active->add_child("variables",bactive);
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
} else {
|
||||
if (immediate) {
|
||||
cfg_ = bak;
|
||||
config *active = get_node(cfg_, namespace_);
|
||||
if (active != NULL) {
|
||||
active->clear_children("variables");
|
||||
active->remove_attribute("variables");
|
||||
if (!bactive.empty())
|
||||
active->add_child("variables",bactive);
|
||||
}
|
||||
}
|
||||
ret = exists;
|
||||
}
|
||||
}
|
||||
while ((active->empty()) && (!namespace_.lineage_.empty())) {
|
||||
name_space prev = namespace_.prev();
|
||||
active = get_node(cfg_, prev);
|
||||
active->clear_children(namespace_.node_);
|
||||
if (active->has_child("variables") && active->child("variables").empty()) {
|
||||
active->clear_children("variables");
|
||||
active->remove_attribute("variables");
|
||||
}
|
||||
namespace_ = prev;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
config persist_file_context::get_var(const std::string &global) const
|
||||
{
|
||||
config ret;
|
||||
// if (cfg_.empty()) {
|
||||
// load_persist_data(namespace_,cfg_,false);
|
||||
// }
|
||||
|
||||
config &cfg = active_->cfg_.child("variables");
|
||||
if (cfg) {
|
||||
const config *active = get_node(cfg_, namespace_);
|
||||
if (active && (active->has_child("variables"))) {
|
||||
const config &cfg = active->child("variables");
|
||||
size_t arrsize = cfg.child_count(global);
|
||||
if (arrsize > 0) {
|
||||
for (size_t i = 0; i < arrsize; i++)
|
||||
|
@ -180,19 +196,16 @@ bool persist_file_context::save_context() {
|
|||
}
|
||||
bool persist_file_context::set_var(const std::string &global,const config &val, bool immediate)
|
||||
{
|
||||
// if (cfg_.empty()) {
|
||||
// load_persist_data(namespace_,cfg_);
|
||||
// }
|
||||
config bak;
|
||||
config bactive;
|
||||
if (immediate) {
|
||||
bak = cfg_;
|
||||
bactive = active_->cfg_.child_or_add("variables");
|
||||
bactive = get_node(bak, namespace_, true)->child_or_add("variables");
|
||||
load();
|
||||
root_node_.init();
|
||||
}
|
||||
|
||||
config &cfg = active_->cfg_.child_or_add("variables");
|
||||
config *active = get_node(cfg_, namespace_, true);
|
||||
config &cfg = active->child_or_add("variables");
|
||||
if (val.has_attribute(global)) {
|
||||
if (val[global].empty()) {
|
||||
clear_var(global,immediate);
|
||||
|
@ -214,17 +227,20 @@ bool persist_file_context::set_var(const std::string &global,const config &val,
|
|||
else if (immediate) {
|
||||
bool ret = save_context();
|
||||
cfg_ = bak;
|
||||
root_node_.init();
|
||||
active_->cfg_.clear_children("variables");
|
||||
active_->cfg_.remove_attribute("variables");
|
||||
active_->cfg_.add_child("variables",bactive);
|
||||
active = get_node(cfg_, namespace_, true);
|
||||
active->clear_children("variables");
|
||||
active->remove_attribute("variables");
|
||||
active->add_child("variables",bactive);
|
||||
return ret;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
void persist_context::set_node(const std::string &name) {
|
||||
active_ = &(root_node_.child(name));
|
||||
namespace_ = name_space(namespace_.namespace_ + "." + name);
|
||||
std::string newspace = namespace_.root_;
|
||||
if (!name.empty())
|
||||
newspace += "." + name;
|
||||
namespace_ = name_space(newspace);
|
||||
}
|
||||
|
||||
std::string persist_context::get_node() const
|
||||
|
|
|
@ -99,80 +99,14 @@ public:
|
|||
}
|
||||
};
|
||||
protected:
|
||||
struct node {
|
||||
typedef std::map<std::string,node*> child_map;
|
||||
|
||||
std::string name_;
|
||||
persist_context *root_;
|
||||
node *parent_;
|
||||
child_map children_;
|
||||
config &cfg_;
|
||||
|
||||
node(std::string name, persist_context *root, config & cfg, node *parent = NULL)
|
||||
: name_(name)
|
||||
, root_(root)
|
||||
, parent_(parent)
|
||||
, children_()
|
||||
, cfg_(cfg)
|
||||
{
|
||||
}
|
||||
|
||||
~node() {
|
||||
for (child_map::iterator i = children_.begin(); i != children_.end(); ++i)
|
||||
delete (i->second);
|
||||
}
|
||||
config &cfg() { return cfg_; }
|
||||
node &add_child(const std::string &name) {
|
||||
children_[name] = new node(name,root_,cfg_.child_or_add(name),this);
|
||||
return *(children_[name]);
|
||||
}
|
||||
bool remove_child(const std::string &name) {
|
||||
bool ret = false;
|
||||
if (children_.find(name) != children_.end()) {
|
||||
cfg_.clear_children(name);
|
||||
cfg_.remove_attribute(name);
|
||||
if (cfg_.child("variables").empty()) {
|
||||
cfg_.clear_children("variables");
|
||||
cfg_.remove_attribute("variables");
|
||||
}
|
||||
delete children_[name];
|
||||
children_.erase(name);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
node &child(const name_space &name) {
|
||||
if (name) {
|
||||
if (children_.find(name.root_) == children_.end())
|
||||
add_child(name.root_);
|
||||
node &chld = *children_[name.root_];
|
||||
return chld.child(name.next());
|
||||
}
|
||||
else return *this;
|
||||
}
|
||||
void init () {
|
||||
for (config::all_children_iterator i = cfg_.ordered_begin(); i != cfg_.ordered_end(); ++i) {
|
||||
if (i->key != "variables") {
|
||||
child(i->key).init();
|
||||
}
|
||||
}
|
||||
if (!cfg_.child("variables"))
|
||||
cfg_.add_child("variables");
|
||||
}
|
||||
};
|
||||
|
||||
config cfg_;
|
||||
name_space namespace_;
|
||||
node root_node_;
|
||||
node *active_;
|
||||
bool valid_;
|
||||
bool in_transaction_;
|
||||
|
||||
persist_context()
|
||||
: cfg_()
|
||||
, namespace_()
|
||||
, root_node_("",this,cfg_)
|
||||
, active_(&root_node_)
|
||||
, valid_(false)
|
||||
, in_transaction_(false)
|
||||
{};
|
||||
|
@ -180,12 +114,36 @@ protected:
|
|||
persist_context(const std::string &name_space)
|
||||
: cfg_()
|
||||
, namespace_(name_space,true)
|
||||
, root_node_(namespace_.root_,this,cfg_)
|
||||
, active_(&root_node_)
|
||||
, valid_(namespace_.valid())
|
||||
, in_transaction_(false)
|
||||
{};
|
||||
|
||||
config *get_node(config &cfg, name_space &ns, bool force = false) {
|
||||
name_space next = ns.next();
|
||||
if (next) {
|
||||
if (force)
|
||||
return get_node(cfg.child_or_add(next.root_), next, true);
|
||||
else if (cfg.has_child(next.root_))
|
||||
return get_node(cfg.child(next.root_), next);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return &cfg;
|
||||
}
|
||||
|
||||
const config *get_node(const config &cfg, const name_space &ns) const {
|
||||
name_space next = ns.next();
|
||||
if (next) {
|
||||
if (cfg.has_child(next.root_))
|
||||
return get_node(cfg.child(next.root_), next);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
return &cfg;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual bool clear_var(const std::string &, bool immediate = false) = 0;
|
||||
virtual config get_var(const std::string &) const = 0;
|
||||
|
@ -231,7 +189,6 @@ public:
|
|||
if (!in_transaction_)
|
||||
return false;
|
||||
load();
|
||||
root_node_.init();
|
||||
in_transaction_ = false;
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue