You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/11/30 11:24:23 UTC

svn commit: r1717223 [19/50] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/...

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/dag.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/dag.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/dag.c Mon Nov 30 10:24:16 2015
@@ -1,4 +1,4 @@
-/* dag.c : DAG-like interface filesystem, private to libsvn_fs
+/* dag.c : DAG-like interface filesystem
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -41,6 +41,7 @@
 #include "svn_private_config.h"
 #include "private/svn_temp_serializer.h"
 #include "temp_serializer.h"
+#include "dag_cache.h"
 
 
 /* Initializing a filesystem.  */
@@ -50,34 +51,12 @@ struct dag_node_t
   /* The filesystem this dag node came from. */
   svn_fs_t *fs;
 
-  /* The node revision ID for this dag node.  */
-  svn_fs_x__id_t id;
-
-  /* In the special case that this node is the root of a transaction
-     that has not yet been modified, the revision of this node is the
-     respective txn's base rev.  Otherwise, this is SVN_INVALID_REVNUM
-     for txn nodes and the respective crev for committed nodes.
-     (Used in svn_fs_node_created_rev.) */
-  svn_revnum_t revision;
-
-  /* The node's type (file, dir, etc.) */
-  svn_node_kind_t kind;
-
-  /* The node's NODE-REVISION, or NULL if we haven't read it in yet.
-     This is allocated in this node's POOL.
-
-     If you're willing to respect all the rules above, you can munge
-     this yourself, but you're probably better off just calling
-     `get_node_revision' and `set_node_revision', which take care of
-     things for you.  */
+  /* The node's NODE-REVISION. */
   svn_fs_x__noderev_t *node_revision;
 
   /* The pool to allocate NODE_REVISION in. */
   apr_pool_t *node_pool;
 
-  /* the path at which this node was created. */
-  const char *created_path;
-
   /* Directory entry lookup hint to speed up consecutive calls to
      svn_fs_x__rep_contents_dir_entry(). Only used for directory nodes.
      Any value is legal but should default to APR_SIZE_MAX. */
@@ -90,20 +69,20 @@ struct dag_node_t
 svn_node_kind_t
 svn_fs_x__dag_node_kind(dag_node_t *node)
 {
-  return node->kind;
+  return node->node_revision->kind;
 }
 
 const svn_fs_x__id_t *
 svn_fs_x__dag_get_id(const dag_node_t *node)
 {
-  return &node->id;
+  return &node->node_revision->noderev_id;
 }
 
 
 const char *
 svn_fs_x__dag_get_created_path(dag_node_t *node)
 {
-  return node->created_path;
+  return node->node_revision->created_path;
 }
 
 
@@ -144,94 +123,35 @@ copy_node_revision(svn_fs_x__noderev_t *
 }
 
 
-/* Set *NODEREV_P to the cached node-revision for NODE.
-   If the node-revision was not already cached in NODE, read it in,
-   allocating the cache in NODE->NODE_POOL.
-
-   If you plan to change the contents of NODE, be careful!  We're
-   handing you a pointer directly to our cached node-revision, not
-   your own copy.  If you change it as part of some operation, but
-   then some Berkeley DB function deadlocks or gets an error, you'll
-   need to back out your changes, or else the cache will reflect
-   changes that never got committed.  It's probably best not to change
-   the structure at all.  */
-static svn_error_t *
-get_node_revision(svn_fs_x__noderev_t **noderev_p,
-                  dag_node_t *node)
-{
-  /* If we've already got a copy, there's no need to read it in.  */
-  if (! node->node_revision)
-    {
-      svn_fs_x__noderev_t *noderev;
-      apr_pool_t *scratch_pool = svn_pool_create(node->node_pool);
-
-      SVN_ERR(svn_fs_x__get_node_revision(&noderev, node->fs, &node->id,
-                                          node->node_pool, scratch_pool));
-      node->node_revision = noderev;
-      svn_pool_destroy(scratch_pool);
-    }
-
-  /* Now NODE->node_revision is set.  */
-  *noderev_p = node->node_revision;
-  return SVN_NO_ERROR;
-}
-
-/* Return the node revision ID of NODE.  The value returned is shared
-   with NODE, and will be deallocated when NODE is.  */
-svn_error_t *
-svn_fs_x__dag_get_node_id(svn_fs_x__id_t *node_id,
-                          dag_node_t *node)
+const svn_fs_x__id_t *
+svn_fs_x__dag_get_node_id(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-  SVN_ERR(get_node_revision(&noderev, node));
-
-  *node_id = noderev->node_id;
-  return SVN_NO_ERROR;
+  return &node->node_revision->node_id;
 }
 
-/* Return the node revision ID of NODE.  The value returned is shared
-   with NODE, and will be deallocated when NODE is.  */
-svn_error_t *
-svn_fs_x__dag_get_copy_id(svn_fs_x__id_t *copy_id,
-                          dag_node_t *node)
+const svn_fs_x__id_t *
+svn_fs_x__dag_get_copy_id(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-  SVN_ERR(get_node_revision(&noderev, node));
-
-  *copy_id = noderev->copy_id;
-  return SVN_NO_ERROR;
+  return &node->node_revision->copy_id;
 }
 
