Author: julianfoad
Date: Thu Dec 10 16:41:40 2009
New Revision: 889320

URL: http://svn.apache.org/viewvc?rev=889320&view=rev
Log:
In BDB, for obliterate, implement converting a committed transaction to a
mutable txn.

* subversion/libsvn_fs_base/obliterate.c,
  subversion/libsvn_fs_base/obliterate.h
    New files, with new functions svn_fs_base__rep_dup() and
    svn_fs_base__node_rev_dup().

* subversion/libsvn_fs_base/revs-txns.c
  (txn_body_begin_obliteration_txn): Make a deep copy of the txn to be
    replaced. Add a doc string.
  (svn_fs_base__begin_obliteration_txn): Remove the "unsupported" error return.
    Add comments.

Added:
    subversion/trunk/subversion/libsvn_fs_base/obliterate.c   (with props)
    subversion/trunk/subversion/libsvn_fs_base/obliterate.h   (with props)
Modified:
    subversion/trunk/subversion/libsvn_fs_base/revs-txns.c

Added: subversion/trunk/subversion/libsvn_fs_base/obliterate.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/obliterate.c?rev=889320&view=auto
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/obliterate.c (added)
+++ subversion/trunk/subversion/libsvn_fs_base/obliterate.c Thu Dec 10 16:41:40 
2009
@@ -0,0 +1,176 @@
+/* obliterate.c : operations related to obliteration
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include <string.h>
+
+#include <apr_tables.h>
+#include <apr_pools.h>
+
+#include "svn_fs.h"
+
+#include "obliterate.h"
+#include "fs.h"
+#include "dag.h"
+#include "trail.h"
+#include "id.h"
+#include "bdb/nodes-table.h"
+#include "bdb/reps-table.h"
+#include "bdb/strings-table.h"
+#include "../libsvn_fs/fs-loader.h"
+
+#include "svn_private_config.h"
+
+
+
+svn_error_t *
+svn_fs_base__rep_dup(const char **new_key,
+                     const char *new_txn_id,
+                     const char *key,
+                     trail_t *trail,
+                     apr_pool_t *pool)
+{
+  representation_t *rep;
+
+  SVN_ERR(svn_fs_bdb__read_rep(&rep, trail->fs, key, trail, pool));
+
+  rep->txn_id = new_txn_id;
+
+  /* Dup the strings and any recursively used representations */
+  if (rep->kind == rep_kind_fulltext)
+    {
+      SVN_ERR(svn_fs_bdb__string_copy(trail->fs,
+                                      &rep->contents.fulltext.string_key,
+                                      rep->contents.fulltext.string_key,
+                                      trail, pool));
+    }
+  else
+    {
+      apr_array_header_t *chunks = rep->contents.delta.chunks;
+      int i;
+
+      for (i = 0; i < chunks->nelts; i++)
+      {
+        rep_delta_chunk_t *w = APR_ARRAY_IDX(chunks, i, rep_delta_chunk_t *);
+
+        SVN_ERR(svn_fs_bdb__string_copy(trail->fs,
+                                        &w->string_key, w->string_key,
+                                        trail, pool));
+        SVN_ERR(svn_fs_base__rep_dup(&w->rep_key, new_txn_id, w->rep_key,
+                                     trail, pool));
+        /* ### w->offset = calc_offset(w->rep_key); ??? */
+      }
+    }
+
+  SVN_ERR(svn_fs_bdb__write_new_rep(new_key, trail->fs, rep, trail, pool));
+  return SVN_NO_ERROR;
+}
+
+/*
+ * ### Use svn_fs_base__dag_copy() instead?
+ * ### Do we need to recurse in order to look for embedded references to
+ *     OLD_TXN_ID even if the current node-rev was not created in txn
+ *     OLD_TXN_ID?
+ */
+svn_error_t *
+svn_fs_base__node_rev_dup(const svn_fs_id_t **new_id,
+                          const svn_fs_id_t *old_id,
+                          const char *new_txn_id,
+                          const char *old_txn_id,
+                          trail_t *trail,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  node_revision_t *noderev;
+
+  /* We only want to dup a node-rev if it "belongs to" (was created in) the
+   * txn we are replacing. */
+  if (strcmp(svn_fs_base__id_txn_id(old_id), old_txn_id) != 0)
+    {
+      *new_id = old_id;
+      return SVN_NO_ERROR;
+    }
+
+  /* Set ID2 to ID except with txn_id NEW_TXN_ID */
+  *new_id = svn_fs_base__id_create(svn_fs_base__id_node_id(old_id),
+                                   svn_fs_base__id_copy_id(old_id), new_txn_id,
+                                   result_pool);
+
+  /* Dup the representation of its text or entries, and recurse to dup the
+   * node-revs of any children. */
+  SVN_ERR(svn_fs_bdb__get_node_revision(&noderev, trail->fs, old_id, trail,
+                                        scratch_pool));
+  if (noderev->kind == svn_node_dir)
+    {
+      /*dag_node_t *old_dag_node;*/
+      dag_node_t *parent_dag_node;
+      apr_hash_t *entries;
+      apr_hash_index_t *hi;
+
+      /* Store the new parent node-rev so we can use dag functions on it */
+      SVN_ERR(svn_fs_bdb__put_node_revision(trail->fs, *new_id, noderev, trail,
+                                            scratch_pool));
+
+      SVN_ERR(svn_fs_base__dag_get_node(&parent_dag_node, trail->fs,
+                                        *new_id, trail, trail->pool));
+
+      /* Get the children */
+      /*SVN_ERR(svn_fs_base__dag_get_node(&old_dag_node, trail->fs, old_id, 
trail,
+                                        trail->pool));*/
+      SVN_ERR(svn_fs_base__dag_dir_entries(&entries, parent_dag_node, trail,
+                                           scratch_pool));
+      /* Caution: 'kind' of each child in 'entries' is 'svn_node_unknown'. */
+
+      /* Dup the children (recursing) */
+      if (entries)
+        for (hi = apr_hash_first(scratch_pool, entries); hi;
+             hi = apr_hash_next(hi))
+          {
+            const char *child_name = svn_apr_hash_index_key(hi);
+            svn_fs_dirent_t *child_entry = svn_apr_hash_index_val(hi);
+            const svn_fs_id_t *new_child_id;
+
+            /* Make a deep copy of the child node-rev. */
+            SVN_ERR(svn_fs_base__node_rev_dup(&new_child_id, child_entry->id,
+                                              new_txn_id, old_txn_id, trail,
+                                              scratch_pool, scratch_pool));
+
+            /* Make the (new) parent node's rep refer to this new child. */
+            SVN_ERR(svn_fs_base__dag_set_entry(parent_dag_node, child_name,
+                                               new_child_id, new_txn_id,
+                                               trail, scratch_pool));
+            /* ### Use instead: svn_fs_base__dag_clone_child() ? */
+          }
+    }
+  else if (noderev->kind == svn_node_file)
+    {
+      SVN_ERR(svn_fs_base__rep_dup(&noderev->data_key, new_txn_id,
+                                   noderev->data_key, trail, result_pool));
+
+      SVN_ERR(svn_fs_bdb__put_node_revision(trail->fs, *new_id, noderev, trail,
+                                            scratch_pool));
+    }
+  else
+    SVN_ERR_MALFUNCTION();
+
+  return SVN_NO_ERROR;
+}
+

