static CfgNode * _get_commit_other_node(CfgNode *cfg1, CfgNode *cfg2, const Cpath& cur_path) { string name, value; bool not_tag_node, is_value, is_leaf_typeless; vector<CfgNode *> rcnodes1, rcnodes2; cnode::cmp_non_leaf_nodes(cfg1, cfg2, rcnodes1, rcnodes2, not_tag_node, is_value, is_leaf_typeless, name, value); if (!cfg1) { return _create_commit_cfg_node(*cfg2, cur_path, COMMIT_STATE_ADDED); } else if (!cfg2) { return _create_commit_cfg_node(*cfg1, cur_path, COMMIT_STATE_DELETED); } CfgNode *cn = _create_commit_cfg_node(*cfg1, cur_path, COMMIT_STATE_UNCHANGED); for (size_t i = 0; i < rcnodes1.size(); i++) { CfgNode *cnode = getCommitTree(rcnodes1[i], rcnodes2[i], cn->getCommitPath()); if (cnode) { cn->addChildNode(cnode); } } if (cn->numChildNodes() < 1) { delete cn; return NULL; } return cn; }
Graph* Connector::connect(Graph* g) { const std::vector<CfgNode*>& nodes = g->getNodes(); std::map<unsigned int, CfgNode*> id2node = getId2Node(nodes); for (unsigned int i = 0; i < nodes.size(); i++) { CfgNode* fromNode = nodes[i]; Cfg* cfg = fromNode->getCfg(); std::vector<unsigned int> nexts = cfg->getNext(); for (unsigned int j = 0; j < nexts.size(); j++) { CfgNode* toNode = id2node[nexts[j]]; if (toNode == NULL) THROWEXCEPTION("next statement is illegal; there is no node with id=%d", nexts[j]); if (connectNodes) // insert the connection in the graph g->addEdge(fromNode, toNode); msg(MSG_INFO, "Connecting module %s[Id = %d] -> %s[Id = %d]", cfg->getName().c_str(), cfg->getID(), id2node[nexts[j]]->getCfg()->getName().c_str(), id2node[nexts[j]]->getCfg()->getID()); if (connectModules) {// connect the modules DPRINTF("connecting instances"); cfg->connectInstances(toNode->getCfg()); } } } return g; }
void ConfigManager::shutdown() { lockGraph(); std::vector<CfgNode*> topoNodes = graph->topoSort(); // shutdown modules for (size_t i = 0; i < topoNodes.size(); i++) { Cfg* cfg = topoNodes[i]->getCfg(); msg(MSG_INFO, "shutting down module %s (id=%u)", cfg->getName().c_str(), cfg->getID()); cfg->shutdown(true, true); } // trigger sensorManager to get the final statistics of this Vermont run if (sensorManager) { sensorManager->retrieveStatistics(true); } // disconnect the modules for (size_t i = 0; i < topoNodes.size(); i++) { CfgNode* n = topoNodes[i]; Cfg* cfg = n->getCfg(); // disconnect the module from its sources .. vector<CfgNode*> sources = graph->getSources(n); msg(MSG_INFO, "disconnecting module %s (id=%u)", cfg->getName().c_str(), cfg->getID()); for (size_t k = 0; k < sources.size(); k++) { sources[k]->getCfg()->disconnectInstances(); } } unlockGraph(); }
static void _set_node_commit_child_delete_failed(CfgNode& node) { // recursively bottom-up node.setCommitChildDeleteFailed(); if (node.getParent()) { _set_node_commit_child_delete_failed(*(node.getParent())); } }
static void _set_node_commit_state(CfgNode& node, CommitState s, bool recursive) { node.setCommitState(s); if (recursive) { for (size_t i = 0; i < node.numChildNodes(); i++) { _set_node_commit_state(*(node.childAt(i)), s, recursive); } } }
// "changed" single-value leaf nodes (this does apply to the value) static CfgNode * _create_commit_cfg_node(const CfgNode& cn, const Cpath& p, const string& val1, const string& val2, bool def1, bool def2) { CfgNode *node = new CfgNode(cn); _set_node_commit_state(*node, COMMIT_STATE_CHANGED, false); _set_node_commit_path(*node, p, false); node->setCommitValue(val1, val2, def1, def2); return node; }
/* "changed" multi-value leaf nodes. note that "changed" state applies to * the "node" itself. the actual states of the node values can be added, * deleted, changed, or unchanged. */ static CfgNode * _create_commit_cfg_node(const CfgNode& cn, const Cpath& p, const vector<string>& values, const vector<CommitState>& states) { CfgNode *node = new CfgNode(cn); _set_node_commit_state(*node, COMMIT_STATE_CHANGED, false); _set_node_commit_path(*node, p, false); node->setCommitMultiValues(values, states); return node; }
static void _set_node_commit_create_failed(CfgNode& node) { // recursively top-down if (node.getCommitState() == COMMIT_STATE_ADDED) { // only set failure if the node is being created node.setCommitCreateFailed(); } for (size_t i = 0; i < node.numChildNodes(); i++) { _set_node_commit_create_failed(*(node.childAt(i))); } }
static void _set_commit_subtree_changed(CfgNode& node) { // recursively bottom-up if (node.commitSubtreeChanged()) { // already set => terminate recursion return; } node.setCommitSubtreeChanged(); if (node.getParent()) { _set_commit_subtree_changed(*(node.getParent())); } }
CfgNode* Graph::addNode(Cfg* cfg) { if (nodes.size() + 1 >= reserved) throw std::runtime_error("can't handle that many nodes"); CfgNode *n = new CfgNode(this, nodes.size()); n->setCfg(cfg); nodes.push_back(n); for (size_t i = 0; i < nodes.size(); i++) { matrix[i][nodes.size()-1] = NULL; matrix[nodes.size()-1][i] = NULL; } return n; }
// nodes other than "changed" leaf nodes static CfgNode * _create_commit_cfg_node(CfgNode& cn, const Cpath& p, CommitState s) { CfgNode *node = new CfgNode(cn); _set_node_commit_state(*node, s, (s != COMMIT_STATE_UNCHANGED)); _set_node_commit_path(*node, p, (s != COMMIT_STATE_UNCHANGED)); if (s == COMMIT_STATE_UNCHANGED) { node->clearChildNodes(); } else { for (size_t i = 0; i < node->numChildNodes(); i++) { node->childAt(i)->setParent(node); } } return node; }
static bool _exec_tmpl_actions(Cstore& cs, CommitState s, char *at_str, const Cpath& path, const Cpath& disp_path, const CfgNode& node, vtw_act_type act, const vtw_def *def) { const vtw_node *actions = node.getActions(act); if (!actions) { // no actions => success return true; } /* XXX this follows the logic in original implementation since some * features are using it. */ const char *aenv = "ACTIVE"; switch (s) { case COMMIT_STATE_ADDED: case COMMIT_STATE_CHANGED: aenv = "SET"; break; case COMMIT_STATE_DELETED: aenv = "DELETE"; break; default: break; } setenv("COMMIT_ACTION", aenv, 1); set_in_delete_action((act == delete_act)); bool ret = cs.executeTmplActions(at_str, path, disp_path, actions, def); set_in_delete_action(false); unsetenv("COMMIT_ACTION"); return ret; }
static void _get_commit_prio_subtrees(CfgNode *sroot, PrioNode& parent) { if (!sroot) { return; } PrioNode *pn = &parent; // need a local copy since nodes can be detached vector<CfgNode *> cnodes = sroot->getChildNodes(); if (sroot->getPriority() && (sroot->isValue() || !sroot->isTag())) { // enforce hierarchical constraint unsigned int prio = sroot->getPriority(); unsigned int pprio = parent.getPriority(); if (prio <= pprio) { // can't have that => make it higher than parent priority OUTPUT_USER("Warning: priority inversion [%s](%u) <= [%s](%u)\n" " changing [%s] to (%u)\n", sroot->getCommitPath().to_string().c_str(), prio, parent.getCommitPath().to_string().c_str(), pprio, sroot->getCommitPath().to_string().c_str(), pprio + 1); sroot->setPriority(pprio + 1); } // only non-"tag node" applies ("tag nodes" not used in prio tree) pn = new PrioNode(sroot); /* record the original parent in config tree. this will be used to * enforce "hierarchical constraint" in the config. skip the tag node * if this is a tag value since commit doesn't act on tag nodes. */ CfgNode *pnode = sroot->getParent(); pn->setCfgParent(sroot->isTag() ? pnode->getParent() : pnode); parent.addChildNode(pn); sroot->detachFromParent(); } for (size_t i = 0; i < cnodes.size(); i++) { _get_commit_prio_subtrees(cnodes[i], *pn); } }
static void _set_node_commit_path(CfgNode& node, const Cpath &p, bool recursive) { node.setCommitPath(p, node.isValue(), node.getValue(), node.getName()); if (recursive) { for (size_t i = 0; i < node.numChildNodes(); i++) { _set_node_commit_path(*(node.childAt(i)), node.getCommitPath(), recursive); } } }
Graph* Connector::connect(Graph* g) { const std::vector<CfgNode*>& nodes = g->getNodes(); std::map<unsigned int, CfgNode*> id2node = getId2Node(nodes); //add a ConnectionQueue to every Module which has more predecessors vector<Cfg*> check; for (unsigned int i = 0; i < nodes.size(); i++) { vector<unsigned int> nexts = nodes[i]->getCfg()->getNext(); for (unsigned int j = 0; j < nexts.size(); j++){ Cfg* successor = id2node[nexts[j]]->getCfg(); bool found = false; for(unsigned int k = 0; k < check.size(); k++){ if(check[k] == successor){ found = true; msg(MSG_INFO, "Creating ConnectionQueue for module %s[Id = %d] because of multiple predecessors", successor->getName().c_str(), successor->getID()); successor->getQueueInstance(true); break; } } if(!found) check.push_back(successor); } } //connect modules for (unsigned int i = 0; i < nodes.size(); i++) { CfgNode* fromNode = nodes[i]; Cfg* cfg = fromNode->getCfg(); std::vector<unsigned int> nexts = cfg->getNext(); if (nexts.size()==0) { cfg->setupWithoutSuccessors(); } else { for (unsigned int j = 0; j < nexts.size(); j++) { CfgNode* toNode = id2node[nexts[j]]; if (toNode == NULL) THROWEXCEPTION("next statement is illegal; there is no node with id=%d", nexts[j]); if (connectNodes) // insert the connection in the graph g->addEdge(fromNode, toNode); msg(MSG_INFO, "Connecting module %s[Id = %d/%08X] -> %s[Id = %d/%08X]", cfg->getName().c_str(), cfg->getID(), cfg->getInstance(), id2node[nexts[j]]->getCfg()->getName().c_str(), id2node[nexts[j]]->getCfg()->getID(), id2node[nexts[j]]->getCfg()->getInstance()); if (connectModules) {// connect the modules DPRINTF("connecting instances"); cfg->connectInstances(toNode->getCfg()); } } } } return g; }
static CommitState _get_commit_multi_state_at(const CfgNode& node, size_t idx) { CommitState s = node.getCommitState(); return (s == COMMIT_STATE_CHANGED ? node.commitMultiStateAt(idx) : s); }
static string _get_commit_multi_value_at(const CfgNode& node, size_t idx) { return (node.getCommitState() == COMMIT_STATE_CHANGED ? node.commitMultiValueAt(idx) : (node.getValues())[idx]); }
static size_t _get_num_commit_multi_values(const CfgNode& node) { return (node.getCommitState() == COMMIT_STATE_CHANGED ? node.numCommitMultiValues() : node.getValues().size()); }
/* execute the specified type of actions on the specified node. * * note that if the "committed list" clist is specified, no action will be * performed except adding the node to the committed list (if needed). */ static bool _exec_node_actions(Cstore& cs, CfgNode& node, vtw_act_type act, CommittedPathListT *clist = NULL) { if (node.isMulti()) { // fail if this is called with a multi node OUTPUT_USER("_exec_node_actions() called with multi[%s]\n", node.getCommitPath().to_string().c_str()); return false; } CommitState s = node.getCommitState(); if (s == COMMIT_STATE_DELETED && node.commitChildDeleteFailed()) { return false; } bool nop = false; if (!node.getActions(act)) { // no actions => success nop = true; } auto_ptr<char> at_str; Cpath pcomps(node.getCommitPath()); tr1::shared_ptr<Cpath> pdisp(new Cpath(pcomps)); bool add_parent_to_committed = false; if (node.isLeaf()) { // single-value node if (s == COMMIT_STATE_CHANGED) { if (node.commitValueBefore() == node.commitValueAfter()) { // value didn't change (only "default" status), so nop nop = true; } at_str.reset(strdup(node.commitValueAfter().c_str())); } else { if (s == COMMIT_STATE_ADDED || s == COMMIT_STATE_DELETED) { // add parent to "committed list" if it's added/deleted add_parent_to_committed = true; } at_str.reset(strdup(node.getValue().c_str())); } pdisp->push(at_str.get()); } else if (node.isValue()) { // tag value at_str.reset(strdup(node.getValue().c_str())); pcomps.pop(); // paths need to be at the "node" level } else { // typeless node at_str.reset(strdup(node.getName().c_str())); } if (clist) { /* note that even though every "tag value" will be added to the * "committed list" here, simply adding the corresponding "tag node" * here does not work. * * basically there are three scenarios for a tag node: * (1) in both active and working * i.e., tag node itself is unchanged => doesn't need to be added * to committed list since "committed query" will check for this * condition first. * (2) only in working * i.e., all tag values are being added so tag node itself is also * being added. in this case, tag node must be considered * "committed" after the first tag value has been processed * successfully. * (3) only in active * i.e., all tag values are being deleted so is tag node itself. * in this case, tag node must be considered "committed" only * after all tag values have been processed successfully. * * cases (2) and (3) cannot be handled here since they depend on the * processing order and outcome of siblings of tag values. therefore, * tag node will never be added to the committed list, and the * "committed query" function will need to handle tag nodes as special * case. */ if (add_parent_to_committed) { tr1::shared_ptr<Cpath> ppdisp(new Cpath(pcomps)); clist->push_back(CommittedPathT(s, ppdisp)); } clist->push_back(CommittedPathT(s, pdisp)); return true; } if (nop) { // nothing to do return true; } if (!_exec_tmpl_actions(cs, s, at_str.get(), pcomps, *(pdisp.get()), node, act, node.getDef())) { if (act == create_act) { _set_node_commit_create_failed(node); } return false; } return true; }
/* execute the specified type of actions on the specified "multi" node (i.e., * multi-value leaf node) during commit. act is one of "delete_act", * "update_act", and "syntax_act", representing the different processing * passes. * * see comment for _exec_node_actions() above about clist. */ static bool _exec_multi_node_actions(Cstore& cs, const CfgNode& node, vtw_act_type act, CommittedPathListT *clist = NULL) { if (!node.isMulti()) { // fail if this is called with a non-multi node OUTPUT_USER("_exec_multi_node_actions() called with non-multi[%s]\n", node.getCommitPath().to_string().c_str()); return false; } const vtw_def *def = node.getDef(); Cpath pcomps(node.getCommitPath()); if (clist) { CommitState s = node.getCommitState(); if (s == COMMIT_STATE_ADDED || s == COMMIT_STATE_DELETED) { /* for multi-value leaf node, add the node itself to the * "committed list" if it is added/deleted. */ tr1::shared_ptr<Cpath> ppdisp(new Cpath(pcomps)); clist->push_back(CommittedPathT(s, ppdisp)); } } for (size_t i = 0; i < _get_num_commit_multi_values(node); i++) { CommitState s = _get_commit_multi_state_at(node, i); if (s == COMMIT_STATE_UNCHANGED) { // nop for unchanged value continue; } string v = _get_commit_multi_value_at(node, i); auto_ptr<char> at_str(strdup(v.c_str())); tr1::shared_ptr<Cpath> pdisp(new Cpath(pcomps)); pdisp->push(v); if (clist) { // add the value to the committed list clist->push_back(CommittedPathT(s, pdisp)); continue; } if (act == syntax_act) { // syntax pass if (s != COMMIT_STATE_ADDED) { continue; } if (!_exec_tmpl_actions(cs, s, at_str.get(), pcomps, *(pdisp.get()), node, syntax_act, def)) { return false; } } else { //// delete or update pass // begin if (!_exec_tmpl_actions(cs, s, at_str.get(), pcomps, *(pdisp.get()), node, begin_act, def)) { return false; } /* note that for CHANGED value we need to do BOTH a delete AND a * create. this is the fix for bug 5460. more information in later * comment about bug 5460. */ if (act == delete_act) { // delete pass if (s == COMMIT_STATE_DELETED || s == COMMIT_STATE_CHANGED) { if (!_exec_tmpl_actions(cs, s, at_str.get(), pcomps, *(pdisp.get()), node, delete_act, def)) { return false; } } } else { // update pass if (s == COMMIT_STATE_ADDED || s == COMMIT_STATE_CHANGED) { if (!_exec_tmpl_actions(cs, s, at_str.get(), pcomps, *(pdisp.get()), node, create_act, def)) { return false; } } } // end if (!_exec_tmpl_actions(cs, s, at_str.get(), pcomps, *(pdisp.get()), node, end_act, def)) { return false; } } } return true; }