]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/subversion/subversion/libsvn_delta/branch_nested.c
Update svn-1.9.7 to 1.10.0.
[FreeBSD/FreeBSD.git] / contrib / subversion / subversion / libsvn_delta / branch_nested.c
1 /*
2  * branch_nested.c : Nested Branches
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23
24 #include <assert.h>
25
26 #include "svn_types.h"
27 #include "svn_error.h"
28 #include "svn_dirent_uri.h"
29 #include "svn_hash.h"
30 #include "svn_iter.h"
31 #include "svn_pools.h"
32
33 #include "private/svn_branch_nested.h"
34 #include "private/svn_branch_impl.h"
35 #include "private/svn_branch_repos.h"
36
37 #include "svn_private_config.h"
38
39
40 void
41 svn_branch__get_outer_branch_and_eid(svn_branch__state_t **outer_branch_p,
42                                      int *outer_eid_p,
43                                      const svn_branch__state_t *branch,
44                                      apr_pool_t *scratch_pool)
45 {
46   const char *outer_bid;
47
48   svn_branch__id_unnest(&outer_bid, outer_eid_p, branch->bid, scratch_pool);
49   *outer_branch_p = NULL;
50   if (outer_bid)
51     {
52       *outer_branch_p
53         = svn_branch__txn_get_branch_by_id(branch->txn, outer_bid,
54                                            scratch_pool);
55     }
56 }
57
58 const char *
59 svn_branch__get_root_rrpath(const svn_branch__state_t *branch,
60                             apr_pool_t *result_pool)
61 {
62   svn_branch__state_t *outer_branch;
63   int outer_eid;
64   const char *root_rrpath;
65
66   svn_branch__get_outer_branch_and_eid(&outer_branch, &outer_eid, branch,
67                                        result_pool);
68   if (outer_branch)
69     {
70       root_rrpath
71         = svn_branch__get_rrpath_by_eid(outer_branch, outer_eid, result_pool);
72     }
73   else
74     {
75       root_rrpath = "";
76     }
77
78   SVN_ERR_ASSERT_NO_RETURN(root_rrpath);
79   return root_rrpath;
80 }
81
82 const char *
83 svn_branch__get_rrpath_by_eid(const svn_branch__state_t *branch,
84                               int eid,
85                               apr_pool_t *result_pool)
86 {
87   const char *path = svn_branch__get_path_by_eid(branch, eid, result_pool);
88   const char *rrpath = NULL;
89
90   if (path)
91     {
92       rrpath = svn_relpath_join(svn_branch__get_root_rrpath(branch, result_pool),
93                                 path, result_pool);
94     }
95   return rrpath;
96 }
97
98 svn_error_t *
99 svn_branch__get_subbranch_at_eid(svn_branch__state_t *branch,
100                                  svn_branch__state_t **subbranch_p,
101                                  int eid,
102                                  apr_pool_t *scratch_pool)
103 {
104   svn_element__content_t *element;
105
106   SVN_ERR(svn_branch__state_get_element(branch, &element, eid, scratch_pool));
107   if (element && element->payload->is_subbranch_root)
108     {
109       const char *branch_id = svn_branch__get_id(branch, scratch_pool);
110       const char *subbranch_id = svn_branch__id_nest(branch_id, eid,
111                                                      scratch_pool);
112
113       *subbranch_p = svn_branch__txn_get_branch_by_id(branch->txn, subbranch_id,
114                                                       scratch_pool);
115     }
116   else
117     {
118       *subbranch_p = NULL;
119     }
120   return SVN_NO_ERROR;
121 }
122
123 /* Set *SUBBRANCH_EIDS_P an array of EIDs of the subbranch-root elements in
124  * BRANCH.
125  */
126 static svn_error_t *
127 svn_branch__get_immediate_subbranch_eids(svn_branch__state_t *branch,
128                                          apr_array_header_t **subbranch_eids_p,
129                                          apr_pool_t *result_pool,
130                                          apr_pool_t *scratch_pool)
131 {
132   apr_array_header_t *subbranch_eids
133     = apr_array_make(result_pool, 0, sizeof(int));
134   svn_element__tree_t *elements;
135   apr_hash_index_t *hi;
136
137   SVN_ERR(svn_branch__state_get_elements(branch, &elements, scratch_pool));
138   for (hi = apr_hash_first(scratch_pool, elements->e_map);
139        hi; hi = apr_hash_next(hi))
140     {
141       int eid = svn_eid__hash_this_key(hi);
142       svn_element__content_t *element = apr_hash_this_val(hi);
143
144       if (element->payload->is_subbranch_root)
145         {
146           APR_ARRAY_PUSH(subbranch_eids, int) = eid;
147         }
148     }
149   *subbranch_eids_p = subbranch_eids;
150   return SVN_NO_ERROR;
151 }
152
153 svn_error_t *
154 svn_branch__get_immediate_subbranches(svn_branch__state_t *branch,
155                                       apr_array_header_t **subbranches_p,
156                                       apr_pool_t *result_pool,
157                                       apr_pool_t *scratch_pool)
158 {
159   apr_array_header_t *subbranch_eids;
160   apr_array_header_t *subbranches
161     = apr_array_make(result_pool, 0, sizeof(void *));
162   const char *branch_id = svn_branch__get_id(branch, scratch_pool);
163   int i;
164
165   SVN_ERR(svn_branch__get_immediate_subbranch_eids(branch, &subbranch_eids,
166                                                    scratch_pool, scratch_pool));
167   for (i = 0; i < subbranch_eids->nelts; i++)
168     {
169       int eid = APR_ARRAY_IDX(subbranch_eids, i, int);
170       const char *subbranch_id
171         = svn_branch__id_nest(branch_id, eid, scratch_pool);
172       svn_branch__state_t *subbranch
173         = svn_branch__txn_get_branch_by_id(branch->txn, subbranch_id,
174                                            scratch_pool);
175
176       SVN_ERR_ASSERT_NO_RETURN(subbranch);
177       APR_ARRAY_PUSH(subbranches, void *) = subbranch;
178     }
179   *subbranches_p = subbranches;
180   return SVN_NO_ERROR;
181 }
182
183 svn_branch__subtree_t *
184 svn_branch__subtree_create(apr_hash_t *e_map,
185                            int root_eid,
186                            apr_pool_t *result_pool)
187 {
188   svn_branch__subtree_t *subtree = apr_pcalloc(result_pool, sizeof(*subtree));
189
190   subtree->tree = svn_element__tree_create(e_map, root_eid, result_pool);
191   subtree->subbranches = apr_hash_make(result_pool);
192   return subtree;
193 }
194
195 svn_error_t *
196 svn_branch__get_subtree(svn_branch__state_t *branch,
197                         svn_branch__subtree_t **subtree_p,
198                         int eid,
199                         apr_pool_t *result_pool)
200 {
201   svn_element__tree_t *element_tree;
202   svn_branch__subtree_t *new_subtree;
203   apr_array_header_t *subbranch_eids;
204   int i;
205   apr_pool_t *iterpool = result_pool;  /* ### not a proper iterpool */
206
207   SVN_ERR(svn_branch__state_get_elements(branch, &element_tree, result_pool));
208   element_tree = svn_element__tree_get_subtree_at_eid(element_tree, eid,
209                                                       result_pool);
210   new_subtree
211     = svn_branch__subtree_create(element_tree->e_map, eid, result_pool);
212
213   /* Add subbranches */
214   SVN_ERR(svn_branch__get_immediate_subbranch_eids(branch, &subbranch_eids,
215                                                    result_pool, result_pool));
216   for (i = 0; i < subbranch_eids->nelts; i++)
217     {
218       int outer_eid = APR_ARRAY_IDX(subbranch_eids, i, int);
219       const char *subbranch_relpath_in_subtree;
220
221       subbranch_relpath_in_subtree
222         = svn_element__tree_get_path_by_eid(new_subtree->tree, outer_eid,
223                                             iterpool);
224
225       /* Is it pathwise at or below EID? If so, add it into the subtree. */
226       if (subbranch_relpath_in_subtree)
227         {
228           svn_branch__state_t *subbranch;
229           svn_branch__subtree_t *this_subtree;
230
231           SVN_ERR(svn_branch__get_subbranch_at_eid(branch, &subbranch,
232                                                    outer_eid, iterpool));
233           if (subbranch)
234             {
235               SVN_ERR(svn_branch__get_subtree(subbranch, &this_subtree,
236                                               svn_branch__root_eid(subbranch),
237                                               result_pool));
238               svn_eid__hash_set(new_subtree->subbranches, outer_eid,
239                                 this_subtree);
240             }
241         }
242     }
243   *subtree_p = new_subtree;
244   return SVN_NO_ERROR;
245 }
246
247 svn_branch__subtree_t *
248 svn_branch__subtree_get_subbranch_at_eid(svn_branch__subtree_t *subtree,
249                                          int eid,
250                                          apr_pool_t *result_pool)
251 {
252   subtree = svn_eid__hash_get(subtree->subbranches, eid);
253
254   return subtree;
255 }
256
257 /* Instantiate ELEMENTS in TO_BRANCH.
258  */
259 static svn_error_t *
260 branch_instantiate_elements(svn_branch__state_t *to_branch,
261                             const svn_element__tree_t *elements,
262                             apr_pool_t *scratch_pool)
263 {
264   apr_hash_index_t *hi;
265
266   for (hi = apr_hash_first(scratch_pool, elements->e_map);
267        hi; hi = apr_hash_next(hi))
268     {
269       int this_eid = svn_eid__hash_this_key(hi);
270       svn_element__content_t *this_element = apr_hash_this_val(hi);
271
272       SVN_ERR(svn_branch__state_set_element(to_branch, this_eid,
273                                             this_element, scratch_pool));
274     }
275
276   return SVN_NO_ERROR;
277 }
278
279 svn_error_t *
280 svn_branch__instantiate_elements_r(svn_branch__state_t *to_branch,
281                                    svn_branch__subtree_t elements,
282                                    apr_pool_t *scratch_pool)
283 {
284   SVN_ERR(branch_instantiate_elements(to_branch, elements.tree,
285                                       scratch_pool));
286
287   /* branch any subbranches */
288   {
289     apr_hash_index_t *hi;
290
291     for (hi = apr_hash_first(scratch_pool, elements.subbranches);
292          hi; hi = apr_hash_next(hi))
293       {
294         int this_outer_eid = svn_eid__hash_this_key(hi);
295         svn_branch__subtree_t *this_subtree = apr_hash_this_val(hi);
296         const char *new_branch_id;
297         svn_branch__state_t *new_branch;
298         /*### svn_branch__history_t *history;*/
299
300         /* branch this subbranch into NEW_BRANCH (recursing) */
301         new_branch_id = svn_branch__id_nest(to_branch->bid, this_outer_eid,
302                                             scratch_pool);
303         SVN_ERR(svn_branch__txn_open_branch(to_branch->txn, &new_branch,
304                                             new_branch_id,
305                                             this_subtree->tree->root_eid,
306                                             NULL /*tree_ref*/,
307                                             scratch_pool, scratch_pool));
308         /*### SVN_ERR(svn_branch__state_set_history(new_branch, history,
309                                               scratch_pool));*/
310
311         SVN_ERR(svn_branch__instantiate_elements_r(new_branch, *this_subtree,
312                                                    scratch_pool));
313       }
314   }
315
316   return SVN_NO_ERROR;
317 }
318
319 /*
320  * ========================================================================
321  */
322
323 svn_error_t *
324 svn_branch__find_nested_branch_element_by_relpath(
325                                 svn_branch__state_t **branch_p,
326                                 int *eid_p,
327                                 svn_branch__state_t *root_branch,
328                                 const char *relpath,
329                                 apr_pool_t *scratch_pool)
330 {
331   /* The path we're looking for is (path-wise) in this branch. See if it
332      is also in a sub-branch. */
333   /* Loop invariants: RELPATH is the path we're looking for, relative to
334      ROOT_BRANCH which is the current level of nesting that we've descended
335      into. */
336   while (TRUE)
337     {
338       apr_array_header_t *subbranch_eids;
339       int i;
340       svn_boolean_t found = FALSE;
341
342       SVN_ERR(svn_branch__get_immediate_subbranch_eids(
343                 root_branch, &subbranch_eids, scratch_pool, scratch_pool));
344       for (i = 0; i < subbranch_eids->nelts; i++)
345         {
346           int outer_eid = APR_ARRAY_IDX(subbranch_eids, i, int);
347           const char *relpath_to_subbranch;
348           const char *relpath_in_subbranch;
349
350           /* Check whether the RELPATH we're looking for is within this
351              subbranch at OUTER_EID. If it is, recurse in the subbranch. */
352           relpath_to_subbranch
353             = svn_branch__get_path_by_eid(root_branch, outer_eid, scratch_pool);
354           relpath_in_subbranch
355             = svn_relpath_skip_ancestor(relpath_to_subbranch, relpath);
356           if (relpath_in_subbranch)
357             {
358               svn_branch__state_t *subbranch;
359
360               SVN_ERR(svn_branch__get_subbranch_at_eid(
361                         root_branch, &subbranch, outer_eid, scratch_pool));
362               /* If the branch hierarchy is not 'flat' then we might find
363                  there is no actual branch where the subbranch-root element
364                  says there should be one. In that case, ignore it. */
365               if (subbranch)
366                 {
367                   root_branch = subbranch;
368                   relpath = relpath_in_subbranch;
369                   found = TRUE;
370                   break;
371                 }
372             }
373         }
374       if (! found)
375         {
376           break;
377         }
378     }
379
380   *branch_p = root_branch;
381   if (eid_p)
382     *eid_p = svn_branch__get_eid_by_path(root_branch, relpath, scratch_pool);
383   return SVN_NO_ERROR;
384 }
385
386 svn_error_t *
387 svn_branch__repos_find_el_rev_by_path_rev(svn_branch__el_rev_id_t **el_rev_p,
388                                 const svn_branch__repos_t *repos,
389                                 svn_revnum_t revnum,
390                                 const char *branch_id,
391                                 const char *relpath,
392                                 apr_pool_t *result_pool,
393                                 apr_pool_t *scratch_pool)
394 {
395   svn_branch__el_rev_id_t *el_rev = apr_palloc(result_pool, sizeof(*el_rev));
396   svn_branch__state_t *branch;
397
398   SVN_ERR(svn_branch__repos_get_branch_by_id(&branch,
399                                              repos, revnum, branch_id,
400                                              scratch_pool));
401   el_rev->rev = revnum;
402   SVN_ERR(svn_branch__find_nested_branch_element_by_relpath(&el_rev->branch,
403                                                             &el_rev->eid,
404                                                             branch, relpath,
405                                                             scratch_pool));
406
407   /* Any relpath must at least be within the originally given branch */
408   SVN_ERR_ASSERT_NO_RETURN(el_rev->branch);
409   *el_rev_p = el_rev;
410   return SVN_NO_ERROR;
411 }
412
413 /* Set *BRANCH_P to the branch found in the repository of TXN, at the
414  * location (in a revision or in this txn) SRC_EL_REV.
415  *
416  * Return an error if REVNUM or BRANCH_ID is not found.
417  */
418 static svn_error_t *
419 branch_in_rev_or_txn(svn_branch__state_t **branch_p,
420                      const svn_branch__rev_bid_eid_t *src_el_rev,
421                      svn_branch__txn_t *txn,
422                      apr_pool_t *result_pool)
423 {
424   if (SVN_IS_VALID_REVNUM(src_el_rev->rev))
425     {
426       SVN_ERR(svn_branch__repos_get_branch_by_id(branch_p,
427                                                  txn->repos,
428                                                  src_el_rev->rev,
429                                                  src_el_rev->bid,
430                                                  result_pool));
431     }
432   else
433     {
434       *branch_p
435         = svn_branch__txn_get_branch_by_id(
436             txn, src_el_rev->bid, result_pool);
437       if (! *branch_p)
438         return svn_error_createf(SVN_BRANCH__ERR, NULL,
439                                  _("Branch %s not found"),
440                                  src_el_rev->bid);
441     }
442
443   return SVN_NO_ERROR;
444 }
445
446 struct svn_branch__txn_priv_t
447 {
448   /* The underlying branch-txn that supports only non-nested branching. */
449   svn_branch__txn_t *wrapped_txn;
450
451 };
452
453 /* Implements nested branching.
454  * An #svn_branch__txn_t method. */
455 static apr_array_header_t *
456 nested_branch_txn_get_branches(const svn_branch__txn_t *txn,
457                                apr_pool_t *result_pool)
458 {
459   /* Just forwarding: nothing more is needed. */
460   apr_array_header_t *branches
461     = svn_branch__txn_get_branches(txn->priv->wrapped_txn,
462                                    result_pool);
463
464   return branches;
465 }
466
467 /* An #svn_branch__txn_t method. */
468 static svn_error_t *
469 nested_branch_txn_delete_branch(svn_branch__txn_t *txn,
470                                 const char *bid,
471                                 apr_pool_t *scratch_pool)
472 {
473   /* Just forwarding: nothing more is needed. */
474   SVN_ERR(svn_branch__txn_delete_branch(txn->priv->wrapped_txn,
475                                         bid,
476                                         scratch_pool));
477   return SVN_NO_ERROR;
478 }
479
480 /* Implements nested branching.
481  * An #svn_branch__txn_t method. */
482 static svn_error_t *
483 nested_branch_txn_get_num_new_eids(const svn_branch__txn_t *txn,
484                                    int *num_new_eids_p,
485                                    apr_pool_t *scratch_pool)
486 {
487   /* Just forwarding: nothing more is needed. */
488   SVN_ERR(svn_branch__txn_get_num_new_eids(txn->priv->wrapped_txn,
489                                            num_new_eids_p,
490                                            scratch_pool));
491   return SVN_NO_ERROR;
492 }
493
494 /* Implements nested branching.
495  * An #svn_branch__txn_t method. */
496 static svn_error_t *
497 nested_branch_txn_new_eid(svn_branch__txn_t *txn,
498                           svn_branch__eid_t *eid_p,
499                           apr_pool_t *scratch_pool)
500 {
501   /* Just forwarding: nothing more is needed. */
502   SVN_ERR(svn_branch__txn_new_eid(txn->priv->wrapped_txn,
503                                   eid_p,
504                                   scratch_pool));
505   return SVN_NO_ERROR;
506 }
507
508 /* Implements nested branching.
509  * An #svn_branch__txn_t method. */
510 static svn_error_t *
511 nested_branch_txn_open_branch(svn_branch__txn_t *txn,
512                               svn_branch__state_t **new_branch_p,
513                               const char *new_branch_id,
514                               int root_eid,
515                               svn_branch__rev_bid_eid_t *tree_ref,
516                               apr_pool_t *result_pool,
517                               apr_pool_t *scratch_pool)
518 {
519   svn_branch__state_t *new_branch;
520
521   SVN_ERR(svn_branch__txn_open_branch(txn->priv->wrapped_txn,
522                                       &new_branch,
523                                       new_branch_id, root_eid, tree_ref,
524                                       result_pool,
525                                       scratch_pool));
526
527   /* Recursively branch any nested branches */
528   if (tree_ref)
529     {
530       svn_branch__state_t *from_branch;
531       svn_branch__subtree_t *from_subtree;
532
533       /* (The way we're doing it here also redundantly re-instantiates all the
534          elements in NEW_BRANCH.) */
535       SVN_ERR(branch_in_rev_or_txn(&from_branch, tree_ref,
536                                    txn->priv->wrapped_txn, scratch_pool));
537       SVN_ERR(svn_branch__get_subtree(from_branch, &from_subtree,
538                                       tree_ref->eid, scratch_pool));
539       SVN_ERR(svn_branch__instantiate_elements_r(new_branch, *from_subtree,
540                                                  scratch_pool));
541     }
542
543   if (new_branch_p)
544     *new_branch_p = new_branch;
545   return SVN_NO_ERROR;
546 }
547
548 /* Implements nested branching.
549  * An #svn_branch__txn_t method. */
550 static svn_error_t *
551 nested_branch_txn_finalize_eids(svn_branch__txn_t *txn,
552                                 apr_pool_t *scratch_pool)
553 {
554   /* Just forwarding: nothing more is needed. */
555   SVN_ERR(svn_branch__txn_finalize_eids(txn->priv->wrapped_txn,
556                                         scratch_pool));
557   return SVN_NO_ERROR;
558 }
559
560 /* Implements nested branching.
561  * An #svn_branch__txn_t method. */
562 static svn_error_t *
563 nested_branch_txn_serialize(svn_branch__txn_t *txn,
564                             svn_stream_t *stream,
565                             apr_pool_t *scratch_pool)
566 {
567   /* Just forwarding: nothing more is needed. */
568   SVN_ERR(svn_branch__txn_serialize(txn->priv->wrapped_txn,
569                                     stream,
570                                     scratch_pool));
571   return SVN_NO_ERROR;
572 }
573
574 /* Implements nested branching.
575  * An #svn_branch__txn_t method. */
576 static svn_error_t *
577 nested_branch_txn_sequence_point(svn_branch__txn_t *txn,
578                                  apr_pool_t *scratch_pool)
579 {
580   svn_branch__txn_t *wrapped_txn = txn->priv->wrapped_txn;
581   apr_array_header_t *branches;
582   int i;
583
584   /* first, purge elements in each branch */
585   SVN_ERR(svn_branch__txn_sequence_point(wrapped_txn, scratch_pool));
586
587   /* second, purge branches that are no longer nested */
588   branches = svn_branch__txn_get_branches(wrapped_txn, scratch_pool);
589   for (i = 0; i < branches->nelts; i++)
590     {
591       svn_branch__state_t *b = APR_ARRAY_IDX(branches, i, void *);
592       svn_branch__state_t *outer_branch;
593       int outer_eid;
594
595       svn_branch__get_outer_branch_and_eid(&outer_branch, &outer_eid,
596                                            b, scratch_pool);
597       if (outer_branch)
598         {
599           svn_element__content_t *element;
600
601           SVN_ERR(svn_branch__state_get_element(outer_branch, &element,
602                                                 outer_eid, scratch_pool));
603           if (! element)
604             SVN_ERR(svn_branch__txn_delete_branch(wrapped_txn, b->bid,
605                                                   scratch_pool));
606         }
607     }
608   return SVN_NO_ERROR;
609 }
610
611 /* An #svn_branch__txn_t method. */
612 static svn_error_t *
613 nested_branch_txn_complete(svn_branch__txn_t *txn,
614                            apr_pool_t *scratch_pool)
615 {
616   /* Just forwarding: nothing more is needed. */
617   SVN_ERR(svn_branch__txn_complete(txn->priv->wrapped_txn,
618                                    scratch_pool));
619   return SVN_NO_ERROR;
620 }
621
622 /* An #svn_branch__txn_t method. */
623 static svn_error_t *
624 nested_branch_txn_abort(svn_branch__txn_t *txn,
625                         apr_pool_t *scratch_pool)
626 {
627   /* Just forwarding: nothing more is needed. */
628   SVN_ERR(svn_branch__txn_abort(txn->priv->wrapped_txn,
629                                 scratch_pool));
630   return SVN_NO_ERROR;
631 }
632
633 svn_branch__txn_t *
634 svn_branch__nested_txn_create(svn_branch__txn_t *wrapped_txn,
635                               apr_pool_t *result_pool)
636 {
637   static const svn_branch__txn_vtable_t vtable = {
638     {0},
639     nested_branch_txn_get_branches,
640     nested_branch_txn_delete_branch,
641     nested_branch_txn_get_num_new_eids,
642     nested_branch_txn_new_eid,
643     nested_branch_txn_open_branch,
644     nested_branch_txn_finalize_eids,
645     nested_branch_txn_serialize,
646     nested_branch_txn_sequence_point,
647     nested_branch_txn_complete,
648     nested_branch_txn_abort,
649   };
650   svn_branch__txn_t *txn
651     = svn_branch__txn_create(&vtable, NULL, NULL, result_pool);
652
653   txn->priv = apr_pcalloc(result_pool, sizeof(*txn->priv));
654   txn->priv->wrapped_txn = wrapped_txn;
655   txn->repos = wrapped_txn->repos;
656   txn->rev = wrapped_txn->rev;
657   txn->base_rev = wrapped_txn->base_rev;
658   return txn;
659 }
660