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;
}