예제 #1
0
/* 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;
}
예제 #2
0
/* 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;
}