Propchange: subversion/trunk/subversion/libsvn_fs_base/obliterate.c
------------------------------------------------------------------------------
    svn:mime-type = text/x-csrc

Added: subversion/trunk/subversion/libsvn_fs_base/obliterate.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/obliterate.h?rev=889320&view=auto
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/obliterate.h (added)
+++ subversion/trunk/subversion/libsvn_fs_base/obliterate.h Thu Dec 10 16:41:40 
2009
@@ -0,0 +1,69 @@
+/* obliterate.h : operations related to obliteration
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#ifndef SVN_LIBSVN_FS_OBLITERATE_H
+#define SVN_LIBSVN_FS_OBLITERATE_H
+
+#include <apr_pools.h>
+
+#include "svn_fs.h"
+#include "trail.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Create a new representation that is a duplicate of the one keyed by KEY,
+ * but make the duplicate refer to NEW_TXN_ID.
+ * Set *NEW_KEY to the key of the new representation.
+ * Work within TRAIL within FS. */
+svn_error_t *
+svn_fs_base__rep_dup(const char **new_key,
+                     const char *new_txn_id,
+                     const char *key,
+                     trail_t *trail,
+                     apr_pool_t *pool);
+
+/* If the node_rev identified by OLD_ID was not created in transaction
+ * OLD_TXN_ID, then set *NEW_ID to OLD_ID and return. Otherwise:
+ * Make a deep copy of node OLD_ID, with any references to OLD_TXN_ID
+ * replaced by NEW_TXN_ID (### and more differences?) The new node-rev-id is
+ * OLD_ID except with the txn-id field changed to NEW_TXN_ID.
+ * Set *NEW_ID to the new node-rev-id, allocated in RESULT_POOL.
+ * Work within TRAIL within FS.
+ */
+svn_error_t *
+svn_fs_base__node_rev_dup(const svn_fs_id_t **new_id,
+                          const svn_fs_id_t *old_id,
+                          const char *new_txn_id,
+                          const char *old_txn_id,
+                          trail_t *trail,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* SVN_LIBSVN_FS_OBLITERATE_H */

Propchange: subversion/trunk/subversion/libsvn_fs_base/obliterate.h
------------------------------------------------------------------------------
    svn:mime-type = text/x-chdr

Modified: subversion/trunk/subversion/libsvn_fs_base/revs-txns.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/revs-txns.c?rev=889320&r1=889319&r2=889320&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/revs-txns.c (original)
+++ subversion/trunk/subversion/libsvn_fs_base/revs-txns.c Thu Dec 10 16:41:40 
2009
@@ -40,6 +40,7 @@
 #include "revs-txns.h"
 #include "key-gen.h"
 #include "id.h"
+#include "obliterate.h"
 #include "bdb/rev-table.h"
 #include "bdb/txn-table.h"
 #include "bdb/copies-table.h"
@@ -692,27 +693,106 @@
   return SVN_NO_ERROR;
 }
 
