Author: julianfoad Date: Wed Apr 15 13:14:56 2015 New Revision: 1673753 URL: http://svn.apache.org/r1673753 Log: On the 'move-tracking-2' branch: In the metadata, note whether each element is a subbranch root element, so that on reading it we can correctly set the element's 'content' field to null.
Previously, everything was working well enough even though such elements had their content set to non-null, but that is not sustainable. * subversion/include/private/svn_branch.h (svn_branch_el_rev_content_t): Update the comment. (svn_branch_subtree_create): New. * subversion/libsvn_delta/branch.c (svn_branch_subtree_create, svn_branch_subtree_get_path_by_eid): New. (parse_element_line, svn_branch_instance_parse, svn_branch_instance_serialize): Add a 'kind' field to the metadata. * subversion/libsvn_delta/compat3e.c (editor3_alter): Allow altering an element whose previous content is null. * subversion/libsvn_delta/element.c (svn_element_content_equal): Allow comparing null element content. * subversion/libsvn_ra/ra_loader.c (default_repos_info): Add a 'kind' field to the initial metadata. * subversion/svnmover/svnmover.c (element_merge): Don't allow a 'double add' to apply to subbranches, as we don't know whether they are identical (and don't want to check). Modified: subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c subversion/branches/move-tracking-2/subversion/libsvn_delta/element.c subversion/branches/move-tracking-2/subversion/libsvn_ra/ra_loader.c subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c Modified: subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h?rev=1673753&r1=1673752&r2=1673753&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h (original) +++ subversion/branches/move-tracking-2/subversion/include/private/svn_branch.h Wed Apr 15 13:14:56 2015 @@ -356,7 +356,8 @@ typedef struct svn_branch_el_rev_content /* struct svn_branch_element_t *parent_element; */ /* element name, or "" for root element; never null */ const char *name; - /* content (kind, props, text, ...) */ + /* content (kind, props, text, ...); + * null if this is a subbranch root element */ svn_element_content_t *content; } svn_branch_el_rev_content_t; @@ -406,6 +407,12 @@ typedef struct svn_branch_subtree_t int root_eid; } svn_branch_subtree_t; +/* Create an empty subtree (no elements populated, not even ROOT_EID). + */ +svn_branch_subtree_t * +svn_branch_subtree_create(int root_eid, + apr_pool_t *result_pool); + /* Return the subtree of BRANCH rooted at EID. */ svn_branch_subtree_t Modified: subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c?rev=1673753&r1=1673752&r2=1673753&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_delta/branch.c Wed Apr 15 13:14:56 2015 @@ -358,6 +358,17 @@ svn_branch_el_rev_content_equal(const sv * ======================================================================== */ +svn_branch_subtree_t * +svn_branch_subtree_create(int root_eid, + apr_pool_t *result_pool) +{ + svn_branch_subtree_t *subtree = apr_pcalloc(result_pool, sizeof(*subtree)); + + subtree->e_map = apr_hash_make(result_pool); + subtree->root_eid = root_eid; + return subtree; +} + /* Validate that NODE is suitable for a mapping of BRANCH:EID. * NODE->content may be null. */ @@ -588,6 +599,25 @@ svn_branch_get_root_rrpath(const svn_bra return root_rrpath; } +static const char * +svn_branch_subtree_get_path_by_eid(const svn_branch_subtree_t *subtree, + int eid, + apr_pool_t *result_pool) +{ + const char *path = ""; + svn_branch_el_rev_content_t *node; + + for (; eid != subtree->root_eid; eid = node->parent_eid) + { + node = svn_int_hash_get(subtree->e_map, eid); + if (! node) + return NULL; + path = svn_relpath_join(node->name, path, result_pool); + } + SVN_ERR_ASSERT_NO_RETURN(eid == subtree->root_eid); + return path; +} + const char * svn_branch_get_path_by_eid(const svn_branch_instance_t *branch, int eid, @@ -916,6 +946,7 @@ parse_branch_line(int *bsid_p, static svn_error_t * parse_element_line(int *bsid_p, int *eid_p, + svn_boolean_t *is_subbranch_p, int *parent_eid_p, const char **name_p, svn_stream_t *stream, @@ -923,6 +954,7 @@ parse_element_line(int *bsid_p, { svn_stringbuf_t *line; svn_boolean_t eof; + char kind[10]; int n; int offset; @@ -930,13 +962,15 @@ parse_element_line(int *bsid_p, SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); SVN_ERR_ASSERT(!eof); - n = sscanf(line->data, "b%de%d: %d%n", + n = sscanf(line->data, "b%de%d: %9s %d%n", bsid_p, eid_p, - parent_eid_p, &offset); - SVN_ERR_ASSERT(n >= 3); /* C std is unclear on whether '%n' counts */ + kind, parent_eid_p, &offset); + SVN_ERR_ASSERT(n >= 4); /* C std is unclear on whether '%n' counts */ SVN_ERR_ASSERT(line->data[offset] == ' '); *name_p = line->data + offset + 1; + *is_subbranch_p = (strcmp(kind, "subbranch") == 0); + if (strcmp(*name_p, "(null)") == 0) *name_p = NULL; else if (strcmp(*name_p, ".") == 0) @@ -963,6 +997,7 @@ svn_branch_instance_parse(svn_branch_ins svn_branch_instance_t *outer_branch; int outer_eid; int eid; + svn_branch_subtree_t *tree; SVN_ERR(parse_branch_line(&bsid, &root_eid, &branch_root_rrpath, stream, scratch_pool)); @@ -985,46 +1020,63 @@ svn_branch_instance_parse(svn_branch_ins result_pool); /* Read in the structure, leaving the content of each element as null */ + tree = svn_branch_subtree_create(root_eid, scratch_pool); for (eid = family->first_eid; eid < family->next_eid; eid++) { int this_bsid, this_eid, this_parent_eid; const char *this_name; + svn_boolean_t is_subbranch; SVN_ERR(parse_element_line(&this_bsid, &this_eid, - &this_parent_eid, &this_name, + &is_subbranch, &this_parent_eid, &this_name, stream, scratch_pool)); if (this_name) { svn_branch_el_rev_content_t *node = svn_branch_el_rev_content_create(this_parent_eid, this_name, - NULL /*content*/, result_pool); + NULL /*content*/, scratch_pool); + if (! is_subbranch) + node->content = (void *)1; - branch_map_set(branch_instance, this_eid, node); + svn_int_hash_set(tree->e_map, this_eid, node); } } /* Populate the content reference for each element, now that we have enough info to calculate full paths */ + /* Subbranch root elements should have content=null */ for (eid = family->first_eid; eid < family->next_eid; eid++) { - svn_branch_el_rev_content_t *node - = svn_branch_map_get(branch_instance, eid); + svn_branch_el_rev_content_t *node = svn_int_hash_get(tree->e_map, eid); if (node) { - const char *rrpath = svn_branch_get_rrpath_by_eid(branch_instance, - eid, scratch_pool); - svn_pathrev_t peg; - svn_element_content_t *content; - - /* Specify the content by reference */ - peg.rev = rev_root->rev; - peg.relpath = rrpath; - content = svn_element_content_create_ref(peg, scratch_pool); + if (node->content == (void *)1) + { + /* ### need to get path within temp hash tree */ + const char *relpath + = svn_branch_subtree_get_path_by_eid(tree, eid, scratch_pool); + const char *rrpath + = svn_relpath_join(svn_branch_get_root_rrpath(branch_instance, + result_pool), + relpath, scratch_pool); + svn_pathrev_t peg; + svn_element_content_t *content; + + /* Specify the content by reference */ + peg.rev = rev_root->rev; + peg.relpath = rrpath; + content = svn_element_content_create_ref(peg, scratch_pool); - svn_branch_map_update(branch_instance, eid, - node->parent_eid, node->name, content); + svn_branch_map_update( + branch_instance, eid, node->parent_eid, node->name, content); + } + else + { + svn_branch_map_update_as_subbranch_root( + branch_instance, eid, node->parent_eid, node->name); + } } } @@ -1177,8 +1229,10 @@ svn_branch_instance_serialize(svn_stream name = "(null)"; } SVN_ERR(svn_stream_printf(stream, scratch_pool, - "b%de%d: %d %s\n", + "b%de%d: %s %d %s\n", branch->sibling_defn->bsid, eid, + node ? (node->content ? "normal" : "subbranch") + : "none", parent_eid, name)); } return SVN_NO_ERROR; Modified: subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c?rev=1673753&r1=1673752&r2=1673753&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_delta/compat3e.c Wed Apr 15 13:14:56 2015 @@ -998,7 +998,12 @@ editor3_alter(void *baton, new_content = svn_branch_map_get(branch, eid)->content; } - svn_branch_map_update(branch, eid, new_parent_eid, new_name, new_content); + if (new_content) + svn_branch_map_update( + branch, eid, new_parent_eid, new_name, new_content); + else + svn_branch_map_update_as_subbranch_root( + branch, eid, new_parent_eid, new_name); return SVN_NO_ERROR; } Modified: subversion/branches/move-tracking-2/subversion/libsvn_delta/element.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_delta/element.c?rev=1673753&r1=1673752&r2=1673753&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_delta/element.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_delta/element.c Wed Apr 15 13:14:56 2015 @@ -94,6 +94,15 @@ svn_element_content_equal(const svn_elem { apr_array_header_t *prop_diffs; + if (!left && !right) + { + return TRUE; + } + else if (!left || !right) + { + return FALSE; + } + /* references are not supported */ SVN_ERR_ASSERT_NO_RETURN(! left->ref.relpath && ! right->ref.relpath); SVN_ERR_ASSERT_NO_RETURN(left->kind != svn_node_unknown Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra/ra_loader.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra/ra_loader.c?rev=1673753&r1=1673752&r2=1673753&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/libsvn_ra/ra_loader.c (original) +++ subversion/branches/move-tracking-2/subversion/libsvn_ra/ra_loader.c Wed Apr 15 13:14:56 2015 @@ -604,7 +604,7 @@ static const char *default_repos_info = "r0:\n" "family: bsids 0 1 eids 0 1 b-instances 1\n" "b0: root-eid 0 at .\n" - "b0e0: -1 .\n"; + "b0e0: normal -1 .\n"; /* Read the branching info string VALUE belonging to revision REVISION. */ Modified: subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c?rev=1673753&r1=1673752&r2=1673753&view=diff ============================================================================== --- subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c (original) +++ subversion/branches/move-tracking-2/subversion/svnmover/svnmover.c Wed Apr 15 13:14:56 2015 @@ -628,7 +628,9 @@ element_merge(svn_branch_el_rev_content_ else if (side1 && side2) { /* Double add (as we already handled the case where YCA also exists) */ + /* May be allowed for equal content of a normal element (not subbranch) */ if (policy->merge_double_add + && side1->content && side2->content /* they are not subbranches */ && svn_branch_el_rev_content_equal(side1, side2, scratch_pool)) { SVN_DBG(("e%d double add",