1333347Speter/* 2333347Speter * branch.c : Element-Based Branching and Move Tracking. 3333347Speter * 4333347Speter * ==================================================================== 5333347Speter * Licensed to the Apache Software Foundation (ASF) under one 6333347Speter * or more contributor license agreements. See the NOTICE file 7333347Speter * distributed with this work for additional information 8333347Speter * regarding copyright ownership. The ASF licenses this file 9333347Speter * to you under the Apache License, Version 2.0 (the 10333347Speter * "License"); you may not use this file except in compliance 11333347Speter * with the License. You may obtain a copy of the License at 12333347Speter * 13333347Speter * http://www.apache.org/licenses/LICENSE-2.0 14333347Speter * 15333347Speter * Unless required by applicable law or agreed to in writing, 16333347Speter * software distributed under the License is distributed on an 17333347Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18333347Speter * KIND, either express or implied. See the License for the 19333347Speter * specific language governing permissions and limitations 20333347Speter * under the License. 21333347Speter * ==================================================================== 22333347Speter */ 23333347Speter 24333347Speter#include <assert.h> 25333347Speter 26333347Speter#include "svn_types.h" 27333347Speter#include "svn_error.h" 28333347Speter#include "svn_dirent_uri.h" 29333347Speter#include "svn_hash.h" 30333347Speter#include "svn_iter.h" 31333347Speter#include "svn_pools.h" 32333347Speter 33333347Speter#include "private/svn_element.h" 34333347Speter#include "private/svn_branch.h" 35333347Speter#include "private/svn_branch_impl.h" 36333347Speter#include "private/svn_sorts_private.h" 37333347Speter 38333347Speter#include "svn_private_config.h" 39333347Speter 40333347Speter 41333347Speter/* Is EID allocated (no matter whether an element with this id exists)? */ 42333347Speter#define EID_IS_ALLOCATED(branch, eid) \ 43333347Speter ((eid) >= (branch)->txn->priv->first_eid \ 44333347Speter && (eid) < (branch)->txn->priv->next_eid) 45333347Speter 46333347Speter#define IS_BRANCH_ROOT_EID(branch, eid) \ 47333347Speter ((eid) == (branch)->priv->element_tree->root_eid) 48333347Speter 49333347Speter/* Is BRANCH1 the same branch as BRANCH2? Compare by full branch-ids; don't 50333347Speter require identical branch objects. */ 51333347Speter#define BRANCH_IS_SAME_BRANCH(branch1, branch2, scratch_pool) \ 52333347Speter (strcmp(svn_branch__get_id(branch1, scratch_pool), \ 53333347Speter svn_branch__get_id(branch2, scratch_pool)) == 0) 54333347Speter 55333347Speterstruct svn_branch__txn_priv_t 56333347Speter{ 57333347Speter /* All branches. */ 58333347Speter apr_array_header_t *branches; 59333347Speter 60333347Speter /* The range of element ids assigned. */ 61333347Speter /* EIDs local to the txn are negative, assigned by decrementing FIRST_EID 62333347Speter * (skipping -1). */ 63333347Speter int first_eid, next_eid; 64333347Speter 65333347Speter}; 66333347Speter 67333347Speterstruct svn_branch__state_priv_t 68333347Speter{ 69333347Speter /* EID -> svn_element__content_t mapping. */ 70333347Speter svn_element__tree_t *element_tree; 71333347Speter 72333347Speter /* Merge history for this branch state. */ 73333347Speter svn_branch__history_t *history; 74333347Speter 75333347Speter svn_boolean_t is_flat; 76333347Speter 77333347Speter}; 78333347Speter 79333347Speterstatic svn_branch__state_t * 80333347Speterbranch_state_create(const char *bid, 81333347Speter int root_eid, 82333347Speter svn_branch__txn_t *txn, 83333347Speter apr_pool_t *result_pool); 84333347Speter 85333347Speterstatic svn_error_t * 86333347Speterbranch_instantiate_elements(svn_branch__state_t *to_branch, 87333347Speter const svn_element__tree_t *elements, 88333347Speter apr_pool_t *scratch_pool); 89333347Speter 90333347Speterstatic svn_error_t * 91333347Spetersvn_branch__map_add_subtree(svn_branch__state_t *to_branch, 92333347Speter int to_eid, 93333347Speter svn_branch__eid_t new_parent_eid, 94333347Speter const char *new_name, 95333347Speter svn_element__tree_t *new_subtree, 96333347Speter apr_pool_t *scratch_pool); 97333347Speter 98333347Speter/* */ 99333347Speterstatic apr_pool_t * 100333347Speterbranch_state_pool_get(svn_branch__state_t *branch) 101333347Speter{ 102333347Speter return apr_hash_pool_get(branch->priv->element_tree->e_map); 103333347Speter} 104333347Speter 105333347Speter/* ### Layering: we didn't want to look at the whole repos in here, but 106333347Speter copying seems to require it. */ 107333347Spetersvn_error_t * 108333347Spetersvn_branch__repos_get_branch_by_id(svn_branch__state_t **branch_p, 109333347Speter const svn_branch__repos_t *repos, 110333347Speter svn_revnum_t revnum, 111333347Speter const char *branch_id, 112333347Speter apr_pool_t *scratch_pool); 113333347Speter 114333347Speter/* */ 115333347Speterstatic svn_error_t * 116333347Speterbranch_in_rev_or_txn(svn_branch__state_t **src_branch, 117333347Speter const svn_branch__rev_bid_eid_t *src_el_rev, 118333347Speter svn_branch__txn_t *txn, 119333347Speter apr_pool_t *result_pool) 120333347Speter{ 121333347Speter if (SVN_IS_VALID_REVNUM(src_el_rev->rev)) 122333347Speter { 123333347Speter SVN_ERR(svn_branch__repos_get_branch_by_id(src_branch, 124333347Speter txn->repos, 125333347Speter src_el_rev->rev, 126333347Speter src_el_rev->bid, 127333347Speter result_pool)); 128333347Speter } 129333347Speter else 130333347Speter { 131333347Speter *src_branch 132333347Speter = svn_branch__txn_get_branch_by_id(txn, src_el_rev->bid, result_pool); 133333347Speter } 134333347Speter 135333347Speter return SVN_NO_ERROR; 136333347Speter} 137333347Speter 138333347Speter/* An #svn_branch__txn_t method. */ 139333347Speterstatic apr_array_header_t * 140333347Speterbranch_txn_get_branches(const svn_branch__txn_t *txn, 141333347Speter apr_pool_t *result_pool) 142333347Speter{ 143333347Speter return apr_array_copy(result_pool, txn->priv->branches); 144333347Speter} 145333347Speter 146333347Speter/* An #svn_branch__txn_t method. */ 147333347Speterstatic svn_error_t * 148333347Speterbranch_txn_delete_branch(svn_branch__txn_t *txn, 149333347Speter const char *bid, 150333347Speter apr_pool_t *scratch_pool) 151333347Speter{ 152333347Speter int i; 153333347Speter 154333347Speter for (i = 0; i < txn->priv->branches->nelts; i++) 155333347Speter { 156333347Speter svn_branch__state_t *b = APR_ARRAY_IDX(txn->priv->branches, i, void *); 157333347Speter 158333347Speter if (strcmp(b->bid, bid) == 0) 159333347Speter { 160362181Sdim SVN_ERR(svn_sort__array_delete2(txn->priv->branches, i, 1)); 161333347Speter break; 162333347Speter } 163333347Speter } 164333347Speter return SVN_NO_ERROR; 165333347Speter} 166333347Speter 167333347Speter/* An #svn_branch__txn_t method. */ 168333347Speterstatic svn_error_t * 169333347Speterbranch_txn_get_num_new_eids(const svn_branch__txn_t *txn, 170333347Speter int *num_new_eids_p, 171333347Speter apr_pool_t *scratch_pool) 172333347Speter{ 173333347Speter if (num_new_eids_p) 174333347Speter *num_new_eids_p = -1 - txn->priv->first_eid; 175333347Speter return SVN_NO_ERROR; 176333347Speter} 177333347Speter 178333347Speter/* An #svn_branch__txn_t method. */ 179333347Speterstatic svn_error_t * 180333347Speterbranch_txn_new_eid(svn_branch__txn_t *txn, 181333347Speter svn_branch__eid_t *eid_p, 182333347Speter apr_pool_t *scratch_pool) 183333347Speter{ 184333347Speter int eid = (txn->priv->first_eid < 0) ? txn->priv->first_eid - 1 : -2; 185333347Speter 186333347Speter txn->priv->first_eid = eid; 187333347Speter if (eid_p) 188333347Speter *eid_p = eid; 189333347Speter return SVN_NO_ERROR; 190333347Speter} 191333347Speter 192333347Speter/* An #svn_branch__txn_t method. */ 193333347Speterstatic svn_error_t * 194333347Speterbranch_txn_open_branch(svn_branch__txn_t *txn, 195333347Speter svn_branch__state_t **new_branch_p, 196333347Speter const char *branch_id, 197333347Speter int root_eid, 198333347Speter svn_branch__rev_bid_eid_t *tree_ref, 199333347Speter apr_pool_t *result_pool, 200333347Speter apr_pool_t *scratch_pool) 201333347Speter{ 202333347Speter svn_branch__state_t *new_branch; 203333347Speter 204333347Speter /* if the branch already exists, just return it, else create it */ 205333347Speter new_branch 206333347Speter = svn_branch__txn_get_branch_by_id(txn, branch_id, scratch_pool); 207333347Speter if (new_branch) 208333347Speter { 209333347Speter SVN_ERR_ASSERT(root_eid == svn_branch__root_eid(new_branch)); 210333347Speter } 211333347Speter else 212333347Speter { 213333347Speter SVN_ERR_ASSERT_NO_RETURN(root_eid != -1); 214333347Speter 215333347Speter new_branch = branch_state_create(branch_id, root_eid, txn, 216333347Speter txn->priv->branches->pool); 217333347Speter APR_ARRAY_PUSH(txn->priv->branches, void *) = new_branch; 218333347Speter } 219333347Speter 220333347Speter if (tree_ref) 221333347Speter { 222333347Speter svn_branch__state_t *from_branch; 223333347Speter svn_element__tree_t *tree; 224333347Speter 225333347Speter SVN_ERR(branch_in_rev_or_txn(&from_branch, tree_ref, txn, scratch_pool)); 226333347Speter /* Source branch must exist */ 227333347Speter if (! from_branch) 228333347Speter { 229333347Speter return svn_error_createf(SVN_BRANCH__ERR, NULL, 230333347Speter _("Cannot branch from r%ld %s e%d: " 231333347Speter "branch does not exist"), 232333347Speter tree_ref->rev, tree_ref->bid, tree_ref->eid); 233333347Speter } 234333347Speter 235333347Speter SVN_ERR_ASSERT(from_branch->priv->is_flat); 236333347Speter 237333347Speter SVN_ERR(svn_branch__state_get_elements(from_branch, &tree, 238333347Speter scratch_pool)); 239333347Speter tree = svn_element__tree_get_subtree_at_eid(tree, tree_ref->eid, 240333347Speter scratch_pool); 241333347Speter /* Source element must exist */ 242333347Speter if (! tree) 243333347Speter { 244333347Speter return svn_error_createf(SVN_BRANCH__ERR, NULL, 245333347Speter _("Cannot branch from r%ld %s e%d: " 246333347Speter "element does not exist"), 247333347Speter tree_ref->rev, tree_ref->bid, tree_ref->eid); 248333347Speter } 249333347Speter 250333347Speter /* Populate the tree from the 'from' source */ 251333347Speter SVN_ERR(branch_instantiate_elements(new_branch, tree, scratch_pool)); 252333347Speter } 253333347Speter 254333347Speter if (new_branch_p) 255333347Speter *new_branch_p = new_branch; 256333347Speter return SVN_NO_ERROR; 257333347Speter} 258333347Speter 259333347Speter/* An #svn_branch__txn_t method. */ 260333347Speterstatic svn_error_t * 261333347Speterbranch_txn_sequence_point(svn_branch__txn_t *txn, 262333347Speter apr_pool_t *scratch_pool) 263333347Speter{ 264333347Speter int i; 265333347Speter 266333347Speter /* purge elements in each branch */ 267333347Speter for (i = 0; i < txn->priv->branches->nelts; i++) 268333347Speter { 269333347Speter svn_branch__state_t *b 270333347Speter = APR_ARRAY_IDX(txn->priv->branches, i, void *); 271333347Speter 272333347Speter SVN_ERR(svn_branch__state_purge(b, scratch_pool)); 273333347Speter } 274333347Speter 275333347Speter return SVN_NO_ERROR; 276333347Speter} 277333347Speter 278333347Speter/* An #svn_branch__txn_t method. */ 279333347Speterstatic svn_error_t * 280333347Speterbranch_txn_complete(svn_branch__txn_t *txn, 281333347Speter apr_pool_t *scratch_pool) 282333347Speter{ 283333347Speter return SVN_NO_ERROR; 284333347Speter} 285333347Speter 286333347Speter/* An #svn_branch__txn_t method. */ 287333347Speterstatic svn_error_t * 288333347Speterbranch_txn_abort(svn_branch__txn_t *txn, 289333347Speter apr_pool_t *scratch_pool) 290333347Speter{ 291333347Speter return SVN_NO_ERROR; 292333347Speter} 293333347Speter 294333347Speter/* 295333347Speter * ======================================================================== 296333347Speter * Branch Txn Object 297333347Speter * ======================================================================== 298333347Speter */ 299333347Speter 300333347Speterapr_array_header_t * 301333347Spetersvn_branch__txn_get_branches(const svn_branch__txn_t *txn, 302333347Speter apr_pool_t *result_pool) 303333347Speter{ 304333347Speter apr_array_header_t *branches 305333347Speter = txn->vtable->get_branches(txn, 306333347Speter result_pool); 307333347Speter return branches; 308333347Speter} 309333347Speter 310333347Spetersvn_error_t * 311333347Spetersvn_branch__txn_delete_branch(svn_branch__txn_t *txn, 312333347Speter const char *bid, 313333347Speter apr_pool_t *scratch_pool) 314333347Speter{ 315333347Speter SVN_ERR(txn->vtable->delete_branch(txn, 316333347Speter bid, 317333347Speter scratch_pool)); 318333347Speter return SVN_NO_ERROR; 319333347Speter} 320333347Speter 321333347Spetersvn_error_t * 322333347Spetersvn_branch__txn_get_num_new_eids(const svn_branch__txn_t *txn, 323333347Speter int *num_new_eids_p, 324333347Speter apr_pool_t *scratch_pool) 325333347Speter{ 326333347Speter SVN_ERR(txn->vtable->get_num_new_eids(txn, 327333347Speter num_new_eids_p, 328333347Speter scratch_pool)); 329333347Speter return SVN_NO_ERROR; 330333347Speter} 331333347Speter 332333347Spetersvn_error_t * 333333347Spetersvn_branch__txn_new_eid(svn_branch__txn_t *txn, 334333347Speter int *new_eid_p, 335333347Speter apr_pool_t *scratch_pool) 336333347Speter{ 337333347Speter SVN_ERR(txn->vtable->new_eid(txn, 338333347Speter new_eid_p, 339333347Speter scratch_pool)); 340333347Speter return SVN_NO_ERROR; 341333347Speter} 342333347Speter 343333347Spetersvn_error_t * 344333347Spetersvn_branch__txn_open_branch(svn_branch__txn_t *txn, 345333347Speter svn_branch__state_t **new_branch_p, 346333347Speter const char *branch_id, 347333347Speter int root_eid, 348333347Speter svn_branch__rev_bid_eid_t *tree_ref, 349333347Speter apr_pool_t *result_pool, 350333347Speter apr_pool_t *scratch_pool) 351333347Speter{ 352333347Speter SVN_ERR(txn->vtable->open_branch(txn, 353333347Speter new_branch_p, 354333347Speter branch_id, 355333347Speter root_eid, tree_ref, result_pool, 356333347Speter scratch_pool)); 357333347Speter return SVN_NO_ERROR; 358333347Speter} 359333347Speter 360333347Spetersvn_error_t * 361333347Spetersvn_branch__txn_finalize_eids(svn_branch__txn_t *txn, 362333347Speter apr_pool_t *scratch_pool) 363333347Speter{ 364333347Speter SVN_ERR(txn->vtable->finalize_eids(txn, 365333347Speter scratch_pool)); 366333347Speter return SVN_NO_ERROR; 367333347Speter} 368333347Speter 369333347Spetersvn_error_t * 370333347Spetersvn_branch__txn_serialize(svn_branch__txn_t *txn, 371333347Speter svn_stream_t *stream, 372333347Speter apr_pool_t *scratch_pool) 373333347Speter{ 374333347Speter SVN_ERR(txn->vtable->serialize(txn, 375333347Speter stream, 376333347Speter scratch_pool)); 377333347Speter return SVN_NO_ERROR; 378333347Speter} 379333347Speter 380333347Spetersvn_error_t * 381333347Spetersvn_branch__txn_sequence_point(svn_branch__txn_t *txn, 382333347Speter apr_pool_t *scratch_pool) 383333347Speter{ 384333347Speter SVN_ERR(txn->vtable->sequence_point(txn, 385333347Speter scratch_pool)); 386333347Speter return SVN_NO_ERROR; 387333347Speter} 388333347Speter 389333347Spetersvn_error_t * 390333347Spetersvn_branch__txn_complete(svn_branch__txn_t *txn, 391333347Speter apr_pool_t *scratch_pool) 392333347Speter{ 393333347Speter SVN_ERR(txn->vtable->complete(txn, 394333347Speter scratch_pool)); 395333347Speter return SVN_NO_ERROR; 396333347Speter} 397333347Speter 398333347Spetersvn_error_t * 399333347Spetersvn_branch__txn_abort(svn_branch__txn_t *txn, 400333347Speter apr_pool_t *scratch_pool) 401333347Speter{ 402333347Speter SVN_ERR(txn->vtable->abort(txn, 403333347Speter scratch_pool)); 404333347Speter return SVN_NO_ERROR; 405333347Speter} 406333347Speter 407333347Spetersvn_branch__txn_t * 408333347Spetersvn_branch__txn_create(const svn_branch__txn_vtable_t *vtable, 409333347Speter svn_cancel_func_t cancel_func, 410333347Speter void *cancel_baton, 411333347Speter apr_pool_t *result_pool) 412333347Speter{ 413333347Speter svn_branch__txn_t *txn = apr_pcalloc(result_pool, sizeof(*txn)); 414333347Speter 415333347Speter txn->vtable = apr_pmemdup(result_pool, vtable, sizeof(*vtable)); 416333347Speter 417333347Speter txn->vtable->vpriv.cancel_func = cancel_func; 418333347Speter txn->vtable->vpriv.cancel_baton = cancel_baton; 419333347Speter 420333347Speter#ifdef ENABLE_ORDERING_CHECK 421333347Speter txn->vtable->vpriv.within_callback = FALSE; 422333347Speter txn->vtable->vpriv.finished = FALSE; 423333347Speter txn->vtable->vpriv.state_pool = result_pool; 424333347Speter#endif 425333347Speter 426333347Speter return txn; 427333347Speter} 428333347Speter 429333347Speter/* 430333347Speter * ======================================================================== 431333347Speter */ 432333347Speter 433333347Speter/* */ 434333347Speterstatic const char * 435333347Speterbranch_finalize_bid(const char *bid, 436333347Speter int mapping_offset, 437333347Speter apr_pool_t *result_pool) 438333347Speter{ 439333347Speter const char *outer_bid; 440333347Speter int outer_eid; 441333347Speter 442333347Speter svn_branch__id_unnest(&outer_bid, &outer_eid, bid, result_pool); 443333347Speter 444333347Speter if (outer_bid) 445333347Speter { 446333347Speter outer_bid = branch_finalize_bid(outer_bid, mapping_offset, result_pool); 447333347Speter } 448333347Speter 449333347Speter if (outer_eid < -1) 450333347Speter { 451333347Speter outer_eid = mapping_offset - outer_eid; 452333347Speter } 453333347Speter 454333347Speter return svn_branch__id_nest(outer_bid, outer_eid, result_pool); 455333347Speter} 456333347Speter 457333347Speter/* Change txn-local EIDs (negative integers) in BRANCH to revision EIDs, by 458333347Speter * assigning a new revision-EID (positive integer) for each one. 459333347Speter */ 460333347Speterstatic svn_error_t * 461333347Speterbranch_finalize_eids(svn_branch__state_t *branch, 462333347Speter int mapping_offset, 463333347Speter apr_pool_t *scratch_pool) 464333347Speter{ 465333347Speter apr_hash_index_t *hi; 466333347Speter 467333347Speter branch->bid = branch_finalize_bid(branch->bid, mapping_offset, 468333347Speter branch_state_pool_get(branch)); 469333347Speter if (branch->priv->element_tree->root_eid < -1) 470333347Speter { 471333347Speter branch->priv->element_tree->root_eid 472333347Speter = mapping_offset - branch->priv->element_tree->root_eid; 473333347Speter } 474333347Speter 475333347Speter for (hi = apr_hash_first(scratch_pool, branch->priv->element_tree->e_map); 476333347Speter hi; hi = apr_hash_next(hi)) 477333347Speter { 478333347Speter int old_eid = svn_eid__hash_this_key(hi); 479333347Speter svn_element__content_t *element = apr_hash_this_val(hi); 480333347Speter 481333347Speter if (old_eid < -1) 482333347Speter { 483333347Speter int new_eid = mapping_offset - old_eid; 484333347Speter 485333347Speter svn_element__tree_set(branch->priv->element_tree, old_eid, NULL); 486333347Speter svn_element__tree_set(branch->priv->element_tree, new_eid, element); 487333347Speter } 488333347Speter if (element->parent_eid < -1) 489333347Speter { 490333347Speter element->parent_eid = mapping_offset - element->parent_eid; 491333347Speter } 492333347Speter } 493333347Speter return SVN_NO_ERROR; 494333347Speter} 495333347Speter 496333347Speter/* An #svn_branch__txn_t method. */ 497333347Speterstatic svn_error_t * 498333347Speterbranch_txn_finalize_eids(svn_branch__txn_t *txn, 499333347Speter apr_pool_t *scratch_pool) 500333347Speter{ 501333347Speter int n_txn_eids = (-1) - txn->priv->first_eid; 502333347Speter int mapping_offset; 503333347Speter apr_array_header_t *branches = branch_txn_get_branches(txn, scratch_pool); 504333347Speter int i; 505333347Speter 506333347Speter if (txn->priv->first_eid == 0) 507333347Speter return SVN_NO_ERROR; 508333347Speter 509333347Speter /* mapping from txn-local (negative) EID to committed (positive) EID is: 510333347Speter txn_local_eid == -2 => committed_eid := (txn.next_eid + 0) 511333347Speter txn_local_eid == -3 => committed_eid := (txn.next_eid + 1) ... */ 512333347Speter mapping_offset = txn->priv->next_eid - 2; 513333347Speter 514333347Speter for (i = 0; i < branches->nelts; i++) 515333347Speter { 516333347Speter svn_branch__state_t *b = APR_ARRAY_IDX(branches, i, void *); 517333347Speter 518333347Speter SVN_ERR(branch_finalize_eids(b, mapping_offset, scratch_pool)); 519333347Speter } 520333347Speter 521333347Speter txn->priv->next_eid += n_txn_eids; 522333347Speter txn->priv->first_eid = 0; 523333347Speter return SVN_NO_ERROR; 524333347Speter} 525333347Speter 526333347Speter/* 527333347Speter * ======================================================================== 528333347Speter */ 529333347Speter 530333347Speterstatic svn_error_t * 531333347Speterbranch_txn_serialize(svn_branch__txn_t *txn, 532333347Speter svn_stream_t *stream, 533333347Speter apr_pool_t *scratch_pool) 534333347Speter{ 535333347Speter apr_array_header_t *branches = branch_txn_get_branches(txn, scratch_pool); 536333347Speter int i; 537333347Speter 538333347Speter SVN_ERR(svn_stream_printf(stream, scratch_pool, 539333347Speter "r%ld: eids %d %d " 540333347Speter "branches %d\n", 541333347Speter txn->rev, 542333347Speter txn->priv->first_eid, txn->priv->next_eid, 543333347Speter branches->nelts)); 544333347Speter 545333347Speter for (i = 0; i < branches->nelts; i++) 546333347Speter { 547333347Speter svn_branch__state_t *branch = APR_ARRAY_IDX(branches, i, void *); 548333347Speter 549333347Speter SVN_ERR(svn_branch__state_serialize(stream, branch, scratch_pool)); 550333347Speter } 551333347Speter return SVN_NO_ERROR; 552333347Speter} 553333347Speter 554333347Speter/* 555333347Speter * ======================================================================== 556333347Speter */ 557333347Speter 558333347Spetersvn_branch__state_t * 559333347Spetersvn_branch__txn_get_branch_by_id(const svn_branch__txn_t *txn, 560333347Speter const char *branch_id, 561333347Speter apr_pool_t *scratch_pool) 562333347Speter{ 563333347Speter apr_array_header_t *branches = svn_branch__txn_get_branches(txn, scratch_pool); 564333347Speter int i; 565333347Speter svn_branch__state_t *branch = NULL; 566333347Speter 567333347Speter for (i = 0; i < branches->nelts; i++) 568333347Speter { 569333347Speter svn_branch__state_t *b = APR_ARRAY_IDX(branches, i, void *); 570333347Speter 571333347Speter if (strcmp(svn_branch__get_id(b, scratch_pool), branch_id) == 0) 572333347Speter { 573333347Speter branch = b; 574333347Speter break; 575333347Speter } 576333347Speter } 577333347Speter return branch; 578333347Speter} 579333347Speter 580333347Speter/* 581333347Speter * ======================================================================== 582333347Speter */ 583333347Speter 584333347Speter/* Create a new branch txn object. 585333347Speter * 586333347Speter * It will have no branches. 587333347Speter */ 588333347Speterstatic svn_branch__txn_t * 589333347Speterbranch_txn_create(svn_branch__repos_t *repos, 590333347Speter svn_revnum_t rev, 591333347Speter svn_revnum_t base_rev, 592333347Speter apr_pool_t *result_pool) 593333347Speter{ 594333347Speter static const svn_branch__txn_vtable_t vtable = { 595333347Speter {0}, 596333347Speter branch_txn_get_branches, 597333347Speter branch_txn_delete_branch, 598333347Speter branch_txn_get_num_new_eids, 599333347Speter branch_txn_new_eid, 600333347Speter branch_txn_open_branch, 601333347Speter branch_txn_finalize_eids, 602333347Speter branch_txn_serialize, 603333347Speter branch_txn_sequence_point, 604333347Speter branch_txn_complete, 605333347Speter branch_txn_abort, 606333347Speter }; 607333347Speter svn_branch__txn_t *txn 608333347Speter = svn_branch__txn_create(&vtable, NULL, NULL, result_pool); 609333347Speter 610333347Speter txn->priv = apr_pcalloc(result_pool, sizeof(*txn->priv)); 611333347Speter txn->repos = repos; 612333347Speter txn->rev = rev; 613333347Speter txn->base_rev = base_rev; 614333347Speter txn->priv->branches = apr_array_make(result_pool, 0, sizeof(void *)); 615333347Speter return txn; 616333347Speter} 617333347Speter 618333347Speter/* 619333347Speter * ======================================================================== 620333347Speter */ 621333347Speter 622333347Speterstatic void 623333347Speterbranch_validate_element(const svn_branch__state_t *branch, 624333347Speter int eid, 625333347Speter const svn_element__content_t *element); 626333347Speter 627333347Speter/* Assert BRANCH satisfies all its invariants. 628333347Speter */ 629333347Speterstatic void 630333347Speterassert_branch_state_invariants(const svn_branch__state_t *branch, 631333347Speter apr_pool_t *scratch_pool) 632333347Speter{ 633333347Speter apr_hash_index_t *hi; 634333347Speter 635333347Speter assert(branch->bid); 636333347Speter assert(branch->txn); 637333347Speter assert(branch->priv->element_tree); 638333347Speter assert(branch->priv->element_tree->e_map); 639333347Speter 640333347Speter /* Validate elements in the map */ 641333347Speter for (hi = apr_hash_first(scratch_pool, branch->priv->element_tree->e_map); 642333347Speter hi; hi = apr_hash_next(hi)) 643333347Speter { 644333347Speter branch_validate_element(branch, svn_eid__hash_this_key(hi), 645333347Speter apr_hash_this_val(hi)); 646333347Speter } 647333347Speter} 648333347Speter 649333347Speter/* An #svn_branch__state_t method. */ 650333347Speterstatic svn_error_t * 651333347Speterbranch_state_copy_one(svn_branch__state_t *branch, 652333347Speter const svn_branch__rev_bid_eid_t *src_el_rev, 653333347Speter svn_branch__eid_t eid, 654333347Speter svn_branch__eid_t new_parent_eid, 655333347Speter const char *new_name, 656333347Speter const svn_element__payload_t *new_payload, 657333347Speter apr_pool_t *scratch_pool) 658333347Speter{ 659333347Speter /* New payload shall be the same as the source if NEW_PAYLOAD is null. */ 660333347Speter /* ### if (! new_payload) 661333347Speter { 662333347Speter new_payload = branch_map_get(branch, eid)->payload; 663333347Speter } 664333347Speter */ 665333347Speter 666333347Speter return SVN_NO_ERROR; 667333347Speter} 668333347Speter 669333347Speter/* Copy a subtree. 670333347Speter * 671333347Speter * Adjust TO_BRANCH and its subbranches (recursively), to reflect a copy 672333347Speter * of a subtree from FROM_EL_REV to TO_PARENT_EID:TO_NAME. 673333347Speter * 674333347Speter * FROM_EL_REV must be an existing element. (It may be a branch root.) 675333347Speter * 676333347Speter * ### TODO: 677333347Speter * If FROM_EL_REV is the root of a subbranch and/or contains nested 678333347Speter * subbranches, also copy them ... 679333347Speter * ### What shall we do with a subbranch? Make plain copies of its raw 680333347Speter * elements; make a subbranch by branching the source subbranch? 681333347Speter * 682333347Speter * TO_PARENT_EID must be a directory element in TO_BRANCH, and TO_NAME a 683333347Speter * non-existing path in it. 684333347Speter */ 685333347Speterstatic svn_error_t * 686333347Spetercopy_subtree(const svn_branch__el_rev_id_t *from_el_rev, 687333347Speter svn_branch__state_t *to_branch, 688333347Speter svn_branch__eid_t to_parent_eid, 689333347Speter const char *to_name, 690333347Speter apr_pool_t *scratch_pool) 691333347Speter{ 692333347Speter svn_element__tree_t *new_subtree; 693333347Speter 694333347Speter SVN_ERR_ASSERT(from_el_rev->branch->priv->is_flat); 695333347Speter 696333347Speter SVN_ERR(svn_branch__state_get_elements(from_el_rev->branch, &new_subtree, 697333347Speter scratch_pool)); 698333347Speter new_subtree = svn_element__tree_get_subtree_at_eid(new_subtree, 699333347Speter from_el_rev->eid, 700333347Speter scratch_pool); 701333347Speter 702333347Speter /* copy the subtree, assigning new EIDs */ 703333347Speter SVN_ERR(svn_branch__map_add_subtree(to_branch, -1 /*to_eid*/, 704333347Speter to_parent_eid, to_name, 705333347Speter new_subtree, 706333347Speter scratch_pool)); 707333347Speter 708333347Speter return SVN_NO_ERROR; 709333347Speter} 710333347Speter 711333347Speter/* An #svn_branch__state_t method. */ 712333347Speterstatic svn_error_t * 713333347Speterbranch_state_copy_tree(svn_branch__state_t *to_branch, 714333347Speter const svn_branch__rev_bid_eid_t *src_el_rev, 715333347Speter svn_branch__eid_t new_parent_eid, 716333347Speter const char *new_name, 717333347Speter apr_pool_t *scratch_pool) 718333347Speter{ 719333347Speter svn_branch__txn_t *txn = to_branch->txn; 720333347Speter svn_branch__state_t *src_branch; 721333347Speter svn_branch__el_rev_id_t *from_el_rev; 722333347Speter 723333347Speter SVN_ERR(branch_in_rev_or_txn(&src_branch, src_el_rev, txn, scratch_pool)); 724333347Speter from_el_rev = svn_branch__el_rev_id_create(src_branch, src_el_rev->eid, 725333347Speter src_el_rev->rev, scratch_pool); 726333347Speter SVN_ERR(copy_subtree(from_el_rev, 727333347Speter to_branch, new_parent_eid, new_name, 728333347Speter scratch_pool)); 729333347Speter 730333347Speter return SVN_NO_ERROR; 731333347Speter} 732333347Speter 733333347Speterconst char * 734333347Spetersvn_branch__get_id(const svn_branch__state_t *branch, 735333347Speter apr_pool_t *result_pool) 736333347Speter{ 737333347Speter return branch->bid; 738333347Speter} 739333347Speter 740333347Speterint 741333347Spetersvn_branch__root_eid(const svn_branch__state_t *branch) 742333347Speter{ 743333347Speter svn_element__tree_t *elements; 744333347Speter 745333347Speter svn_error_clear(svn_branch__state_get_elements(branch, &elements, 746333347Speter NULL/*scratch_pool*/)); 747333347Speter return elements->root_eid; 748333347Speter} 749333347Speter 750333347Spetersvn_branch__el_rev_id_t * 751333347Spetersvn_branch__el_rev_id_create(svn_branch__state_t *branch, 752333347Speter int eid, 753333347Speter svn_revnum_t rev, 754333347Speter apr_pool_t *result_pool) 755333347Speter{ 756333347Speter svn_branch__el_rev_id_t *id = apr_palloc(result_pool, sizeof(*id)); 757333347Speter 758333347Speter id->branch = branch; 759333347Speter id->eid = eid; 760333347Speter id->rev = rev; 761333347Speter return id; 762333347Speter} 763333347Speter 764333347Spetersvn_branch__el_rev_id_t * 765333347Spetersvn_branch__el_rev_id_dup(const svn_branch__el_rev_id_t *old_id, 766333347Speter apr_pool_t *result_pool) 767333347Speter{ 768333347Speter if (! old_id) 769333347Speter return NULL; 770333347Speter 771333347Speter return svn_branch__el_rev_id_create(old_id->branch, 772333347Speter old_id->eid, 773333347Speter old_id->rev, 774333347Speter result_pool); 775333347Speter} 776333347Speter 777333347Spetersvn_branch__rev_bid_eid_t * 778333347Spetersvn_branch__rev_bid_eid_create(svn_revnum_t rev, 779333347Speter const char *branch_id, 780333347Speter int eid, 781333347Speter apr_pool_t *result_pool) 782333347Speter{ 783333347Speter svn_branch__rev_bid_eid_t *id = apr_palloc(result_pool, sizeof(*id)); 784333347Speter 785333347Speter id->bid = apr_pstrdup(result_pool, branch_id); 786333347Speter id->eid = eid; 787333347Speter id->rev = rev; 788333347Speter return id; 789333347Speter} 790333347Speter 791333347Spetersvn_branch__rev_bid_eid_t * 792333347Spetersvn_branch__rev_bid_eid_dup(const svn_branch__rev_bid_eid_t *old_id, 793333347Speter apr_pool_t *result_pool) 794333347Speter{ 795333347Speter svn_branch__rev_bid_eid_t *id; 796333347Speter 797333347Speter if (! old_id) 798333347Speter return NULL; 799333347Speter 800333347Speter id = apr_pmemdup(result_pool, old_id, sizeof(*id)); 801333347Speter id->bid = apr_pstrdup(result_pool, old_id->bid); 802333347Speter return id; 803333347Speter} 804333347Speter 805333347Spetersvn_branch__rev_bid_t * 806333347Spetersvn_branch__rev_bid_create(svn_revnum_t rev, 807333347Speter const char *branch_id, 808333347Speter apr_pool_t *result_pool) 809333347Speter{ 810333347Speter svn_branch__rev_bid_t *id = apr_palloc(result_pool, sizeof(*id)); 811333347Speter 812333347Speter id->bid = apr_pstrdup(result_pool, branch_id); 813333347Speter id->rev = rev; 814333347Speter return id; 815333347Speter} 816333347Speter 817333347Spetersvn_branch__rev_bid_t * 818333347Spetersvn_branch__rev_bid_dup(const svn_branch__rev_bid_t *old_id, 819333347Speter apr_pool_t *result_pool) 820333347Speter{ 821333347Speter svn_branch__rev_bid_t *id; 822333347Speter 823333347Speter if (! old_id) 824333347Speter return NULL; 825333347Speter 826333347Speter id = apr_pmemdup(result_pool, old_id, sizeof(*id)); 827333347Speter id->bid = apr_pstrdup(result_pool, old_id->bid); 828333347Speter return id; 829333347Speter} 830333347Speter 831333347Spetersvn_boolean_t 832333347Spetersvn_branch__rev_bid_equal(const svn_branch__rev_bid_t *id1, 833333347Speter const svn_branch__rev_bid_t *id2) 834333347Speter{ 835333347Speter return (id1->rev == id2->rev 836333347Speter && strcmp(id1->bid, id2->bid) == 0); 837333347Speter} 838333347Speter 839333347Spetersvn_branch__history_t * 840333347Spetersvn_branch__history_create_empty(apr_pool_t *result_pool) 841333347Speter{ 842333347Speter svn_branch__history_t *history 843333347Speter = svn_branch__history_create(NULL, result_pool); 844333347Speter 845333347Speter return history; 846333347Speter} 847333347Speter 848333347Spetersvn_branch__history_t * 849333347Spetersvn_branch__history_create(apr_hash_t *parents, 850333347Speter apr_pool_t *result_pool) 851333347Speter{ 852333347Speter svn_branch__history_t *history 853333347Speter = apr_pcalloc(result_pool, sizeof(*history)); 854333347Speter 855333347Speter history->parents = apr_hash_make(result_pool); 856333347Speter if (parents) 857333347Speter { 858333347Speter apr_hash_index_t *hi; 859333347Speter 860333347Speter for (hi = apr_hash_first(result_pool, parents); 861333347Speter hi; hi = apr_hash_next(hi)) 862333347Speter { 863333347Speter const char *bid = apr_hash_this_key(hi); 864333347Speter svn_branch__rev_bid_t *val = apr_hash_this_val(hi); 865333347Speter 866333347Speter svn_hash_sets(history->parents, 867333347Speter apr_pstrdup(result_pool, bid), 868333347Speter svn_branch__rev_bid_dup(val, result_pool)); 869333347Speter } 870333347Speter } 871333347Speter return history; 872333347Speter} 873333347Speter 874333347Spetersvn_branch__history_t * 875333347Spetersvn_branch__history_dup(const svn_branch__history_t *old, 876333347Speter apr_pool_t *result_pool) 877333347Speter{ 878333347Speter svn_branch__history_t *history = NULL; 879333347Speter 880333347Speter if (old) 881333347Speter { 882333347Speter history 883333347Speter = svn_branch__history_create(old->parents, result_pool); 884333347Speter } 885333347Speter return history; 886333347Speter} 887333347Speter 888333347Speter 889333347Speter/* 890333347Speter * ======================================================================== 891333347Speter * Branch mappings 892333347Speter * ======================================================================== 893333347Speter */ 894333347Speter 895333347Speter/* Validate that ELEMENT is suitable for a mapping of BRANCH:EID. 896333347Speter * ELEMENT->payload may be null. 897333347Speter */ 898333347Speterstatic void 899333347Speterbranch_validate_element(const svn_branch__state_t *branch, 900333347Speter int eid, 901333347Speter const svn_element__content_t *element) 902333347Speter{ 903333347Speter SVN_ERR_ASSERT_NO_RETURN(element); 904333347Speter 905333347Speter /* Parent EID must be valid and different from this element's EID, or -1 906333347Speter iff this is the branch root element. */ 907333347Speter SVN_ERR_ASSERT_NO_RETURN( 908333347Speter IS_BRANCH_ROOT_EID(branch, eid) 909333347Speter ? (element->parent_eid == -1) 910333347Speter : (element->parent_eid != eid 911333347Speter && EID_IS_ALLOCATED(branch, element->parent_eid))); 912333347Speter 913333347Speter /* Element name must be given, and empty iff EID is the branch root. */ 914333347Speter SVN_ERR_ASSERT_NO_RETURN( 915333347Speter element->name 916333347Speter && IS_BRANCH_ROOT_EID(branch, eid) == (*element->name == '\0')); 917333347Speter 918333347Speter SVN_ERR_ASSERT_NO_RETURN(svn_element__payload_invariants(element->payload)); 919333347Speter if (element->payload->is_subbranch_root) 920333347Speter { 921333347Speter /* a subbranch root element must not be the branch root element */ 922333347Speter SVN_ERR_ASSERT_NO_RETURN(! IS_BRANCH_ROOT_EID(branch, eid)); 923333347Speter } 924333347Speter} 925333347Speter 926333347Speterstatic svn_error_t * 927333347Speterbranch_state_get_elements(const svn_branch__state_t *branch, 928333347Speter svn_element__tree_t **element_tree_p, 929333347Speter apr_pool_t *result_pool) 930333347Speter{ 931333347Speter *element_tree_p = branch->priv->element_tree; 932333347Speter return SVN_NO_ERROR; 933333347Speter} 934333347Speter 935333347Speterstatic svn_element__content_t * 936333347Speterbranch_get_element(const svn_branch__state_t *branch, 937333347Speter int eid) 938333347Speter{ 939333347Speter svn_element__content_t *element; 940333347Speter 941333347Speter element = svn_element__tree_get(branch->priv->element_tree, eid); 942333347Speter 943333347Speter if (element) 944333347Speter branch_validate_element(branch, eid, element); 945333347Speter return element; 946333347Speter} 947333347Speter 948333347Speterstatic svn_error_t * 949333347Speterbranch_state_get_element(const svn_branch__state_t *branch, 950333347Speter svn_element__content_t **element_p, 951333347Speter int eid, 952333347Speter apr_pool_t *result_pool) 953333347Speter{ 954333347Speter *element_p = branch_get_element(branch, eid); 955333347Speter return SVN_NO_ERROR; 956333347Speter} 957333347Speter 958333347Speter/* In BRANCH, set element EID to ELEMENT. 959333347Speter * 960333347Speter * If ELEMENT is null, delete element EID. 961333347Speter * 962333347Speter * Assume ELEMENT is already allocated with sufficient lifetime. 963333347Speter */ 964333347Speterstatic void 965333347Speterbranch_map_set(svn_branch__state_t *branch, 966333347Speter int eid, 967333347Speter const svn_element__content_t *element) 968333347Speter{ 969333347Speter apr_pool_t *map_pool = apr_hash_pool_get(branch->priv->element_tree->e_map); 970333347Speter 971333347Speter SVN_ERR_ASSERT_NO_RETURN(EID_IS_ALLOCATED(branch, eid)); 972333347Speter if (element) 973333347Speter branch_validate_element(branch, eid, element); 974333347Speter 975333347Speter svn_element__tree_set(branch->priv->element_tree, eid, element); 976333347Speter branch->priv->is_flat = FALSE; 977333347Speter assert_branch_state_invariants(branch, map_pool); 978333347Speter} 979333347Speter 980333347Speter/* An #svn_branch__state_t method. */ 981333347Speterstatic svn_error_t * 982333347Speterbranch_state_set_element(svn_branch__state_t *branch, 983333347Speter svn_branch__eid_t eid, 984333347Speter const svn_element__content_t *element, 985333347Speter apr_pool_t *scratch_pool) 986333347Speter{ 987333347Speter apr_pool_t *map_pool = apr_hash_pool_get(branch->priv->element_tree->e_map); 988333347Speter 989333347Speter /* EID must be a valid element id */ 990333347Speter SVN_ERR_ASSERT(EID_IS_ALLOCATED(branch, eid)); 991333347Speter 992333347Speter if (element) 993333347Speter { 994333347Speter element = svn_element__content_dup(element, map_pool); 995333347Speter 996333347Speter /* NEW_PAYLOAD must be specified, either in full or by reference */ 997333347Speter SVN_ERR_ASSERT(element->payload); 998333347Speter 999333347Speter if ((element->parent_eid == -1) != IS_BRANCH_ROOT_EID(branch, eid) 1000333347Speter || (*element->name == '\0') != IS_BRANCH_ROOT_EID(branch, eid)) 1001333347Speter { 1002333347Speter return svn_error_createf(SVN_BRANCH__ERR, NULL, 1003333347Speter _("Cannot set e%d to (parent=e%d, name='%s'): " 1004333347Speter "branch root is e%d"), 1005333347Speter eid, element->parent_eid, element->name, 1006333347Speter branch->priv->element_tree->root_eid); 1007333347Speter } 1008333347Speter } 1009333347Speter 1010333347Speter /* Insert the new version */ 1011333347Speter branch_map_set(branch, eid, element); 1012333347Speter return SVN_NO_ERROR; 1013333347Speter} 1014333347Speter 1015333347Speter/* An #svn_branch__state_t method. */ 1016333347Speterstatic svn_error_t * 1017333347Speterbranch_state_purge(svn_branch__state_t *branch, 1018333347Speter apr_pool_t *scratch_pool) 1019333347Speter{ 1020333347Speter svn_element__tree_purge_orphans(branch->priv->element_tree->e_map, 1021333347Speter branch->priv->element_tree->root_eid, 1022333347Speter scratch_pool); 1023333347Speter branch->priv->is_flat = TRUE; 1024333347Speter return SVN_NO_ERROR; 1025333347Speter} 1026333347Speter 1027333347Speter/* An #svn_branch__state_t method. */ 1028333347Speterstatic svn_error_t * 1029333347Speterbranch_state_get_history(svn_branch__state_t *branch, 1030333347Speter svn_branch__history_t **history_p, 1031333347Speter apr_pool_t *result_pool) 1032333347Speter{ 1033333347Speter if (history_p) 1034333347Speter { 1035333347Speter *history_p 1036333347Speter = svn_branch__history_dup(branch->priv->history, result_pool); 1037333347Speter } 1038333347Speter return SVN_NO_ERROR; 1039333347Speter} 1040333347Speter 1041333347Speter/* An #svn_branch__state_t method. */ 1042333347Speterstatic svn_error_t * 1043333347Speterbranch_state_set_history(svn_branch__state_t *branch, 1044333347Speter const svn_branch__history_t *history, 1045333347Speter apr_pool_t *scratch_pool) 1046333347Speter{ 1047333347Speter apr_pool_t *branch_pool = branch_state_pool_get(branch); 1048333347Speter 1049333347Speter branch->priv->history 1050333347Speter = svn_branch__history_dup(history, branch_pool); 1051333347Speter return SVN_NO_ERROR; 1052333347Speter} 1053333347Speter 1054333347Speterconst char * 1055333347Spetersvn_branch__get_path_by_eid(const svn_branch__state_t *branch, 1056333347Speter int eid, 1057333347Speter apr_pool_t *result_pool) 1058333347Speter{ 1059333347Speter svn_element__tree_t *elements; 1060333347Speter 1061333347Speter SVN_ERR_ASSERT_NO_RETURN(EID_IS_ALLOCATED(branch, eid)); 1062333347Speter /*SVN_ERR_ASSERT_NO_RETURN(branch->priv->is_flat);*/ 1063333347Speter 1064333347Speter svn_error_clear(svn_branch__state_get_elements(branch, &elements, result_pool)); 1065333347Speter return svn_element__tree_get_path_by_eid(elements, eid, result_pool); 1066333347Speter} 1067333347Speter 1068333347Speterint 1069333347Spetersvn_branch__get_eid_by_path(const svn_branch__state_t *branch, 1070333347Speter const char *path, 1071333347Speter apr_pool_t *scratch_pool) 1072333347Speter{ 1073333347Speter svn_element__tree_t *elements; 1074333347Speter apr_hash_index_t *hi; 1075333347Speter 1076333347Speter /*SVN_ERR_ASSERT_NO_RETURN(branch->priv->is_flat);*/ 1077333347Speter 1078333347Speter /* ### This is a crude, linear search */ 1079333347Speter svn_error_clear(svn_branch__state_get_elements(branch, &elements, scratch_pool)); 1080333347Speter for (hi = apr_hash_first(scratch_pool, elements->e_map); 1081333347Speter hi; hi = apr_hash_next(hi)) 1082333347Speter { 1083333347Speter int eid = svn_eid__hash_this_key(hi); 1084333347Speter const char *this_path = svn_element__tree_get_path_by_eid(elements, eid, 1085333347Speter scratch_pool); 1086333347Speter 1087333347Speter if (! this_path) 1088333347Speter { 1089333347Speter /* Mapping is not complete; this element is in effect not present. */ 1090333347Speter continue; 1091333347Speter } 1092333347Speter if (strcmp(path, this_path) == 0) 1093333347Speter { 1094333347Speter return eid; 1095333347Speter } 1096333347Speter } 1097333347Speter 1098333347Speter return -1; 1099333347Speter} 1100333347Speter 1101333347Speter/* Create a copy of NEW_SUBTREE in TO_BRANCH. 1102333347Speter * 1103333347Speter * For each non-root element in NEW_SUBTREE, create a new element with 1104333347Speter * a new EID, no matter what EID is used to represent it in NEW_SUBTREE. 1105333347Speter * 1106333347Speter * For the new subtree root element, if TO_EID is -1, generate a new EID, 1107333347Speter * otherwise alter (if it exists) or instantiate the element TO_EID. 1108333347Speter * 1109333347Speter * Set the new subtree root element's parent to NEW_PARENT_EID and name to 1110333347Speter * NEW_NAME. 1111333347Speter */ 1112333347Speterstatic svn_error_t * 1113333347Spetersvn_branch__map_add_subtree(svn_branch__state_t *to_branch, 1114333347Speter int to_eid, 1115333347Speter svn_branch__eid_t new_parent_eid, 1116333347Speter const char *new_name, 1117333347Speter svn_element__tree_t *new_subtree, 1118333347Speter apr_pool_t *scratch_pool) 1119333347Speter{ 1120333347Speter apr_hash_index_t *hi; 1121333347Speter svn_element__content_t *new_root_content; 1122333347Speter 1123333347Speter /* Get a new EID for the root element, if not given. */ 1124333347Speter if (to_eid == -1) 1125333347Speter { 1126333347Speter SVN_ERR(svn_branch__txn_new_eid(to_branch->txn, &to_eid, 1127333347Speter scratch_pool)); 1128333347Speter } 1129333347Speter 1130333347Speter /* Create the new subtree root element */ 1131333347Speter new_root_content = svn_element__tree_get(new_subtree, new_subtree->root_eid); 1132333347Speter new_root_content = svn_element__content_create(new_parent_eid, new_name, 1133333347Speter new_root_content->payload, 1134333347Speter scratch_pool); 1135333347Speter SVN_ERR(branch_state_set_element(to_branch, to_eid, new_root_content, 1136333347Speter scratch_pool)); 1137333347Speter 1138333347Speter /* Process its immediate children */ 1139333347Speter for (hi = apr_hash_first(scratch_pool, new_subtree->e_map); 1140333347Speter hi; hi = apr_hash_next(hi)) 1141333347Speter { 1142333347Speter int this_from_eid = svn_eid__hash_this_key(hi); 1143333347Speter svn_element__content_t *from_element = apr_hash_this_val(hi); 1144333347Speter 1145333347Speter if (from_element->parent_eid == new_subtree->root_eid) 1146333347Speter { 1147333347Speter svn_element__tree_t *this_subtree; 1148333347Speter 1149333347Speter /* Recurse. (We don't try to check whether it's a directory node, 1150333347Speter as we might not have the node kind in the map.) */ 1151333347Speter this_subtree 1152333347Speter = svn_element__tree_create(new_subtree->e_map, this_from_eid, 1153333347Speter scratch_pool); 1154333347Speter SVN_ERR(svn_branch__map_add_subtree(to_branch, -1 /*to_eid*/, 1155333347Speter to_eid, from_element->name, 1156333347Speter this_subtree, scratch_pool)); 1157333347Speter } 1158333347Speter } 1159333347Speter 1160333347Speter return SVN_NO_ERROR; 1161333347Speter} 1162333347Speter 1163333347Speter/* Instantiate elements in a branch. 1164333347Speter * 1165333347Speter * In TO_BRANCH, instantiate (or alter, if existing) each element of 1166333347Speter * ELEMENTS, each with its given tree structure (parent, name) and payload. 1167333347Speter */ 1168333347Speterstatic svn_error_t * 1169333347Speterbranch_instantiate_elements(svn_branch__state_t *to_branch, 1170333347Speter const svn_element__tree_t *elements, 1171333347Speter apr_pool_t *scratch_pool) 1172333347Speter{ 1173333347Speter apr_hash_index_t *hi; 1174333347Speter 1175333347Speter for (hi = apr_hash_first(scratch_pool, elements->e_map); 1176333347Speter hi; hi = apr_hash_next(hi)) 1177333347Speter { 1178333347Speter int this_eid = svn_eid__hash_this_key(hi); 1179333347Speter svn_element__content_t *this_element = apr_hash_this_val(hi); 1180333347Speter 1181333347Speter branch_map_set(to_branch, this_eid, 1182333347Speter svn_element__content_dup( 1183333347Speter this_element, 1184333347Speter apr_hash_pool_get(to_branch->priv->element_tree->e_map))); 1185333347Speter } 1186333347Speter 1187333347Speter return SVN_NO_ERROR; 1188333347Speter} 1189333347Speter 1190333347Speter/* 1191333347Speter * ======================================================================== 1192333347Speter * Branch State Object 1193333347Speter * ======================================================================== 1194333347Speter */ 1195333347Speter 1196333347Spetersvn_error_t * 1197333347Spetersvn_branch__state_get_elements(const svn_branch__state_t *branch, 1198333347Speter svn_element__tree_t **element_tree_p, 1199333347Speter apr_pool_t *result_pool) 1200333347Speter{ 1201333347Speter SVN_ERR(branch->vtable->get_elements(branch, 1202333347Speter element_tree_p, 1203333347Speter result_pool)); 1204333347Speter return SVN_NO_ERROR; 1205333347Speter} 1206333347Speter 1207333347Spetersvn_error_t * 1208333347Spetersvn_branch__state_get_element(const svn_branch__state_t *branch, 1209333347Speter svn_element__content_t **element_p, 1210333347Speter int eid, 1211333347Speter apr_pool_t *result_pool) 1212333347Speter{ 1213333347Speter SVN_ERR(branch->vtable->get_element(branch, 1214333347Speter element_p, eid, result_pool)); 1215333347Speter return SVN_NO_ERROR; 1216333347Speter} 1217333347Speter 1218333347Spetersvn_error_t * 1219333347Spetersvn_branch__state_set_element(svn_branch__state_t *branch, 1220333347Speter int eid, 1221333347Speter const svn_element__content_t *element, 1222333347Speter apr_pool_t *scratch_pool) 1223333347Speter{ 1224333347Speter SVN_ERR(branch->vtable->set_element(branch, 1225333347Speter eid, element, 1226333347Speter scratch_pool)); 1227333347Speter return SVN_NO_ERROR; 1228333347Speter} 1229333347Speter 1230333347Spetersvn_error_t * 1231333347Spetersvn_branch__state_alter_one(svn_branch__state_t *branch, 1232333347Speter svn_branch__eid_t eid, 1233333347Speter svn_branch__eid_t new_parent_eid, 1234333347Speter const char *new_name, 1235333347Speter const svn_element__payload_t *new_payload, 1236333347Speter apr_pool_t *scratch_pool) 1237333347Speter{ 1238333347Speter svn_element__content_t *element 1239333347Speter = svn_element__content_create(new_parent_eid, new_name, new_payload, 1240333347Speter scratch_pool); 1241333347Speter 1242333347Speter SVN_ERR(svn_branch__state_set_element(branch, eid, element, scratch_pool)); 1243333347Speter return SVN_NO_ERROR; 1244333347Speter} 1245333347Speter 1246333347Spetersvn_error_t * 1247333347Spetersvn_branch__state_copy_tree(svn_branch__state_t *branch, 1248333347Speter const svn_branch__rev_bid_eid_t *src_el_rev, 1249333347Speter svn_branch__eid_t new_parent_eid, 1250333347Speter const char *new_name, 1251333347Speter apr_pool_t *scratch_pool) 1252333347Speter{ 1253333347Speter SVN_ERR(branch->vtable->copy_tree(branch, 1254333347Speter src_el_rev, new_parent_eid, new_name, 1255333347Speter scratch_pool)); 1256333347Speter return SVN_NO_ERROR; 1257333347Speter} 1258333347Speter 1259333347Spetersvn_error_t * 1260333347Spetersvn_branch__state_delete_one(svn_branch__state_t *branch, 1261333347Speter svn_branch__eid_t eid, 1262333347Speter apr_pool_t *scratch_pool) 1263333347Speter{ 1264333347Speter SVN_ERR(svn_branch__state_set_element(branch, eid, NULL, scratch_pool)); 1265333347Speter return SVN_NO_ERROR; 1266333347Speter} 1267333347Speter 1268333347Spetersvn_error_t * 1269333347Spetersvn_branch__state_purge(svn_branch__state_t *branch, 1270333347Speter apr_pool_t *scratch_pool) 1271333347Speter{ 1272333347Speter SVN_ERR(branch->vtable->purge(branch, 1273333347Speter scratch_pool)); 1274333347Speter return SVN_NO_ERROR; 1275333347Speter} 1276333347Speter 1277333347Spetersvn_error_t * 1278333347Spetersvn_branch__state_get_history(svn_branch__state_t *branch, 1279333347Speter svn_branch__history_t **history_p, 1280333347Speter apr_pool_t *result_pool) 1281333347Speter{ 1282333347Speter SVN_ERR(branch->vtable->get_history(branch, 1283333347Speter history_p, 1284333347Speter result_pool)); 1285333347Speter SVN_ERR_ASSERT(*history_p); 1286333347Speter return SVN_NO_ERROR; 1287333347Speter} 1288333347Speter 1289333347Spetersvn_error_t * 1290333347Spetersvn_branch__state_set_history(svn_branch__state_t *branch, 1291333347Speter const svn_branch__history_t *history, 1292333347Speter apr_pool_t *scratch_pool) 1293333347Speter{ 1294333347Speter SVN_ERR_ASSERT(history); 1295333347Speter SVN_ERR(branch->vtable->set_history(branch, 1296333347Speter history, 1297333347Speter scratch_pool)); 1298333347Speter return SVN_NO_ERROR; 1299333347Speter} 1300333347Speter 1301333347Spetersvn_branch__state_t * 1302333347Spetersvn_branch__state_create(const svn_branch__state_vtable_t *vtable, 1303333347Speter svn_cancel_func_t cancel_func, 1304333347Speter void *cancel_baton, 1305333347Speter apr_pool_t *result_pool) 1306333347Speter{ 1307333347Speter svn_branch__state_t *b = apr_pcalloc(result_pool, sizeof(*b)); 1308333347Speter 1309333347Speter b->vtable = apr_pmemdup(result_pool, vtable, sizeof(*vtable)); 1310333347Speter 1311333347Speter b->vtable->vpriv.cancel_func = cancel_func; 1312333347Speter b->vtable->vpriv.cancel_baton = cancel_baton; 1313333347Speter 1314333347Speter#ifdef ENABLE_ORDERING_CHECK 1315333347Speter b->vtable->vpriv.within_callback = FALSE; 1316333347Speter b->vtable->vpriv.finished = FALSE; 1317333347Speter b->vtable->vpriv.state_pool = result_pool; 1318333347Speter#endif 1319333347Speter 1320333347Speter return b; 1321333347Speter} 1322333347Speter 1323333347Speter/* Create a new branch state object. 1324333347Speter * 1325333347Speter * It will have no elements (not even a root element). 1326333347Speter */ 1327333347Speterstatic svn_branch__state_t * 1328333347Speterbranch_state_create(const char *bid, 1329333347Speter int root_eid, 1330333347Speter svn_branch__txn_t *txn, 1331333347Speter apr_pool_t *result_pool) 1332333347Speter{ 1333333347Speter static const svn_branch__state_vtable_t vtable = { 1334333347Speter {0}, 1335333347Speter branch_state_get_elements, 1336333347Speter branch_state_get_element, 1337333347Speter branch_state_set_element, 1338333347Speter branch_state_copy_one, 1339333347Speter branch_state_copy_tree, 1340333347Speter branch_state_purge, 1341333347Speter branch_state_get_history, 1342333347Speter branch_state_set_history, 1343333347Speter }; 1344333347Speter svn_branch__state_t *b 1345333347Speter = svn_branch__state_create(&vtable, NULL, NULL, result_pool); 1346333347Speter 1347333347Speter b->priv = apr_pcalloc(result_pool, sizeof(*b->priv)); 1348333347Speter b->bid = apr_pstrdup(result_pool, bid); 1349333347Speter b->txn = txn; 1350333347Speter b->priv->element_tree = svn_element__tree_create(NULL, root_eid, result_pool); 1351333347Speter assert_branch_state_invariants(b, result_pool); 1352333347Speter b->priv->is_flat = TRUE; 1353333347Speter b->priv->history = svn_branch__history_create_empty(result_pool); 1354333347Speter return b; 1355333347Speter} 1356333347Speter 1357333347Speter/* 1358333347Speter * ======================================================================== 1359333347Speter * Parsing and Serializing 1360333347Speter * ======================================================================== 1361333347Speter */ 1362333347Speter 1363333347Spetersvn_string_t * 1364333347Spetersvn_branch__get_default_r0_metadata(apr_pool_t *result_pool) 1365333347Speter{ 1366333347Speter static const char *default_repos_info 1367333347Speter = "r0: eids 0 1 branches 1\n" 1368333347Speter "B0 root-eid 0 num-eids 1\n" 1369333347Speter "history: parents 0\n" 1370333347Speter "e0: normal -1 .\n"; 1371333347Speter 1372333347Speter return svn_string_create(default_repos_info, result_pool); 1373333347Speter} 1374333347Speter 1375333347Speter/* */ 1376333347Speterstatic svn_error_t * 1377333347Speterparse_branch_line(char *bid_p, 1378333347Speter int *root_eid_p, 1379333347Speter int *num_eids_p, 1380333347Speter svn_stream_t *stream, 1381333347Speter apr_pool_t *result_pool, 1382333347Speter apr_pool_t *scratch_pool) 1383333347Speter{ 1384333347Speter svn_stringbuf_t *line; 1385333347Speter svn_boolean_t eof; 1386333347Speter int n; 1387333347Speter 1388333347Speter /* Read a line */ 1389333347Speter SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); 1390333347Speter SVN_ERR_ASSERT(!eof); 1391333347Speter 1392333347Speter n = sscanf(line->data, "%s root-eid %d num-eids %d", 1393333347Speter bid_p, root_eid_p, num_eids_p); 1394333347Speter SVN_ERR_ASSERT(n == 3); 1395333347Speter 1396333347Speter return SVN_NO_ERROR; 1397333347Speter} 1398333347Speter 1399333347Speter/* Parse the history metadata for BRANCH. 1400333347Speter */ 1401333347Speterstatic svn_error_t * 1402333347Speterhistory_parse(svn_branch__history_t **history_p, 1403333347Speter svn_stream_t *stream, 1404333347Speter apr_pool_t *result_pool, 1405333347Speter apr_pool_t *scratch_pool) 1406333347Speter{ 1407333347Speter svn_branch__history_t *history 1408333347Speter = svn_branch__history_create_empty(result_pool); 1409333347Speter svn_stringbuf_t *line; 1410333347Speter svn_boolean_t eof; 1411333347Speter int n; 1412333347Speter int num_parents; 1413333347Speter int i; 1414333347Speter 1415333347Speter /* Read a line */ 1416333347Speter SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); 1417333347Speter SVN_ERR_ASSERT(!eof); 1418333347Speter 1419333347Speter n = sscanf(line->data, "history: parents %d", 1420333347Speter &num_parents); 1421333347Speter SVN_ERR_ASSERT(n == 1); 1422333347Speter 1423333347Speter for (i = 0; i < num_parents; i++) 1424333347Speter { 1425333347Speter svn_revnum_t rev; 1426333347Speter char bid[100]; 1427333347Speter 1428333347Speter SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); 1429333347Speter SVN_ERR_ASSERT(!eof); 1430333347Speter 1431333347Speter n = sscanf(line->data, "parent: r%ld.%99s", 1432333347Speter &rev, bid); 1433333347Speter SVN_ERR_ASSERT(n == 2); 1434333347Speter 1435333347Speter svn_hash_sets(history->parents, 1436333347Speter apr_pstrdup(result_pool, bid), 1437333347Speter svn_branch__rev_bid_create(rev, bid, result_pool)); 1438333347Speter } 1439333347Speter 1440333347Speter if (history_p) 1441333347Speter *history_p = history; 1442333347Speter return SVN_NO_ERROR; 1443333347Speter} 1444333347Speter 1445333347Speter/* Parse the mapping for one element. 1446333347Speter */ 1447333347Speterstatic svn_error_t * 1448333347Speterparse_element_line(int *eid_p, 1449333347Speter svn_boolean_t *is_subbranch_p, 1450333347Speter int *parent_eid_p, 1451333347Speter const char **name_p, 1452333347Speter svn_stream_t *stream, 1453333347Speter apr_pool_t *result_pool, 1454333347Speter apr_pool_t *scratch_pool) 1455333347Speter{ 1456333347Speter svn_stringbuf_t *line; 1457333347Speter svn_boolean_t eof; 1458333347Speter char kind[10]; 1459333347Speter int n; 1460333347Speter int offset; 1461333347Speter 1462333347Speter /* Read a line */ 1463333347Speter SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); 1464333347Speter SVN_ERR_ASSERT(!eof); 1465333347Speter 1466333347Speter n = sscanf(line->data, "e%d: %9s %d%n", 1467333347Speter eid_p, 1468333347Speter kind, parent_eid_p, &offset); 1469333347Speter SVN_ERR_ASSERT(n >= 3); /* C std is unclear on whether '%n' counts */ 1470333347Speter SVN_ERR_ASSERT(line->data[offset] == ' '); 1471333347Speter 1472333347Speter *name_p = apr_pstrdup(result_pool, line->data + offset + 1); 1473333347Speter *is_subbranch_p = (strcmp(kind, "subbranch") == 0); 1474333347Speter 1475333347Speter if (strcmp(*name_p, "(null)") == 0) 1476333347Speter *name_p = NULL; 1477333347Speter else if (strcmp(*name_p, ".") == 0) 1478333347Speter *name_p = ""; 1479333347Speter 1480333347Speter return SVN_NO_ERROR; 1481333347Speter} 1482333347Speter 1483333347Speterconst char * 1484333347Spetersvn_branch__id_nest(const char *outer_bid, 1485333347Speter int outer_eid, 1486333347Speter apr_pool_t *result_pool) 1487333347Speter{ 1488333347Speter if (!outer_bid) 1489333347Speter return apr_psprintf(result_pool, "B%d", outer_eid); 1490333347Speter 1491333347Speter return apr_psprintf(result_pool, "%s.%d", outer_bid, outer_eid); 1492333347Speter} 1493333347Speter 1494333347Spetervoid 1495333347Spetersvn_branch__id_unnest(const char **outer_bid, 1496333347Speter int *outer_eid, 1497333347Speter const char *bid, 1498333347Speter apr_pool_t *result_pool) 1499333347Speter{ 1500333347Speter char *last_dot = strrchr(bid, '.'); 1501333347Speter 1502333347Speter if (last_dot) /* BID looks like "B3.11" or "B3.11.22" etc. */ 1503333347Speter { 1504333347Speter *outer_bid = apr_pstrndup(result_pool, bid, last_dot - bid); 1505333347Speter *outer_eid = atoi(last_dot + 1); 1506333347Speter } 1507333347Speter else /* looks like "B0" or B22" (with no dot) */ 1508333347Speter { 1509333347Speter *outer_bid = NULL; 1510333347Speter *outer_eid = atoi(bid + 1); 1511333347Speter } 1512333347Speter} 1513333347Speter 1514333347Speter/* Create a new branch *NEW_BRANCH, initialized 1515333347Speter * with info parsed from STREAM, allocated in RESULT_POOL. 1516333347Speter */ 1517333347Speterstatic svn_error_t * 1518333347Spetersvn_branch__state_parse(svn_branch__state_t **new_branch, 1519333347Speter svn_branch__txn_t *txn, 1520333347Speter svn_stream_t *stream, 1521333347Speter apr_pool_t *result_pool, 1522333347Speter apr_pool_t *scratch_pool) 1523333347Speter{ 1524333347Speter char bid[1000]; 1525333347Speter int root_eid, num_eids; 1526333347Speter svn_branch__state_t *branch_state; 1527333347Speter int i; 1528333347Speter 1529333347Speter SVN_ERR(parse_branch_line(bid, &root_eid, &num_eids, 1530333347Speter stream, scratch_pool, scratch_pool)); 1531333347Speter 1532333347Speter branch_state = branch_state_create(bid, root_eid, txn, 1533333347Speter result_pool); 1534333347Speter 1535333347Speter /* Read in the merge history. */ 1536333347Speter SVN_ERR(history_parse(&branch_state->priv->history, 1537333347Speter stream, result_pool, scratch_pool)); 1538333347Speter 1539333347Speter /* Read in the structure. Set the payload of each normal element to a 1540333347Speter (branch-relative) reference. */ 1541333347Speter for (i = 0; i < num_eids; i++) 1542333347Speter { 1543333347Speter int eid, this_parent_eid; 1544333347Speter const char *this_name; 1545333347Speter svn_boolean_t is_subbranch; 1546333347Speter 1547333347Speter SVN_ERR(parse_element_line(&eid, 1548333347Speter &is_subbranch, &this_parent_eid, &this_name, 1549333347Speter stream, scratch_pool, scratch_pool)); 1550333347Speter 1551333347Speter if (this_name) 1552333347Speter { 1553333347Speter svn_element__payload_t *payload; 1554333347Speter svn_element__content_t *element; 1555333347Speter 1556333347Speter if (! is_subbranch) 1557333347Speter { 1558333347Speter payload = svn_element__payload_create_ref(txn->rev, bid, eid, 1559333347Speter result_pool); 1560333347Speter } 1561333347Speter else 1562333347Speter { 1563333347Speter payload 1564333347Speter = svn_element__payload_create_subbranch(result_pool); 1565333347Speter } 1566333347Speter element = svn_element__content_create(this_parent_eid, 1567333347Speter this_name, payload, 1568333347Speter scratch_pool); 1569333347Speter SVN_ERR(branch_state_set_element(branch_state, eid, element, 1570333347Speter scratch_pool)); 1571333347Speter } 1572333347Speter } 1573333347Speter 1574333347Speter branch_state->priv->is_flat = TRUE; 1575333347Speter *new_branch = branch_state; 1576333347Speter return SVN_NO_ERROR; 1577333347Speter} 1578333347Speter 1579333347Spetersvn_error_t * 1580333347Spetersvn_branch__txn_parse(svn_branch__txn_t **txn_p, 1581333347Speter svn_branch__repos_t *repos, 1582333347Speter svn_stream_t *stream, 1583333347Speter apr_pool_t *result_pool, 1584333347Speter apr_pool_t *scratch_pool) 1585333347Speter{ 1586333347Speter svn_branch__txn_t *txn; 1587333347Speter svn_revnum_t rev; 1588333347Speter int first_eid, next_eid; 1589333347Speter int num_branches; 1590333347Speter svn_stringbuf_t *line; 1591333347Speter svn_boolean_t eof; 1592333347Speter int n; 1593333347Speter int j; 1594333347Speter 1595333347Speter SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); 1596333347Speter SVN_ERR_ASSERT(! eof); 1597333347Speter n = sscanf(line->data, "r%ld: eids %d %d " 1598333347Speter "branches %d", 1599333347Speter &rev, 1600333347Speter &first_eid, &next_eid, 1601333347Speter &num_branches); 1602333347Speter SVN_ERR_ASSERT(n == 4); 1603333347Speter 1604333347Speter txn = branch_txn_create(repos, rev, rev - 1, result_pool); 1605333347Speter txn->priv->first_eid = first_eid; 1606333347Speter txn->priv->next_eid = next_eid; 1607333347Speter 1608333347Speter /* parse the branches */ 1609333347Speter for (j = 0; j < num_branches; j++) 1610333347Speter { 1611333347Speter svn_branch__state_t *branch; 1612333347Speter 1613333347Speter SVN_ERR(svn_branch__state_parse(&branch, txn, stream, 1614333347Speter result_pool, scratch_pool)); 1615333347Speter APR_ARRAY_PUSH(txn->priv->branches, void *) = branch; 1616333347Speter } 1617333347Speter 1618333347Speter *txn_p = txn; 1619333347Speter return SVN_NO_ERROR; 1620333347Speter} 1621333347Speter 1622333347Speter/* Serialize the history metadata for BRANCH. 1623333347Speter */ 1624333347Speterstatic svn_error_t * 1625333347Speterhistory_serialize(svn_stream_t *stream, 1626333347Speter svn_branch__history_t *history, 1627333347Speter apr_pool_t *scratch_pool) 1628333347Speter{ 1629333347Speter apr_array_header_t *ancestors_sorted; 1630333347Speter int i; 1631333347Speter 1632333347Speter /* Write entries in sorted order for stability -- so that for example 1633333347Speter we can test parse-then-serialize by expecting identical output. */ 1634333347Speter ancestors_sorted = svn_sort__hash(history->parents, 1635333347Speter svn_sort_compare_items_lexically, 1636333347Speter scratch_pool); 1637333347Speter SVN_ERR(svn_stream_printf(stream, scratch_pool, 1638333347Speter "history: parents %d\n", 1639333347Speter ancestors_sorted->nelts)); 1640333347Speter for (i = 0; i < ancestors_sorted->nelts; i++) 1641333347Speter { 1642333347Speter svn_sort__item_t *item 1643333347Speter = &APR_ARRAY_IDX(ancestors_sorted, i, svn_sort__item_t); 1644333347Speter svn_branch__rev_bid_t *rev_bid = item->value; 1645333347Speter 1646333347Speter SVN_ERR(svn_stream_printf(stream, scratch_pool, 1647333347Speter "parent: r%ld.%s\n", 1648333347Speter rev_bid->rev, rev_bid->bid)); 1649333347Speter } 1650333347Speter 1651333347Speter return SVN_NO_ERROR; 1652333347Speter} 1653333347Speter 1654333347Speter/* Write to STREAM a parseable representation of BRANCH. 1655333347Speter */ 1656333347Spetersvn_error_t * 1657333347Spetersvn_branch__state_serialize(svn_stream_t *stream, 1658333347Speter svn_branch__state_t *branch, 1659333347Speter apr_pool_t *scratch_pool) 1660333347Speter{ 1661333347Speter svn_eid__hash_iter_t *ei; 1662333347Speter 1663333347Speter SVN_ERR_ASSERT(branch->priv->is_flat); 1664333347Speter 1665333347Speter SVN_ERR(svn_stream_printf(stream, scratch_pool, 1666333347Speter "%s root-eid %d num-eids %d\n", 1667333347Speter svn_branch__get_id(branch, scratch_pool), 1668333347Speter branch->priv->element_tree->root_eid, 1669333347Speter apr_hash_count(branch->priv->element_tree->e_map))); 1670333347Speter 1671333347Speter SVN_ERR(history_serialize(stream, branch->priv->history, 1672333347Speter scratch_pool)); 1673333347Speter 1674333347Speter for (SVN_EID__HASH_ITER_SORTED_BY_EID(ei, branch->priv->element_tree->e_map, 1675333347Speter scratch_pool)) 1676333347Speter { 1677333347Speter int eid = ei->eid; 1678333347Speter svn_element__content_t *element = branch_get_element(branch, eid); 1679333347Speter int parent_eid; 1680333347Speter const char *name; 1681333347Speter 1682333347Speter SVN_ERR_ASSERT(element); 1683333347Speter parent_eid = element->parent_eid; 1684333347Speter name = element->name[0] ? element->name : "."; 1685333347Speter SVN_ERR(svn_stream_printf(stream, scratch_pool, 1686333347Speter "e%d: %s %d %s\n", 1687333347Speter eid, 1688333347Speter element ? ((! element->payload->is_subbranch_root) 1689333347Speter ? "normal" : "subbranch") 1690333347Speter : "none", 1691333347Speter parent_eid, name)); 1692333347Speter } 1693333347Speter return SVN_NO_ERROR; 1694333347Speter} 1695333347Speter 1696333347Speter/* 1697333347Speter * ======================================================================== 1698333347Speter */ 1699333347Speter 1700