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 [21/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/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.c Mon Nov 30 10:24:16 2015
@@ -1,4 +1,4 @@
-/* low_level.c --- low level r/w access to fs_x file structures
+/* low_level.c --- low level r/w access to FSX file structures
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -56,7 +56,6 @@
 #define ACTION_ADD         "add"
 #define ACTION_DELETE      "delete"
 #define ACTION_REPLACE     "replace"
-#define ACTION_RESET       "reset"
 
 /* True and False flags. */
 #define FLAG_TRUE          "true"
@@ -103,6 +102,19 @@ parse_revnum(svn_revnum_t *rev,
   return SVN_NO_ERROR;
 }
 
+/* If ERR is not NULL, wrap it MESSAGE.  The latter must have an %ld
+ * format parameter that will be filled with REV. */
+static svn_error_t *
+wrap_footer_error(svn_error_t *err,
+                  const char *message,
+                  svn_revnum_t rev)
+{
+  if (err)
+    return svn_error_quick_wrapf(err, message, rev);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_fs_x__parse_footer(apr_off_t *l2p_offset,
                        svn_checksum_t **l2p_checksum,
@@ -110,6 +122,7 @@ svn_fs_x__parse_footer(apr_off_t *l2p_of
                        svn_checksum_t **p2l_checksum,
                        svn_stringbuf_t *footer,
                        svn_revnum_t rev,
+                       apr_off_t footer_offset,
                        apr_pool_t *result_pool)
 {
   apr_int64_t val;
@@ -118,17 +131,20 @@ svn_fs_x__parse_footer(apr_off_t *l2p_of
   /* Get the L2P offset. */
   const char *str = svn_cstring_tokenize(" ", &last_str);
   if (str == NULL)
-    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                            _("Invalid revision footer"));
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Invalid r%ld footer", rev);
 
-  SVN_ERR(svn_cstring_atoi64(&val, str));
+  SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0,
+                                                 footer_offset - 1, 10),
+                            "Invalid L2P offset in r%ld footer",
+                            rev));
   *l2p_offset = (apr_off_t)val;
 
   /* Get the L2P checksum. */
   str = svn_cstring_tokenize(" ", &last_str);
   if (str == NULL)
-    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                            _("Invalid revision footer"));
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Invalid r%ld footer", rev);
 
   SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str,
                                  result_pool));
@@ -136,17 +152,33 @@ svn_fs_x__parse_footer(apr_off_t *l2p_of
   /* Get the P2L offset. */
   str = svn_cstring_tokenize(" ", &last_str);
   if (str == NULL)
-    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                            _("Invalid revision footer"));
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Invalid r%ld footer", rev);
 
-  SVN_ERR(svn_cstring_atoi64(&val, str));
+  SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0,
+                                                 footer_offset - 1, 10),
+                            "Invalid P2L offset in r%ld footer",
+                            rev));
   *p2l_offset = (apr_off_t)val;
 
+  /* The P2L indes follows the L2P index */
+  if (*p2l_offset <= *l2p_offset)
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "P2L offset %s must be larger than L2P offset %s"
+                             " in r%ld footer",
+                             apr_psprintf(result_pool,
+                                          "%" APR_UINT64_T_HEX_FMT,
+                                          (apr_uint64_t)*p2l_offset),
+                             apr_psprintf(result_pool,
+                                          "%" APR_UINT64_T_HEX_FMT,
+                                          (apr_uint64_t)*l2p_offset),
+                             rev);
+
   /* Get the P2L checksum. */
   str = svn_cstring_tokenize(" ", &last_str);
   if (str == NULL)
-    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                            _("Invalid revision footer"));
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Invalid r%ld footer", rev);
 
   SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str,
                                  result_pool));
@@ -845,10 +877,6 @@ read_change(svn_fs_x__change_t **change_
     {
       change->change_kind = svn_fs_path_change_replace;
     }
-  else if (strcmp(str, ACTION_RESET) == 0)
-    {
-      change->change_kind = svn_fs_path_change_reset;
-    }
   else
     {
       return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -1036,9 +1064,6 @@ write_change_entry(svn_stream_t *stream,
     case svn_fs_path_change_replace:
       change_string = ACTION_REPLACE;
       break;
-    case svn_fs_path_change_reset:
-      change_string = ACTION_RESET;
-      break;
     default:
       return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                _("Invalid change type %d"),

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/low_level.h Mon Nov 30 10:24:16 2015
@@ -1,4 +1,4 @@
-/* low_level.c --- low level r/w access to fs_x file structures
+/* low_level.c --- low level r/w access to FSX file structures
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS__LOW_LEVEL_H
-#define SVN_LIBSVN_FS__LOW_LEVEL_H
+#ifndef SVN_LIBSVN_FS_X_LOW_LEVEL_H
+#define SVN_LIBSVN_FS_X_LOW_LEVEL_H
 
 #include "svn_fs.h"
 
@@ -50,6 +50,8 @@ extern "C" {
  * *P2L_OFFSET, respectively.  Also, return the expected checksums in
  * in *L2P_CHECKSUM and *P2L_CHECKSUM.
  *
+ * FOOTER_OFFSET is used for validation.
+ *
  * Note that REV is only used to construct nicer error objects that
  * mention this revision.  Allocate the checksums in RESULT_POOL.
  */
@@ -60,6 +62,7 @@ svn_fs_x__parse_footer(apr_off_t *l2p_of
                        svn_checksum_t **p2l_checksum,
                        svn_stringbuf_t *footer,
                        svn_revnum_t rev,
+                       apr_off_t footer_offset,
                        apr_pool_t *result_pool);
 
 /* Given the offset of the L2P index data in L2P_OFFSET, the content
@@ -211,4 +214,4 @@ svn_fs_x__write_changes(svn_stream_t *st
 }
 #endif /* __cplusplus */
 
-#endif /* SVN_LIBSVN_FS__LOW_LEVEL_H */
+#endif /* SVN_LIBSVN_FS_X_LOW_LEVEL_H */

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/noderevs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/noderevs.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/noderevs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/noderevs.c Mon Nov 30 10:24:16 2015
@@ -361,7 +361,7 @@ svn_error_t *
 svn_fs_x__noderevs_get(svn_fs_x__noderev_t **noderev_p,
                        const svn_fs_x__noderevs_t *container,
                        apr_size_t idx,
-                       apr_pool_t *pool)
+                       apr_pool_t *result_pool)
 {
   svn_fs_x__noderev_t *noderev;
   binary_noderev_t *binary_noderev;
@@ -373,14 +373,14 @@ svn_fs_x__noderevs_get(svn_fs_x__noderev
   /* validate index */
   if (idx >= (apr_size_t)container->noderevs->nelts)
     return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL,
-                             apr_psprintf(pool,
+                             apr_psprintf(result_pool,
                                           _("Node revision index %%%s"
                                             " exceeds container size %%d"),
                                           APR_SIZE_T_FMT),
                              idx, container->noderevs->nelts);
 
   /* allocate result struct and fill it field by field */
-  noderev = apr_pcalloc(pool, sizeof(*noderev));
+  noderev = apr_pcalloc(result_pool, sizeof(*noderev));
   binary_noderev = &APR_ARRAY_IDX(container->noderevs, idx, binary_noderev_t);
 
   noderev->kind = (svn_node_kind_t)(binary_noderev->flags & NODEREV_KIND_MASK);
@@ -398,7 +398,7 @@ svn_fs_x__noderevs_get(svn_fs_x__noderev
         = svn_fs_x__string_table_get(container->paths,
                                      binary_noderev->copyfrom_path,
                                      NULL,
-                                     pool);
+                                     result_pool);
       noderev->copyfrom_rev = binary_noderev->copyfrom_rev;
     }
   else
@@ -413,7 +413,7 @@ svn_fs_x__noderevs_get(svn_fs_x__noderev
         = svn_fs_x__string_table_get(container->paths,
                                      binary_noderev->copyroot_path,
                                      NULL,
-                                     pool);
+                                     result_pool);
       noderev->copyroot_rev = binary_noderev->copyroot_rev;
     }
   else
@@ -425,16 +425,16 @@ svn_fs_x__noderevs_get(svn_fs_x__noderev
   noderev->predecessor_count = binary_noderev->predecessor_count;
 
   SVN_ERR(get_representation(&noderev->prop_rep, container->reps,
-                             binary_noderev->prop_rep, pool));
+                             binary_noderev->prop_rep, result_pool));
   SVN_ERR(get_representation(&noderev->data_rep, container->reps,
-                             binary_noderev->data_rep, pool));
+                             binary_noderev->data_rep, result_pool));
 
   if (binary_noderev->flags & NODEREV_HAS_CPATH)
     noderev->created_path
       = svn_fs_x__string_table_get(container->paths,
                                    binary_noderev->created_path,
                                    NULL,
-                                   pool);
+                                   result_pool);
 
   noderev->mergeinfo_count = binary_noderev->mergeinfo_count;
 
@@ -578,15 +578,15 @@ svn_fs_x__write_noderevs_container(svn_s
   return SVN_NO_ERROR;
 }
 