+/* Create a new transaction that is a mutable duplicate of the committed
+ * transaction in a particular revision, and able to become a replacement
+ * for the transaction in that revision. The duplicate transaction has a new
+ * txn-id and is a deep copy of the old one. All references to the txn-id
+ * within the copied parts of it are updated.
+ *
+ * The resulting transaction should be committed by
+ * svn_fs_base__commit_obliteration_txn(), not by a normal commit.
+ *
+ * BATON is of type (struct begin_txn_args *).
+ * BATON->base_rev is the revision on which the existing revision
+ * is based, i.e. one less than the number of the revision to be replaced.
+ * BATON->flags must be 0: specifically, the CHECK_OOD and CHECK_LOCKS
+ * flags are not supported.
+ *
+ * Set BATON->txn_p to point to the new transaction object, allocated in
+ * TRAIL->pool.
+ */
 static svn_error_t *
 txn_body_begin_obliteration_txn(void *baton, trail_t *trail)
 {
   struct begin_txn_args *args = baton;
-  const svn_fs_id_t *root_id;
-  const char *txn_id;
-
-  SVN_ERR(svn_fs_base__rev_get_root(&root_id, trail->fs, args->base_rev,
-                                    trail, trail->pool));
-  SVN_ERR(svn_fs_bdb__create_txn(&txn_id, trail->fs, root_id,
+  int replacing_rev = args->base_rev + 1;
+  const svn_fs_id_t *base_root_id;
+  const char *old_txn_id, *new_txn_id;
+  transaction_t *old_txn, *new_txn;
+
+  /* Obliteration doesn't support these flags */
+  SVN_ERR_ASSERT(! (args->flags & SVN_FS_TXN_CHECK_OOD));
+  SVN_ERR_ASSERT(! (args->flags & SVN_FS_TXN_CHECK_LOCKS));
+
+  /*
+   * This is like a combination of "dup the txn" and "make the txn mutable".
+   * "Dup the txn" means making a deep copy, but with a new txn id.
+   * "Make mutable" is like the opposite of finalizing a txn.
+   *
+   * To dup the txn in r50:
+   *   * dup TRANSACTIONS<t50> to TRANSACTIONS<t50'>
+   *   * dup all referenced NODES<*.*.t50> (not old nodes that are referenced)
+   *   * dup all referenced REPRESENTATIONS<*> to REPRESENTATIONS<*'>
+   *   * create new STRINGS<*> where necessary (###?)
+   *
+   * At commit time:
+   *   * dup all CHANGES<t50> to CHANGES<t50'>
+   *   * update COPIES<cpy_id> (We need to keep the copy IDs the same, but will
+   *       need to modify the copy src_txn fields.)
+   *   * update NODE-ORIGINS<node_id>
+   *   * update CHECKSUM-REPS<csum>
+   */
+
+  /* Implementation:
+   *   - create a new txn (to get a new txn-id)
+   *   - read the new txn
+   *   - modify the new txn locally, duplicating parts of the old txn
+   *   - write the modified new txn
+   *   - return a reference to the new txn
+   */
+
+  /* Create a new txn whose 'root' and 'base root' node-rev ids both point
+   * to the previous revision, like txn_body_begin_txn() does. */
+  SVN_ERR(svn_fs_base__rev_get_root(&base_root_id, trail->fs,
+                                    args->base_rev, trail, trail->pool));
+  SVN_ERR(svn_fs_bdb__create_txn(&new_txn_id, trail->fs, base_root_id,
                                  trail, trail->pool));
 
-  /* ### No need for "CHECK_OOD" and "CHECK_LOCKS" like the non-oblit case? */
-
-  *args->txn_p = make_txn(trail->fs, txn_id, args->base_rev, trail->pool);
+  /* Read the old and new txns */
+  SVN_ERR(svn_fs_base__rev_get_txn_id(&old_txn_id, trail->fs, replacing_rev,
+                                      trail, trail->pool));
+  SVN_ERR(svn_fs_bdb__get_txn(&old_txn, trail->fs, old_txn_id, trail,
+                              trail->pool));
+  SVN_ERR(svn_fs_bdb__get_txn(&new_txn, trail->fs, new_txn_id, trail,
+                              trail->pool));
+
+  /* Populate NEW_TXN with a duplicate of the contents of OLD_TXN. */
+
+  SVN_ERR_ASSERT(new_txn->kind == transaction_kind_normal);
+
+  /* Dup the old txn's root node-rev (recursively). */
+  SVN_ERR(svn_fs_base__node_rev_dup(&new_txn->root_id, old_txn->root_id,
+                                    new_txn_id, old_txn_id, trail,
+                                    trail->pool, trail->pool));
+
+  /* Dup txn->proplist */
+  new_txn->proplist = old_txn->proplist;
+
+  /* Leave txn->copies as NULL until commit time. We do not dup the "copies"
+   * table rows because we do not want new copy-ids because copy-ids pervade
+   * the whole history of the repository inside node-rev-ids. */
+
+  /* Save the modified transaction */
+  SVN_ERR(svn_fs_bdb__put_txn(trail->fs, new_txn, new_txn_id, trail,
+                              trail->pool));
+
+  /* Make and return an in-memory txn object referring to the new txn */
+  *args->txn_p = make_txn(trail->fs, new_txn_id, args->base_rev,
+                          trail->pool);
   return SVN_NO_ERROR;
 }
 
 
-
-
 /* Note:  it is acceptable for this function to call back into
    public FS API interfaces because it does not itself use trails.  */
 svn_error_t *
@@ -747,6 +827,13 @@
 }
 
 
+/* Create a new transaction in FS that is a mutable clone of the transaction
+ * in revision REPLACING_REV and is intended to replace it. Set *TXN_P to
+ * point to the new transaction.
+ *
+ * This is like svn_fs_base__begin_txn() except that it populates the new txn
+ * with a mutable clone of revision REPLACING_REV, and it does not support the
+ * CHECK_OOD and CHECK_LOCKS flags, and it does not change the date stamp. */
 svn_error_t *
 svn_fs_base__begin_obliteration_txn(svn_fs_txn_t **txn_p,
                                     svn_fs_t *fs,
@@ -758,6 +845,9 @@
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
+  /* Make a mutable duplicate of replacing_rev's txn. */
+  /* ### Does all of the duplication need to be done inside the retry_txn?
+   * It is currently inside. */
   args.txn_p = &txn;
   args.base_rev = replacing_rev - 1;
   args.flags = 0;
@@ -766,7 +856,7 @@
 
   *txn_p = txn;
 
-  return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
+  return SVN_NO_ERROR;
 }
 
 


Reply via email to