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;
}
Exemple #3
0
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;
}