You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2010/03/01 11:29:50 UTC

svn commit: r917450 - in /subversion/trunk/subversion/libsvn_fs_base: dag.c dag.h reps-strings.c reps-strings.h tree.c

Author: julianfoad
Date: Mon Mar  1 10:29:50 2010
New Revision: 917450

URL: http://svn.apache.org/viewvc?rev=917450&view=rev
Log:
>From Philip Martin's "obliterate-like-deltify" branch, bring in a new kind
of obliterate function which obliterates the changes made by a particular
rep. This is here to experiment with; there are no calls to it yet.

* subversion/libsvn_fs_base/dag.c,
  subversion/libsvn_fs_base/dag.h
  (svn_fs_base__dag_obliterate_rep): New function, renamed from the
    function svn_fs_base__dag_obliterate() on the branch.

* subversion/libsvn_fs_base/reps-strings.c,
  subversion/libsvn_fs_base/reps-strings.h
  (svn_fs_base__rep_obliterate): New function.

* subversion/libsvn_fs_base/tree.c
  (txn_obliterate_rep_args): New struct.
  (txn_body_obliterate_rep, svn_fs_base__obliterate_rep): New functions.

Modified:
    subversion/trunk/subversion/libsvn_fs_base/dag.c
    subversion/trunk/subversion/libsvn_fs_base/dag.h
    subversion/trunk/subversion/libsvn_fs_base/reps-strings.c
    subversion/trunk/subversion/libsvn_fs_base/reps-strings.h
    subversion/trunk/subversion/libsvn_fs_base/tree.c

Modified: subversion/trunk/subversion/libsvn_fs_base/dag.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/dag.c?rev=917450&r1=917449&r2=917450&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/dag.c (original)
+++ subversion/trunk/subversion/libsvn_fs_base/dag.c Mon Mar  1 10:29:50 2010
@@ -1530,6 +1530,33 @@
 }
 
 
+svn_error_t *
+svn_fs_base__dag_obliterate_rep(dag_node_t *node,
+                                dag_node_t *pred_node,
+                                trail_t *trail,
+                                apr_pool_t *pool)
+{
+  node_revision_t *node_rev, *pred_node_rev;
+  svn_fs_t *fs = svn_fs_base__dag_get_fs(node);
+  const char *pred_key;
+
+  SVN_ERR(svn_fs_bdb__get_node_revision(&node_rev, fs, node->id, trail, pool));
+  if (pred_node)
+    {
+      SVN_ERR(svn_fs_bdb__get_node_revision(&pred_node_rev, fs, pred_node->id,
+                                            trail, pool));
+      pred_key = pred_node_rev->data_key;
+    }
+  else
+    {
+      pred_key = NULL;
+    }
+
+  return svn_fs_base__rep_obliterate(trail->fs, node_rev->data_key, pred_key,
+                                     trail, pool);
+}
+
+
 /* Maybe store a `checksum-reps' index record for the representation whose
    key is REP.  (If there's already a rep for this checksum, we don't
    bother overwriting it.)  */

Modified: subversion/trunk/subversion/libsvn_fs_base/dag.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/dag.h?rev=917450&r1=917449&r2=917450&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/dag.h (original)
+++ subversion/trunk/subversion/libsvn_fs_base/dag.h Mon Mar  1 10:29:50 2010
@@ -558,6 +558,15 @@
                                       trail_t *trail,
                                       apr_pool_t *pool);
 
+/* Obliterate NODE's data by constructing a new representation that
+   consists of a no-change delta from PRED_NODE, and changing NODE to
+   use that new rep, and leaving the old rep alone in case it is used
+   by other nodes.  If PRED_NODE is null
+   then construct a representation with an empty fulltext instead. */
+svn_error_t *svn_fs_base__dag_obliterate_rep(dag_node_t *node,
+                                             dag_node_t *pred_node,
+                                             trail_t *trail,
+                                             apr_pool_t *pool);
 
 /* Index NODE's backing data representations by their checksum.  Do
    this as part of TRAIL.  Use POOL for allocations. */

