]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/subversion/subversion/include/private/svn_branch.h
Update Subversion and dependencies to 1.14.0 LTS.
[FreeBSD/FreeBSD.git] / contrib / subversion / subversion / include / private / svn_branch.h
1 /**
2  * @copyright
3  * ====================================================================
4  *    Licensed to the Apache Software Foundation (ASF) under one
5  *    or more contributor license agreements.  See the NOTICE file
6  *    distributed with this work for additional information
7  *    regarding copyright ownership.  The ASF licenses this file
8  *    to you under the Apache License, Version 2.0 (the
9  *    "License"); you may not use this file except in compliance
10  *    with the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *    Unless required by applicable law or agreed to in writing,
15  *    software distributed under the License is distributed on an
16  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  *    KIND, either express or implied.  See the License for the
18  *    specific language governing permissions and limitations
19  *    under the License.
20  * ====================================================================
21  * @endcopyright
22  *
23  * @file svn_branch.h
24  * @brief Operating on a branched version history
25  *
26  * @since New in ???.
27  */
28
29 /* Transactions
30  *
31  * A 'txn' contains a set of changes to the branches/elements.
32  *
33  * To make changes you say, for example, "for element 5: I want the parent
34  * element to be 3 now, and its name to be 'bar', and its content to be
35  * {props=... text=...}". That sets up a move and/or rename and/or
36  * content-change (or possibly a no-op for all three aspects) for element 5.
37  *
38  * Before or after (or at the same time, if we make a parallelizable
39  * implementation) we can make edits to the other elements, including
40  * element 3.
41  *
42  * So at the time of the edit method 'change e5: let its parent be e3'
43  * we might or might not have even created e3, if that happens to be an
44  * element that we wish to create rather than one that already existed.
45  *
46  * We allow this non-ordering because we want the changes to different
47  * elements to be totally independent.
48  *
49  * So at any given 'moment' in time during specifying the changes to a
50  * txn, the txn state is not necessarily one that maps directly to a
51  * flat tree (single-rooted, no cycles, no clashes of paths, etc.).
52  *
53  * Once we've finished specifying the edits, then the txn state will be
54  * converted to a flat tree, and that's the final result. But we can't
55  * query an arbitrary txn (potentially in the middle of making changes
56  * to it) by path, because the paths are not fully defined yet.
57  *
58  * So there are three kinds of operations:
59  *
60  * - query involving paths
61  *   => requires a flat tree state to query, not an in-progress txn
62  *
63  * - query, not involving paths
64  *   => accepts a txn-in-progress or a flat tree
65  *
66  * - modify (not involving paths)
67  *   => requires a txn
68  *
69  * Currently, a txn is represented by 'svn_branch__txn_t', with
70  * 'svn_branch__state_t' for the individual branches in it. A flat tree is
71  * represented by 'svn_branch__subtree_t'. But there is currently not a
72  * clean separation; there is some overlap and some warts such as the
73  * 'svn_branch__txn_sequence_point' method.
74  */
75
76
77 #ifndef SVN_BRANCH_H
78 #define SVN_BRANCH_H
79
80 #include <apr_pools.h>
81
82 #include "svn_types.h"
83 #include "svn_error.h"
84 #include "svn_io.h"    /* for svn_stream_t  */
85 #include "svn_delta.h"
86
87 #include "private/svn_element.h"
88
89 #ifdef __cplusplus
90 extern "C" {
91 #endif /* __cplusplus */
92
93
94 /* ### */
95 #define SVN_BRANCH__ERR 123456
96
97 /** Element Identifier (EID).
98  *
99  * An element may appear in any or all branches, and its EID is the same in
100  * each branch in which the element appears.
101  *
102  * By definition, an element keeps the same EID for its whole lifetime, even
103  * if deleted from all branches and later 'resurrected'.
104  *
105  * In principle, an EID is an arbitrary token and has no intrinsic
106  * relationships (except equality) to other EIDs. The current implementation
107  * uses integers and allocates them sequentially from a central counter, but
108  * the implementation may be changed.
109  *
110  * ### In most places the code currently says 'int', verbatim.
111  */
112 typedef int svn_branch__eid_t;
113
114 typedef struct svn_branch__el_rev_id_t svn_branch__el_rev_id_t;
115
116 typedef struct svn_branch__rev_bid_eid_t svn_branch__rev_bid_eid_t;
117
118 typedef struct svn_branch__rev_bid_t svn_branch__rev_bid_t;
119
120 typedef struct svn_branch__state_t svn_branch__state_t;
121
122 /* Per-repository branching info.
123  */
124 typedef struct svn_branch__repos_t svn_branch__repos_t;
125
126 /* Methods (conceptually public, but called indirectly) for a transaction.
127  */
128 typedef struct svn_branch__txn_vtable_t svn_branch__txn_vtable_t;
129
130 /* Private data for a transaction.
131  */
132 typedef struct svn_branch__txn_priv_t svn_branch__txn_priv_t;
133
134 /* A container for all the branching metadata for a specific revision (or
135  * an uncommitted transaction).
136  */
137 typedef struct svn_branch__txn_t
138 {
139   /* Methods (conceptually public, but called indirectly). */
140   svn_branch__txn_vtable_t *vtable;
141
142   /* Private data. */
143   svn_branch__txn_priv_t *priv;
144
145   /* Public data. */
146
147   /* The repository in which this revision exists. */
148   svn_branch__repos_t *repos;
149
150   /* If committed, the revision number; else SVN_INVALID_REVNUM. */
151   svn_revnum_t rev;
152
153   /* If committed, the previous revision number, else the revision number
154      on which this transaction is based. */
155   svn_revnum_t base_rev;
156
157 } svn_branch__txn_t;
158
159 /* Create a new branch txn object.
160  */
161 svn_branch__txn_t *
162 svn_branch__txn_create(const svn_branch__txn_vtable_t *vtable,
163                        svn_cancel_func_t cancel_func,
164                        void *cancel_baton,
165                        apr_pool_t *result_pool);
166
167 /* Return all the branches in TXN.
168  *
169  * These branches are available for reading. (Some of them may also be
170  * mutable.)
171  *
172  * ### Rename to 'list_branches' & return only their ids?
173  *
174  * Return an empty array if there are none.
175  */
176 apr_array_header_t *
177 svn_branch__txn_get_branches(const svn_branch__txn_t *txn,
178                              apr_pool_t *result_pool);
179
180 /* Return the branch whose id is BRANCH_ID in TXN.
181  *
182  * Return NULL if not found.
183  *
184  * Note: a branch id is, in behavioural terms, an arbitrary token. In the
185  * current implementation it is constructed from the hierarchy of subbranch
186  * root EIDs leading to the branch, but that may be changed in future.
187  *
188  * See also: svn_branch__get_id().
189  */
190 svn_branch__state_t *
191 svn_branch__txn_get_branch_by_id(const svn_branch__txn_t *txn,
192                                  const char *branch_id,
193                                  apr_pool_t *scratch_pool);
194
195 svn_error_t *
196 svn_branch__txn_get_num_new_eids(const svn_branch__txn_t *txn,
197                                  int *num_new_eids_p,
198                                  apr_pool_t *scratch_pool);
199
200 /* Assign a new txn-scope element id in TXN.
201  */
202 svn_error_t *
203 svn_branch__txn_new_eid(svn_branch__txn_t *txn,
204                         int *new_eid_p,
205                         apr_pool_t *scratch_pool);
206
207 /** Open for writing, either a new branch or an existing branch.
208  *
209  * When creating a new branch, declare its root element id to be ROOT_EID. Do
210  * not instantiate the root element, nor any other elements.
211  *
212  * TREE_REF specifies the initial tree content, by reference to a committed
213  * tree. It overwrites any existing tree, even if the branch was already
214  * mutable in the txn.
215  *
216  * If TREE_REF is null, then the initial tree is empty for a new branch
217  * (not already present in the txn), or the branch's current tree if the
218  * branch was already present (readable or mutable) in the txn.
219  *
220  * ### TODO: Take a 'history' parameter; 'none' is a valid option.
221  *
222  * We use a common 'open subbranch' method for both 'find' and 'add'
223  * cases, according to the principle that 'editing' a txn should dictate
224  * the new state without reference to the old state.
225  *
226  * This method returns a mutable 'branch state' object which is a part of
227  * the txn.
228  *
229  * ### When opening ('finding') an existing branch, ROOT_EID should match
230  *     it. (Should we check, and throw an error if not?)
231  */
232 svn_error_t *
233 svn_branch__txn_open_branch(svn_branch__txn_t *txn,
234                             svn_branch__state_t **new_branch_p,
235                             const char *branch_id,
236                             int root_eid,
237                             svn_branch__rev_bid_eid_t *tree_ref,
238                             apr_pool_t *result_pool,
239                             apr_pool_t *scratch_pool);
240
241 /** Register a sequence point.
242  *
243  * At a sequence point, elements are arranged in a tree hierarchy: each
244  * element has exactly one parent element, except the root, and so on.
245  * Translation between paths and element addressing is defined only at
246  * a sequence point.
247  *
248  * The other edit operations -- add, alter, delete, etc. -- result in a
249  * state that is not a sequence point.
250  *
251  * The new transaction begins at a sequence point. Completion of editing
252  * (svn_branch__txn_complete()) also creates a sequence point.
253  */
254 svn_error_t *
255 svn_branch__txn_sequence_point(svn_branch__txn_t *txn,
256                                apr_pool_t *scratch_pool);
257
258 /** Finalize this transaction.
259  *
260  * Notify that the edit has been completed successfully.
261  */
262 svn_error_t *
263 svn_branch__txn_complete(svn_branch__txn_t *txn,
264                          apr_pool_t *scratch_pool);
265
266 /** Abandon this transaction.
267  *
268  * Notify that editing this transaction was not successful.
269  */
270 svn_error_t *
271 svn_branch__txn_abort(svn_branch__txn_t *txn,
272                       apr_pool_t *scratch_pool);
273
274 /* Change txn-local EIDs (negative integers) in TXN to revision EIDs, by
275  * assigning a new revision-EID (positive integer) for each one.
276  *
277  * Rewrite TXN->first_eid and TXN->next_eid accordingly.
278  */
279 svn_error_t *
280 svn_branch__txn_finalize_eids(svn_branch__txn_t *txn,
281                               apr_pool_t *scratch_pool);
282
283 /* Often, branches have the same root element. For example,
284  * branching /trunk to /branches/br1 results in:
285  *
286  *      branch 1: (root-EID=100)
287  *          EID 100 => /trunk
288  *          ...
289  *      branch 2: (root-EID=100)
290  *          EID 100 => /branches/br1
291  *          ...
292  *
293  * However, the root element of one branch may correspond to a non-root
294  * element of another branch.
295  *
296  * Continuing the same example, branching from the trunk subtree
297  * /trunk/D (which is not itself a branch root) results in:
298  *
299  *      branch 3: (root-EID=104)
300  *          EID 100 => (nil)
301  *          ...
302  *          EID 104 => /branches/branch-of-trunk-subtree-D
303  *          ...
304  */
305
306 /* Methods (conceptually public, but called indirectly) for a branch state.
307  */
308 typedef struct svn_branch__state_vtable_t svn_branch__state_vtable_t;
309
310 /* Private data for a branch state.
311  */
312 typedef struct svn_branch__state_priv_t svn_branch__state_priv_t;
313
314 /* A branch state.
315  *
316  * A branch state object describes one version of one branch.
317  */
318 struct svn_branch__state_t
319 {
320   /* Methods (conceptually public, but called indirectly). */
321   svn_branch__state_vtable_t *vtable;
322
323   /* Private data. */
324   svn_branch__state_priv_t *priv;
325
326   /* Public data. */
327
328   /* The branch identifier (starting with 'B') */
329   const char *bid;
330
331   /* The revision to which this branch state belongs */
332   /* ### Later we should remove this and let a single state be sharable
333      by multiple txns. */
334   svn_branch__txn_t *txn;
335
336 };
337
338 /* Create a new branch state object.
339  */
340 svn_branch__state_t *
341 svn_branch__state_create(const svn_branch__state_vtable_t *vtable,
342                          svn_cancel_func_t cancel_func,
343                          void *cancel_baton,
344                          apr_pool_t *result_pool);
345
346 /* Get the full id of branch BRANCH.
347  *
348  * Branch id format:
349  *      B<top-level-branch-num>[.<1st-level-eid>[.<2nd-level-eid>[...]]]
350  *
351  * Note: a branch id is, in behavioural terms, an arbitrary token. In the
352  * current implementation it is constructed from the hierarchy of subbranch
353  * root EIDs leading to the branch, but that may be changed in future.
354  *
355  * See also: svn_branch__txn_get_branch_by_id().
356  */
357 const char *
358 svn_branch__get_id(const svn_branch__state_t *branch,
359                    apr_pool_t *result_pool);
360
361 /* Return the element id of the root element of BRANCH.
362  */
363 int
364 svn_branch__root_eid(const svn_branch__state_t *branch);
365
366 /* Return the id of the branch nested in OUTER_BID at element OUTER_EID.
367  *
368  * For a top-level branch, OUTER_BID is null and OUTER_EID is the
369  * top-level branch number.
370  *
371  * (Such branches need not exist. This works purely with ids, making use
372  * of the fact that nested branch ids are predictable based on the nesting
373  * element id.)
374  */
375 const char *
376 svn_branch__id_nest(const char *outer_bid,
377                     int outer_eid,
378                     apr_pool_t *result_pool);
379
380 /* Given a nested branch id BID, set *OUTER_BID to the outer branch's id
381  * and *OUTER_EID to the nesting element in the outer branch.
382  *
383  * For a top-level branch, set *OUTER_BID to NULL and *OUTER_EID to the
384  * top-level branch number.
385  *
386  * (Such branches need not exist. This works purely with ids, making use
387  * of the fact that nested branch ids are predictable based on the nesting
388  * element id.)
389  */
390 void
391 svn_branch__id_unnest(const char **outer_bid,
392                       int *outer_eid,
393                       const char *bid,
394                       apr_pool_t *result_pool);
395
396 /* Remove the branch with id BID from the list of branches in TXN.
397  */
398 svn_error_t *
399 svn_branch__txn_delete_branch(svn_branch__txn_t *txn,
400                               const char *bid,
401                               apr_pool_t *scratch_pool);
402
403 /* Branch-Element-Revision */
404 struct svn_branch__el_rev_id_t
405 {
406   /* The branch state that applies to REV. */
407   svn_branch__state_t *branch;
408   /* Element. */
409   int eid;
410   /* Revision. SVN_INVALID_REVNUM means 'in this transaction', not 'head'.
411      ### Do we need this if BRANCH refers to a particular branch-revision? */
412   svn_revnum_t rev;
413
414 };
415
416 /* Revision-branch-element id. */
417 struct svn_branch__rev_bid_eid_t
418 {
419   /* Revision. SVN_INVALID_REVNUM means 'in this transaction', not 'head'. */
420   svn_revnum_t rev;
421   /* The branch id in revision REV. */
422   const char *bid;
423   /* Element id. */
424   int eid;
425
426 };
427
428 /* Revision-branch id. */
429 struct svn_branch__rev_bid_t
430 {
431   /* Revision. SVN_INVALID_REVNUM means 'in this transaction', not 'head'. */
432   svn_revnum_t rev;
433   /* The branch id in revision REV. */
434   const char *bid;
435
436 };
437
438 /* Return a new el_rev_id object constructed with *shallow* copies of BRANCH,
439  * EID and REV, allocated in RESULT_POOL.
440  */
441 svn_branch__el_rev_id_t *
442 svn_branch__el_rev_id_create(svn_branch__state_t *branch,
443                              int eid,
444                              svn_revnum_t rev,
445                              apr_pool_t *result_pool);
446
447 /* Return a new id object constructed with a deep copy of OLD_ID,
448  * allocated in RESULT_POOL. */
449 svn_branch__el_rev_id_t *
450 svn_branch__el_rev_id_dup(const svn_branch__el_rev_id_t *old_id,
451                           apr_pool_t *result_pool);
452
453 /* Return a new id object constructed with deep copies of REV, BRANCH_ID
454  * and EID, allocated in RESULT_POOL.
455  */
456 svn_branch__rev_bid_eid_t *
457 svn_branch__rev_bid_eid_create(svn_revnum_t rev,
458                                const char *branch_id,
459                                int eid,
460                                apr_pool_t *result_pool);
461 svn_branch__rev_bid_t *
462 svn_branch__rev_bid_create(svn_revnum_t rev,
463                            const char *branch_id,
464                            apr_pool_t *result_pool);
465
466 /* Return a new id object constructed with a deep copy of OLD_ID,
467  * allocated in RESULT_POOL. */
468 svn_branch__rev_bid_eid_t *
469 svn_branch__rev_bid_eid_dup(const svn_branch__rev_bid_eid_t *old_id,
470                             apr_pool_t *result_pool);
471 svn_branch__rev_bid_t *
472 svn_branch__rev_bid_dup(const svn_branch__rev_bid_t *old_id,
473                         apr_pool_t *result_pool);
474
475 svn_boolean_t
476 svn_branch__rev_bid_equal(const svn_branch__rev_bid_t *id1,
477                           const svn_branch__rev_bid_t *id2);
478
479 typedef struct svn_branch__history_t
480 {
481   /* The immediate parents of this state in the branch/merge graph.
482      Hash of (BID -> svn_branch__rev_bid_t). */
483   apr_hash_t *parents;
484 } svn_branch__history_t;
485
486 svn_branch__history_t *
487 svn_branch__history_create_empty(apr_pool_t *result_pool);
488
489 svn_branch__history_t *
490 svn_branch__history_create(apr_hash_t *parents,
491                            apr_pool_t *result_pool);
492
493 svn_branch__history_t *
494 svn_branch__history_dup(const svn_branch__history_t *old,
495                         apr_pool_t *result_pool);
496
497 /* Return the mapping of elements in branch BRANCH.
498  */
499 svn_error_t *
500 svn_branch__state_get_elements(const svn_branch__state_t *branch,
501                                svn_element__tree_t **element_tree_p,
502                                apr_pool_t *result_pool);
503
504 /* In BRANCH, get element EID (parent, name, payload).
505  *
506  * If element EID is not present, return null.
507  */
508 svn_error_t *
509 svn_branch__state_get_element(const svn_branch__state_t *branch,
510                               svn_element__content_t **element_p,
511                               int eid,
512                               apr_pool_t *result_pool);
513
514 /** Equivalent to
515  *    alter_one(..., element->parent_eid, element->name, element->payload),
516  * or, if @a element is null, to
517  *    delete_one(...).
518  */
519 svn_error_t *
520 svn_branch__state_set_element(svn_branch__state_t *branch,
521                               int eid,
522                               const svn_element__content_t *element,
523                               apr_pool_t *result_pool);
524
525 /** Specify that the element of @a branch identified by @a eid shall not
526  * be present.
527  *
528  * The delete is not explicitly recursive. However, as an effect of the
529  * final 'flattening' of a branch state into a single tree, each element
530  * in the final state that still has this element as its parent will also
531  * be deleted, recursively.
532  *
533  * The element @a eid must not be the root element of @a branch.
534  *
535  * ### Options for Out-Of-Date Checking on Rebase
536  *
537  *   We may want to specify what kind of OOD check takes place. The
538  *   following two options differ in what happens to an element that is
539  *   added, on the other side, as a child of this deleted element.
540  *
541  *   Rebase option 1: The rebase checks for changes in the whole subtree,
542  *   excluding any portions of the subtree for which an explicit delete or
543  *   move-away has been issued. The check includes checking that the other
544  *   side has not added any child. In other words, the deletion is
545  *   interpreted as an action affecting a subtree (dynamically rooted at
546  *   this element), rather than as an action affecting a single element or
547  *   a fixed set of elements that was explicitly or implicitly specified
548  *   by the sender.
549  *
550  *   To delete a mixed-rev subtree, the client sends an explicit delete for
551  *   each subtree that has a different base revision from its parent.
552  *
553  *   Rebase option 2: The rebase checks for changes to this element only.
554  *   The sender can send an explicit delete for each existing child element
555  *   that it requires to be checked as well. However, there is no way for
556  *   the sender to specify whether a child element added by the other side
557  *   should be considered an out-of-date error or silently deleted.
558  *
559  *   It would also be possible to let the caller specify, at some suitable
560  *   granularity, which option to use.
561  */
562 svn_error_t *
563 svn_branch__state_delete_one(svn_branch__state_t *branch,
564                              svn_branch__eid_t eid,
565                              apr_pool_t *scratch_pool);
566
567 /** Specify the tree position and payload of the element of @a branch
568  * identified by @a eid.
569  *
570  * Set the element's parent EID, name and payload to @a new_parent_eid,
571  * @a new_name and @a new_payload respectively.
572  *
573  * This may create a new element or alter an existing element.
574  *
575  * If the element ...                   we can describe the effect as ...
576  *
577  *   exists in the branch               =>  altering it;
578  *   previously existed in the branch   =>  resurrecting it;
579  *   only existed in other branches     =>  branching it;
580  *   never existed anywhere             =>  creating or adding it.
581  *
582  * However, these are imprecise descriptions and not mutually exclusive.
583  * For example, if it existed previously in this branch and another, then
584  * we may describe the result as 'resurrecting' and/or as 'branching'.
585  *
586  * Duplicate @a new_name and @a new_payload into the branch's pool.
587  */
588 svn_error_t *
589 svn_branch__state_alter_one(svn_branch__state_t *branch,
590                             svn_branch__eid_t eid,
591                             svn_branch__eid_t new_parent_eid,
592                             const char *new_name,
593                             const svn_element__payload_t *new_payload,
594                             apr_pool_t *scratch_pool);
595
596 svn_error_t *
597 svn_branch__state_copy_tree(svn_branch__state_t *branch,
598                             const svn_branch__rev_bid_eid_t *src_el_rev,
599                             svn_branch__eid_t new_parent_eid,
600                             const char *new_name,
601                             apr_pool_t *scratch_pool);
602
603 /* Purge orphaned elements in BRANCH.
604  */
605 svn_error_t *
606 svn_branch__state_purge(svn_branch__state_t *branch,
607                         apr_pool_t *scratch_pool);
608
609 /* Get the merge history of BRANCH.
610  */
611 svn_error_t *
612 svn_branch__state_get_history(svn_branch__state_t *branch,
613                               svn_branch__history_t **merge_history_p,
614                               apr_pool_t *result_pool);
615
616 /* Set the merge history of BRANCH.
617  */
618 svn_error_t *
619 svn_branch__state_set_history(svn_branch__state_t *branch,
620                               const svn_branch__history_t *merge_history,
621                               apr_pool_t *scratch_pool);
622
623 /* Return the branch-relative path of element EID in BRANCH.
624  *
625  * If the element EID does not currently exist in BRANCH, return NULL.
626  *
627  * ### TODO: Clarify sequencing requirements.
628  */
629 const char *
630 svn_branch__get_path_by_eid(const svn_branch__state_t *branch,
631                             int eid,
632                             apr_pool_t *result_pool);
633
634 /* Return the EID for the branch-relative path PATH in BRANCH.
635  *
636  * If no element of BRANCH is at this path, return -1.
637  *
638  * ### TODO: Clarify sequencing requirements.
639  */
640 int
641 svn_branch__get_eid_by_path(const svn_branch__state_t *branch,
642                             const char *path,
643                             apr_pool_t *scratch_pool);
644
645 /* Get the default branching metadata for r0 of a new repository.
646  */
647 svn_string_t *
648 svn_branch__get_default_r0_metadata(apr_pool_t *result_pool);
649
650 /* Create a new txn object *TXN_P, initialized with info
651  * parsed from STREAM, allocated in RESULT_POOL.
652  */
653 svn_error_t *
654 svn_branch__txn_parse(svn_branch__txn_t **txn_p,
655                       svn_branch__repos_t *repos,
656                       svn_stream_t *stream,
657                       apr_pool_t *result_pool,
658                       apr_pool_t *scratch_pool);
659
660 /* Write to STREAM a parseable representation of TXN.
661  */
662 svn_error_t *
663 svn_branch__txn_serialize(svn_branch__txn_t *txn,
664                           svn_stream_t *stream,
665                           apr_pool_t *scratch_pool);
666
667 /* Write to STREAM a parseable representation of BRANCH.
668  */
669 svn_error_t *
670 svn_branch__state_serialize(svn_stream_t *stream,
671                             svn_branch__state_t *branch,
672                             apr_pool_t *scratch_pool);
673
674
675 #ifdef __cplusplus
676 }
677 #endif /* __cplusplus */
678
679 #endif /* SVN_BRANCH_H */