⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tree.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
      svn_fs_dirent_t *s_entry, *t_entry;      const void *key;      void *val;      apr_ssize_t klen;      svn_pool_clear(iterpool);      apr_hash_this(hi, &key, &klen, &val);      s_entry = val;      t_entry = apr_hash_get(t_entries, key, klen);      /* If NAME exists in TARGET, declare a conflict. */      if (t_entry)        return conflict_err(conflict_p,                            svn_path_join(target_path,                                          t_entry->name,                                          iterpool));      SVN_ERR(svn_fs_fs__dag_set_entry              (target, s_entry->name, s_entry->id, s_entry->kind,               txn_id, iterpool));    }  svn_pool_destroy(iterpool);  SVN_ERR(svn_fs_fs__dag_get_predecessor_count(&pred_count, source, pool));  SVN_ERR(update_ancestry(fs, source_id, target_id, txn_id, target_path,                          pred_count, pool));  return SVN_NO_ERROR;}/* Merge changes between an ancestor and BATON->source_node into   BATON->txn.  The ancestor is either BATON->ancestor_node, or if   that is null, BATON->txn's base node.   If the merge is successful, BATON->txn's base will become   BATON->source_node, and its root node will have a new ID, a   successor of BATON->source_node. */static svn_error_t *merge_changes(dag_node_t *ancestor_node,              dag_node_t *source_node,              svn_fs_txn_t *txn,              svn_stringbuf_t *conflict,              apr_pool_t *pool){  dag_node_t *txn_root_node;  const svn_fs_id_t *source_id;  svn_fs_t *fs = txn->fs;  const char *txn_id = txn->id;  source_id = svn_fs_fs__dag_get_id(source_node);    SVN_ERR(svn_fs_fs__dag_txn_root(&txn_root_node, fs, txn_id, pool));  if (ancestor_node == NULL)    {      SVN_ERR(svn_fs_fs__dag_txn_base_root(&ancestor_node, fs,                                           txn_id, pool));    }    if (svn_fs_fs__id_eq(svn_fs_fs__dag_get_id(ancestor_node),                       svn_fs_fs__dag_get_id(txn_root_node)))    {      /* If no changes have been made in TXN since its current base,         then it can't conflict with any changes since that base.  So         we just set *both* its base and root to source, making TXN         in effect a repeat of source. */            /* ### kff todo: this would, of course, be a mighty silly thing         for the caller to do, and we might want to consider whether         this response is really appropriate. */      abort();    }  else    SVN_ERR(merge(conflict, "/", txn_root_node,                  source_node, ancestor_node, txn_id, pool));  return SVN_NO_ERROR;}svn_error_t *svn_fs_fs__commit_txn(const char **conflict_p,                      svn_revnum_t *new_rev_p,                       svn_fs_txn_t *txn,                      apr_pool_t *pool){  /* How do commits work in Subversion?   *   * When you're ready to commit, here's what you have:   *   *    1. A transaction, with a mutable tree hanging off it.   *    2. A base revision, against which TXN_TREE was made.   *    3. A latest revision, which may be newer than the base rev.   *   * The problem is that if latest != base, then one can't simply   * attach the txn root as the root of the new revision, because that   * would lose all the changes between base and latest.  It is also   * not acceptable to insist that base == latest; in a busy   * repository, commits happen too fast to insist that everyone keep   * their entire tree up-to-date at all times.  Non-overlapping   * changes should not interfere with each other.   *   * The solution is to merge the changes between base and latest into   * the txn tree [see the function merge()].  The txn tree is the   * only one of the three trees that is mutable, so it has to be the   * one to adjust.   *   * You might have to adjust it more than once, if a new latest   * revision gets committed while you were merging in the previous   * one.  For example:   *   *    1. Jane starts txn T, based at revision 6.   *    2. Someone commits (or already committed) revision 7.   *    3. Jane's starts merging the changes between 6 and 7 into T.   *    4. Meanwhile, someone commits revision 8.   *    5. Jane finishes the 6-->7 merge.  T could now be committed   *       against a latest revision of 7, if only that were still the   *       latest.  Unfortunately, 8 is now the latest, so...    *    6. Jane starts merging the changes between 7 and 8 into T.   *    7. Meanwhile, no one commits any new revisions.  Whew.   *    8. Jane commits T, creating revision 9, whose tree is exactly   *       T's tree, except immutable now.   *   * Lather, rinse, repeat.   */  svn_error_t *err;  svn_revnum_t new_rev;  svn_fs_t *fs = txn->fs;  /* Initialize output params. */  new_rev = SVN_INVALID_REVNUM;  if (conflict_p)    *conflict_p = NULL;  while (1729)    {      svn_revnum_t youngish_rev;      svn_fs_root_t *youngish_root;      dag_node_t *youngish_root_node;      svn_stringbuf_t *conflict = svn_stringbuf_create("", pool);      /* Get the *current* youngest revision, in one short-lived         Berkeley transaction.  (We don't want the revisions table         locked while we do the main merge.)  We call it "youngish"         because new revisions might get committed after we've         obtained it. */      SVN_ERR(svn_fs_fs__youngest_rev(&youngish_rev, fs, pool));      SVN_ERR(svn_fs_fs__revision_root(&youngish_root, fs, youngish_rev,                                       pool));      /* Get the dag node for the youngest revision, also in one         Berkeley transaction.  Later we'll use it as the SOURCE         argument to a merge, and if the merge succeeds, this youngest         root node will become the new base root for the svn txn that         was the target of the merge (but note that the youngest rev         may have changed by then -- that's why we're careful to get         this root in its own bdb txn here). */      SVN_ERR(get_root(&youngish_root_node, youngish_root, pool));            /* Try to merge.  If the merge succeeds, the base root node of         TARGET's txn will become the same as youngish_root_node, so         any future merges will only be between that node and whatever         the root node of the youngest rev is by then. */       err = merge_changes(NULL, youngish_root_node, txn, conflict, pool);      if (err)        {          if ((err->apr_err == SVN_ERR_FS_CONFLICT) && conflict_p)            *conflict_p = conflict->data;          return err;        }      txn->base_rev = youngish_rev;      /* Try to commit. */      err = svn_fs_fs__commit(&new_rev, fs, txn, pool);      if (err && (err->apr_err == SVN_ERR_FS_TXN_OUT_OF_DATE))        {          /* Did someone else finish committing a new revision while we             were in mid-merge or mid-commit?  If so, we'll need to             loop again to merge the new changes in, then try to             commit again.  Or if that's not what happened, then just             return the error. */          svn_revnum_t youngest_rev;          SVN_ERR(svn_fs_fs__youngest_rev(&youngest_rev, fs, pool));          if (youngest_rev == youngish_rev)            return err;          else            svn_error_clear(err);        }      else if (err)        {          return err;        }      else        {          /* Set the return value -- our brand spankin' new revision! */          *new_rev_p = new_rev;          return SVN_NO_ERROR;        }    }  /* NOTREACHED */}/* Merge changes between two nodes into a third node.  Given nodes   SOURCE_PATH under SOURCE_ROOT, TARGET_PATH under TARGET_ROOT and   ANCESTOR_PATH under ANCESTOR_ROOT, modify target to contain all the   changes between the ancestor and source.  If there are conflicts,   return SVN_ERR_FS_CONFLICT and set *CONFLICT_P to a textual   description of the offending changes.  Perform any temporary   allocations in POOL. */static svn_error_t *fs_merge(const char **conflict_p,         svn_fs_root_t *source_root,         const char *source_path,         svn_fs_root_t *target_root,         const char *target_path,         svn_fs_root_t *ancestor_root,         const char *ancestor_path,         apr_pool_t *pool){  dag_node_t *source, *ancestor;  svn_fs_txn_t *txn;  svn_error_t *err;  svn_stringbuf_t *conflict = svn_stringbuf_create("", pool);  if (! target_root->is_txn_root)    return not_txn(target_root);  /* Paranoia. */  if ((source_root->fs != ancestor_root->fs)      || (target_root->fs != ancestor_root->fs))    {      return svn_error_create        (SVN_ERR_FS_CORRUPT, NULL,         _("Bad merge; ancestor, source, and target not all in same fs"));    }  /* ### kff todo: is there any compelling reason to get the nodes in     one db transaction?  Right now we don't; txn_body_get_root() gets     one node at a time.  This will probably need to change:     Jim Blandy <jimb@zwingli.cygnus.com> writes:     > svn_fs_merge needs to be a single transaction, to protect it against     > people deleting parents of nodes it's working on, etc.  */  /* Get the ancestor node. */  SVN_ERR(get_root(&ancestor, ancestor_root, pool));  /* Get the source node. */  SVN_ERR(get_root(&source, source_root, pool));    /* Open a txn for the txn root into which we're merging. */  SVN_ERR(svn_fs_fs__open_txn(&txn, ancestor_root->fs, target_root->txn,                              pool));  /* Merge changes between ANCESTOR and SOURCE into TXN. */  err = merge_changes(ancestor, source, txn, conflict, pool);  if (err)    {      if ((err->apr_err == SVN_ERR_FS_CONFLICT) && conflict_p)        *conflict_p = conflict->data;      return err;    }  return SVN_NO_ERROR;}svn_error_t *svn_fs_fs__deltify(svn_fs_t *fs,                   svn_revnum_t revision,                   apr_pool_t *pool){  /* Deltify is a no-op for fs_fs. */  return SVN_NO_ERROR;}/* Directories.  *//* Set *TABLE_P to a newly allocated APR hash table containing the   entries of the directory at PATH in ROOT.  The keys of the table   are entry names, as byte strings, excluding the final null   character; the table's values are pointers to svn_fs_dirent_t   structures.  Allocate the table and its contents in POOL. */static svn_error_t *fs_dir_entries(apr_hash_t **table_p,               svn_fs_root_t *root,               const char *path,               apr_pool_t *pool){  dag_node_t *node;  apr_hash_t *entries;  /* Get the entries for this path and copy them into the callers's     pool. */  SVN_ERR(get_dag(&node, root, path, pool));  SVN_ERR(svn_fs_fs__dag_dir_entries(&entries, node, pool));  *table_p = svn_fs_fs__copy_dir_entries(entries, pool);  return SVN_NO_ERROR;}/* Create a new directory named PATH in ROOT.  The new directory has   no entries, and no properties.  ROOT must be the root of a   transaction, not a revision.  Do any necessary temporary allocation   in POOL.  */static svn_error_t *fs_make_dir(svn_fs_root_t *root,            const char *path,            apr_pool_t *pool){  parent_path_t *parent_path;  dag_node_t *sub_dir;  const char *txn_id = root->txn;  SVN_ERR(open_path(&parent_path, root, path, open_path_last_optional,                    txn_id, pool));  /* Check (recursively) to see if some lock is 'reserving' a path at     that location, or even some child-path; if so, check that we can     use it. */  if (root->txn_flags & SVN_FS_TXN_CHECK_LOCKS)    SVN_ERR(svn_fs_fs__allow_locked_operation(path, root->fs, TRUE, FALSE,                                              pool));  /* If there's already a sub-directory by that name, complain.  This     also catches the case of trying to make a subdirectory named `/'.  */  if (parent_path->node)    return already_exists(root, path);  /* Create the subdirectory.  */  SVN_ERR(make_path_mutable(root, parent_path->parent, path, pool));  SVN_ERR(svn_fs_fs__dag_make_dir(&sub_dir,                                  parent_path->parent->node,                                   parent_path_path(parent_path->parent,                                                    pool),                                  parent_path->entry,                                  txn_id,                                  pool));  /* Add this directory to the path cache. */  dag_node_cache_set(root, parent_path_path(parent_path, pool), sub_dir);  /* Make a record of this modification in the changes table. */  SVN_ERR(add_change(root->fs, txn_id, path, svn_fs_fs__dag_get_id(sub_dir),                     svn_fs_path_change_add, 0, 0, SVN_INVALID_REVNUM, NULL,                     pool));  return SVN_NO_ERROR;}                              /* Delete the node at PATH under ROOT.  ROOT must be a transaction   root.  Perform temporary allocations in POOL. */static svn_error_t *fs_delete_node(svn_fs_root_t *root,               const char *path,               apr_pool_t *pool){  parent_path_t *parent_path;  const char *txn_id = root->txn;  if (! root->is_txn_root)    return not_txn(root);  SVN_ERR(open_path(&parent_path, root, path, 0, txn_id, pool));  /* We can't remove the root of the filesystem.  */  if (! parent_path->parent)    return svn_error_create(SVN_ERR_FS_ROOT_DIR, NULL,      

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -