diff options
author | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
---|---|---|
committer | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
commit | 3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch) | |
tree | 7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/libsvn_delta/branch_nested.c | |
parent | a55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff) |
Import Subversion-1.10.0vendor/subversion/subversion-1.10.0
Notes
Notes:
svn path=/vendor/subversion/dist/; revision=333347
svn path=/vendor/subversion/subversion-1.10.0/; revision=333348; tag=vendor/subversion/subversion-1.10.0
Diffstat (limited to 'subversion/libsvn_delta/branch_nested.c')
-rw-r--r-- | subversion/libsvn_delta/branch_nested.c | 660 |
1 files changed, 660 insertions, 0 deletions
diff --git a/subversion/libsvn_delta/branch_nested.c b/subversion/libsvn_delta/branch_nested.c new file mode 100644 index 000000000000..191d2d3b154b --- /dev/null +++ b/subversion/libsvn_delta/branch_nested.c @@ -0,0 +1,660 @@ +/* + * branch_nested.c : Nested Branches + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#include <assert.h> + +#include "svn_types.h" +#include "svn_error.h" +#include "svn_dirent_uri.h" +#include "svn_hash.h" +#include "svn_iter.h" +#include "svn_pools.h" + +#include "private/svn_branch_nested.h" +#include "private/svn_branch_impl.h" +#include "private/svn_branch_repos.h" + +#include "svn_private_config.h" + + +void +svn_branch__get_outer_branch_and_eid(svn_branch__state_t **outer_branch_p, + int *outer_eid_p, + const svn_branch__state_t *branch, + apr_pool_t *scratch_pool) +{ + const char *outer_bid; + + svn_branch__id_unnest(&outer_bid, outer_eid_p, branch->bid, scratch_pool); + *outer_branch_p = NULL; + if (outer_bid) + { + *outer_branch_p + = svn_branch__txn_get_branch_by_id(branch->txn, outer_bid, + scratch_pool); + } +} + +const char * +svn_branch__get_root_rrpath(const svn_branch__state_t *branch, + apr_pool_t *result_pool) +{ + svn_branch__state_t *outer_branch; + int outer_eid; + const char *root_rrpath; + + svn_branch__get_outer_branch_and_eid(&outer_branch, &outer_eid, branch, + result_pool); + if (outer_branch) + { + root_rrpath + = svn_branch__get_rrpath_by_eid(outer_branch, outer_eid, result_pool); + } + else + { + root_rrpath = ""; + } + + SVN_ERR_ASSERT_NO_RETURN(root_rrpath); + return root_rrpath; +} + +const char * +svn_branch__get_rrpath_by_eid(const svn_branch__state_t *branch, + int eid, + apr_pool_t *result_pool) +{ + const char *path = svn_branch__get_path_by_eid(branch, eid, result_pool); + const char *rrpath = NULL; + + if (path) + { + rrpath = svn_relpath_join(svn_branch__get_root_rrpath(branch, result_pool), + path, result_pool); + } + return rrpath; +} + +svn_error_t * +svn_branch__get_subbranch_at_eid(svn_branch__state_t *branch, + svn_branch__state_t **subbranch_p, + int eid, + apr_pool_t *scratch_pool) +{ + svn_element__content_t *element; + + SVN_ERR(svn_branch__state_get_element(branch, &element, eid, scratch_pool)); + if (element && element->payload->is_subbranch_root) + { + const char *branch_id = svn_branch__get_id(branch, scratch_pool); + const char *subbranch_id = svn_branch__id_nest(branch_id, eid, + scratch_pool); + + *subbranch_p = svn_branch__txn_get_branch_by_id(branch->txn, subbranch_id, + scratch_pool); + } + else + { + *subbranch_p = NULL; + } + return SVN_NO_ERROR; +} + +/* Set *SUBBRANCH_EIDS_P an array of EIDs of the subbranch-root elements in + * BRANCH. + */ +static svn_error_t * +svn_branch__get_immediate_subbranch_eids(svn_branch__state_t *branch, + apr_array_header_t **subbranch_eids_p, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *subbranch_eids + = apr_array_make(result_pool, 0, sizeof(int)); + svn_element__tree_t *elements; + apr_hash_index_t *hi; + + SVN_ERR(svn_branch__state_get_elements(branch, &elements, scratch_pool)); + for (hi = apr_hash_first(scratch_pool, elements->e_map); + hi; hi = apr_hash_next(hi)) + { + int eid = svn_eid__hash_this_key(hi); + svn_element__content_t *element = apr_hash_this_val(hi); + + if (element->payload->is_subbranch_root) + { + APR_ARRAY_PUSH(subbranch_eids, int) = eid; + } + } + *subbranch_eids_p = subbranch_eids; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_branch__get_immediate_subbranches(svn_branch__state_t *branch, + apr_array_header_t **subbranches_p, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *subbranch_eids; + apr_array_header_t *subbranches + = apr_array_make(result_pool, 0, sizeof(void *)); + const char *branch_id = svn_branch__get_id(branch, scratch_pool); + int i; + + SVN_ERR(svn_branch__get_immediate_subbranch_eids(branch, &subbranch_eids, + scratch_pool, scratch_pool)); + for (i = 0; i < subbranch_eids->nelts; i++) + { + int eid = APR_ARRAY_IDX(subbranch_eids, i, int); + const char *subbranch_id + = svn_branch__id_nest(branch_id, eid, scratch_pool); + svn_branch__state_t *subbranch + = svn_branch__txn_get_branch_by_id(branch->txn, subbranch_id, + scratch_pool); + + SVN_ERR_ASSERT_NO_RETURN(subbranch); + APR_ARRAY_PUSH(subbranches, void *) = subbranch; + } + *subbranches_p = subbranches; + return SVN_NO_ERROR; +} + +svn_branch__subtree_t * +svn_branch__subtree_create(apr_hash_t *e_map, + int root_eid, + apr_pool_t *result_pool) +{ + svn_branch__subtree_t *subtree = apr_pcalloc(result_pool, sizeof(*subtree)); + + subtree->tree = svn_element__tree_create(e_map, root_eid, result_pool); + subtree->subbranches = apr_hash_make(result_pool); + return subtree; +} + +svn_error_t * +svn_branch__get_subtree(svn_branch__state_t *branch, + svn_branch__subtree_t **subtree_p, + int eid, + apr_pool_t *result_pool) +{ + svn_element__tree_t *element_tree; + svn_branch__subtree_t *new_subtree; + apr_array_header_t *subbranch_eids; + int i; + apr_pool_t *iterpool = result_pool; /* ### not a proper iterpool */ + + SVN_ERR(svn_branch__state_get_elements(branch, &element_tree, result_pool)); + element_tree = svn_element__tree_get_subtree_at_eid(element_tree, eid, + result_pool); + new_subtree + = svn_branch__subtree_create(element_tree->e_map, eid, result_pool); + + /* Add subbranches */ + SVN_ERR(svn_branch__get_immediate_subbranch_eids(branch, &subbranch_eids, + result_pool, result_pool)); + for (i = 0; i < subbranch_eids->nelts; i++) + { + int outer_eid = APR_ARRAY_IDX(subbranch_eids, i, int); + const char *subbranch_relpath_in_subtree; + + subbranch_relpath_in_subtree + = svn_element__tree_get_path_by_eid(new_subtree->tree, outer_eid, + iterpool); + + /* Is it pathwise at or below EID? If so, add it into the subtree. */ + if (subbranch_relpath_in_subtree) + { + svn_branch__state_t *subbranch; + svn_branch__subtree_t *this_subtree; + + SVN_ERR(svn_branch__get_subbranch_at_eid(branch, &subbranch, + outer_eid, iterpool)); + if (subbranch) + { + SVN_ERR(svn_branch__get_subtree(subbranch, &this_subtree, + svn_branch__root_eid(subbranch), + result_pool)); + svn_eid__hash_set(new_subtree->subbranches, outer_eid, + this_subtree); + } + } + } + *subtree_p = new_subtree; + return SVN_NO_ERROR; +} + +svn_branch__subtree_t * +svn_branch__subtree_get_subbranch_at_eid(svn_branch__subtree_t *subtree, + int eid, + apr_pool_t *result_pool) +{ + subtree = svn_eid__hash_get(subtree->subbranches, eid); + + return subtree; +} + +/* Instantiate ELEMENTS in TO_BRANCH. + */ +static svn_error_t * +branch_instantiate_elements(svn_branch__state_t *to_branch, + const svn_element__tree_t *elements, + apr_pool_t *scratch_pool) +{ + apr_hash_index_t *hi; + + for (hi = apr_hash_first(scratch_pool, elements->e_map); + hi; hi = apr_hash_next(hi)) + { + int this_eid = svn_eid__hash_this_key(hi); + svn_element__content_t *this_element = apr_hash_this_val(hi); + + SVN_ERR(svn_branch__state_set_element(to_branch, this_eid, + this_element, scratch_pool)); + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_branch__instantiate_elements_r(svn_branch__state_t *to_branch, + svn_branch__subtree_t elements, + apr_pool_t *scratch_pool) +{ + SVN_ERR(branch_instantiate_elements(to_branch, elements.tree, + scratch_pool)); + + /* branch any subbranches */ + { + apr_hash_index_t *hi; + + for (hi = apr_hash_first(scratch_pool, elements.subbranches); + hi; hi = apr_hash_next(hi)) + { + int this_outer_eid = svn_eid__hash_this_key(hi); + svn_branch__subtree_t *this_subtree = apr_hash_this_val(hi); + const char *new_branch_id; + svn_branch__state_t *new_branch; + /*### svn_branch__history_t *history;*/ + + /* branch this subbranch into NEW_BRANCH (recursing) */ + new_branch_id = svn_branch__id_nest(to_branch->bid, this_outer_eid, + scratch_pool); + SVN_ERR(svn_branch__txn_open_branch(to_branch->txn, &new_branch, + new_branch_id, + this_subtree->tree->root_eid, + NULL /*tree_ref*/, + scratch_pool, scratch_pool)); + /*### SVN_ERR(svn_branch__state_set_history(new_branch, history, + scratch_pool));*/ + + SVN_ERR(svn_branch__instantiate_elements_r(new_branch, *this_subtree, + scratch_pool)); + } + } + + return SVN_NO_ERROR; +} + +/* + * ======================================================================== + */ + +svn_error_t * +svn_branch__find_nested_branch_element_by_relpath( + svn_branch__state_t **branch_p, + int *eid_p, + svn_branch__state_t *root_branch, + const char *relpath, + apr_pool_t *scratch_pool) +{ + /* The path we're looking for is (path-wise) in this branch. See if it + is also in a sub-branch. */ + /* Loop invariants: RELPATH is the path we're looking for, relative to + ROOT_BRANCH which is the current level of nesting that we've descended + into. */ + while (TRUE) + { + apr_array_header_t *subbranch_eids; + int i; + svn_boolean_t found = FALSE; + + SVN_ERR(svn_branch__get_immediate_subbranch_eids( + root_branch, &subbranch_eids, scratch_pool, scratch_pool)); + for (i = 0; i < subbranch_eids->nelts; i++) + { + int outer_eid = APR_ARRAY_IDX(subbranch_eids, i, int); + const char *relpath_to_subbranch; + const char *relpath_in_subbranch; + + /* Check whether the RELPATH we're looking for is within this + subbranch at OUTER_EID. If it is, recurse in the subbranch. */ + relpath_to_subbranch + = svn_branch__get_path_by_eid(root_branch, outer_eid, scratch_pool); + relpath_in_subbranch + = svn_relpath_skip_ancestor(relpath_to_subbranch, relpath); + if (relpath_in_subbranch) + { + svn_branch__state_t *subbranch; + + SVN_ERR(svn_branch__get_subbranch_at_eid( + root_branch, &subbranch, outer_eid, scratch_pool)); + /* If the branch hierarchy is not 'flat' then we might find + there is no actual branch where the subbranch-root element + says there should be one. In that case, ignore it. */ + if (subbranch) + { + root_branch = subbranch; + relpath = relpath_in_subbranch; + found = TRUE; + break; + } + } + } + if (! found) + { + break; + } + } + + *branch_p = root_branch; + if (eid_p) + *eid_p = svn_branch__get_eid_by_path(root_branch, relpath, scratch_pool); + return SVN_NO_ERROR; +} + +svn_error_t * +svn_branch__repos_find_el_rev_by_path_rev(svn_branch__el_rev_id_t **el_rev_p, + const svn_branch__repos_t *repos, + svn_revnum_t revnum, + const char *branch_id, + const char *relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_branch__el_rev_id_t *el_rev = apr_palloc(result_pool, sizeof(*el_rev)); + svn_branch__state_t *branch; + + SVN_ERR(svn_branch__repos_get_branch_by_id(&branch, + repos, revnum, branch_id, + scratch_pool)); + el_rev->rev = revnum; + SVN_ERR(svn_branch__find_nested_branch_element_by_relpath(&el_rev->branch, + &el_rev->eid, + branch, relpath, + scratch_pool)); + + /* Any relpath must at least be within the originally given branch */ + SVN_ERR_ASSERT_NO_RETURN(el_rev->branch); + *el_rev_p = el_rev; + return SVN_NO_ERROR; +} + +/* Set *BRANCH_P to the branch found in the repository of TXN, at the + * location (in a revision or in this txn) SRC_EL_REV. + * + * Return an error if REVNUM or BRANCH_ID is not found. + */ +static svn_error_t * +branch_in_rev_or_txn(svn_branch__state_t **branch_p, + const svn_branch__rev_bid_eid_t *src_el_rev, + svn_branch__txn_t *txn, + apr_pool_t *result_pool) +{ + if (SVN_IS_VALID_REVNUM(src_el_rev->rev)) + { + SVN_ERR(svn_branch__repos_get_branch_by_id(branch_p, + txn->repos, + src_el_rev->rev, + src_el_rev->bid, + result_pool)); + } + else + { + *branch_p + = svn_branch__txn_get_branch_by_id( + txn, src_el_rev->bid, result_pool); + if (! *branch_p) + return svn_error_createf(SVN_BRANCH__ERR, NULL, + _("Branch %s not found"), + src_el_rev->bid); + } + + return SVN_NO_ERROR; +} + +struct svn_branch__txn_priv_t +{ + /* The underlying branch-txn that supports only non-nested branching. */ + svn_branch__txn_t *wrapped_txn; + +}; + +/* Implements nested branching. + * An #svn_branch__txn_t method. */ +static apr_array_header_t * +nested_branch_txn_get_branches(const svn_branch__txn_t *txn, + apr_pool_t *result_pool) +{ + /* Just forwarding: nothing more is needed. */ + apr_array_header_t *branches + = svn_branch__txn_get_branches(txn->priv->wrapped_txn, + result_pool); + + return branches; +} + +/* An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_delete_branch(svn_branch__txn_t *txn, + const char *bid, + apr_pool_t *scratch_pool) +{ + /* Just forwarding: nothing more is needed. */ + SVN_ERR(svn_branch__txn_delete_branch(txn->priv->wrapped_txn, + bid, + scratch_pool)); + return SVN_NO_ERROR; +} + +/* Implements nested branching. + * An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_get_num_new_eids(const svn_branch__txn_t *txn, + int *num_new_eids_p, + apr_pool_t *scratch_pool) +{ + /* Just forwarding: nothing more is needed. */ + SVN_ERR(svn_branch__txn_get_num_new_eids(txn->priv->wrapped_txn, + num_new_eids_p, + scratch_pool)); + return SVN_NO_ERROR; +} + +/* Implements nested branching. + * An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_new_eid(svn_branch__txn_t *txn, + svn_branch__eid_t *eid_p, + apr_pool_t *scratch_pool) +{ + /* Just forwarding: nothing more is needed. */ + SVN_ERR(svn_branch__txn_new_eid(txn->priv->wrapped_txn, + eid_p, + scratch_pool)); + return SVN_NO_ERROR; +} + +/* Implements nested branching. + * An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_open_branch(svn_branch__txn_t *txn, + svn_branch__state_t **new_branch_p, + const char *new_branch_id, + int root_eid, + svn_branch__rev_bid_eid_t *tree_ref, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_branch__state_t *new_branch; + + SVN_ERR(svn_branch__txn_open_branch(txn->priv->wrapped_txn, + &new_branch, + new_branch_id, root_eid, tree_ref, + result_pool, + scratch_pool)); + + /* Recursively branch any nested branches */ + if (tree_ref) + { + svn_branch__state_t *from_branch; + svn_branch__subtree_t *from_subtree; + + /* (The way we're doing it here also redundantly re-instantiates all the + elements in NEW_BRANCH.) */ + SVN_ERR(branch_in_rev_or_txn(&from_branch, tree_ref, + txn->priv->wrapped_txn, scratch_pool)); + SVN_ERR(svn_branch__get_subtree(from_branch, &from_subtree, + tree_ref->eid, scratch_pool)); + SVN_ERR(svn_branch__instantiate_elements_r(new_branch, *from_subtree, + scratch_pool)); + } + + if (new_branch_p) + *new_branch_p = new_branch; + return SVN_NO_ERROR; +} + +/* Implements nested branching. + * An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_finalize_eids(svn_branch__txn_t *txn, + apr_pool_t *scratch_pool) +{ + /* Just forwarding: nothing more is needed. */ + SVN_ERR(svn_branch__txn_finalize_eids(txn->priv->wrapped_txn, + scratch_pool)); + return SVN_NO_ERROR; +} + +/* Implements nested branching. + * An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_serialize(svn_branch__txn_t *txn, + svn_stream_t *stream, + apr_pool_t *scratch_pool) +{ + /* Just forwarding: nothing more is needed. */ + SVN_ERR(svn_branch__txn_serialize(txn->priv->wrapped_txn, + stream, + scratch_pool)); + return SVN_NO_ERROR; +} + +/* Implements nested branching. + * An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_sequence_point(svn_branch__txn_t *txn, + apr_pool_t *scratch_pool) +{ + svn_branch__txn_t *wrapped_txn = txn->priv->wrapped_txn; + apr_array_header_t *branches; + int i; + + /* first, purge elements in each branch */ + SVN_ERR(svn_branch__txn_sequence_point(wrapped_txn, scratch_pool)); + + /* second, purge branches that are no longer nested */ + branches = svn_branch__txn_get_branches(wrapped_txn, scratch_pool); + for (i = 0; i < branches->nelts; i++) + { + svn_branch__state_t *b = APR_ARRAY_IDX(branches, i, void *); + svn_branch__state_t *outer_branch; + int outer_eid; + + svn_branch__get_outer_branch_and_eid(&outer_branch, &outer_eid, + b, scratch_pool); + if (outer_branch) + { + svn_element__content_t *element; + + SVN_ERR(svn_branch__state_get_element(outer_branch, &element, + outer_eid, scratch_pool)); + if (! element) + SVN_ERR(svn_branch__txn_delete_branch(wrapped_txn, b->bid, + scratch_pool)); + } + } + return SVN_NO_ERROR; +} + +/* An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_complete(svn_branch__txn_t *txn, + apr_pool_t *scratch_pool) +{ + /* Just forwarding: nothing more is needed. */ + SVN_ERR(svn_branch__txn_complete(txn->priv->wrapped_txn, + scratch_pool)); + return SVN_NO_ERROR; +} + +/* An #svn_branch__txn_t method. */ +static svn_error_t * +nested_branch_txn_abort(svn_branch__txn_t *txn, + apr_pool_t *scratch_pool) +{ + /* Just forwarding: nothing more is needed. */ + SVN_ERR(svn_branch__txn_abort(txn->priv->wrapped_txn, + scratch_pool)); + return SVN_NO_ERROR; +} + +svn_branch__txn_t * +svn_branch__nested_txn_create(svn_branch__txn_t *wrapped_txn, + apr_pool_t *result_pool) +{ + static const svn_branch__txn_vtable_t vtable = { + {0}, + nested_branch_txn_get_branches, + nested_branch_txn_delete_branch, + nested_branch_txn_get_num_new_eids, + nested_branch_txn_new_eid, + nested_branch_txn_open_branch, + nested_branch_txn_finalize_eids, + nested_branch_txn_serialize, + nested_branch_txn_sequence_point, + nested_branch_txn_complete, + nested_branch_txn_abort, + }; + svn_branch__txn_t *txn + = svn_branch__txn_create(&vtable, NULL, NULL, result_pool); + + txn->priv = apr_pcalloc(result_pool, sizeof(*txn->priv)); + txn->priv->wrapped_txn = wrapped_txn; + txn->repos = wrapped_txn->repos; + txn->rev = wrapped_txn->rev; + txn->base_rev = wrapped_txn->base_rev; + return txn; +} + |