-/* Return the node ID of NODE.  The value returned is shared with NODE,
-   and will be deallocated when NODE is.  */
-svn_error_t *
-svn_fs_x__dag_related_node(svn_boolean_t *same,
-                           dag_node_t *lhs,
+svn_boolean_t
+svn_fs_x__dag_related_node(dag_node_t *lhs,
                            dag_node_t *rhs)
 {
-  svn_fs_x__id_t lhs_node, rhs_node;
-
-  SVN_ERR(svn_fs_x__dag_get_node_id(&lhs_node, lhs));
-  SVN_ERR(svn_fs_x__dag_get_node_id(&rhs_node, rhs));
-  *same = svn_fs_x__id_eq(&lhs_node, &rhs_node);
-
-  return SVN_NO_ERROR;
+  return svn_fs_x__id_eq(&lhs->node_revision->node_id,
+                         &rhs->node_revision->node_id);
 }
 
-svn_error_t *
-svn_fs_x__dag_same_line_of_history(svn_boolean_t *same,
-                                   dag_node_t *lhs,
+svn_boolean_t
+svn_fs_x__dag_same_line_of_history(dag_node_t *lhs,
                                    dag_node_t *rhs)
 {
-  svn_fs_x__noderev_t *lhs_noderev, *rhs_noderev;
-
-  SVN_ERR(get_node_revision(&lhs_noderev, lhs));
-  SVN_ERR(get_node_revision(&rhs_noderev, rhs));
-
-  *same = svn_fs_x__id_eq(&lhs_noderev->node_id, &rhs_noderev->node_id)
-       && svn_fs_x__id_eq(&lhs_noderev->copy_id, &rhs_noderev->copy_id);
+  svn_fs_x__noderev_t *lhs_noderev = lhs->node_revision;
+  svn_fs_x__noderev_t *rhs_noderev = rhs->node_revision;
 
-  return SVN_NO_ERROR;
+  return svn_fs_x__id_eq(&lhs_noderev->node_id, &rhs_noderev->node_id)
+      && svn_fs_x__id_eq(&lhs_noderev->copy_id, &rhs_noderev->copy_id);
 }
 
 svn_boolean_t
@@ -240,7 +160,6 @@ svn_fs_x__dag_check_mutable(const dag_no
   return svn_fs_x__is_txn(svn_fs_x__dag_get_id(node)->change_set);
 }
 
-
 svn_error_t *
 svn_fs_x__dag_get_node(dag_node_t **node,
                        svn_fs_t *fs,
@@ -254,7 +173,6 @@ svn_fs_x__dag_get_node(dag_node_t **node
   /* Construct the node. */
   new_node = apr_pcalloc(result_pool, sizeof(*new_node));
   new_node->fs = fs;
-  new_node->id = *id;
   new_node->hint = APR_SIZE_MAX;
 
   /* Grab the contents so we can inspect the node's kind and created path. */
@@ -263,17 +181,6 @@ svn_fs_x__dag_get_node(dag_node_t **node
   new_node->node_pool = result_pool;
   new_node->node_revision = noderev;
 
-  /* Initialize the KIND and CREATED_PATH attributes */
-  new_node->kind = noderev->kind;
-  new_node->created_path = noderev->created_path;
-
-  /* Support our quirky svn_fs_node_created_rev API.
-     Untouched txn roots report the base rev as theirs. */
-  new_node->revision
-    = (  svn_fs_x__is_fresh_txn_root(noderev)
-       ? svn_fs_x__get_revnum(noderev->predecessor_id.change_set)
-       : svn_fs_x__get_revnum(id->change_set));
-
   /* Return a fresh new node */
   *node = new_node;
   return SVN_NO_ERROR;
@@ -283,76 +190,50 @@ svn_fs_x__dag_get_node(dag_node_t **node
 svn_revnum_t
 svn_fs_x__dag_get_revision(const dag_node_t *node)
 {
-  return node->revision;
+  svn_fs_x__noderev_t *noderev = node->node_revision;
+  return (  svn_fs_x__is_fresh_txn_root(noderev)
+          ? svn_fs_x__get_revnum(noderev->predecessor_id.change_set)
+          : svn_fs_x__get_revnum(noderev->noderev_id.change_set));
 }
 
-
-svn_error_t *
-svn_fs_x__dag_get_predecessor_id(svn_fs_x__id_t *id_p,
-                                 dag_node_t *node)
+const svn_fs_x__id_t *
+svn_fs_x__dag_get_predecessor_id(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  SVN_ERR(get_node_revision(&noderev, node));
-  *id_p = noderev->predecessor_id;
-
-  return SVN_NO_ERROR;
+  return &node->node_revision->predecessor_id;
 }
 
-
-svn_error_t *
-svn_fs_x__dag_get_predecessor_count(int *count,
-                                    dag_node_t *node)
+int
+svn_fs_x__dag_get_predecessor_count(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  SVN_ERR(get_node_revision(&noderev, node));
-  *count = noderev->predecessor_count;
-  return SVN_NO_ERROR;
+  return node->node_revision->predecessor_count;
 }
 
-svn_error_t *
-svn_fs_x__dag_get_mergeinfo_count(apr_int64_t *count,
-                                  dag_node_t *node)
+apr_int64_t
+svn_fs_x__dag_get_mergeinfo_count(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  SVN_ERR(get_node_revision(&noderev, node));
-  *count = noderev->mergeinfo_count;
-  return SVN_NO_ERROR;
+  return node->node_revision->mergeinfo_count;
 }
 
-svn_error_t *
-svn_fs_x__dag_has_mergeinfo(svn_boolean_t *has_mergeinfo,
-                            dag_node_t *node)
+svn_boolean_t
+svn_fs_x__dag_has_mergeinfo(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  SVN_ERR(get_node_revision(&noderev, node));
-  *has_mergeinfo = noderev->has_mergeinfo;
-  return SVN_NO_ERROR;
+  return node->node_revision->has_mergeinfo;
 }
 
-svn_error_t *
-svn_fs_x__dag_has_descendants_with_mergeinfo(svn_boolean_t *do_they,
-                                             dag_node_t *node)
+svn_boolean_t
+svn_fs_x__dag_has_descendants_with_mergeinfo(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
+  svn_fs_x__noderev_t *noderev = node->node_revision;
 
-  if (node->kind != svn_node_dir)
-    {
-      *do_they = FALSE;
-      return SVN_NO_ERROR;
-    }
+  if (noderev->kind != svn_node_dir)
+      return FALSE;
 
-  SVN_ERR(get_node_revision(&noderev, node));
   if (noderev->mergeinfo_count > 1)
-    *do_they = TRUE;
+    return TRUE;
   else if (noderev->mergeinfo_count == 1 && !noderev->has_mergeinfo)
-    *do_they = TRUE;
-  else
-    *do_they = FALSE;
-  return SVN_NO_ERROR;
+    return TRUE;
+
+  return FALSE;
 }
 
 
@@ -362,16 +243,15 @@ svn_fs_x__dag_has_descendants_with_merge
 
 /* Set *ID_P to the noderev-id for entry NAME in PARENT.  If no such
    entry, set *ID_P to NULL but do not error. */
-static svn_error_t *
-dir_entry_id_from_node(svn_fs_x__id_t *id_p,
+svn_error_t *
+svn_fs_x__dir_entry_id(svn_fs_x__id_t *id_p,
                        dag_node_t *parent,
                        const char *name,
                        apr_pool_t *scratch_pool)
 {
   svn_fs_x__dirent_t *dirent;
-  svn_fs_x__noderev_t *noderev;
+  svn_fs_x__noderev_t *noderev = parent->node_revision;
 
-  SVN_ERR(get_node_revision(&noderev, parent));
   if (noderev->kind != svn_node_dir)
     return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
                             _("Can't get entries of non-directory"));
@@ -411,14 +291,16 @@ set_entry(dag_node_t *parent,
           svn_fs_x__txn_id_t txn_id,
           apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *parent_noderev;
-
-  /* Get the parent's node-revision. */
-  SVN_ERR(get_node_revision(&parent_noderev, parent));
+  svn_fs_x__noderev_t *parent_noderev = parent->node_revision;
 
   /* Set the new entry. */
-  return svn_fs_x__set_entry(parent->fs, txn_id, parent_noderev, name, id,
-                             kind, parent->node_pool, scratch_pool);
+  SVN_ERR(svn_fs_x__set_entry(parent->fs, txn_id, parent_noderev, name, id,
+                              kind, parent->node_pool, scratch_pool));
+
+  /* Update cached data. */
+  svn_fs_x__update_dag_cache(parent);
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -439,7 +321,8 @@ make_entry(dag_node_t **child_p,
            apr_pool_t *result_pool,
            apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t new_noderev, *parent_noderev;
+  svn_fs_x__noderev_t new_noderev;
+  svn_fs_x__noderev_t *parent_noderev = parent->node_revision;
 
   /* Make sure that NAME is a single path component. */
   if (! svn_path_is_single_path_component(name))
@@ -448,7 +331,7 @@ make_entry(dag_node_t **child_p,
        _("Attempted to create a node with an illegal name '%s'"), name);
 
   /* Make sure that parent is a directory */
-  if (parent->kind != svn_node_dir)
+  if (parent_noderev->kind != svn_node_dir)
     return svn_error_create
       (SVN_ERR_FS_NOT_DIRECTORY, NULL,
        _("Attempted to create entry in non-directory parent"));
@@ -464,7 +347,6 @@ make_entry(dag_node_t **child_p,
   new_noderev.kind = is_dir ? svn_node_dir : svn_node_file;
   new_noderev.created_path = svn_fspath__join(parent_path, name, result_pool);
 
-  SVN_ERR(get_node_revision(&parent_noderev, parent));
   new_noderev.copyroot_path = apr_pstrdup(result_pool,
                                           parent_noderev->copyroot_path);
   new_noderev.copyroot_rev = parent_noderev->copyroot_rev;
@@ -495,9 +377,7 @@ svn_fs_x__dag_dir_entries(apr_array_head
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  SVN_ERR(get_node_revision(&noderev, node));
+  svn_fs_x__noderev_t *noderev = node->node_revision;
 
   if (noderev->kind != svn_node_dir)
     return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
@@ -517,7 +397,7 @@ svn_fs_x__dag_set_entry(dag_node_t *node
                         apr_pool_t *scratch_pool)
 {
   /* Check it's a directory. */
-  if (node->kind != svn_node_dir)
+  if (node->node_revision->kind != svn_node_dir)
     return svn_error_create
       (SVN_ERR_FS_NOT_DIRECTORY, NULL,
        _("Attempted to set entry in non-directory node"));
@@ -541,16 +421,8 @@ svn_fs_x__dag_get_proplist(apr_hash_t **
                            apr_pool_t *result_pool,
                            apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *noderev;
-  apr_hash_t *proplist = NULL;
-
-  SVN_ERR(get_node_revision(&noderev, node));
-
-  SVN_ERR(svn_fs_x__get_proplist(&proplist, node->fs, noderev, result_pool,
-                                 scratch_pool));
-
-  *proplist_p = proplist;
-
+  SVN_ERR(svn_fs_x__get_proplist(proplist_p, node->fs, node->node_revision,
+                                 result_pool, scratch_pool));
   return SVN_NO_ERROR;
 }
 
@@ -560,37 +432,51 @@ svn_fs_x__dag_set_proplist(dag_node_t *n
                            apr_hash_t *proplist,
                            apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *noderev;
-
   /* Sanity check: this node better be mutable! */
   if (! svn_fs_x__dag_check_mutable(node))
     {
-      svn_string_t *idstr = svn_fs_x__id_unparse(&node->id, scratch_pool);
+      svn_string_t *idstr
+        = svn_fs_x__id_unparse(&node->node_revision->noderev_id,
+                               scratch_pool);
       return svn_error_createf
         (SVN_ERR_FS_NOT_MUTABLE, NULL,
          "Can't set proplist on *immutable* node-revision %s",
          idstr->data);
     }
 
-  /* Go get a fresh NODE-REVISION for this node. */
-  SVN_ERR(get_node_revision(&noderev, node));
-
   /* Set the new proplist. */
-  return svn_fs_x__set_proplist(node->fs, noderev, proplist, scratch_pool);
+  SVN_ERR(svn_fs_x__set_proplist(node->fs, node->node_revision, proplist,
+                                 scratch_pool));
+  svn_fs_x__update_dag_cache(node);
+
+  return SVN_NO_ERROR;
 }
 
+/* Write NODE's NODEREV element to disk.  Update the DAG cache.
+   Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+noderev_changed(dag_node_t *node,
+                apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_fs_x__put_node_revision(node->fs, node->node_revision,
+                                      scratch_pool));
+  svn_fs_x__update_dag_cache(node);
+
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_fs_x__dag_increment_mergeinfo_count(dag_node_t *node,
                                         apr_int64_t increment,
                                         apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *noderev;
+  svn_fs_x__noderev_t *noderev = node->node_revision;
 
   /* Sanity check: this node better be mutable! */
   if (! svn_fs_x__dag_check_mutable(node))
     {
-      svn_string_t *idstr = svn_fs_x__id_unparse(&node->id, scratch_pool);
+      svn_string_t *idstr = svn_fs_x__id_unparse(&noderev->noderev_id,
+                                                 scratch_pool);
       return svn_error_createf
         (SVN_ERR_FS_NOT_MUTABLE, NULL,
          "Can't increment mergeinfo count on *immutable* node-revision %s",
@@ -600,13 +486,11 @@ svn_fs_x__dag_increment_mergeinfo_count(
   if (increment == 0)
     return SVN_NO_ERROR;
 
-  /* Go get a fresh NODE-REVISION for this node. */
-  SVN_ERR(get_node_revision(&noderev, node));
-
   noderev->mergeinfo_count += increment;
   if (noderev->mergeinfo_count < 0)
     {
-      svn_string_t *idstr = svn_fs_x__id_unparse(&node->id, scratch_pool);
+      svn_string_t *idstr = svn_fs_x__id_unparse(&noderev->noderev_id,
+                                                 scratch_pool);
       return svn_error_createf
         (SVN_ERR_FS_CORRUPT, NULL,
          apr_psprintf(scratch_pool,
@@ -617,7 +501,8 @@ svn_fs_x__dag_increment_mergeinfo_count(
     }
   if (noderev->mergeinfo_count > 1 && noderev->kind == svn_node_file)
     {
-      svn_string_t *idstr = svn_fs_x__id_unparse(&node->id, scratch_pool);
+      svn_string_t *idstr = svn_fs_x__id_unparse(&noderev->noderev_id,
+                                                 scratch_pool);
       return svn_error_createf
         (SVN_ERR_FS_CORRUPT, NULL,
          apr_psprintf(scratch_pool,
@@ -628,7 +513,7 @@ svn_fs_x__dag_increment_mergeinfo_count(
     }
 
   /* Flush it out. */
-  return svn_fs_x__put_node_revision(node->fs, noderev, scratch_pool);
+  return noderev_changed(node, scratch_pool);
 }
 
 svn_error_t *
@@ -636,55 +521,38 @@ svn_fs_x__dag_set_has_mergeinfo(dag_node
                                 svn_boolean_t has_mergeinfo,
                                 apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *noderev;
-
   /* Sanity check: this node better be mutable! */
   if (! svn_fs_x__dag_check_mutable(node))
     {
-      svn_string_t *idstr = svn_fs_x__id_unparse(&node->id, scratch_pool);
+      svn_string_t *idstr
+        = svn_fs_x__id_unparse(&node->node_revision->noderev_id,
+                               scratch_pool);
       return svn_error_createf
         (SVN_ERR_FS_NOT_MUTABLE, NULL,
          "Can't set mergeinfo flag on *immutable* node-revision %s",
          idstr->data);
     }
 
-  /* Go get a fresh NODE-REVISION for this node. */
-  SVN_ERR(get_node_revision(&noderev, node));
-
-  noderev->has_mergeinfo = has_mergeinfo;
+  node->node_revision->has_mergeinfo = has_mergeinfo;
 
   /* Flush it out. */
-  return svn_fs_x__put_node_revision(node->fs, noderev, scratch_pool);
+  return noderev_changed(node, scratch_pool);
 }
 
 
 /*** Roots. ***/
 
 svn_error_t *
-svn_fs_x__dag_revision_root(dag_node_t **node_p,
-                            svn_fs_t *fs,
-                            svn_revnum_t rev,
-                            apr_pool_t *result_pool,
-                            apr_pool_t *scratch_pool)
-{
-  svn_fs_x__id_t root_id;
-
-  svn_fs_x__init_rev_root(&root_id, rev);
-  return svn_fs_x__dag_get_node(node_p, fs, &root_id, result_pool,
-                                scratch_pool);
-}
-
-
-svn_error_t *
-svn_fs_x__dag_txn_root(dag_node_t **node_p,
-                       svn_fs_t *fs,
-                       svn_fs_x__txn_id_t txn_id,
-                       apr_pool_t *result_pool,
-                       apr_pool_t *scratch_pool)
+svn_fs_x__dag_root(dag_node_t **node_p,
+                   svn_fs_t *fs,
+                   svn_fs_x__change_set_t change_set,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
 {
   svn_fs_x__id_t root_id;
+  root_id.change_set = change_set;
+  root_id.number = SVN_FS_X__ITEM_INDEX_ROOT_NODE;
 
-  svn_fs_x__init_txn_root(&root_id, txn_id);
   return svn_fs_x__dag_get_node(node_p, fs, &root_id, result_pool,
                                 scratch_pool);
 }
@@ -734,14 +602,11 @@ svn_fs_x__dag_clone_child(dag_node_t **c
     }
   else
     {
-      svn_fs_x__noderev_t *noderev, *parent_noderev;
-
-      /* Go get a fresh NODE-REVISION for current child node. */
-      SVN_ERR(get_node_revision(&noderev, cur_entry));
+      svn_fs_x__noderev_t *noderev = cur_entry->node_revision;
 
       if (is_parent_copyroot)
         {
-          SVN_ERR(get_node_revision(&parent_noderev, parent));
+          svn_fs_x__noderev_t *parent_noderev = parent->node_revision;
           noderev->copyroot_rev = parent_noderev->copyroot_rev;
           noderev->copyroot_path = apr_pstrdup(scratch_pool,
                                                parent_noderev->copyroot_path);
@@ -796,7 +661,7 @@ delete_if_mutable(svn_fs_t *fs,
     return SVN_NO_ERROR;
 
   /* Else it's mutable.  Recurse on directories... */
-  if (node->kind == svn_node_dir)
+  if (node->node_revision->kind == svn_node_dir)
     {
       apr_array_header_t *entries;
       int i;
@@ -829,13 +694,13 @@ svn_fs_x__dag_delete(dag_node_t *parent,
                      svn_fs_x__txn_id_t txn_id,
                      apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *parent_noderev;
+  svn_fs_x__noderev_t *parent_noderev = parent->node_revision;
   svn_fs_t *fs = parent->fs;
   svn_fs_x__dirent_t *dirent;
   apr_pool_t *subpool;
 
   /* Make sure parent is a directory. */
-  if (parent->kind != svn_node_dir)
+  if (parent_noderev->kind != svn_node_dir)
     return svn_error_createf
       (SVN_ERR_FS_NOT_DIRECTORY, NULL,
        "Attempted to delete entry '%s' from *non*-directory node", name);
@@ -852,9 +717,9 @@ svn_fs_x__dag_delete(dag_node_t *parent,
       (SVN_ERR_FS_NOT_SINGLE_PATH_COMPONENT, NULL,
        "Attempted to delete a node with an illegal name '%s'", name);
 
-  /* Get a fresh NODE-REVISION for the parent node. */
-  SVN_ERR(get_node_revision(&parent_noderev, parent));
-
+  /* We allocate a few potentially heavy temporary objects (file buffers
+     and directories).  Make sure we don't keep them around for longer
+     than necessary. */
   subpool = svn_pool_create(scratch_pool);
 
   /* Search this directory for a dirent with that NAME. */
@@ -871,13 +736,13 @@ svn_fs_x__dag_delete(dag_node_t *parent,
        "Delete failed--directory has no entry '%s'", name);
 
   /* If mutable, remove it and any mutable children from db. */
-  SVN_ERR(delete_if_mutable(parent->fs, &dirent->id, scratch_pool));
-  svn_pool_destroy(subpool);
+  SVN_ERR(delete_if_mutable(parent->fs, &dirent->id, subpool));
 
   /* Remove this entry from its parent's entries list. */
-  return svn_fs_x__set_entry(parent->fs, txn_id, parent_noderev, name,
-                             NULL, svn_node_unknown, parent->node_pool,
-                             scratch_pool);
+  SVN_ERR(set_entry(parent, name, NULL, svn_node_unknown, txn_id, subpool));
+
+  svn_pool_destroy(subpool);
+  return SVN_NO_ERROR;
 }
 
 
@@ -916,23 +781,16 @@ svn_fs_x__dag_get_contents(svn_stream_t
                            dag_node_t *file,
                            apr_pool_t *result_pool)
 {
-  svn_fs_x__noderev_t *noderev;
-  svn_stream_t *contents;
-
   /* Make sure our node is a file. */
-  if (file->kind != svn_node_file)
+  if (file->node_revision->kind != svn_node_file)
     return svn_error_createf
       (SVN_ERR_FS_NOT_FILE, NULL,
        "Attempted to get textual contents of a *non*-file node");
 
-  /* Go get a fresh node-revision for FILE. */
-  SVN_ERR(get_node_revision(&noderev, file));
-
   /* Get a stream to the contents. */
-  SVN_ERR(svn_fs_x__get_contents(&contents, file->fs,
-                                 noderev->data_rep, TRUE, result_pool));
-
-  *contents_p = contents;
+  SVN_ERR(svn_fs_x__get_contents(contents_p, file->fs,
+                                 file->node_revision->data_rep, TRUE,
+                                 result_pool));
 
   return SVN_NO_ERROR;
 }
@@ -945,23 +803,16 @@ svn_fs_x__dag_get_file_delta_stream(svn_
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *src_noderev;
-  svn_fs_x__noderev_t *tgt_noderev;
+  svn_fs_x__noderev_t *src_noderev = source ? source->node_revision : NULL;
+  svn_fs_x__noderev_t *tgt_noderev = target->node_revision;
 
   /* Make sure our nodes are files. */
-  if ((source && source->kind != svn_node_file)
-      || target->kind != svn_node_file)
+  if ((source && src_noderev->kind != svn_node_file)
+      || tgt_noderev->kind != svn_node_file)
     return svn_error_createf
       (SVN_ERR_FS_NOT_FILE, NULL,
        "Attempted to get textual contents of a *non*-file node");
 
-  /* Go get fresh node-revisions for the nodes. */
-  if (source)
-    SVN_ERR(get_node_revision(&src_noderev, source));
-  else
-    src_noderev = NULL;
-  SVN_ERR(get_node_revision(&tgt_noderev, target));
-
   /* Get the delta stream. */
   return svn_fs_x__get_file_delta_stream(stream_p, target->fs,
                                          src_noderev, tgt_noderev,
@@ -976,13 +827,8 @@ svn_fs_x__dag_try_process_file_contents(
                                         void* baton,
                                         apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  /* Go get fresh node-revisions for the nodes. */
-  SVN_ERR(get_node_revision(&noderev, node));
-
   return svn_fs_x__try_process_file_contents(success, node->fs,
-                                             noderev,
+                                             node->node_revision,
                                              processor, baton, scratch_pool);
 }
 
@@ -991,18 +837,13 @@ svn_error_t *
 svn_fs_x__dag_file_length(svn_filesize_t *length,
                           dag_node_t *file)
 {
-  svn_fs_x__noderev_t *noderev;
-
   /* Make sure our node is a file. */
-  if (file->kind != svn_node_file)
+  if (file->node_revision->kind != svn_node_file)
     return svn_error_createf
       (SVN_ERR_FS_NOT_FILE, NULL,
        "Attempted to get length of a *non*-file node");
 
-  /* Go get a fresh node-revision for FILE, and . */
-  SVN_ERR(get_node_revision(&noderev, file));
-
-  return svn_fs_x__file_length(length, noderev);
+  return svn_fs_x__file_length(length, file->node_revision);
 }
 
 
@@ -1012,16 +853,13 @@ svn_fs_x__dag_file_checksum(svn_checksum
                             svn_checksum_kind_t kind,
                             apr_pool_t *result_pool)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  if (file->kind != svn_node_file)
+  if (file->node_revision->kind != svn_node_file)
     return svn_error_createf
       (SVN_ERR_FS_NOT_FILE, NULL,
        "Attempted to get checksum of a *non*-file node");
 
-  SVN_ERR(get_node_revision(&noderev, file));
-
-  return svn_fs_x__file_checksum(checksum, noderev, kind, result_pool);
+  return svn_fs_x__file_checksum(checksum, file->node_revision, kind,
+                                 result_pool);
 }
 
 
@@ -1030,11 +868,8 @@ svn_fs_x__dag_get_edit_stream(svn_stream
                               dag_node_t *file,
                               apr_pool_t *result_pool)
 {
-  svn_fs_x__noderev_t *noderev;
-  svn_stream_t *ws;
-
   /* Make sure our node is a file. */
-  if (file->kind != svn_node_file)
+  if (file->node_revision->kind != svn_node_file)
     return svn_error_createf
       (SVN_ERR_FS_NOT_FILE, NULL,
        "Attempted to set textual contents of a *non*-file node");
@@ -1045,13 +880,8 @@ svn_fs_x__dag_get_edit_stream(svn_stream
       (SVN_ERR_FS_NOT_MUTABLE, NULL,
        "Attempted to set textual contents of an immutable node");
 
-  /* Get the node revision. */
-  SVN_ERR(get_node_revision(&noderev, file));
-
-  SVN_ERR(svn_fs_x__set_contents(&ws, file->fs, noderev, result_pool));
-
-  *contents = ws;
-
+  SVN_ERR(svn_fs_x__set_contents(contents, file->fs, file->node_revision,
+                                 result_pool));
   return SVN_NO_ERROR;
 }
 
@@ -1072,9 +902,10 @@ svn_fs_x__dag_finalize_edits(dag_node_t
         return svn_checksum_mismatch_err(checksum, file_checksum,
                                          scratch_pool,
                                          _("Checksum mismatch for '%s'"),
-                                         file->created_path);
+                                         file->node_revision->created_path);
     }
 
+  svn_fs_x__update_dag_cache(file);
   return SVN_NO_ERROR;
 }
 
@@ -1086,101 +917,14 @@ svn_fs_x__dag_dup(const dag_node_t *node
   /* Allocate our new node. */
   dag_node_t *new_node = apr_pmemdup(result_pool, node, sizeof(*new_node));
 
-  /* Only copy cached svn_fs_x__noderev_t for immutable nodes. */
-  if (node->node_revision && !svn_fs_x__dag_check_mutable(node))
-    {
-      new_node->node_revision = copy_node_revision(node->node_revision,
-                                                   result_pool);
-      new_node->created_path = new_node->node_revision->created_path;
-    }
-  else
-    {
-      new_node->node_revision = NULL;
-      new_node->created_path = apr_pstrdup(result_pool, node->created_path);
-    }
-
+  /* Copy sub-structures. */
+  new_node->node_revision = copy_node_revision(node->node_revision,
+                                               result_pool);
   new_node->node_pool = result_pool;
 
   return new_node;
 }
 
-dag_node_t *
-svn_fs_x__dag_copy_into_pool(dag_node_t *node,
-                             apr_pool_t *result_pool)
-{
-  return (node->node_pool == result_pool
-            ? node
-            : svn_fs_x__dag_dup(node, result_pool));
-}
-
-svn_error_t *
-svn_fs_x__dag_serialize(void **data,
-                        apr_size_t *data_len,
-                        void *in,
-                        apr_pool_t *pool)
-{
-  dag_node_t *node = in;
-  svn_stringbuf_t *serialized;
-
-  /* create an serialization context and serialize the dag node as root */
-  svn_temp_serializer__context_t *context =
-      svn_temp_serializer__init(node,
-                                sizeof(*node),
-                                1024 - SVN_TEMP_SERIALIZER__OVERHEAD,
-                                pool);
-
-  /* for mutable nodes, we will _never_ cache the noderev */
-  if (node->node_revision && !svn_fs_x__dag_check_mutable(node))
-    {
-      svn_fs_x__noderev_serialize(context, &node->node_revision);
-    }
-  else
-    {
-      svn_temp_serializer__set_null(context,
-                                    (const void * const *)&node->node_revision);
-      svn_temp_serializer__add_string(context, &node->created_path);
-    }
-
-  /* The deserializer will use its own pool. */
-  svn_temp_serializer__set_null(context,
-                                (const void * const *)&node->node_pool);
-
-  /* return serialized data */
-  serialized = svn_temp_serializer__get(context);
-  *data = serialized->data;
-  *data_len = serialized->len;
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_fs_x__dag_deserialize(void **out,
-                          void *data,
-                          apr_size_t data_len,
-                          apr_pool_t *pool)
-{
-  dag_node_t *node = (dag_node_t *)data;
-  if (data_len == 0)
-    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                            _("Empty noderev in cache"));
-
-  /* Copy the _full_ buffer as it also contains the sub-structures. */
-  node->fs = NULL;
-
-  /* fixup all references to sub-structures */
-  svn_fs_x__noderev_deserialize(node, &node->node_revision, pool);
-  node->node_pool = pool;
-
-  if (node->node_revision)
-    node->created_path = node->node_revision->created_path;
-  else
-    svn_temp_deserializer__resolve(node, (void**)&node->created_path);
-
-  /* return result */
-  *out = node;
-
-  return SVN_NO_ERROR;
-}
 
 svn_error_t *
 svn_fs_x__dag_open(dag_node_t **child_p,
@@ -1192,7 +936,7 @@ svn_fs_x__dag_open(dag_node_t **child_p,
   svn_fs_x__id_t node_id;
 
   /* Ensure that NAME exists in PARENT's entry list. */
-  SVN_ERR(dir_entry_id_from_node(&node_id, parent, name, scratch_pool));
+  SVN_ERR(svn_fs_x__dir_entry_id(&node_id, parent, name, scratch_pool));
   if (! svn_fs_x__id_used(&node_id))
     {
       *child_p = NULL;
@@ -1219,13 +963,12 @@ svn_fs_x__dag_copy(dag_node_t *to_node,
 
   if (preserve_history)
     {
-      svn_fs_x__noderev_t *from_noderev, *to_noderev;
+      svn_fs_x__noderev_t *to_noderev;
       svn_fs_x__id_t copy_id;
       svn_fs_t *fs = svn_fs_x__dag_get_fs(from_node);
 
       /* Make a copy of the original node revision. */
-      SVN_ERR(get_node_revision(&from_noderev, from_node));
-      to_noderev = copy_node_revision(from_noderev, scratch_pool);
+      to_noderev = copy_node_revision(from_node->node_revision, scratch_pool);
 
       /* Reserve a copy ID for this new copy. */
       SVN_ERR(svn_fs_x__reserve_copy_id(&copy_id, fs, txn_id, scratch_pool));
@@ -1253,7 +996,8 @@ svn_fs_x__dag_copy(dag_node_t *to_node,
     }
 
   /* Set the entry in to_node to the new id. */
-  return svn_fs_x__dag_set_entry(to_node, entry, id, from_node->kind,
+  return svn_fs_x__dag_set_entry(to_node, entry, id,
+                                 from_node->node_revision->kind,
                                  txn_id, scratch_pool);
 }
 
@@ -1269,7 +1013,8 @@ svn_fs_x__dag_things_different(svn_boole
                                svn_boolean_t strict,
                                apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *noderev1, *noderev2;
+  svn_fs_x__noderev_t *noderev1 = node1->node_revision;
+  svn_fs_x__noderev_t *noderev2 = node2->node_revision;
   svn_fs_t *fs;
   svn_boolean_t same;
 
@@ -1280,10 +1025,6 @@ svn_fs_x__dag_things_different(svn_boole
 
   fs = svn_fs_x__dag_get_fs(node1);
 
-  /* The node revision skels for these two nodes. */
-  SVN_ERR(get_node_revision(&noderev1, node1));
-  SVN_ERR(get_node_revision(&noderev2, node2));
-
   /* Compare property keys. */
   if (props_changed != NULL)
     {
@@ -1300,48 +1041,25 @@ svn_fs_x__dag_things_different(svn_boole
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
+void
 svn_fs_x__dag_get_copyroot(svn_revnum_t *rev,
                            const char **path,
                            dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  /* Go get a fresh node-revision for NODE. */
-  SVN_ERR(get_node_revision(&noderev, node));
-
-  *rev = noderev->copyroot_rev;
-  *path = noderev->copyroot_path;
-
-  return SVN_NO_ERROR;
+  *rev = node->node_revision->copyroot_rev;
+  *path = node->node_revision->copyroot_path;
 }
 
-svn_error_t *
-svn_fs_x__dag_get_copyfrom_rev(svn_revnum_t *rev,
-                               dag_node_t *node)
+svn_revnum_t
+svn_fs_x__dag_get_copyfrom_rev(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  /* Go get a fresh node-revision for NODE. */
-  SVN_ERR(get_node_revision(&noderev, node));
-
-  *rev = noderev->copyfrom_rev;
-
-  return SVN_NO_ERROR;
+  return node->node_revision->copyfrom_rev;
 }
 
-svn_error_t *
-svn_fs_x__dag_get_copyfrom_path(const char **path,
-                                dag_node_t *node)
+const char *
+svn_fs_x__dag_get_copyfrom_path(dag_node_t *node)
 {
-  svn_fs_x__noderev_t *noderev;
-
-  /* Go get a fresh node-revision for NODE. */
-  SVN_ERR(get_node_revision(&noderev, node));
-
-  *path = noderev->copyfrom_path;
-
-  return SVN_NO_ERROR;
+  return node->node_revision->copyfrom_path;
 }
 
 svn_error_t *
@@ -1349,20 +1067,17 @@ svn_fs_x__dag_update_ancestry(dag_node_t
                               dag_node_t *source,
                               apr_pool_t *scratch_pool)
 {
-  svn_fs_x__noderev_t *source_noderev, *target_noderev;
+  svn_fs_x__noderev_t *source_noderev = source->node_revision;
+  svn_fs_x__noderev_t *target_noderev = target->node_revision;
 
   if (! svn_fs_x__dag_check_mutable(target))
     return svn_error_createf
       (SVN_ERR_FS_NOT_MUTABLE, NULL,
        _("Attempted to update ancestry of non-mutable node"));
 
-  SVN_ERR(get_node_revision(&source_noderev, source));
-  SVN_ERR(get_node_revision(&target_noderev, target));
-
   target_noderev->predecessor_id = source_noderev->noderev_id;
   target_noderev->predecessor_count = source_noderev->predecessor_count;
   target_noderev->predecessor_count++;
 
-  return svn_fs_x__put_node_revision(target->fs, target_noderev,
-                                     scratch_pool);
+  return noderev_changed(target, scratch_pool);
 }

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/dag.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/dag.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/dag.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/dag.h Mon Nov 30 10:24:16 2015
@@ -1,4 +1,4 @@
-/* dag.h : DAG-like interface filesystem, private to libsvn_fs
+/* dag.h : DAG-like interface filesystem
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS_DAG_H
-#define SVN_LIBSVN_FS_DAG_H
+#ifndef SVN_LIBSVN_FS_X_DAG_H
+#define SVN_LIBSVN_FS_X_DAG_H
 
 #include "svn_fs.h"
 #include "svn_delta.h"
@@ -82,28 +82,6 @@ dag_node_t *
 svn_fs_x__dag_dup(const dag_node_t *node,
                   apr_pool_t *result_pool);
 
-/* If NODE has been allocated in POOL, return NODE.  Otherwise, return
-   a copy created in RESULT_POOL with svn_fs_fs__dag_dup. */
-dag_node_t *
-svn_fs_x__dag_copy_into_pool(dag_node_t *node,
-                             apr_pool_t *result_pool);
-
-/* Serialize a DAG node, except don't try to preserve the 'fs' member.
-   Implements svn_cache__serialize_func_t */
-svn_error_t *
-svn_fs_x__dag_serialize(void **data,
-                        apr_size_t *data_len,
-                        void *in,
-                        apr_pool_t *pool);
-
-/* Deserialize a DAG node, leaving the 'fs' member as NULL.
-   Implements svn_cache__deserialize_func_t */
-svn_error_t *
-svn_fs_x__dag_deserialize(void **out,
-                          void *data,
-                          apr_size_t data_len,
-                          apr_pool_t *pool);
-
 /* Return the filesystem containing NODE.  */
 svn_fs_t *
 svn_fs_x__dag_get_fs(dag_node_t *node);
@@ -128,27 +106,23 @@ svn_fs_x__dag_get_id(const dag_node_t *n
 
 /* Return the node ID of NODE.  The value returned is shared with NODE,
    and will be deallocated when NODE is.  */
-svn_error_t *
-svn_fs_x__dag_get_node_id(svn_fs_x__id_t *node_id,
-                          dag_node_t *node);
+const svn_fs_x__id_t *
+svn_fs_x__dag_get_node_id(dag_node_t *node);
 
 /* Return the copy ID of NODE.  The value returned is shared with NODE,
    and will be deallocated when NODE is.  */
-svn_error_t *
-svn_fs_x__dag_get_copy_id(svn_fs_x__id_t *copy_id,
-                          dag_node_t *node);
+const svn_fs_x__id_t *
+svn_fs_x__dag_get_copy_id(dag_node_t *node);
 
-/* Set *SAME to TRUE, if nodes LHS and RHS have the same node ID. */
-svn_error_t *
-svn_fs_x__dag_related_node(svn_boolean_t *same,
-                           dag_node_t *lhs,
+/* Return TRUE, iff nodes LHS and RHS have the same node ID. */
+svn_boolean_t
+svn_fs_x__dag_related_node(dag_node_t *lhs,
                            dag_node_t *rhs);
 
-/* Set *SAME to TRUE, if nodes LHS and RHS have the same node and copy IDs.
+/* Return TRUE, iff nodes LHS and RHS have the same node and copy IDs.
  */
-svn_error_t *
-svn_fs_x__dag_same_line_of_history(svn_boolean_t *same,
-                                   dag_node_t *lhs,
+svn_boolean_t
+svn_fs_x__dag_same_line_of_history(dag_node_t *lhs,
                                    dag_node_t *rhs);
 
 /* Return the created path of NODE.  The value returned is shared
@@ -157,41 +131,31 @@ const char *
 svn_fs_x__dag_get_created_path(dag_node_t *node);
 
 
-/* Set *ID_P to the node revision ID of NODE's immediate predecessor.
+/* Return the node revision ID of NODE's immediate predecessor.
  */
-svn_error_t *
-svn_fs_x__dag_get_predecessor_id(svn_fs_x__id_t *id_p,
-                                 dag_node_t *node);
-
+const svn_fs_x__id_t *
+svn_fs_x__dag_get_predecessor_id(dag_node_t *node);
 
-/* Set *COUNT to the number of predecessors NODE has (recursively).
+/* Return the number of predecessors NODE has (recursively).
  */
-/* ### This function is currently only used by 'verify'. */
-svn_error_t *
-svn_fs_x__dag_get_predecessor_count(int *count,
-                                    dag_node_t *node);
+int
+svn_fs_x__dag_get_predecessor_count(dag_node_t *node);
 
-/* Set *COUNT to the number of node under NODE (inclusive) with
-   svn:mergeinfo properties.
+/* Return the number of node under NODE (inclusive) with svn:mergeinfo
+   properties.
  */
-svn_error_t *
-svn_fs_x__dag_get_mergeinfo_count(apr_int64_t *count,
-                                  dag_node_t *node);
+apr_int64_t
+svn_fs_x__dag_get_mergeinfo_count(dag_node_t *node);
 
-/* Set *DO_THEY to a flag indicating whether or not NODE is a
-   directory with at least one descendant (not including itself) with
-   svn:mergeinfo.
+/* Return TRUE, iff NODE is a directory with at least one descendant (not
+   including itself) with svn:mergeinfo.
  */
-svn_error_t *
-svn_fs_x__dag_has_descendants_with_mergeinfo(svn_boolean_t *do_they,
-                                             dag_node_t *node);
+svn_boolean_t
+svn_fs_x__dag_has_descendants_with_mergeinfo(dag_node_t *node);
 
-/* Set *HAS_MERGEINFO to a flag indicating whether or not NODE itself
-   has svn:mergeinfo set on it.
- */
-svn_error_t *
-svn_fs_x__dag_has_mergeinfo(svn_boolean_t *has_mergeinfo,
-                            dag_node_t *node);
+/* Return TRUE, iff NODE itself has svn:mergeinfo set on it.  */
+svn_boolean_t
+svn_fs_x__dag_has_mergeinfo(dag_node_t *node);
 
 /* Return non-zero IFF NODE is currently mutable. */
 svn_boolean_t
@@ -252,25 +216,15 @@ svn_fs_x__dag_set_has_mergeinfo(dag_node
 /* Revision and transaction roots.  */
 
 
-/* Open the root of revision REV of filesystem FS, allocating from
+/* Open the root of change set CHANGE_SET of filesystem FS, allocating from
    RESULT_POOL.  Set *NODE_P to the new node.  Use SCRATCH_POOL for
    temporary allocations.*/
 svn_error_t *
-svn_fs_x__dag_revision_root(dag_node_t **node_p,
-                            svn_fs_t *fs,
-                            svn_revnum_t rev,
-                            apr_pool_t *result_pool,
-                            apr_pool_t *scratch_pool);
-
-
-/* Set *NODE_P to the root of transaction TXN_ID in FS, allocating
-   from RESULT_POOL.  Use SCRATCH_POOL for temporary allocations. */
-svn_error_t *
-svn_fs_x__dag_txn_root(dag_node_t **node_p,
-                       svn_fs_t *fs,
-                       svn_fs_x__txn_id_t txn_id,
-                       apr_pool_t *result_pool,
-                       apr_pool_t *scratch_pool);
+svn_fs_x__dag_root(dag_node_t **node_p,
+                   svn_fs_t *fs,
+                   svn_fs_x__change_set_t change_set,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool);
 
 
 /* Directories.  */
@@ -289,6 +243,14 @@ svn_fs_x__dag_open(dag_node_t **child_p,
                    apr_pool_t *scratch_pool);
 
 
+/* Set *ID_P to the noderev-id for entry NAME in PARENT.  If no such
+   entry exists, set *ID_P to "unused" but do not error. */
+svn_error_t *
+svn_fs_x__dir_entry_id(svn_fs_x__id_t *id_p,
+                       dag_node_t *parent,
+                       const char *name,
+                       apr_pool_t *scratch_pool);
+
 /* Set *ENTRIES_P to an array of NODE's entries, sorted by entry names,
    and the values are svn_fs_x__dirent_t. The returned table (and elements)
    is allocated in RESULT_POOL, temporaries in SCRATCH_POOL. */
@@ -548,22 +510,20 @@ svn_fs_x__dag_things_different(svn_boole
 /* Set *REV and *PATH to the copyroot revision and path of node NODE, or
    to SVN_INVALID_REVNUM and NULL if no copyroot exists.
  */
-svn_error_t *
+void
 svn_fs_x__dag_get_copyroot(svn_revnum_t *rev,
                            const char **path,
                            dag_node_t *node);
 
-/* Set *REV to the copyfrom revision associated with NODE.
+/* Return the copyfrom revision associated with NODE.
  */
-svn_error_t *
-svn_fs_x__dag_get_copyfrom_rev(svn_revnum_t *rev,
-                               dag_node_t *node);
+svn_revnum_t
+svn_fs_x__dag_get_copyfrom_rev(dag_node_t *node);
 
-/* Set *PATH to the copyfrom path associated with NODE.
+/* Return the copyfrom path associated with NODE.
  */
-svn_error_t *
-svn_fs_x__dag_get_copyfrom_path(const char **path,
-                                dag_node_t *node);
+const char *
+svn_fs_x__dag_get_copyfrom_path(dag_node_t *node);
 
 /* Update *TARGET so that SOURCE is it's predecessor.
 
@@ -577,4 +537,4 @@ svn_fs_x__dag_update_ancestry(dag_node_t
 }
 #endif /* __cplusplus */
 
-#endif /* SVN_LIBSVN_FS_DAG_H */
+#endif /* SVN_LIBSVN_FS_X_DAG_H */

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs.c Mon Nov 30 10:24:16 2015
@@ -27,12 +27,12 @@
 #include <apr_general.h>
 #include <apr_pools.h>
 #include <apr_file_io.h>
-#include <apr_thread_mutex.h>
 
 #include "svn_fs.h"
 #include "svn_delta.h"
 #include "svn_version.h"
 #include "svn_pools.h"
+#include "batch_fsync.h"
 #include "fs.h"
 #include "fs_x.h"
 #include "pack.h"
@@ -137,6 +137,18 @@ x_serialized_init(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_x__initialize_shared_data(svn_fs_t *fs,
+                                 svn_mutex__t *common_pool_lock,
+                                 apr_pool_t *scratch_pool,
+                                 apr_pool_t *common_pool)
+{
+  SVN_MUTEX__WITH_LOCK(common_pool_lock,
+                       x_serialized_init(fs, common_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 
 /* This function is provided for Subversion 1.0.x compatibility.  It
@@ -165,9 +177,11 @@ x_freeze_body(void *baton,
 
   SVN_ERR(svn_fs_x__exists_rep_cache(&exists, b->fs, scratch_pool));
   if (exists)
-    SVN_ERR(svn_fs_x__lock_rep_cache(b->fs, scratch_pool));
-
-  SVN_ERR(b->freeze_func(b->freeze_baton, scratch_pool));
+    SVN_ERR(svn_fs_x__with_rep_cache_lock(b->fs,
+                                          b->freeze_func, b->freeze_baton,
+                                          scratch_pool));
+  else
+    SVN_ERR(b->freeze_func(b->freeze_baton, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -216,20 +230,11 @@ x_info(const void **fsx_info,
   return SVN_NO_ERROR;
 }
 
-/* Wrapper around svn_fs_x__revision_prop() adapting between function
-   signatures. */
 static svn_error_t *
-x_revision_prop(svn_string_t **value_p,
-                svn_fs_t *fs,
-                svn_revnum_t rev,
-                const char *propname,
-                apr_pool_t *pool)
+x_refresh_revprops(svn_fs_t *fs,
+                   apr_pool_t *scratch_pool)
 {
-  apr_pool_t *scratch_pool = svn_pool_create(pool);
-  SVN_ERR(svn_fs_x__revision_prop(value_p, fs, rev, propname, pool,
-                                  scratch_pool));
-  svn_pool_destroy(scratch_pool);
-
+  svn_fs_x__invalidate_revprop_generation(fs);
   return SVN_NO_ERROR;
 }
 
@@ -239,14 +244,14 @@ static svn_error_t *
 x_revision_proplist(apr_hash_t **proplist_p,
                     svn_fs_t *fs,
                     svn_revnum_t rev,
-                    apr_pool_t *pool)
+                    svn_boolean_t refresh,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
 {
-  apr_pool_t *scratch_pool = svn_pool_create(pool);
-
   /* No need to bypass the caches for r/o access to revprops. */
   SVN_ERR(svn_fs_x__get_revision_proplist(proplist_p, fs, rev, FALSE,
-                                          pool, scratch_pool));
-  svn_pool_destroy(scratch_pool);
+                                          refresh, result_pool,
+                                          scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -260,7 +265,8 @@ x_set_uuid(svn_fs_t *fs,
 {
   /* Whenever we set a new UUID, imply that FS will also be a different
    * instance (on formats that support this). */
-  return svn_error_trace(svn_fs_x__set_uuid(fs, uuid, NULL, scratch_pool));
+  return svn_error_trace(svn_fs_x__set_uuid(fs, uuid, NULL, TRUE,
+                                            scratch_pool));
 }
 
 /* Wrapper around svn_fs_x__begin_txn() providing the scratch pool. */
@@ -283,7 +289,8 @@ x_begin_txn(svn_fs_txn_t **txn_p,
 /* The vtable associated with a specific open filesystem. */
 static fs_vtable_t fs_vtable = {
   svn_fs_x__youngest_rev,
-  x_revision_prop,
+  x_refresh_revprops,
+  svn_fs_x__revision_prop,
   x_revision_proplist,
   svn_fs_x__change_rev_prop,
   x_set_uuid,
@@ -314,6 +321,8 @@ static svn_error_t *
 initialize_fs_struct(svn_fs_t *fs)
 {
   svn_fs_x__data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
+  ffd->revprop_generation = -1;
+
   fs->vtable = &fs_vtable;
   fs->fsap_data = ffd;
   return SVN_NO_ERROR;
@@ -534,24 +543,17 @@ x_hotcopy(svn_fs_t *src_fs,
   if (cancel_func)
     SVN_ERR(cancel_func(cancel_baton));
 
-  /* Test target repo when in INCREMENTAL mode, initialize it when not.
-   * For this, we need our FS internal data structures to be temporarily
-   * available. */
+  SVN_ERR(svn_fs__check_fs(dst_fs, FALSE));
   SVN_ERR(initialize_fs_struct(dst_fs));
-  SVN_ERR(svn_fs_x__hotcopy_prepare_target(src_fs, dst_fs, dst_path,
-                                           incremental, scratch_pool));
-  uninitialize_fs_struct(dst_fs);
 
-  /* Now, the destination repo should open just fine. */
-  SVN_ERR(x_open(dst_fs, dst_path, common_pool_lock, scratch_pool,
-                 common_pool));
-  if (cancel_func)
-    SVN_ERR(cancel_func(cancel_baton));
-
-  /* Now, we may copy data as needed ... */
-  return svn_fs_x__hotcopy(src_fs, dst_fs, incremental,
-                           notify_func, notify_baton,
-                           cancel_func, cancel_baton, scratch_pool);
+  /* In INCREMENTAL mode, svn_fs_x__hotcopy() will open DST_FS.
+     Otherwise, it's not an FS yet --- possibly just an empty dir --- so
+     can't be opened.
+   */
+  return svn_fs_x__hotcopy(src_fs, dst_fs, src_path, dst_path,
+                            incremental, notify_func, notify_baton,
+                            cancel_func, cancel_baton, common_pool_lock,
+                            scratch_pool, common_pool);
 }
 
 
@@ -662,6 +664,8 @@ svn_fs_x__init(const svn_version_t *load
                              loader_version->major);
   SVN_ERR(svn_ver_check_list2(x_version(), checklist, svn_ver_equal));
 
+  SVN_ERR(svn_fs_x__batch_fsync_init());
+
   *vtable = &library_vtable;
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/fs.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs.h Mon Nov 30 10:24:16 2015
@@ -1,4 +1,4 @@
-/* fs.h : interface to Subversion filesystem, private to libsvn_fs
+/* fs.h : interface to Subversion filesystem
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS_X_H
-#define SVN_LIBSVN_FS_X_H
+#ifndef SVN_LIBSVN_FS_X_FS_H
+#define SVN_LIBSVN_FS_X_FS_H
 
 #include <apr_pools.h>
 #include <apr_hash.h>
@@ -53,12 +53,11 @@ extern "C" {
 #define PATH_FORMAT           "format"           /* Contains format number */
 #define PATH_UUID             "uuid"             /* Contains UUID */
 #define PATH_CURRENT          "current"          /* Youngest revision */
+#define PATH_NEXT             "next"             /* Revision begin written. */
 #define PATH_LOCK_FILE        "write-lock"       /* Revision lock file */
 #define PATH_PACK_LOCK_FILE   "pack-lock"        /* Pack lock file */
 #define PATH_REVS_DIR         "revs"             /* Directory of revisions */
-#define PATH_REVPROPS_DIR     "revprops"         /* Directory of revprops */
 #define PATH_TXNS_DIR         "transactions"     /* Directory of transactions */
-#define PATH_NODE_ORIGINS_DIR "node-origins"     /* Lazy node-origin cache */
 #define PATH_TXN_PROTOS_DIR   "txn-protorevs"    /* Directory of proto-revs */
 #define PATH_TXN_CURRENT      "txn-current"      /* File with next txn key */
 #define PATH_TXN_CURRENT_LOCK "txn-current-lock" /* Lock for txn-current */
@@ -81,8 +80,6 @@ extern "C" {
 /* Names of special files and file extensions for transactions */
 #define PATH_CHANGES       "changes"       /* Records changes made so far */
 #define PATH_TXN_PROPS     "props"         /* Transaction properties */
-#define PATH_TXN_PROPS_FINAL "props-final" /* Final transaction properties
-                                              before moving to revprops */
 #define PATH_NEXT_IDS      "next-ids"      /* Next temporary ID assignments */
 #define PATH_PREFIX_NODE   "node."         /* Prefix for node filename */
 #define PATH_EXT_TXN       ".txn"          /* Extension of txn dir */
@@ -124,7 +121,11 @@ extern "C" {
    Note: If you bump this, please update the switch statement in
          svn_fs_x__create() as well.
  */
-#define SVN_FS_X__FORMAT_NUMBER   1
+#define SVN_FS_X__FORMAT_NUMBER   2
+
+/* Latest experimental format number.  Experimental formats are only
+   compatible with themselves. */
+#define SVN_FS_X__EXPERIMENTAL_FORMAT_NUMBER   2
 
 /* On most operating systems apr implements file locks per process, not
    per file.  On Windows apr implements the locking as per file handle
@@ -179,11 +180,15 @@ typedef struct svn_fs_x__shared_data_t
      declaration here.  Any subset may be acquired and held at any given
      time but their relative acquisition order must not change.
 
-     (lock 'txn-current' before 'pack' before 'write' before 'txn-list') */
+     (lock 'pack' before 'write' before 'txn-current' before 'txn-list') */
 
   /* A lock for intra-process synchronization when accessing the TXNS list. */
   svn_mutex__t *txn_list_lock;
 
+  /* A lock for intra-process synchronization when locking the
+     txn-current file. */
+  svn_mutex__t *txn_current_lock;
+
   /* A lock for intra-process synchronization when grabbing the
      repository write lock. */
   svn_mutex__t *fs_write_lock;
@@ -192,10 +197,6 @@ typedef struct svn_fs_x__shared_data_t
      repository pack operation lock. */
   svn_mutex__t *fs_pack_lock;
 
-  /* A lock for intra-process synchronization when locking the
-     txn-current file. */
-  svn_mutex__t *txn_current_lock;
-
   /* The common pool, under which this object is allocated, subpools
      of which are used to allocate the transaction objects. */
   apr_pool_t *common_pool;
@@ -281,13 +282,9 @@ typedef struct svn_fs_x__data_t
      e.g. memcached may be ignored as caching is an optional feature. */
   svn_boolean_t fail_stop;
 
-  /* Caches native dag_node_t* instances and acts as a 1st level cache */
+  /* Caches native dag_node_t* instances */
   svn_fs_x__dag_cache_t *dag_node_cache;
 
-  /* DAG node cache for immutable nodes.  Maps (revision, fspath)
-     to (dag_node_t *). This is the 2nd level cache for DAG nodes. */
-  svn_cache__t *rev_node_cache;
-
   /* A cache of the contents of immutable directories; maps from
      unparsed FS ID to a apr_hash_t * mapping (const char *) dirent
      names to (svn_fs_x__dirent_t *). */
@@ -297,9 +294,8 @@ typedef struct svn_fs_x__data_t
      rep key (revision/offset) to svn_stringbuf_t. */
   svn_cache__t *fulltext_cache;
 
-  /* Access object to the revprop "generation". Will be NULL until
-     the first access.  May be also get closed and set to NULL again. */
-  apr_file_t *revprop_generation_file;
+  /* Revprop generation number.  Will be -1 if it has to reread from disk. */
+  apr_int64_t revprop_generation;
 
   /* Revision property cache.  Maps from (rev,generation) to apr_hash_t. */
   svn_cache__t *revprop_cache;
@@ -307,12 +303,6 @@ typedef struct svn_fs_x__data_t
   /* Node properties cache.  Maps from rep key to apr_hash_t. */
   svn_cache__t *properties_cache;
 
-  /* Pack manifest cache; a cache mapping (svn_revnum_t) shard number to
-     a manifest; and a manifest is a mapping from (svn_revnum_t) revision
-     number offset within a shard to (apr_off_t) byte-offset in the
-     respective pack file. */
-  svn_cache__t *packed_offset_cache;
-
   /* Cache for txdelta_window_t objects;
    * the key is svn_fs_x__window_cache_key_t */
   svn_cache__t *txdelta_window_cache;
@@ -345,15 +335,6 @@ typedef struct svn_fs_x__data_t
      (revision, item index) pair */
   svn_cache__t *rep_header_cache;
 
-  /* Cache for svn_mergeinfo_t objects; the key is a combination of
-     revision, inheritance flags and path. */
-  svn_cache__t *mergeinfo_cache;
-
-  /* Cache for presence of svn_mergeinfo_t on a noderev; the key is a
-     combination of revision, inheritance flags and path; value is "1"
-     if the node has mergeinfo, "0" if it doesn't. */
-  svn_cache__t *mergeinfo_existence_cache;
-
   /* Cache for l2p_header_t objects; the key is (revision, is-packed).
      Will be NULL for pre-format7 repos */
   svn_cache__t *l2p_header_cache;
@@ -420,6 +401,7 @@ typedef struct svn_fs_x__data_t
   /* Pointer to svn_fs_open. */
   svn_error_t *(*svn_fs_open_)(svn_fs_t **, const char *, apr_hash_t *,
                                apr_pool_t *, apr_pool_t *);
+
 } svn_fs_x__data_t;
 
 
@@ -566,9 +548,21 @@ typedef struct svn_fs_x__change_t
   svn_tristate_t mergeinfo_mod;
 } svn_fs_x__change_t;
 
+
+/*** Directory (only used at the cache interface) ***/
+typedef struct svn_fs_x__dir_data_t
+{
+  /* Contents, i.e. all directory entries, sorted by name. */
+  apr_array_header_t *entries;
+
+  /* SVN_INVALID_FILESIZE for committed data, otherwise the length of the
+   * in-txn on-disk representation of that directory. */
+  svn_filesize_t txn_filesize;
+} svn_fs_x__dir_data_t;
+
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
-#endif /* SVN_LIBSVN_FS_X_H */
+#endif /* SVN_LIBSVN_FS_X_FS_H */

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs_id.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs_id.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/fs_id.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs_id.c Mon Nov 30 10:24:16 2015
@@ -85,6 +85,13 @@ struct svn_fs_x__id_context_t
      is not.*/
   const char *fs_path;
 
+  /* If FS is NULL, this points to svn_fs_open() as passed to the library. */
+  svn_error_t *(*svn_fs_open_)(svn_fs_t **,
+      const char *,
+      apr_hash_t *,
+      apr_pool_t *,
+      apr_pool_t *);
+
   /* Pool that this context struct got allocated in. */
   apr_pool_t *owner;
 
@@ -118,11 +125,14 @@ static apr_status_t
 fs_cleanup(void *baton)
 {
   svn_fs_x__id_context_t *context = baton;
+  svn_fs_x__data_t *ffd = context->fs->fsap_data;
 
   /* Remember the FS_PATH to potentially reopen and mark the FS as n/a. */
   context->fs_path = apr_pstrdup(context->owner, context->fs->path);
+  context->svn_fs_open_ = ffd->svn_fs_open_;
   context->fs = NULL;
 
+
   /* No need for further notifications because from now on, everything is
      allocated in OWNER. */
   apr_pool_cleanup_kill(context->owner, context, owner_cleanup);
@@ -137,8 +147,12 @@ get_fs(svn_fs_x__id_context_t *context)
 {
   if (!context->fs)
     {
-      svn_error_t *err = svn_fs_open2(&context->fs, context->fs_path, NULL,
-                                      context->owner, context->owner);
+      svn_error_t *err;
+
+      SVN_ERR_ASSERT_NO_RETURN(context->svn_fs_open_);
+
+      err = context->svn_fs_open_(&context->fs, context->fs_path, NULL,
+                                  context->owner, context->owner);
       if (err)
         {
           svn_error_clear(err);
@@ -217,13 +231,7 @@ id_compare(const svn_fs_id_t *a,
 
   /* Quick check: same IDs? */
   if (svn_fs_x__id_eq(&id_a->noderev_id, &id_b->noderev_id))
-    return svn_fs_node_same;
-
-  /* Items from different txns are unrelated. */
-  if (   svn_fs_x__is_txn(id_a->noderev_id.change_set)
-      && svn_fs_x__is_txn(id_b->noderev_id.change_set)
-      && id_a->noderev_id.change_set != id_b->noderev_id.change_set)
-    return svn_fs_node_unrelated;
+    return svn_fs_node_unchanged;
 
   /* Fetch the nodesrevs, compare the IDs of the nodes they belong to and
      clean up any temporaries.  If we can't find one of the noderevs, don't

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.c Mon Nov 30 10:24:16 2015
@@ -95,13 +95,27 @@ check_format(int format)
 {
   /* Put blacklisted versions here. */
 
-  /* We support all formats from 1-current simultaneously */
-  if (1 <= format && format <= SVN_FS_X__FORMAT_NUMBER)
+  /* We support any format if it matches the current format. */
+  if (format == SVN_FS_X__FORMAT_NUMBER)
+    return SVN_NO_ERROR;
+
+  /* Experimental formats are only supported if they match the current, but
+   * that case has already been handled. So, reject any experimental format.
+   */
+  if (SVN_FS_X__EXPERIMENTAL_FORMAT_NUMBER >= format)
+    return svn_error_createf(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL,
+      _("Unsupported experimental FSX format '%d' found; current format is '%d'"),
+      format, SVN_FS_X__FORMAT_NUMBER);
+
+  /* By default, we will support any non-experimental format released so far.
+   */
+  if (format <= SVN_FS_X__FORMAT_NUMBER)
     return SVN_NO_ERROR;
 
   return svn_error_createf(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL,
-     _("Expected FS format between '1' and '%d'; found format '%d'"),
-     SVN_FS_X__FORMAT_NUMBER, format);
+     _("Expected FSX format between '%d' and '%d'; found format '%d'"),
+     SVN_FS_X__EXPERIMENTAL_FORMAT_NUMBER + 1, SVN_FS_X__FORMAT_NUMBER,
+     format);
 }
 
 /* Read the format file at PATH and set *PFORMAT to the format version found
@@ -184,8 +198,9 @@ svn_fs_x__write_format(svn_fs_t *fs,
     }
   else
     {
-      SVN_ERR(svn_io_write_atomic(path, sb->data, sb->len,
-                                  NULL /* copy_perms_path */, scratch_pool));
+      SVN_ERR(svn_io_write_atomic2(path, sb->data, sb->len,
+                                   NULL /* copy_perms_path */,
+                                   TRUE, scratch_pool));
     }
 
   /* And set the perms to make it read only */
@@ -587,8 +602,9 @@ svn_fs_x__open(svn_fs_t *fs,
   /* Read the configuration file. */
   SVN_ERR(read_config(ffd, fs->path, fs->pool, scratch_pool));
 
-  return svn_error_trace(svn_fs_x__read_current(&ffd->youngest_rev_cache,
-                                                fs, scratch_pool));
+  ffd->youngest_rev_cache = 0;
+
+  return SVN_NO_ERROR;
 }
 
 /* Baton type bridging svn_fs_x__upgrade and upgrade_body carrying
@@ -840,16 +856,16 @@ static svn_error_t *
 write_revision_zero(svn_fs_t *fs,
                     apr_pool_t *scratch_pool)
 {
-  /* Use an explicit sub-pool to have full control over temp file lifetimes.
-   * Since we have it, use it for everything else as well. */
-  apr_pool_t *subpool = svn_pool_create(scratch_pool);
-  const char *path_revision_zero = svn_fs_x__path_rev(fs, 0, subpool);
+  const char *path_revision_zero = svn_fs_x__path_rev(fs, 0, scratch_pool);
   apr_hash_t *proplist;
   svn_string_t date;
+  svn_stream_t *stream;
+  svn_stringbuf_t *revprops;
 
   apr_array_header_t *index_entries;
   svn_fs_x__p2l_entry_t *entry;
   svn_fs_x__revision_file_t *rev_file;
+  apr_file_t *apr_file;
   const char *l2p_proto_index, *p2l_proto_index;
 
   /* Construct a skeleton r0 with no indexes. */
@@ -860,62 +876,73 @@ write_revision_zero(svn_fs_t *fs,
                                                 "count: 0\n"
                                                 "cpath: /\n"
                                                 "\n",
-                                                subpool);
+                                                scratch_pool);
   svn_string_t *changes_str = svn_string_create("\n",
-                                                subpool);
-  svn_string_t *r0 = svn_string_createf(subpool, "%s%s",
+                                                scratch_pool);
+  svn_string_t *r0 = svn_string_createf(scratch_pool, "%s%s",
                                         noderev_str->data,
                                         changes_str->data);
 
   /* Write skeleton r0 to disk. */
-  SVN_ERR(svn_io_file_create(path_revision_zero, r0->data, subpool));
+  SVN_ERR(svn_io_file_create(path_revision_zero, r0->data, scratch_pool));
 
   /* Construct the index P2L contents: describe the 2 items we have.
      Be sure to create them in on-disk order. */
-  index_entries = apr_array_make(subpool, 2, sizeof(entry));
+  index_entries = apr_array_make(scratch_pool, 2, sizeof(entry));
 
-  entry = apr_pcalloc(subpool, sizeof(*entry));
+  entry = apr_pcalloc(scratch_pool, sizeof(*entry));
   entry->offset = 0;
   entry->size = (apr_off_t)noderev_str->len;
   entry->type = SVN_FS_X__ITEM_TYPE_NODEREV;
   entry->item_count = 1;
-  entry->items = apr_pcalloc(subpool, sizeof(*entry->items));
+  entry->items = apr_pcalloc(scratch_pool, sizeof(*entry->items));
   entry->items[0].change_set = 0;
   entry->items[0].number = SVN_FS_X__ITEM_INDEX_ROOT_NODE;
   APR_ARRAY_PUSH(index_entries, svn_fs_x__p2l_entry_t *) = entry;
 
-  entry = apr_pcalloc(subpool, sizeof(*entry));
+  entry = apr_pcalloc(scratch_pool, sizeof(*entry));
   entry->offset = (apr_off_t)noderev_str->len;
   entry->size = (apr_off_t)changes_str->len;
   entry->type = SVN_FS_X__ITEM_TYPE_CHANGES;
   entry->item_count = 1;
-  entry->items = apr_pcalloc(subpool, sizeof(*entry->items));
+  entry->items = apr_pcalloc(scratch_pool, sizeof(*entry->items));
   entry->items[0].change_set = 0;
   entry->items[0].number = SVN_FS_X__ITEM_INDEX_CHANGES;
   APR_ARRAY_PUSH(index_entries, svn_fs_x__p2l_entry_t *) = entry;
 
   /* Now re-open r0, create proto-index files from our entries and
-      rewrite the index section of r0. */
-  SVN_ERR(svn_fs_x__open_pack_or_rev_file_writable(&rev_file, fs, 0,
-                                                   subpool, subpool));
+     rewrite the index section of r0. */
+  SVN_ERR(svn_fs_x__rev_file_open_writable(&rev_file, fs, 0,
+                                           scratch_pool, scratch_pool));
   SVN_ERR(svn_fs_x__p2l_index_from_p2l_entries(&p2l_proto_index, fs,
                                                rev_file, index_entries,
-                                               subpool, subpool));
+                                               scratch_pool, scratch_pool));
   SVN_ERR(svn_fs_x__l2p_index_from_p2l_entries(&l2p_proto_index, fs,
                                                index_entries,
-                                               subpool, subpool));
-  SVN_ERR(svn_fs_x__add_index_data(fs, rev_file->file, l2p_proto_index,
-                                   p2l_proto_index, 0, subpool));
+                                               scratch_pool, scratch_pool));
+  SVN_ERR(svn_fs_x__rev_file_get(&apr_file, rev_file));
+  SVN_ERR(svn_fs_x__add_index_data(fs, apr_file, l2p_proto_index,
+                                   p2l_proto_index, 0, scratch_pool));
   SVN_ERR(svn_fs_x__close_revision_file(rev_file));
 
-  SVN_ERR(svn_io_set_file_read_only(path_revision_zero, FALSE, fs->pool));
+  SVN_ERR(svn_io_set_file_read_only(path_revision_zero, FALSE, scratch_pool));
 
   /* Set a date on revision 0. */
-  date.data = svn_time_to_cstring(apr_time_now(), fs->pool);
+  date.data = svn_time_to_cstring(apr_time_now(), scratch_pool);
   date.len = strlen(date.data);
-  proplist = apr_hash_make(fs->pool);
+  proplist = apr_hash_make(scratch_pool);
   svn_hash_sets(proplist, SVN_PROP_REVISION_DATE, &date);
-  return svn_fs_x__set_revision_proplist(fs, 0, proplist, fs->pool);
+
+  revprops = svn_stringbuf_create_empty(scratch_pool);
+  stream = svn_stream_from_stringbuf(revprops, scratch_pool);
+  SVN_ERR(svn_hash_write2(proplist, stream, SVN_HASH_TERMINATOR,
+                          scratch_pool));
+  SVN_ERR(svn_stream_close(stream));
+
+  SVN_ERR(svn_io_file_create(svn_fs_x__path_revprops(fs, 0, scratch_pool),
+                             revprops->data, scratch_pool));
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -935,14 +962,9 @@ svn_fs_x__create_file_tree(svn_fs_t *fs,
 
   /* Create the revision data directories. */
   SVN_ERR(svn_io_make_dir_recursively(
-                              svn_fs_x__path_rev_shard(fs, 0, scratch_pool),
+                              svn_fs_x__path_shard(fs, 0, scratch_pool),
                               scratch_pool));
 
-  /* Create the revprops directory. */
-  SVN_ERR(svn_io_make_dir_recursively(
-                         svn_fs_x__path_revprops_shard(fs, 0, scratch_pool),
-                         scratch_pool));
-
   /* Create the transaction directory. */
   SVN_ERR(svn_io_make_dir_recursively(
                                   svn_fs_x__path_txns_dir(fs, scratch_pool),
@@ -954,14 +976,13 @@ svn_fs_x__create_file_tree(svn_fs_t *fs,
                             scratch_pool));
 
   /* Create the 'current' file. */
-  SVN_ERR(svn_io_file_create_empty(svn_fs_x__path_current(fs, scratch_pool),
-                                   scratch_pool));
-  SVN_ERR(svn_fs_x__write_current(fs, 0, scratch_pool));
+  SVN_ERR(svn_io_file_create(svn_fs_x__path_current(fs, scratch_pool),
+                             "0\n", scratch_pool));
 
   /* Create the 'uuid' file. */
   SVN_ERR(svn_io_file_create_empty(svn_fs_x__path_lock(fs, scratch_pool),
                                    scratch_pool));
-  SVN_ERR(svn_fs_x__set_uuid(fs, NULL, NULL, scratch_pool));
+  SVN_ERR(svn_fs_x__set_uuid(fs, NULL, NULL, FALSE, scratch_pool));
 
   /* Create the fsfs.conf file. */
   SVN_ERR(write_config(fs, scratch_pool));
@@ -984,6 +1005,9 @@ svn_fs_x__create_file_tree(svn_fs_t *fs,
                           scratch_pool));
 
   /* Initialize the revprop caching info. */
+  SVN_ERR(svn_io_file_create_empty(
+                        svn_fs_x__path_revprop_generation(fs, scratch_pool),
+                        scratch_pool));
   SVN_ERR(svn_fs_x__reset_revprop_generation_file(fs, scratch_pool));
 
   ffd->youngest_rev_cache = 0;
@@ -1040,6 +1064,7 @@ svn_error_t *
 svn_fs_x__set_uuid(svn_fs_t *fs,
                    const char *uuid,
                    const char *instance_id,
+                   svn_boolean_t overwrite,
                    apr_pool_t *scratch_pool)
 {
   svn_fs_x__data_t *ffd = fs->fsap_data;
@@ -1058,11 +1083,23 @@ svn_fs_x__set_uuid(svn_fs_t *fs,
   svn_stringbuf_appendcstr(contents, "\n");
 
   /* We use the permissions of the 'current' file, because the 'uuid'
-     file does not exist during repository creation. */
-  SVN_ERR(svn_io_write_atomic(uuid_path, contents->data, contents->len,
-                              /* perms */
-                              svn_fs_x__path_current(fs, scratch_pool),
-                              scratch_pool));
+     file does not exist during repository creation.
+
+     svn_io_write_atomic2() does a load of magic to allow it to
+     replace version files that already exist.  We only need to do
+     that when we're allowed to overwrite an existing file. */
+  if (! overwrite)
+    {
+      /* Create the file */
+      SVN_ERR(svn_io_file_create(uuid_path, contents->data, scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(svn_io_write_atomic2(uuid_path, contents->data, contents->len,
+                                   /* perms */
+                                   svn_fs_x__path_current(fs, scratch_pool),
+                                   TRUE, scratch_pool));
+    }
 
   fs->uuid = apr_pstrdup(fs->pool, uuid);
   ffd->instance_id = apr_pstrdup(fs->pool, instance_id);
@@ -1100,13 +1137,14 @@ svn_fs_x__revision_prop(svn_string_t **v
                         svn_fs_t *fs,
                         svn_revnum_t rev,
                         const char *propname,
+                        svn_boolean_t refresh,
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool)
 {
   apr_hash_t *table;
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
-  SVN_ERR(svn_fs_x__get_revision_proplist(&table, fs, rev, FALSE,
+  SVN_ERR(svn_fs_x__get_revision_proplist(&table, fs, rev, FALSE, refresh,
                                           scratch_pool, scratch_pool));
 
   *value_p = svn_string_dup(svn_hash_gets(table, propname), result_pool);
@@ -1133,17 +1171,18 @@ change_rev_prop_body(void *baton,
 {
   change_rev_prop_baton_t *cb = baton;
   apr_hash_t *table;
+  const svn_string_t *present_value;
 
   /* Read current revprop values from disk (never from cache).
      Even if somehow the cache got out of sync, we want to make sure that
      we read, update and write up-to-date data. */
   SVN_ERR(svn_fs_x__get_revision_proplist(&table, cb->fs, cb->rev, TRUE,
-                                          scratch_pool, scratch_pool));
+                                          TRUE, scratch_pool, scratch_pool));
+  present_value = svn_hash_gets(table, cb->name);
 
   if (cb->old_value_p)
     {
       const svn_string_t *wanted_value = *cb->old_value_p;
-      const svn_string_t *present_value = svn_hash_gets(table, cb->name);
       if ((!wanted_value != !present_value)
           || (wanted_value && present_value
               && !svn_string_compare(wanted_value, present_value)))
@@ -1156,6 +1195,13 @@ change_rev_prop_body(void *baton,
         }
       /* Fall through. */
     }
+
+  /* If the prop-set is a no-op, skip the actual write. */
+  if ((!present_value && !cb->value)
+      || (present_value && cb->value
+          && svn_string_compare(present_value, cb->value)))
+    return SVN_NO_ERROR;
+
   svn_hash_sets(table, cb->name, cb->value);
 
   return svn_fs_x__set_revision_proplist(cb->fs, cb->rev, table,
@@ -1205,8 +1251,11 @@ svn_fs_x__info_format(int *fs_format,
     {
     case 1:
       break;
+    case 2:
+      (*supports_version)->minor = 10;
+      break;
 #ifdef SVN_DEBUG
-# if SVN_FS_X__FORMAT_NUMBER != 1
+# if SVN_FS_X__FORMAT_NUMBER != 2
 #  error "Need to add a 'case' statement here"
 # endif
 #endif

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/fs_x.h Mon Nov 30 10:24:16 2015
@@ -1,4 +1,4 @@
-/* fs_x.h : interface to the native filesystem layer
+/* fs_x.h : interface to the FSX layer
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS__FS_X_H
-#define SVN_LIBSVN_FS__FS_X_H
+#ifndef SVN_LIBSVN_FS_X_FS_X_H
+#define SVN_LIBSVN_FS_X_FS_X_H
 
 #include "fs.h"
 
@@ -41,6 +41,16 @@ svn_fs_x__open(svn_fs_t *fs,
                const char *path,
                apr_pool_t *scratch_pool);
 
+/* Initialize parts of the FS data that are being shared across multiple
+   filesystem objects.  Use COMMON_POOL for process-wide and SCRATCH_POOL
+   for temporary allocations.  Use COMMON_POOL_LOCK to ensure that the
+   initialization is serialized. */
+svn_error_t *
+svn_fs_x__initialize_shared_data(svn_fs_t *fs,
+                                 svn_mutex__t *common_pool_lock,
+                                 apr_pool_t *scratch_pool,
+                                 apr_pool_t *common_pool);
+
 /* Upgrade the fsx filesystem FS.  Indicate progress via the optional
  * NOTIFY_FUNC callback using NOTIFY_BATON.  The optional CANCEL_FUNC
  * will periodically be called with CANCEL_BATON to allow for preemption.
@@ -138,11 +148,16 @@ svn_fs_x__create(svn_fs_t *fs,
 
 /* Set the uuid of repository FS to UUID and the instance ID to INSTANCE_ID.
    If any of them is NULL, use a newly generated UUID / ID instead.
+
+   If OVERWRITE is not set, the uuid file must not exist yet implying this
+   is a fresh repository.
+
    Perform temporary allocations in SCRATCH_POOL. */
 svn_error_t *
 svn_fs_x__set_uuid(svn_fs_t *fs,
                    const char *uuid,
                    const char *instance_id,
+                   svn_boolean_t overwrite,
                    apr_pool_t *scratch_pool);
 
 /* Read the format number and maximum number of files per directory
@@ -160,12 +175,15 @@ svn_fs_x__write_format(svn_fs_t *fs,
 
 /* Find the value of the property named PROPNAME in transaction REV.
    Return the contents in *VALUE_P, allocated from RESULT_POOL.
+   If REFRESH is not set, continue using the potentially outdated
+   revprop generation value in FS->FSAP_DATA.
    Use SCRATCH_POOL for temporary allocations. */
 svn_error_t *
 svn_fs_x__revision_prop(svn_string_t **value_p,
                         svn_fs_t *fs,
                         svn_revnum_t rev,
                         const char *propname,
+                        svn_boolean_t refresh,
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool);