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