-/* Allocate a svn_fs_x__representation_t array in POOL and return it in
- * REPS_P.  Deserialize the data in REP_STREAM and DIGEST_STREAM and store
+/* Allocate a svn_fs_x__representation_t array in RESULT_POOL and return it
+ * in REPS_P.  Deserialize the data in REP_STREAM and DIGEST_STREAM and store
  * the resulting representations into the *REPS_P.
  */
 static svn_error_t *
 read_reps(apr_array_header_t **reps_p,
           svn_packed__int_stream_t *rep_stream,
           svn_packed__byte_stream_t *digest_stream,
-          apr_pool_t *pool)
+          apr_pool_t *result_pool)
 {
   apr_size_t i;
   apr_size_t len;
@@ -595,7 +595,8 @@ read_reps(apr_array_header_t **reps_p,
   apr_size_t count
     = svn_packed__int_count(svn_packed__first_int_substream(rep_stream));
   apr_array_header_t *reps
-    = apr_array_make(pool, (int)count, sizeof(svn_fs_x__representation_t));
+    = apr_array_make(result_pool, (int)count,
+                     sizeof(svn_fs_x__representation_t));
 
   for (i = 0; i < count; ++i)
     {
@@ -613,7 +614,7 @@ read_reps(apr_array_header_t **reps_p,
       bytes = svn_packed__get_bytes(digest_stream, &len);
       if (len != sizeof(rep.md5_digest))
         return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL,
-                                 apr_psprintf(pool,
+                                 apr_psprintf(result_pool,
                                               _("Unexpected MD5"
                                                 " digest size %%%s"),
                                               APR_SIZE_T_FMT),
@@ -625,7 +626,7 @@ read_reps(apr_array_header_t **reps_p,
           bytes = svn_packed__get_bytes(digest_stream, &len);
           if (len != sizeof(rep.sha1_digest))
             return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL,
-                                     apr_psprintf(pool,
+                                     apr_psprintf(result_pool,
                                                   _("Unexpected SHA1"
                                                     " digest size %%%s"),
                                                   APR_SIZE_T_FMT),
@@ -766,15 +767,15 @@ svn_error_t *
 svn_fs_x__deserialize_noderevs_container(void **out,
                                          void *data,
                                          apr_size_t data_len,
-                                         apr_pool_t *pool)
+                                         apr_pool_t *result_pool)
 {
   svn_fs_x__noderevs_t *noderevs = (svn_fs_x__noderevs_t *)data;
 
   /* de-serialize sub-structures */
   svn_fs_x__deserialize_string_table(noderevs, &noderevs->paths);
-  svn_fs_x__deserialize_apr_array(noderevs, &noderevs->ids, pool);
-  svn_fs_x__deserialize_apr_array(noderevs, &noderevs->reps, pool);
-  svn_fs_x__deserialize_apr_array(noderevs, &noderevs->noderevs, pool);
+  svn_fs_x__deserialize_apr_array(noderevs, &noderevs->ids, result_pool);
+  svn_fs_x__deserialize_apr_array(noderevs, &noderevs->reps, result_pool);
+  svn_fs_x__deserialize_apr_array(noderevs, &noderevs->noderevs, result_pool);
 
   /* done */
   *out = noderevs;

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/noderevs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/noderevs.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/noderevs.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/noderevs.h Mon Nov 30 10:24:16 2015
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS__NODEREVS_H
-#define SVN_LIBSVN_FS__NODEREVS_H
+#ifndef SVN_LIBSVN_FS_X_NODEREVS_H
+#define SVN_LIBSVN_FS_X_NODEREVS_H
 
 #include "svn_io.h"
 #include "fs.h"
@@ -76,7 +76,7 @@ svn_error_t *
 svn_fs_x__noderevs_get(svn_fs_x__noderev_t **noderev_p,
                        const svn_fs_x__noderevs_t *container,
                        apr_size_t idx,
-                       apr_pool_t *pool);
+                       apr_pool_t *result_pool);
 
 /* I/O interface. */
 
@@ -114,7 +114,7 @@ svn_error_t *
 svn_fs_x__deserialize_noderevs_container(void **out,
                                           void *data,
                                           apr_size_t data_len,
-                                          apr_pool_t *pool);
+                                          apr_pool_t *result_pool);
 
 /* Implements svn_cache__partial_getter_func_t for svn_fs_x__noderevs_t,
  * setting *OUT to the svn_fs_x__noderev_t selected by the apr_uint32_t index

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/pack.c Mon Nov 30 10:24:16 2015
@@ -106,9 +106,6 @@ typedef struct path_order_t
   /* when this change happened */
   svn_revnum_t revision;
 
-  /* this is a directory node */
-  svn_boolean_t is_dir;
-
   /* length of the expanded representation content */
   apr_int64_t expanded_size;
 
@@ -247,6 +244,7 @@ initialize_pack_context(pack_context_t *
                         const char *shard_dir,
                         svn_revnum_t shard_rev,
                         int max_items,
+                        svn_fs_x__batch_fsync_t *batch,
                         svn_cancel_func_t cancel_func,
                         void *cancel_baton,
                         apr_pool_t *pool)
@@ -275,9 +273,9 @@ initialize_pack_context(pack_context_t *
   context->pack_file_dir = pack_file_dir;
   context->pack_file_path
     = svn_dirent_join(pack_file_dir, PATH_PACKED, pool);
-  SVN_ERR(svn_io_file_open(&context->pack_file, context->pack_file_path,
-                           APR_WRITE | APR_BUFFERED | APR_BINARY | APR_EXCL
-                             | APR_CREATE, APR_OS_DEFAULT, pool));
+
+  SVN_ERR(svn_fs_x__batch_fsync_open_file(&context->pack_file, batch,
+                                          context->pack_file_path, pool));
 
   /* Proto index files */
   SVN_ERR(svn_fs_x__l2p_proto_index_open(
@@ -382,8 +380,6 @@ close_pack_context(pack_context_t *conte
   SVN_ERR(svn_io_remove_file2(proto_l2p_index_path, FALSE, scratch_pool));
   SVN_ERR(svn_io_remove_file2(proto_p2l_index_path, FALSE, scratch_pool));
 
-  SVN_ERR(svn_io_file_close(context->pack_file, scratch_pool));
-
   return SVN_NO_ERROR;
 }
 
@@ -478,6 +474,7 @@ copy_item_to_temp(pack_context_t *contex
                   svn_fs_x__p2l_entry_t *entry,
                   apr_pool_t *scratch_pool)
 {
+  apr_file_t *file;
   svn_fs_x__p2l_entry_t *new_entry
     = svn_fs_x__p2l_entry_dup(entry, context->info_pool);
 
@@ -485,7 +482,8 @@ copy_item_to_temp(pack_context_t *contex
                                     scratch_pool));
   APR_ARRAY_PUSH(entries, svn_fs_x__p2l_entry_t *) = new_entry;
 
-  SVN_ERR(copy_file_data(context, temp_file, rev_file->file, entry->size,
+  SVN_ERR(svn_fs_x__rev_file_get(&file, rev_file));
+  SVN_ERR(copy_file_data(context, temp_file, file, entry->size,
                          scratch_pool));
 
   return SVN_NO_ERROR;
@@ -567,6 +565,8 @@ copy_rep_to_temp(pack_context_t *context
                  apr_pool_t *scratch_pool)
 {
   svn_fs_x__rep_header_t *rep_header;
+  svn_stream_t *stream;
+  apr_file_t *file;
   apr_off_t source_offset = entry->offset;
 
   /* create a copy of ENTRY, make it point to the copy destination and
@@ -577,7 +577,8 @@ copy_rep_to_temp(pack_context_t *context
   add_item_rep_mapping(context, entry);
 
   /* read & parse the representation header */
-  SVN_ERR(svn_fs_x__read_rep_header(&rep_header, rev_file->stream,
+  SVN_ERR(svn_fs_x__rev_file_stream(&stream, rev_file));
+  SVN_ERR(svn_fs_x__read_rep_header(&rep_header, stream,
                                     scratch_pool, scratch_pool));
 
   /* if the representation is a delta against some other rep, link the two */
@@ -594,10 +595,10 @@ copy_rep_to_temp(pack_context_t *context
     }
 
   /* copy the whole rep (including header!) to our temp file */
-  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &source_offset,
-                           scratch_pool));
-  SVN_ERR(copy_file_data(context, context->reps_file, rev_file->file,
-                         entry->size, scratch_pool));
+  SVN_ERR(svn_fs_x__rev_file_seek(rev_file, NULL, source_offset));
+  SVN_ERR(svn_fs_x__rev_file_get(&file, rev_file));
+  SVN_ERR(copy_file_data(context, context->reps_file, file, entry->size,
+                         scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -616,22 +617,20 @@ compare_dir_entries(const svn_sort__item
   const svn_fs_dirent_t *lhs = (const svn_fs_dirent_t *) a->value;
   const svn_fs_dirent_t *rhs = (const svn_fs_dirent_t *) b->value;
 
-  if (lhs->kind != rhs->kind)
-    return lhs->kind == svn_node_dir ? -1 : 1;
-
   return strcmp(lhs->name, rhs->name);
 }
 
 apr_array_header_t *
 svn_fs_x__order_dir_entries(svn_fs_t *fs,
                             apr_hash_t *directory,
-                            apr_pool_t *pool)
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
 {
   apr_array_header_t *ordered
-    = svn_sort__hash(directory, compare_dir_entries, pool);
+    = svn_sort__hash(directory, compare_dir_entries, scratch_pool);
 
   apr_array_header_t *result
-    = apr_array_make(pool, ordered->nelts, sizeof(svn_fs_dirent_t *));
+    = apr_array_make(result_pool, ordered->nelts, sizeof(svn_fs_dirent_t *));
 
   int i;
   for (i = 0; i < ordered->nelts; ++i)
@@ -686,25 +685,28 @@ copy_node_to_temp(pack_context_t *contex
   path_order_t *path_order = apr_pcalloc(context->info_pool,
                                          sizeof(*path_order));
   svn_fs_x__noderev_t *noderev;
+  svn_stream_t *stream;
+  apr_file_t *file;
   const char *sort_path;
   apr_off_t source_offset = entry->offset;
 
   /* read & parse noderev */
-  SVN_ERR(svn_fs_x__read_noderev(&noderev, rev_file->stream, scratch_pool,
+  SVN_ERR(svn_fs_x__rev_file_stream(&stream, rev_file));
+  SVN_ERR(svn_fs_x__read_noderev(&noderev, stream, scratch_pool,
                                  scratch_pool));
 
   /* create a copy of ENTRY, make it point to the copy destination and
    * store it in CONTEXT */
   entry = svn_fs_x__p2l_entry_dup(entry, context->info_pool);
   SVN_ERR(svn_fs_x__get_file_offset(&entry->offset, context->reps_file,
-                                     scratch_pool));
+                                    scratch_pool));
   add_item_rep_mapping(context, entry);
 
   /* copy the noderev to our temp file */
-  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &source_offset,
-                           scratch_pool));
-  SVN_ERR(copy_file_data(context, context->reps_file, rev_file->file,
-                         entry->size, scratch_pool));
+  SVN_ERR(svn_fs_x__rev_file_seek(rev_file, NULL, source_offset));
+  SVN_ERR(svn_fs_x__rev_file_get(&file, rev_file));
+  SVN_ERR(copy_file_data(context, context->reps_file, file, entry->size,
+                         scratch_pool));
 
   /* if the node has a data representation, make that the node's "base".
    * This will (often) cause the noderev to be placed right in front of
@@ -731,7 +733,6 @@ copy_node_to_temp(pack_context_t *contex
   path_order->path = svn_prefix_string__create(context->paths, sort_path);
   path_order->node_id = noderev->node_id;
   path_order->revision = svn_fs_x__get_revnum(noderev->noderev_id.change_set);
-  path_order->is_dir = noderev->kind == svn_node_dir;
   path_order->noderev_id = noderev->noderev_id;
   APR_ARRAY_PUSH(context->path_order, path_order_t *) = path_order;
 
@@ -775,13 +776,8 @@ compare_path_order(const path_order_t *
   const path_order_t * lhs = *lhs_p;
   const path_order_t * rhs = *rhs_p;
 
-  /* cluster all directories */
-  int diff = rhs->is_dir - lhs->is_dir;
-  if (diff)
-    return diff;
-
   /* lexicographic order on path and node (i.e. latest first) */
-  diff = svn_prefix_string__compare(lhs->path, rhs->path);
+  int diff = svn_prefix_string__compare(lhs->path, rhs->path);
   if (diff)
     return diff;
 
@@ -1233,7 +1229,7 @@ write_reps_containers(pack_context_t *co
     = apr_array_make(scratch_pool, 64, sizeof(svn_fs_x__id_t));
   svn_fs_x__revision_file_t *file;
 
-  SVN_ERR(svn_fs_x__wrap_temp_rev_file(&file, context->fs, temp_file,
+  SVN_ERR(svn_fs_x__rev_file_wrap_temp(&file, context->fs, temp_file,
                                        scratch_pool));
 
   /* copy all items in strict order */
@@ -1722,18 +1718,19 @@ pack_range(pack_context_t *context,
     {
       apr_off_t offset = 0;
       svn_fs_x__revision_file_t *rev_file;
+      svn_fs_x__index_info_t l2p_index_info;
 
       /* Get the rev file dimensions (mainly index locations). */
-      SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, context->fs,
-                                              revision, revpool, iterpool));
-      SVN_ERR(svn_fs_x__auto_read_footer(rev_file));
+      SVN_ERR(svn_fs_x__rev_file_init(&rev_file, context->fs, revision,
+                                      revpool));
+      SVN_ERR(svn_fs_x__rev_file_l2p_info(&l2p_index_info, rev_file));
 
       /* store the indirect array index */
       APR_ARRAY_PUSH(context->rev_offsets, int) = context->reps->nelts;
 
       /* read the phys-to-log index file until we covered the whole rev file.
        * That index contains enough info to build both target indexes from it. */
-      while (offset < rev_file->l2p_offset)
+      while (offset < l2p_index_info.start)
         {
           /* read one cluster */
           int i;
@@ -1757,10 +1754,9 @@ pack_range(pack_context_t *context,
 
               /* process entry while inside the rev file */
               offset = entry->offset;
-              if (offset < rev_file->l2p_offset)
+              if (offset < l2p_index_info.start)
                 {
-                  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset,
-                                           iterpool));
+                  SVN_ERR(svn_fs_x__rev_file_seek(rev_file, NULL, offset));
 
                   if (entry->type == SVN_FS_X__ITEM_TYPE_CHANGES)
                     SVN_ERR(copy_item_to_temp(context,
@@ -1842,6 +1838,7 @@ append_revision(pack_context_t *context,
   apr_off_t offset = 0;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   svn_fs_x__revision_file_t *rev_file;
+  apr_file_t *file;
   apr_finfo_t finfo;
 
   /* Get the size of the file. */
@@ -1852,11 +1849,11 @@ append_revision(pack_context_t *context,
   SVN_ERR(svn_io_stat(&finfo, path, APR_FINFO_SIZE, scratch_pool));
 
   /* Copy all the bits from the rev file to the end of the pack file. */
-  SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, context->fs,
-                                          context->start_rev, scratch_pool,
-                                          iterpool));
-  SVN_ERR(copy_file_data(context, context->pack_file, rev_file->file,
-                         finfo.size, iterpool));
+  SVN_ERR(svn_fs_x__rev_file_init(&rev_file, context->fs, context->start_rev,
+                                  scratch_pool));
+  SVN_ERR(svn_fs_x__rev_file_get(&file, rev_file));
+  SVN_ERR(copy_file_data(context, context->pack_file, file, finfo.size,
+                         iterpool));
 
   /* mark the start of a new revision */
   SVN_ERR(svn_fs_x__l2p_proto_index_add_revision(context->proto_l2p_index,
@@ -1916,6 +1913,7 @@ append_revision(pack_context_t *context,
  * SHARD_DIR into the PACK_FILE_DIR, using SCRATCH_POOL for temporary
  * allocations.  Limit the extra memory consumption to MAX_MEM bytes.
  * CANCEL_FUNC and CANCEL_BATON are what you think they are.
+ * Schedule necessary fsync calls in BATCH.
  */
 static svn_error_t *
 pack_log_addressed(svn_fs_t *fs,
@@ -1923,6 +1921,7 @@ pack_log_addressed(svn_fs_t *fs,
                    const char *shard_dir,
                    svn_revnum_t shard_rev,
                    apr_size_t max_mem,
+                   svn_fs_x__batch_fsync_t *batch,
                    svn_cancel_func_t cancel_func,
                    void *cancel_baton,
                    apr_pool_t *scratch_pool)
@@ -1949,7 +1948,7 @@ pack_log_addressed(svn_fs_t *fs,
 
   /* set up a pack context */
   SVN_ERR(initialize_pack_context(&context, fs, pack_file_dir, shard_dir,
-                                  shard_rev, max_items, cancel_func,
+                                  shard_rev, max_items, batch, cancel_func,
                                   cancel_baton, scratch_pool));
 
   /* phase 1: determine the size of the revisions to pack */
@@ -2002,77 +2001,11 @@ pack_log_addressed(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
-/* Given REV in FS, set *REV_OFFSET to REV's offset in the packed file.
-   Use SCRATCH_POOL for temporary allocations. */
-svn_error_t *
-svn_fs_x__get_packed_offset(apr_off_t *rev_offset,
-                            svn_fs_t *fs,
-                            svn_revnum_t rev,
-                            apr_pool_t *scratch_pool)
-{
-  svn_fs_x__data_t *ffd = fs->fsap_data;
-  svn_stream_t *manifest_stream;
-  svn_boolean_t is_cached;
-  svn_revnum_t shard;
-  apr_int64_t shard_pos;
-  apr_array_header_t *manifest;
-  apr_pool_t *iterpool;
-
-  shard = rev / ffd->max_files_per_dir;
-
-  /* position of the shard within the manifest */
-  shard_pos = rev % ffd->max_files_per_dir;
-
-  /* fetch exactly that element into *rev_offset, if the manifest is found
-     in the cache */
-  SVN_ERR(svn_cache__get_partial((void **) rev_offset, &is_cached,
-                                 ffd->packed_offset_cache, &shard,
-                                 svn_fs_x__get_sharded_offset, &shard_pos,
-                                 scratch_pool));
-
-  if (is_cached)
-      return SVN_NO_ERROR;
-
-  /* Open the manifest file. */
-  SVN_ERR(svn_stream_open_readonly(&manifest_stream,
-                    svn_fs_x__path_rev_packed(fs, rev, PATH_MANIFEST,
-                                              scratch_pool),
-                    scratch_pool, scratch_pool));
-
-  /* While we're here, let's just read the entire manifest file into an array,
-     so we can cache the entire thing. */
-  iterpool = svn_pool_create(scratch_pool);
-  manifest = apr_array_make(scratch_pool, ffd->max_files_per_dir,
-                            sizeof(apr_off_t));
-  while (1)
-    {
-      svn_boolean_t eof;
-      apr_int64_t val;
-
-      svn_pool_clear(iterpool);
-      SVN_ERR(svn_fs_x__read_number_from_stream(&val, &eof, manifest_stream,
-                                                iterpool));
-      if (eof)
-        break;
-
-      APR_ARRAY_PUSH(manifest, apr_off_t) = (apr_off_t)val;
-    }
-  svn_pool_destroy(iterpool);
-
-  *rev_offset = APR_ARRAY_IDX(manifest, rev % ffd->max_files_per_dir,
-                              apr_off_t);
-
-  /* Close up shop and cache the array. */
-  SVN_ERR(svn_stream_close(manifest_stream));
-  return svn_cache__set(ffd->packed_offset_cache, &shard, manifest,
-                        scratch_pool);
-}
-
 /* In filesystem FS, pack the revision SHARD containing exactly
  * MAX_FILES_PER_DIR revisions from SHARD_PATH into the PACK_FILE_DIR,
  * using SCRATCH_POOL for temporary allocations.  Try to limit the amount of
  * temporary memory needed to MAX_MEM bytes.  CANCEL_FUNC and CANCEL_BATON
- * are what you think they are.
+ * are what you think they are.  Schedule necessary fsync calls in BATCH.
  *
  * If for some reason we detect a partial packing already performed, we
  * remove the pack file and start again.
@@ -2086,6 +2019,7 @@ pack_rev_shard(svn_fs_t *fs,
                apr_int64_t shard,
                int max_files_per_dir,
                apr_size_t max_mem,
+               svn_fs_x__batch_fsync_t *batch,
                svn_cancel_func_t cancel_func,
                void *cancel_baton,
                apr_pool_t *scratch_pool)
@@ -2102,10 +2036,11 @@ pack_rev_shard(svn_fs_t *fs,
 
   /* Create the new directory and pack file. */
   SVN_ERR(svn_io_dir_make(pack_file_dir, APR_OS_DEFAULT, scratch_pool));
+  SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, pack_file_dir, scratch_pool));
 
   /* Index information files */
   SVN_ERR(pack_log_addressed(fs, pack_file_dir, shard_path, shard_rev,
-                              max_mem, cancel_func, cancel_baton,
+                             max_mem, batch, cancel_func, cancel_baton,
                              scratch_pool));
 
   SVN_ERR(svn_io_copy_perms(shard_path, pack_file_dir, scratch_pool));
@@ -2114,11 +2049,9 @@ pack_rev_shard(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
-/* In the file system at FS_PATH, pack the SHARD in REVS_DIR and
- * REVPROPS_DIR containing exactly MAX_FILES_PER_DIR revisions, using
- * SCRATCH_POOL temporary for allocations.  REVPROPS_DIR will be NULL if
- * revprop packing is not supported.  COMPRESSION_LEVEL and MAX_PACK_SIZE
- * will be ignored in that case.
+/* In the file system at FS_PATH, pack the SHARD in DIR containing exactly
+ * MAX_FILES_PER_DIR revisions, using SCRATCH_POOL temporary for allocations.
+ * COMPRESSION_LEVEL and MAX_PACK_SIZE will be ignored in that case.
  *
  * CANCEL_FUNC and CANCEL_BATON are what you think they are; similarly
  * NOTIFY_FUNC and NOTIFY_BATON.
@@ -2127,8 +2060,7 @@ pack_rev_shard(svn_fs_t *fs,
  * remove the pack file and start again.
  */
 static svn_error_t *
-pack_shard(const char *revs_dir,
-           const char *revsprops_dir,
+pack_shard(const char *dir,
            svn_fs_t *fs,
            apr_int64_t shard,
            int max_files_per_dir,
@@ -2141,49 +2073,41 @@ pack_shard(const char *revs_dir,
            apr_pool_t *scratch_pool)
 {
   svn_fs_x__data_t *ffd = fs->fsap_data;
-  const char *rev_shard_path, *rev_pack_file_dir;
-  const char *revprops_shard_path, *revprops_pack_file_dir;
+  const char *shard_path, *pack_file_dir;
+  svn_fs_x__batch_fsync_t *batch;
 
   /* Notify caller we're starting to pack this shard. */
   if (notify_func)
     SVN_ERR(notify_func(notify_baton, shard, svn_fs_pack_notify_start,
                         scratch_pool));
 
+  /* Perform all fsyncs through this instance. */
+  SVN_ERR(svn_fs_x__batch_fsync_create(&batch, scratch_pool));
+
   /* Some useful paths. */
-  rev_pack_file_dir = svn_dirent_join(revs_dir,
+  pack_file_dir = svn_dirent_join(dir,
                   apr_psprintf(scratch_pool,
                                "%" APR_INT64_T_FMT PATH_EXT_PACKED_SHARD,
                                shard),
                   scratch_pool);
-  rev_shard_path = svn_dirent_join(revs_dir,
+  shard_path = svn_dirent_join(dir,
                       apr_psprintf(scratch_pool, "%" APR_INT64_T_FMT, shard),
                       scratch_pool);
 
   /* pack the revision content */
-  SVN_ERR(pack_rev_shard(fs, rev_pack_file_dir, rev_shard_path,
-                         shard, max_files_per_dir, DEFAULT_MAX_MEM,
+  SVN_ERR(pack_rev_shard(fs, pack_file_dir, shard_path,
+                         shard, max_files_per_dir, DEFAULT_MAX_MEM, batch,
                          cancel_func, cancel_baton, scratch_pool));
 
-  /* if enabled, pack the revprops in an equivalent way */
-  if (revsprops_dir)
-    {
-      revprops_pack_file_dir = svn_dirent_join(revsprops_dir,
-                   apr_psprintf(scratch_pool,
-                                "%" APR_INT64_T_FMT PATH_EXT_PACKED_SHARD,
-                                shard),
-                   scratch_pool);
-      revprops_shard_path = svn_dirent_join(revsprops_dir,
-                   apr_psprintf(scratch_pool, "%" APR_INT64_T_FMT, shard),
-                   scratch_pool);
-
-      SVN_ERR(svn_fs_x__pack_revprops_shard(revprops_pack_file_dir,
-                                            revprops_shard_path,
-                                            shard, max_files_per_dir,
-                                            (int)(0.9 * max_pack_size),
-                                            compression_level,
-                                            cancel_func, cancel_baton,
-                                            scratch_pool));
-    }
+  /* pack the revprops in an equivalent way */
+  SVN_ERR(svn_fs_x__pack_revprops_shard(fs,
+                                        pack_file_dir,
+                                        shard_path,
+                                        shard, max_files_per_dir,
+                                        (int)(0.9 * max_pack_size),
+                                        compression_level, batch,
+                                        cancel_func, cancel_baton,
+                                        scratch_pool));
 
   /* Update the min-unpacked-rev file to reflect our newly packed shard. */
   SVN_ERR(svn_fs_x__write_min_unpacked_rev(fs,
@@ -2191,35 +2115,12 @@ pack_shard(const char *revs_dir,
                           scratch_pool));
   ffd->min_unpacked_rev = (svn_revnum_t)((shard + 1) * max_files_per_dir);
 
-  /* Finally, remove the existing shard directories.
-   * For revprops, clean up older obsolete shards as well as they might
-   * have been left over from an interrupted FS upgrade. */
-  SVN_ERR(svn_io_remove_dir2(rev_shard_path, TRUE,
+  /* Ensure that packed file is written to disk.*/
+  SVN_ERR(svn_fs_x__batch_fsync_run(batch, scratch_pool));
+
+  /* Finally, remove the existing shard directories. */
+  SVN_ERR(svn_io_remove_dir2(shard_path, TRUE,
                              cancel_func, cancel_baton, scratch_pool));
-  if (revsprops_dir)
-    {
-      svn_node_kind_t kind = svn_node_dir;
-      apr_int64_t to_cleanup = shard;
-      do
-        {
-          SVN_ERR(svn_fs_x__delete_revprops_shard(revprops_shard_path,
-                                                  to_cleanup,
-                                                  max_files_per_dir,
-                                                  cancel_func, cancel_baton,
-                                                  scratch_pool));
-
-          /* If the previous shard exists, clean it up as well.
-             Don't try to clean up shard 0 as it we can't tell quickly
-             whether it actually needs cleaning up. */
-          revprops_shard_path = svn_dirent_join(revsprops_dir,
-                                                apr_psprintf(scratch_pool,
-                                                          "%" APR_INT64_T_FMT,
-                                                          --to_cleanup),
-                                                scratch_pool);
-          SVN_ERR(svn_io_check_path(revprops_shard_path, &kind, scratch_pool));
-        }
-      while (kind == svn_node_dir && to_cleanup > 0);
-    }
 
   /* Notify caller we're starting to pack this shard. */
   if (notify_func)
@@ -2229,6 +2130,34 @@ pack_shard(const char *revs_dir,
   return SVN_NO_ERROR;
 }
 
+/* Read the youngest rev and the first non-packed rev info for FS from disk.
+   Set *FULLY_PACKED when there is no completed unpacked shard.
+   Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+get_pack_status(svn_boolean_t *fully_packed,
+                svn_fs_t *fs,
+                apr_pool_t *scratch_pool)
+{
+  svn_fs_x__data_t *ffd = fs->fsap_data;
+  apr_int64_t completed_shards;
+  svn_revnum_t youngest;
+
+  SVN_ERR(svn_fs_x__read_min_unpacked_rev(&ffd->min_unpacked_rev, fs,
+                                          scratch_pool));
+
+  SVN_ERR(svn_fs_x__youngest_rev(&youngest, fs, scratch_pool));
+  completed_shards = (youngest + 1) / ffd->max_files_per_dir;
+
+  /* See if we've already completed all possible shards thus far. */
+  if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir))
+    *fully_packed = TRUE;
+  else
+    *fully_packed = FALSE;
+
+  return SVN_NO_ERROR;
+}
+
 typedef struct pack_baton_t
 {
   svn_fs_t *fs;
@@ -2261,25 +2190,25 @@ pack_body(void *baton,
   svn_fs_x__data_t *ffd = pb->fs->fsap_data;
   apr_int64_t completed_shards;
   apr_int64_t i;
-  svn_revnum_t youngest;
   apr_pool_t *iterpool;
-  const char *rev_data_path;
-  const char *revprops_data_path = NULL;
+  const char *data_path;
+  svn_boolean_t fully_packed;
 
-  /* If we aren't using sharding, we can't do any packing, so quit. */
-  SVN_ERR(svn_fs_x__read_min_unpacked_rev(&ffd->min_unpacked_rev, pb->fs,
-                                          scratch_pool));
-
-  SVN_ERR(svn_fs_x__youngest_rev(&youngest, pb->fs, scratch_pool));
-  completed_shards = (youngest + 1) / ffd->max_files_per_dir;
+  /* Since another process might have already packed the repo,
+     we need to re-read the pack status. */
+  SVN_ERR(get_pack_status(&fully_packed, pb->fs, scratch_pool));
+  if (fully_packed)
+    {
+      if (pb->notify_func)
+        (*pb->notify_func)(pb->notify_baton,
+                           ffd->min_unpacked_rev / ffd->max_files_per_dir,
+                           svn_fs_pack_notify_noop, scratch_pool);
 
-  /* See if we've already completed all possible shards thus far. */
-  if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir))
-    return SVN_NO_ERROR;
+      return SVN_NO_ERROR;
+    }
 
-  rev_data_path = svn_dirent_join(pb->fs->path, PATH_REVS_DIR, scratch_pool);
-  revprops_data_path = svn_dirent_join(pb->fs->path, PATH_REVPROPS_DIR,
-                                        scratch_pool);
+  completed_shards = (ffd->youngest_rev_cache + 1) / ffd->max_files_per_dir;
+  data_path = svn_dirent_join(pb->fs->path, PATH_REVS_DIR, scratch_pool);
 
   iterpool = svn_pool_create(scratch_pool);
   for (i = ffd->min_unpacked_rev / ffd->max_files_per_dir;
@@ -2291,7 +2220,7 @@ pack_body(void *baton,
       if (pb->cancel_func)
         SVN_ERR(pb->cancel_func(pb->cancel_baton));
 
-      SVN_ERR(pack_shard(rev_data_path, revprops_data_path,
+      SVN_ERR(pack_shard(data_path,
                          pb->fs, i, ffd->max_files_per_dir,
                          ffd->revprop_pack_size,
                          ffd->compress_packed_revprops
@@ -2314,6 +2243,23 @@ svn_fs_x__pack(svn_fs_t *fs,
                apr_pool_t *scratch_pool)
 {
   pack_baton_t pb = { 0 };
+  svn_boolean_t fully_packed;
+
+  /* Is there we even anything to do?. */
+  SVN_ERR(get_pack_status(&fully_packed, fs, scratch_pool));
+  if (fully_packed)
+    {
+      svn_fs_x__data_t *ffd = fs->fsap_data;
+
+      if (notify_func)
+        (*notify_func)(notify_baton,
+                       ffd->min_unpacked_rev / ffd->max_files_per_dir,
+                       svn_fs_pack_notify_noop, scratch_pool);
+
+      return SVN_NO_ERROR;
+    }
+
+  /* Lock the repo and start the pack process. */
   pb.fs = fs;
   pb.notify_func = notify_func;
   pb.notify_baton = notify_baton;

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/pack.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/pack.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/pack.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/pack.h Mon Nov 30 10:24:16 2015
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS__PACK_H
-#define SVN_LIBSVN_FS__PACK_H
+#ifndef SVN_LIBSVN_FS_X_PACK_H
+#define SVN_LIBSVN_FS_X_PACK_H
 
 #include "fs.h"
 
@@ -39,25 +39,16 @@ svn_fs_x__pack(svn_fs_t *fs,
                void *cancel_baton,
                apr_pool_t *scratch_pool);
 
-/**
- * For the packed revision REV in FS,  determine the offset within the
- * revision pack file and return it in REV_OFFSET.
- * Use SCRATCH_POOL for temporary allocations.
- */
-svn_error_t *
-svn_fs_x__get_packed_offset(apr_off_t *rev_offset,
-                            svn_fs_t *fs,
-                            svn_revnum_t rev,
-                            apr_pool_t *scratch_pool);
-
 /* Return the svn_dir_entry_t* objects of DIRECTORY in an APR array
- * allocated in POOL with entries added in storage (on-disk) order.
- * FS format will be used to pick the optimal ordering strategy.
+ * allocated in RESULT_POOL with entries added in storage (on-disk) order.
+ * FS' format will be used to pick the optimal ordering strategy.  Use
+ * SCRATCH_POOL for temporary allocations.
  */
 apr_array_header_t *
 svn_fs_x__order_dir_entries(svn_fs_t *fs,
                             apr_hash_t *directory,
-                            apr_pool_t *pool);
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
 
 
 #endif

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/recovery.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/recovery.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/recovery.c Mon Nov 30 10:24:16 2015
@@ -22,6 +22,7 @@
 
 #include "recovery.h"
 
+#include "svn_dirent_uri.h"
 #include "svn_hash.h"
 #include "svn_pools.h"
 #include "private/svn_string_private.h"
@@ -38,6 +39,22 @@
 
 #include "svn_private_config.h"
 
+/* Set *EXISTS to TRUE, if the revision / pack file for REV exists in FS.
+   Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+revision_file_exists(svn_boolean_t *exists,
+                     svn_fs_t *fs,
+                     svn_revnum_t rev,
+                     apr_pool_t *scratch_pool)
+{
+  svn_node_kind_t kind;
+  const char *path = svn_fs_x__path_rev_absolute(fs, rev, scratch_pool);
+  SVN_ERR(svn_io_check_path(path, &kind, scratch_pool));
+
+  *exists = kind == svn_node_file;
+  return SVN_NO_ERROR;
+}
+
 /* Part of the recovery procedure.  Return the largest revision *REV in
    filesystem FS.  Use SCRATCH_POOL for temporary allocation. */
 static svn_error_t *
@@ -56,19 +73,12 @@ recover_get_largest_revision(svn_fs_t *f
   /* Keep doubling right, until we find a revision that doesn't exist. */
   while (1)
     {
-      svn_error_t *err;
-      svn_fs_x__revision_file_t *file;
+      svn_boolean_t exists;
       svn_pool_clear(iterpool);
 
-      err = svn_fs_x__open_pack_or_rev_file(&file, fs, right, iterpool,
-                                            iterpool);
-      if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
-        {
-          svn_error_clear(err);
-          break;
-        }
-      else
-        SVN_ERR(err);
+      SVN_ERR(revision_file_exists(&exists, fs, right, iterpool));
+      if (!exists)
+        break;
 
       right <<= 1;
     }
@@ -80,22 +90,14 @@ recover_get_largest_revision(svn_fs_t *f
   while (left + 1 < right)
     {
       svn_revnum_t probe = left + ((right - left) / 2);
-      svn_error_t *err;
-      svn_fs_x__revision_file_t *file;
+      svn_boolean_t exists;
       svn_pool_clear(iterpool);
 
-      err = svn_fs_x__open_pack_or_rev_file(&file, fs, probe, iterpool,
-                                            iterpool);
-      if (err && err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
-        {
-          svn_error_clear(err);
-          right = probe;
-        }
+      SVN_ERR(revision_file_exists(&exists, fs, probe, iterpool));
+      if (exists)
+        left = probe;
       else
-        {
-          SVN_ERR(err);
-          left = probe;
-        }
+        right = probe;
     }
 
   svn_pool_destroy(iterpool);
@@ -105,6 +107,86 @@ recover_get_largest_revision(svn_fs_t *f
   return SVN_NO_ERROR;
 }
 
+/* Delete all files and sub-directories (recursively) of DIR_PATH but
+   leave DIR_PATH itself in place.  Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+clear_directory(const char *dir_path,
+                apr_pool_t *scratch_pool)
+{
+  apr_hash_t *dirents;
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  SVN_ERR(svn_io_get_dirents3(&dirents, dir_path, TRUE, scratch_pool,
+                              scratch_pool));
+
+  for (hi = apr_hash_first(scratch_pool, dirents);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *path;
+      const char *name;
+      svn_dirent_t *dirent;
+
+      svn_pool_clear(iterpool);
+      apr_hash_this(hi, (const void **)&name, NULL, (void **)&dirent);
+
+      path = svn_dirent_join(dir_path, name, iterpool);
+      if (dirent->kind == svn_node_dir)
+        SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, iterpool));
+      else
+        SVN_ERR(svn_io_remove_file2(path, TRUE, iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Delete all uncommitted transaction data from FS.
+   Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+discard_transactions(svn_fs_t *fs,
+                     apr_pool_t *scratch_pool)
+{
+  svn_fs_x__data_t *ffd = fs->fsap_data;
+  svn_fs_x__shared_data_t *ffsd = ffd->shared;
+
+  /* In case this FS has been opened more than once in this process,
+     we should purge their shared transaction data as well.  We do the
+     same as abort_txn would, except that we don't expect all txn files
+     to be complete on disk. */
+  while (ffsd->txns)
+    {
+      svn_fs_x__shared_txn_data_t *txn = ffsd->txns;
+      ffsd->txns = txn->next;
+
+      svn_pool_destroy(txn->pool);
+    }
+
+  /* Remove anything from the transaction folders. */
+  SVN_ERR(clear_directory(svn_fs_x__path_txns_dir(fs, scratch_pool),
+                          scratch_pool));
+  SVN_ERR(clear_directory(svn_fs_x__path_txn_proto_revs(fs, scratch_pool),
+                          scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Reset txn-current in FS.  Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+reset_txn_number(svn_fs_t *fs,
+                 apr_pool_t *scratch_pool)
+{
+  const char *initial_txn = "0\n";
+  SVN_ERR(svn_io_write_atomic2(svn_fs_x__path_txn_current(fs, scratch_pool),
+                               initial_txn, strlen(initial_txn),
+                               svn_fs_x__path_uuid(fs, scratch_pool),
+                               FALSE, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Baton used for recover_body below. */
 typedef struct recover_baton_t {
   svn_fs_t *fs;
@@ -133,7 +215,13 @@ recover_body(void *baton,
   /* The admin may have created a plain copy of this repo before attempting
      to recover it (hotcopy may or may not work with corrupted repos).
      Bump the instance ID. */
-  SVN_ERR(svn_fs_x__set_uuid(fs, fs->uuid, NULL, scratch_pool));
+  SVN_ERR(svn_fs_x__set_uuid(fs, fs->uuid, NULL, TRUE, scratch_pool));
+
+  /* Because transactions are not resilient against system crashes,
+     any existing transaction is suspect (and would probably not be
+     reopened anyway).  Get rid of those. */
+  SVN_ERR(discard_transactions(fs, scratch_pool));
+  SVN_ERR(reset_txn_number(fs, scratch_pool));
 
   /* We need to know the largest revision in the filesystem. */
   SVN_ERR(recover_get_largest_revision(fs, &max_rev, scratch_pool));

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/recovery.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/recovery.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/recovery.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/recovery.h Mon Nov 30 10:24:16 2015
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS__RECOVERY_H
-#define SVN_LIBSVN_FS__RECOVERY_H
+#ifndef SVN_LIBSVN_FS_X_RECOVERY_H
+#define SVN_LIBSVN_FS_X_RECOVERY_H
 
 #include "fs.h"
 

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache-db.sql
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache-db.sql?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache-db.sql (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache-db.sql Mon Nov 30 10:24:16 2015
@@ -65,3 +65,6 @@ WHERE revision > ?1
 -- STMT_LOCK_REP
 BEGIN TRANSACTION;
 INSERT INTO rep_cache VALUES ('dummy', 0, 0, 0, 0)
+
+-- STMT_UNLOCK_REP
+ROLLBACK TRANSACTION;

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.c Mon Nov 30 10:24:16 2015
@@ -369,16 +369,48 @@ svn_fs_x__del_rep_reference(svn_fs_t *fs
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_fs_x__lock_rep_cache(svn_fs_t *fs,
-                         apr_pool_t *scratch_pool)
+/* Start a transaction to take an SQLite reserved lock that prevents
+   other writes.
+
+   See unlock_rep_cache(). */
+static svn_error_t *
+lock_rep_cache(svn_fs_t *fs,
+               apr_pool_t *pool)
 {
   svn_fs_x__data_t *ffd = fs->fsap_data;
 
   if (! ffd->rep_cache_db)
-    SVN_ERR(svn_fs_x__open_rep_cache(fs, scratch_pool));
+    SVN_ERR(svn_fs_x__open_rep_cache(fs, pool));
 
   SVN_ERR(svn_sqlite__exec_statements(ffd->rep_cache_db, STMT_LOCK_REP));
 
   return SVN_NO_ERROR;
 }
+
+/* End the transaction started by lock_rep_cache(). */
+static svn_error_t *
+unlock_rep_cache(svn_fs_t *fs,
+                 apr_pool_t *pool)
+{
+  svn_fs_x__data_t *ffd = fs->fsap_data;
+
+  SVN_ERR_ASSERT(ffd->rep_cache_db); /* was opened by lock_rep_cache() */
+
+  SVN_ERR(svn_sqlite__exec_statements(ffd->rep_cache_db, STMT_UNLOCK_REP));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__with_rep_cache_lock(svn_fs_t *fs,
+                              svn_error_t *(*body)(void *,
+                                                   apr_pool_t *),
+                              void *baton,
+                              apr_pool_t *pool)
+{
+  svn_error_t *err;
+
+  SVN_ERR(lock_rep_cache(fs, pool));
+  err = body(baton, pool);
+  return svn_error_compose_create(err, unlock_rep_cache(fs, pool));
+}

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/rep-cache.h Mon Nov 30 10:24:16 2015
@@ -88,12 +88,16 @@ svn_fs_x__del_rep_reference(svn_fs_t *fs
                             svn_revnum_t youngest,
                             apr_pool_t *scratch_pool);
 
+
 /* Start a transaction to take an SQLite reserved lock that prevents
-   other writes. */
+   other writes, call BODY, end the transaction, and return what BODY returned.
+ */
 svn_error_t *
-svn_fs_x__lock_rep_cache(svn_fs_t *fs,
-                         apr_pool_t *scratch_pool);
-
+svn_fs_x__with_rep_cache_lock(svn_fs_t *fs,
+                              svn_error_t *(*body)(void *baton,
+                                                   apr_pool_t *pool),
+                              void *baton,
+                              apr_pool_t *pool);
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/reps.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/reps.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/reps.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/reps.c Mon Nov 30 10:24:16 2015
@@ -417,8 +417,8 @@ svn_fs_x__reps_add_base(svn_fs_x__reps_b
   apr_size_t idx;
   SVN_ERR(svn_fs_x__get_contents(&stream, builder->fs, rep, FALSE,
                                  scratch_pool));
-  SVN_ERR(svn_string_from_stream(&contents, stream, scratch_pool,
-                                 scratch_pool));
+  SVN_ERR(svn_string_from_stream2(&contents, stream, SVN__STREAM_CHUNK_SIZE,
+                                  scratch_pool));
   SVN_ERR(svn_fs_x__reps_add(&idx, builder, contents));
 
   base.revision = svn_fs_x__get_revnum(rep->id.change_set);
@@ -641,16 +641,17 @@ svn_fs_x__reps_get(svn_fs_x__rep_extract
                    svn_fs_t *fs,
                    const svn_fs_x__reps_t *container,
                    apr_size_t idx,
-                   apr_pool_t *pool)
+                   apr_pool_t *result_pool)
 {
   apr_uint32_t first = container->first_instructions[idx];
   apr_uint32_t last = container->first_instructions[idx + 1];
 
   /* create the extractor object */
-  svn_fs_x__rep_extractor_t *result = apr_pcalloc(pool, sizeof(*result));
+  svn_fs_x__rep_extractor_t *result = apr_pcalloc(result_pool,
+                                                  sizeof(*result));
   result->fs = fs;
-  result->result = svn_stringbuf_create_empty(pool);
-  result->pool = pool;
+  result->result = svn_stringbuf_create_empty(result_pool);
+  result->pool = result_pool;
 
   /* fill all the bits of the result that we can, i.e. all but bits coming
    * from base representations */
@@ -900,7 +901,7 @@ svn_error_t *
 svn_fs_x__deserialize_reps_container(void **out,
                                      void *data,
                                      apr_size_t data_len,
-                                     apr_pool_t *pool)
+                                     apr_pool_t *result_pool)
 {
   svn_fs_x__reps_t *reps = (svn_fs_x__reps_t *)data;
 

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/reps.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/reps.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/reps.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/reps.h Mon Nov 30 10:24:16 2015
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS__REPS_H
-#define SVN_LIBSVN_FS__REPS_H
+#ifndef SVN_LIBSVN_FS_X_REPS_H
+#define SVN_LIBSVN_FS_X_REPS_H
 
 #include "svn_io.h"
 #include "fs.h"
@@ -112,14 +112,14 @@ svn_fs_x__reps_estimate_size(const svn_f
 /* Read from representation containers. */
 
 /* For fulltext IDX in CONTAINER in filesystem FS, create an extract object
- * allocated in POOL and return it in *EXTRACTOR.
+ * allocated in RESULT_POOL and return it in *EXTRACTOR.
  */
 svn_error_t *
 svn_fs_x__reps_get(svn_fs_x__rep_extractor_t **extractor,
                    svn_fs_t *fs,
                    const svn_fs_x__reps_t *container,
                    apr_size_t idx,
-                   apr_pool_t *pool);
+                   apr_pool_t *result_pool);
 
 /* Let the EXTRACTOR object fetch all parts of the desired fulltext and
  * return the latter in *CONTENTS.  If SIZE is not 0, return SIZE bytes
@@ -172,7 +172,7 @@ svn_error_t *
 svn_fs_x__deserialize_reps_container(void **out,
                                      void *data,
                                      apr_size_t data_len,
-                                     apr_pool_t *pool);
+                                     apr_pool_t *result_pool);
 
 /* Implements svn_cache__partial_getter_func_t for svn_fs_x__reps_t,
  * setting *OUT to an svn_fs_x__rep_extractor_t object defined by the

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.c Mon Nov 30 10:24:16 2015
@@ -20,6 +20,8 @@
  * ====================================================================
  */
 
+#include "svn_pools.h"
+
 #include "rev_file.h"
 #include "fs_x.h"
 #include "index.h"
@@ -31,6 +33,46 @@
 #include "private/svn_io_private.h"
 #include "svn_private_config.h"
 
+struct svn_fs_x__revision_file_t
+{
+  /* the filesystem that this revision file belongs to */
+  svn_fs_t *fs;
+
+  /* Meta-data to FILE. */
+  svn_fs_x__rev_file_info_t file_info;
+
+  /* rev / pack file */
+  apr_file_t *file;
+
+  /* stream based on FILE and not NULL exactly when FILE is not NULL */
+  svn_stream_t *stream;
+
+  /* the opened P2L index stream or NULL.  Always NULL for txns. */
+  svn_fs_x__packed_number_stream_t *p2l_stream;
+
+  /* the opened L2P index stream or NULL.  Always NULL for txns. */
+  svn_fs_x__packed_number_stream_t *l2p_stream;
+
+  /* Copied from FS->FFD->BLOCK_SIZE upon creation.  It allows us to
+   * use aligned seek() without having the FS handy. */
+  apr_off_t block_size;
+
+  /* Info on the L2P index within FILE.
+   * Elements are -1 / NULL until svn_fs_x__auto_read_footer gets called. */
+  svn_fs_x__index_info_t l2p_info;
+
+  /* Info on the P2L index within FILE.
+   * Elements are -1 / NULL until svn_fs_x__auto_read_footer gets called. */
+  svn_fs_x__index_info_t p2l_info;
+
+  /* Pool used for all sub-structure allocations (file, streams etc.).
+     A sub-pool of OWNER. NULL until the lazily initilized. */
+  apr_pool_t *pool;
+
+  /* Pool that this structure got allocated in. */
+  apr_pool_t *owner;
+};
+
 /* Return a new revision file instance, allocated in RESULT_POOL, for
  * filesystem FS.  Set its pool member to the provided RESULT_POOL. */
 static svn_fs_x__revision_file_t *
@@ -38,22 +80,24 @@ create_revision_file(svn_fs_t *fs,
                      apr_pool_t *result_pool)
 {
   svn_fs_x__data_t *ffd = fs->fsap_data;
-  svn_fs_x__revision_file_t *file = apr_palloc(result_pool, sizeof(*file));
-
-  file->is_packed = FALSE;
-  file->start_revision = SVN_INVALID_REVNUM;
 
+  svn_fs_x__revision_file_t *file = apr_palloc(result_pool, sizeof(*file));
+  file->fs = fs;
+  file->file_info.is_packed = FALSE;
+  file->file_info.start_revision = SVN_INVALID_REVNUM;
   file->file = NULL;
   file->stream = NULL;
   file->p2l_stream = NULL;
   file->l2p_stream = NULL;
   file->block_size = ffd->block_size;
-  file->l2p_offset = -1;
-  file->l2p_checksum = NULL;
-  file->p2l_offset = -1;
-  file->p2l_checksum = NULL;
-  file->footer_offset = -1;
-  file->pool = result_pool;
+  file->l2p_info.start = -1;
+  file->l2p_info.end = -1;
+  file->l2p_info.checksum = NULL;
+  file->p2l_info.start = -1;
+  file->p2l_info.end = -1;
+  file->p2l_info.checksum = NULL;
+  file->pool = NULL;
+  file->owner = result_pool;
 
   return file;
 }
@@ -68,8 +112,8 @@ init_revision_file(svn_fs_t *fs,
 {
   svn_fs_x__revision_file_t *file = create_revision_file(fs, result_pool);
 
-  file->is_packed = svn_fs_x__is_packed_rev(fs, revision);
-  file->start_revision = svn_fs_x__packed_base_rev(fs, revision);
+  file->file_info.is_packed = svn_fs_x__is_packed_rev(fs, revision);
+  file->file_info.start_revision = svn_fs_x__packed_base_rev(fs, revision);
 
   return file;
 }
@@ -137,20 +181,31 @@ auto_make_writable(const char *path,
   return SVN_NO_ERROR;
 }
 
+/* Return the pool to be used for allocations with FILE.
+   Lazily created that pool upon the first call. */
+static apr_pool_t *
+get_file_pool(svn_fs_x__revision_file_t *file)
+{
+  if (file->pool == NULL)
+    file->pool = svn_pool_create(file->owner);
+
+  return file->pool;
+}
+
 /* Core implementation of svn_fs_fs__open_pack_or_rev_file working on an
  * existing, initialized FILE structure.  If WRITABLE is TRUE, give write
  * access to the file - temporarily resetting the r/o state if necessary.
  */
 static svn_error_t *
 open_pack_or_rev_file(svn_fs_x__revision_file_t *file,
-                      svn_fs_t *fs,
-                      svn_revnum_t rev,
                       svn_boolean_t writable,
-                      apr_pool_t *result_pool,
                       apr_pool_t *scratch_pool)
 {
   svn_error_t *err;
   svn_boolean_t retry = FALSE;
+  svn_fs_t *fs = file->fs;
+  svn_revnum_t rev = file->file_info.start_revision;
+  apr_pool_t *file_pool = get_file_pool(file);
 
   do
     {
@@ -161,19 +216,19 @@ open_pack_or_rev_file(svn_fs_x__revision
                         : APR_READ | APR_BUFFERED;
 
       /* We may have to *temporarily* enable write access. */
-      err = writable ? auto_make_writable(path, result_pool, scratch_pool)
+      err = writable ? auto_make_writable(path, file_pool, scratch_pool)
                      : SVN_NO_ERROR;
 
       /* open the revision file in buffered r/o or r/w mode */
       if (!err)
         err = svn_io_file_open(&apr_file, path, flags, APR_OS_DEFAULT,
-                               result_pool);
+                               file_pool);
 
       if (!err)
         {
           file->file = apr_file;
           file->stream = svn_stream_from_aprfile2(apr_file, TRUE,
-                                                  result_pool);
+                                                  file_pool);
 
           return SVN_NO_ERROR;
         }
@@ -191,7 +246,7 @@ open_pack_or_rev_file(svn_fs_x__revision
 
           /* We failed for the first time. Refresh cache & retry. */
           SVN_ERR(svn_fs_x__update_min_unpacked_rev(fs, scratch_pool));
-              file->start_revision = svn_fs_x__packed_base_rev(fs, rev);
+          file->file_info.start_revision = svn_fs_x__packed_base_rev(fs, rev);
 
           retry = TRUE;
         }
@@ -206,39 +261,52 @@ open_pack_or_rev_file(svn_fs_x__revision
 }
 
 svn_error_t *
-svn_fs_x__open_pack_or_rev_file(svn_fs_x__revision_file_t **file,
-                                 svn_fs_t *fs,
-                                 svn_revnum_t rev,
-                                 apr_pool_t *result_pool,
-                                 apr_pool_t *scratch_pool)
+svn_fs_x__rev_file_init(svn_fs_x__revision_file_t **file,
+                        svn_fs_t *fs,
+                        svn_revnum_t rev,
+                        apr_pool_t *result_pool)
 {
   *file = init_revision_file(fs, rev, result_pool);
-  return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, FALSE,
-                                               result_pool, scratch_pool));
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_fs_x__open_pack_or_rev_file_writable(svn_fs_x__revision_file_t** file,
-                                         svn_fs_t* fs,
-                                         svn_revnum_t rev,
-                                         apr_pool_t* result_pool,
-                                         apr_pool_t *scratch_pool)
+svn_fs_x__rev_file_open_writable(svn_fs_x__revision_file_t** file,
+                                 svn_fs_t* fs,
+                                 svn_revnum_t rev,
+                                 apr_pool_t* result_pool,
+                                 apr_pool_t *scratch_pool)
 {
   *file = init_revision_file(fs, rev, result_pool);
-  return svn_error_trace(open_pack_or_rev_file(*file, fs, rev, TRUE,
-                                               result_pool, scratch_pool));
+  return svn_error_trace(open_pack_or_rev_file(*file, TRUE, scratch_pool));
 }
 
-svn_error_t *
-svn_fs_x__auto_read_footer(svn_fs_x__revision_file_t *file)
+/* If the revision file in FILE has not been opened, yet, do it now. */
+static svn_error_t *
+auto_open(svn_fs_x__revision_file_t *file)
+{
+  if (file->file == NULL)
+    SVN_ERR(open_pack_or_rev_file(file, FALSE, get_file_pool(file)));
+
+  return SVN_NO_ERROR;
+}
+
+/* If the footer data in FILE has not been read, yet, do so now.
+ * Index locations will only be read upon request as we assume they get
+ * cached and the FILE is usually used for REP data access only.
+ * Hence, the separate step.
+ */
+static svn_error_t *
+auto_read_footer(svn_fs_x__revision_file_t *file)
 {
-  if (file->l2p_offset == -1)
+  if (file->l2p_info.start == -1)
     {
       apr_off_t filesize = 0;
       unsigned char footer_length;
       svn_stringbuf_t *footer;
 
       /* Determine file size. */
+      SVN_ERR(auto_open(file));
       SVN_ERR(svn_io_file_seek(file->file, APR_END, &filesize, file->pool));
 
       /* Read last byte (containing the length of the footer). */
@@ -258,22 +326,25 @@ svn_fs_x__auto_read_footer(svn_fs_x__rev
       footer->data[footer->len] = '\0';
 
       /* Extract index locations. */
-      SVN_ERR(svn_fs_x__parse_footer(&file->l2p_offset, &file->l2p_checksum,
-                                     &file->p2l_offset, &file->p2l_checksum,
-                                     footer, file->start_revision,
-                                     file->pool));
-      file->footer_offset = filesize - footer_length - 1;
+      SVN_ERR(svn_fs_x__parse_footer(&file->l2p_info.start,
+                                     &file->l2p_info.checksum,
+                                     &file->p2l_info.start,
+                                     &file->p2l_info.checksum,
+                                     footer, file->file_info.start_revision,
+                                     filesize - footer_length - 1, file->pool));
+      file->l2p_info.end = file->p2l_info.start;
+      file->p2l_info.end = filesize - footer_length - 1;
     }
 
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_fs_x__open_proto_rev_file(svn_fs_x__revision_file_t **file,
-                               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__rev_file_open_proto_rev(svn_fs_x__revision_file_t **file,
+                                  svn_fs_t *fs,
+                                  svn_fs_x__txn_id_t txn_id,
+                                  apr_pool_t* result_pool,
+                                  apr_pool_t *scratch_pool)
 {
   apr_file_t *apr_file;
   SVN_ERR(svn_io_file_open(&apr_file,
@@ -282,12 +353,12 @@ svn_fs_x__open_proto_rev_file(svn_fs_x__
                            APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
                            result_pool));
 
-  return svn_error_trace(svn_fs_x__wrap_temp_rev_file(file, fs, apr_file,
+  return svn_error_trace(svn_fs_x__rev_file_wrap_temp(file, fs, apr_file,
                                                       result_pool));
 }
 
 svn_error_t *
-svn_fs_x__wrap_temp_rev_file(svn_fs_x__revision_file_t **file,
+svn_fs_x__rev_file_wrap_temp(svn_fs_x__revision_file_t **file,
                              svn_fs_t *fs,
                              apr_file_t *temp_file,
                              apr_pool_t *result_pool)
@@ -300,17 +371,159 @@ svn_fs_x__wrap_temp_rev_file(svn_fs_x__r
 }
 
 svn_error_t *
+svn_fs_x__rev_file_info(svn_fs_x__rev_file_info_t *info,
+                        svn_fs_x__revision_file_t *file)
+{
+  SVN_ERR(auto_open(file));
+
+  *info = file->file_info;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__rev_file_name(const char **filename,
+                        svn_fs_x__revision_file_t *file,
+                        apr_pool_t *result_pool)
+{
+  SVN_ERR(auto_open(file));
+
+  return svn_error_trace(svn_io_file_name_get(filename, file->file,
+                                              result_pool));
+}
+
+svn_error_t *
+svn_fs_x__rev_file_stream(svn_stream_t **stream,
+                          svn_fs_x__revision_file_t *file)
+{
+  SVN_ERR(auto_open(file));
+
+  *stream = file->stream;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__rev_file_get(apr_file_t **apr_file,
+                       svn_fs_x__revision_file_t *file)
+{
+  SVN_ERR(auto_open(file));
+
+  *apr_file = file->file;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__rev_file_l2p_index(svn_fs_x__packed_number_stream_t **stream,
+                             svn_fs_x__revision_file_t *file)
+{
+  if (file->l2p_stream == NULL)
+    {
+      SVN_ERR(auto_read_footer(file));
+      SVN_ERR(svn_fs_x__packed_stream_open(&file->l2p_stream,
+                                           file->file,
+                                           file->l2p_info.start,
+                                           file->l2p_info.end,
+                                           SVN_FS_X__L2P_STREAM_PREFIX,
+                                           (apr_size_t)file->block_size,
+                                           file->pool,
+                                           file->pool));
+    }
+
+  *stream = file->l2p_stream;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__rev_file_p2l_index(svn_fs_x__packed_number_stream_t **stream,
+                             svn_fs_x__revision_file_t *file)
+{
+  if (file->p2l_stream== NULL)
+    {
+      SVN_ERR(auto_read_footer(file));
+      SVN_ERR(svn_fs_x__packed_stream_open(&file->p2l_stream,
+                                           file->file,
+                                           file->p2l_info.start,
+                                           file->p2l_info.end,
+                                           SVN_FS_X__P2L_STREAM_PREFIX,
+                                           (apr_size_t)file->block_size,
+                                           file->pool,
+                                           file->pool));
+    }
+
+  *stream = file->p2l_stream;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__rev_file_l2p_info(svn_fs_x__index_info_t *info,
+                            svn_fs_x__revision_file_t *file)
+{
+  SVN_ERR(auto_read_footer(file));
+  *info = file->l2p_info;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__rev_file_p2l_info(svn_fs_x__index_info_t *info,
+                            svn_fs_x__revision_file_t *file)
+{
+  SVN_ERR(auto_read_footer(file));
+  *info = file->p2l_info;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__rev_file_seek(svn_fs_x__revision_file_t *file,
+                        apr_off_t *buffer_start,
+                        apr_off_t offset)
+{
+  SVN_ERR(auto_open(file));
+  return svn_error_trace(svn_io_file_aligned_seek(file->file,
+                                                  file->block_size,
+                                                  buffer_start, offset,
+                                                  file->pool));
+}
+
+svn_error_t *
+svn_fs_x__rev_file_offset(apr_off_t *offset,
+                          svn_fs_x__revision_file_t *file)
+{
+  SVN_ERR(auto_open(file));
+  return svn_error_trace(svn_fs_x__get_file_offset(offset, file->file,
+                                                   file->pool));
+}
+
+svn_error_t *
+svn_fs_x__rev_file_read(svn_fs_x__revision_file_t *file,
+                        void *buf,
+                        apr_size_t nbytes)
+{
+  SVN_ERR(auto_open(file));
+  return svn_error_trace(svn_io_file_read_full2(file->file, buf, nbytes,
+                                                NULL, NULL, file->pool));
+}
+
+svn_error_t *
 svn_fs_x__close_revision_file(svn_fs_x__revision_file_t *file)
 {
+  /* Close sub-objects properly */
   if (file->stream)
     SVN_ERR(svn_stream_close(file->stream));
   if (file->file)
     SVN_ERR(svn_io_file_close(file->file, file->pool));
 
+  /* Release the memory. */
+  if (file->pool)
+    svn_pool_clear(file->pool);
+
+  /* Reset pointers to objects previously allocated from FILE->POOL. */
   file->file = NULL;
   file->stream = NULL;
   file->l2p_stream = NULL;
   file->p2l_stream = NULL;
 
+  /* Cause any index data getters to re-read the footer. */
+  file->l2p_info.start = -1;
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/rev_file.h Mon Nov 30 10:24:16 2015
@@ -26,11 +26,14 @@
 #include "svn_fs.h"
 #include "id.h"
 
-/* In format 7, index files must be read in sync with the respective
- * revision / pack file.  I.e. we must use packed index files for packed
- * rev files and unpacked ones for non-packed rev files.  So, the whole
- * point is to open them with matching "is packed" setting in case some
- * background pack process was run.
+/* In FSX, index data must be read in sync with the respective revision /
+ * pack file.  I.e. we must use packed index files for packed rev files and
+ * unpacked ones for non-packed rev files.  So, the whole point is to open
+ * them with matching "is packed" setting in case some background pack
+ * process was run.
+ *
+ * Another thing that this allows us is to lazily open the file, i.e. open
+ * it upon first access.
  */
 
 /* Opaque index stream type.
@@ -38,11 +41,22 @@
 typedef struct svn_fs_x__packed_number_stream_t
   svn_fs_x__packed_number_stream_t;
 
-/* Data file, including indexes data, and associated properties for
- * START_REVISION.  As the FILE is kept open, background pack operations
- * will not cause access to this file to fail.
- */
-typedef struct svn_fs_x__revision_file_t
+/* Location and content meta data for an index. */
+typedef struct svn_fs_x__index_info_t
+{
+  /* Offset within the pack / rev file at which the index data starts. */
+  apr_off_t start;
+
+  /* First offset behind the index data. */
+  apr_off_t end;
+
+  /* MD5 checksum on the whole on-disk representation of the index. */
+  svn_checksum_t *checksum;
+
+} svn_fs_x__index_info_t;
+
+/* Location and content meta data for a revision / pack file. */
+typedef struct svn_fs_x__rev_file_info_t
 {
   /* first (potentially only) revision in the rev / pack file.
    * SVN_INVALID_REVNUM for txn proto-rev files. */
@@ -51,60 +65,24 @@ typedef struct svn_fs_x__revision_file_t
   /* the revision was packed when the first file / stream got opened */
   svn_boolean_t is_packed;
 
-  /* rev / pack file */
-  apr_file_t *file;
+} svn_fs_x__rev_file_info_t;
 
-  /* stream based on FILE and not NULL exactly when FILE is not NULL */
-  svn_stream_t *stream;
-
-  /* the opened P2L index stream or NULL.  Always NULL for txns. */
-  svn_fs_x__packed_number_stream_t *p2l_stream;
+/* Data file, including indexes data, and associated properties for
+ * START_REVISION.  As the FILE is kept open, background pack operations
+ * will not cause access to this file to fail.
+ */
+typedef struct svn_fs_x__revision_file_t svn_fs_x__revision_file_t;
 
-  /* the opened L2P index stream or NULL.  Always NULL for txns. */
-  svn_fs_x__packed_number_stream_t *l2p_stream;
-
-  /* Copied from FS->FFD->BLOCK_SIZE upon creation.  It allows us to
-   * use aligned seek() without having the FS handy. */
-  apr_off_t block_size;
-
-  /* Offset within FILE at which the rev data ends and the L2P index
-   * data starts. Less than P2L_OFFSET. -1 if svn_fs_fs__auto_read_footer
-   * has not been called, yet. */
-  apr_off_t l2p_offset;
-
-  /* MD5 checksum on the whole on-disk representation of the L2P index.
-   * NULL if svn_fs_fs__auto_read_footer has not been called, yet. */
-  svn_checksum_t *l2p_checksum;
-
-  /* Offset within FILE at which the L2P index ends and the P2L index
-   * data starts. Greater than L2P_OFFSET. -1 if svn_fs_fs__auto_read_footer
-   * has not been called, yet. */
-  apr_off_t p2l_offset;
-
-  /* MD5 checksum on the whole on-disk representation of the P2L index.
-   * NULL if svn_fs_fs__auto_read_footer has not been called, yet. */
-  svn_checksum_t *p2l_checksum;
-
-  /* Offset within FILE at which the P2L index ends and the footer starts.
-   * Greater than P2L_OFFSET. -1 if svn_fs_fs__auto_read_footer has not
-   * been called, yet. */
-  apr_off_t footer_offset;
-
-  /* pool containing this object */
-  apr_pool_t *pool;
-} svn_fs_x__revision_file_t;
-
-/* Open the correct revision file for REV.  If the filesystem FS has
- * been packed, *FILE will be set to the packed file; otherwise, set *FILE
- * to the revision file for REV.  Return SVN_ERR_FS_NO_SUCH_REVISION if the
- * file doesn't exist.  Allocate *FILE in RESULT_POOL and use SCRATCH_POOL
- * for temporaries. */
-svn_error_t *
-svn_fs_x__open_pack_or_rev_file(svn_fs_x__revision_file_t **file,
-                                svn_fs_t *fs,
-                                svn_revnum_t rev,
-                                apr_pool_t *result_pool,
-                                apr_pool_t *scratch_pool);
+/* Initialize the revision / pack file access structure in *FILE for reading
+ * revision REV from filesystem FS.  The file will not be opened until the
+ * first call to any of the access functions.
+ *
+ * Allocate *FILE in RESULT_POOL. */
+svn_error_t *
+svn_fs_x__rev_file_init(svn_fs_x__revision_file_t **file,
+                        svn_fs_t *fs,
+                        svn_revnum_t rev,
+                        apr_pool_t *result_pool);
 
 /* Open the correct revision file for REV with read and write access.
  * If necessary, temporarily reset the file's read-only state.  If the
@@ -114,39 +92,101 @@ svn_fs_x__open_pack_or_rev_file(svn_fs_x
  * Return SVN_ERR_FS_NO_SUCH_REVISION if the file doesn't exist.
  * Allocate *FILE in RESULT_POOL and use SCRATCH_POOLfor temporaries. */
 svn_error_t *
-svn_fs_x__open_pack_or_rev_file_writable(svn_fs_x__revision_file_t **file,
-                                         svn_fs_t *fs,
-                                         svn_revnum_t rev,
-                                         apr_pool_t *result_pool,
-                                         apr_pool_t *scratch_pool);
-
-/* If the footer data in FILE has not been read, yet, do so now.
- * Index locations will only be read upon request as we assume they get
- * cached and the FILE is usually used for REP data access only.
- * Hence, the separate step.
- */
-svn_error_t *
-svn_fs_x__auto_read_footer(svn_fs_x__revision_file_t *file);
+svn_fs_x__rev_file_open_writable(svn_fs_x__revision_file_t **file,
+                                 svn_fs_t *fs,
+                                 svn_revnum_t rev,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool);
 
 /* Open the proto-rev file of transaction TXN_ID in FS and return it in *FILE.
  * Allocate *FILE in RESULT_POOL use and SCRATCH_POOL for temporaries.. */
 svn_error_t *
-svn_fs_x__open_proto_rev_file(svn_fs_x__revision_file_t **file,
-                              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__rev_file_open_proto_rev(svn_fs_x__revision_file_t **file,
+                                  svn_fs_t *fs,
+                                  svn_fs_x__txn_id_t txn_id,
+                                  apr_pool_t* result_pool,
+                                  apr_pool_t *scratch_pool);
 
 /* Wrap the TEMP_FILE, used in the context of FS, into a revision file
  * struct, allocated in RESULT_POOL, and return it in *FILE.
  */
 svn_error_t *
-svn_fs_x__wrap_temp_rev_file(svn_fs_x__revision_file_t **file,
+svn_fs_x__rev_file_wrap_temp(svn_fs_x__revision_file_t **file,
                              svn_fs_t *fs,
                              apr_file_t *temp_file,
                              apr_pool_t *result_pool);
 
-/* Close all files and streams in FILE.
+/* Access functions */
+
+/* Copy the L2P index info for FILE into *INFO.
+ */
+svn_error_t *
+svn_fs_x__rev_file_info(svn_fs_x__rev_file_info_t *info,
+                        svn_fs_x__revision_file_t *file);
+
+/* Convenience wrapper around svn_io_file_name_get. */
+svn_error_t *
+svn_fs_x__rev_file_name(const char **filename,
+                        svn_fs_x__revision_file_t *file,
+                        apr_pool_t *result_pool);
+
+/* Set *STREAM to the shared stream object of FILE.
+ */
+svn_error_t *
+svn_fs_x__rev_file_stream(svn_stream_t **stream,
+                          svn_fs_x__revision_file_t *file);
+
+/* Set *APR_FILE to the shared file object of FILE.
+ */
+svn_error_t *
+svn_fs_x__rev_file_get(apr_file_t **apr_file,
+                       svn_fs_x__revision_file_t *file);
+
+/* Set *STREAM to the shared L2P data stream of FILE.
+ */
+svn_error_t *
+svn_fs_x__rev_file_l2p_index(svn_fs_x__packed_number_stream_t **stream,
+                             svn_fs_x__revision_file_t *file);
+
+/* Set *STREAM to the shared P2L data stream of FILE.
+ */
+svn_error_t *
+svn_fs_x__rev_file_p2l_index(svn_fs_x__packed_number_stream_t **stream,
+                             svn_fs_x__revision_file_t *file);
+
+/* Copy the L2P index info for FILE into *INFO.
+ */
+svn_error_t *
+svn_fs_x__rev_file_l2p_info(svn_fs_x__index_info_t *info,
+                            svn_fs_x__revision_file_t *file);
+
+/* Copy the P2L index info for FILE into *INFO.
+ */
+svn_error_t *
+svn_fs_x__rev_file_p2l_info(svn_fs_x__index_info_t *info,
+                            svn_fs_x__revision_file_t *file);
+
+/* File manipulation. */
+
+/* Convenience wrapper around svn_io_file_aligned_seek. */
+svn_error_t *
+svn_fs_x__rev_file_seek(svn_fs_x__revision_file_t *file,
+                        apr_off_t *buffer_start,
+                        apr_off_t offset);
+
+/* Convenience wrapper around svn_fs_x__get_file_offset. */
+svn_error_t *
+svn_fs_x__rev_file_offset(apr_off_t *offset,
+                          svn_fs_x__revision_file_t *file);
+
+/* Convenience wrapper around svn_io_file_read_full2. */
+svn_error_t *
+svn_fs_x__rev_file_read(svn_fs_x__revision_file_t *file,
+                        void *buf,
+                        apr_size_t nbytes);
+
+/* Close all files and streams in FILE.  They will be reopened automatically
+ * by any of the above access functions.
  */
 svn_error_t *
 svn_fs_x__close_revision_file(svn_fs_x__revision_file_t *file);