Modified: subversion/trunk/subversion/libsvn_fs_base/reps-strings.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/reps-strings.c?rev=917450&r1=917449&r2=917450&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/reps-strings.c (original)
+++ subversion/trunk/subversion/libsvn_fs_base/reps-strings.c Mon Mar  1 10:29:50 2010
@@ -1621,3 +1621,132 @@
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *svn_fs_base__rep_obliterate(svn_fs_t *fs,
+                                         const char *key,
+                                         const char *pred_key,
+                                         trail_t *trail,
+                                         apr_pool_t *pool)
+{
+  const char *new_str = NULL;
+  representation_t *empty;
+  svn_stream_t *new_stream;
+  struct write_svndiff_strings_baton new_baton;
+  svn_stream_t *pred_stream1, *pred_stream2;
+  svn_txdelta_stream_t *txdelta_stream;
+  base_fs_data_t *bfd = fs->fsap_data;
+  svn_txdelta_window_handler_t new_handler;
+  void *new_handler_baton;
+  apr_pool_t *wpool;
+  apr_array_header_t *windows;
+  window_write_t *ww;
+  svn_txdelta_window_t *window;
+  svn_filesize_t tview_off = 0;
+  svn_filesize_t diffsize = 0;
+  const unsigned char *digest;
+  representation_t *pred_rep;
+  representation_t new_rep;
+  rep_delta_chunk_t *chunk;
+  apr_array_header_t *chunks;
+  int i;
+
+  if (!pred_key)
+    {
+      /* No predecessor so just write a new empty rep */
+      SVN_ERR(svn_fs_bdb__string_append(fs, &new_str, 0, NULL, trail, pool));
+      empty = make_fulltext_rep(new_str, NULL,
+                                svn_checksum_empty_checksum(svn_checksum_md5,
+                                                            pool),
+                                svn_checksum_empty_checksum(svn_checksum_sha1,
+                                                            pool),
+                                pool);
+      SVN_ERR(svn_fs_bdb__write_rep(fs, key, empty, trail, pool));
+
+      return SVN_NO_ERROR;
+    }
+
+  if (!strcmp(key, pred_key))
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             _("Attempt to obliterate '%s' using itself "),
+                             key);
+
+  new_baton.fs = fs;
+  new_baton.trail = trail;
+  new_baton.header_read = FALSE;
+  new_stream = svn_stream_create(&new_baton, pool);
+  svn_stream_set_write(new_stream, write_svndiff_strings);
+
+  /* ### Is there a simpler way to write a no-change delta? */
+  SVN_ERR(svn_fs_base__rep_contents_read_stream(&pred_stream1, fs, pred_key,
+                                                TRUE, trail, pool));
+  SVN_ERR(svn_fs_base__rep_contents_read_stream(&pred_stream2, fs, pred_key,
+                                                TRUE, trail, pool));
+  svn_txdelta(&txdelta_stream, pred_stream1, pred_stream2, pool);
+
+  if (bfd->format >= SVN_FS_BASE__MIN_SVNDIFF1_FORMAT)
+    svn_txdelta_to_svndiff2(&new_handler, &new_handler_baton,
+                            new_stream, 1, pool);
+  else
+    svn_txdelta_to_svndiff2(&new_handler, &new_handler_baton,
+                            new_stream, 0, pool);
+
+  wpool = svn_pool_create(pool);
+  windows = apr_array_make(pool, 1, sizeof(ww));
+  do
+    {
+      new_baton.size = 0;
+      new_baton.key = NULL;
+      svn_pool_clear(wpool);
+
+      SVN_ERR(svn_txdelta_next_window(&window, txdelta_stream, wpool));
+      SVN_ERR(new_handler(window, new_handler_baton));
+      if (window)
+        {
+          ww = apr_pcalloc(pool, sizeof(*ww));
+          ww->key = new_baton.key;
+          ww->svndiff_len = new_baton.size;
+          ww->text_off = tview_off;
+          ww->text_len = window->tview_len;
+          APR_ARRAY_PUSH(windows, window_write_t *) = ww;
+          tview_off += window->tview_len;
+          diffsize += ww->svndiff_len;
+        }
+    } while (window);
+
+  svn_pool_destroy(wpool);
+
+  digest = svn_txdelta_md5_digest(txdelta_stream);
+  if (!digest)
+    return svn_error_createf(SVN_ERR_DELTA_MD5_CHECKSUM_ABSENT, NULL,
+                             _("Failed to calculate MD5 digest for '%s'"),
+                             pred_key);
+  /* ### Check the digest against something?  pred_rep->md5_checksum? */
+
+  SVN_ERR(svn_fs_bdb__read_rep(&pred_rep, fs, pred_key, trail, pool));
+  new_rep.md5_checksum = svn_checksum_dup(pred_rep->md5_checksum, pool);
+  new_rep.sha1_checksum = svn_checksum_dup(pred_rep->sha1_checksum, pool);
+  new_rep.kind = rep_kind_delta;
+  new_rep.txn_id = NULL;
+
+  chunks = apr_array_make(pool, windows->nelts, sizeof(chunk));
+
+  for (i = 0; i < windows->nelts; i++)
+    {
+      ww = APR_ARRAY_IDX(windows, i, window_write_t *);
+
+      chunk = apr_palloc(pool, sizeof(*chunk));
+      chunk->offset = ww->text_off;
+
+      chunk->version = new_baton.version;
+      chunk->string_key = ww->key;
+      chunk->size = ww->text_len;
+      chunk->rep_key = pred_key;
+
+      APR_ARRAY_PUSH(chunks, rep_delta_chunk_t *) = chunk;
+    }
+
+  new_rep.contents.delta.chunks = chunks;
+  SVN_ERR(svn_fs_bdb__write_rep(fs, key, &new_rep, trail, pool));
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/trunk/subversion/libsvn_fs_base/reps-strings.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/reps-strings.h?rev=917450&r1=917449&r2=917450&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/reps-strings.h (original)
+++ subversion/trunk/subversion/libsvn_fs_base/reps-strings.h Mon Mar  1 10:29:50 2010
@@ -168,6 +168,18 @@
                                       trail_t *trail,
                                       apr_pool_t *pool);
 
+/* Obliterate KEY's data by creating a new rep that consists of a
+   no-change delta from PRED_KEY's data.  If PRED_KEY is null then
+   construct an empty fulltext instead of a delta.  KEY's old data
+   remains in the database in case some other key's data is derived
+   from it. */
+/* ### TODO: clarify.  What kind of objects are KEY and PRED_KEY, and what
+   does it do with the new rep? */
+svn_error_t *svn_fs_base__rep_obliterate(svn_fs_t *fs,
+                                         const char *key,
+                                         const char *pred_key,
+                                         trail_t *trail,
+                                         apr_pool_t *pool);
 
 
 #ifdef __cplusplus

Modified: subversion/trunk/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/tree.c?rev=917450&r1=917449&r2=917450&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/trunk/subversion/libsvn_fs_base/tree.c Mon Mar  1 10:29:50 2010
@@ -2940,6 +2940,94 @@
 }
 
 
+struct txn_obliterate_rep_args
+{
+  const svn_fs_id_t *id;
+  svn_boolean_t has_pred;
+  const svn_fs_id_t *pred_id;
+};
+
+static svn_error_t *
+txn_body_obliterate_rep(void *baton, trail_t *trail)
+{
+  struct txn_obliterate_rep_args *args = baton;
+  dag_node_t *node, *pred_node;
+
+  SVN_ERR(svn_fs_base__dag_get_node(&node, trail->fs, args->id,
+                                    trail, trail->pool));
+  if (args->has_pred)
+    {
+      SVN_ERR(svn_fs_base__dag_get_node(&pred_node, trail->fs, args->pred_id,
+                                        trail, trail->pool));
+    }
+  else
+    {
+      pred_node = NULL;
+    }
+
+  SVN_ERR(svn_fs_base__dag_obliterate_rep(node, pred_node, trail, trail->pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_base__obliterate_rep(svn_fs_t *fs,
+                            const char *path,
+                            svn_revnum_t revision,
+                            apr_pool_t *pool)
+{
+  svn_fs_root_t *root;
+  const char *txn_id;
+  struct rev_get_txn_id_args get_txn_args;
+  const svn_fs_id_t *id;
+  svn_node_kind_t kind;
+  struct txn_pred_count_args pred_count_args;
+  struct txn_obliterate_rep_args oblit_args;
+
+  SVN_ERR(svn_fs_base__revision_root(&root, fs, revision, pool));
+  get_txn_args.txn_id = &txn_id;
+  get_txn_args.revision = revision;
+  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_rev_get_txn_id, &get_txn_args,
+                                 FALSE, pool));
+
+  SVN_ERR(base_node_id(&id, root, path, pool));
+  if (strcmp(svn_fs_base__id_txn_id(id), txn_id))
+    return svn_error_createf(SVN_ERR_FS_NOT_MUTABLE, NULL,
+                             _("Unexpected immutable node at '%s'"), path);
+
+  SVN_ERR(base_check_path(&kind, root, path, pool));
+  if (kind != svn_node_file)
+    return svn_error_createf(SVN_ERR_FS_NOT_FILE, NULL,
+                             _("Cannot obliterate '%s' as it is not a file"),
+                             path);
+
+  pred_count_args.id = id;
+  SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_pred_count, &pred_count_args,
+                                 FALSE, pool));
+
+  if (pred_count_args.pred_count > 0)
+    {
+      struct txn_pred_id_args pred_id_args;
+
+      pred_id_args.id = id;
+      pred_id_args.pool = pool;
+      SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_pred_id, &pred_id_args,
+                                     FALSE, pool));
+
+      oblit_args.has_pred = TRUE;
+      oblit_args.pred_id = pred_id_args.pred_id;
+    }
+  else
+    {
+      oblit_args.has_pred = FALSE;
+    }
+  oblit_args.id = id;
+
+  return svn_fs_base__retry_txn(fs, txn_body_obliterate_rep, &oblit_args,
+                                TRUE, pool);
+}
+
+
 
 /* Modifying directories */