subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From i...@apache.org
Subject svn commit: r1686174 [7/18] - in /subversion/branches/reuse-ra-session: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ subversion/bindings/javahl/ subversion/bindings/javahl/native/ subversion/bindings/javahl/native/jniwrapper/ ...
Date Thu, 18 Jun 2015 10:35:33 GMT
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/id.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/id.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/id.c Thu Jun 18 10:35:30 2015
@@ -365,14 +365,21 @@ svn_fs_fs__id_check_related(const svn_fs
   if (a == b)
     return TRUE;
 
-  /* If both node_ids start with _ and they have differing transaction
-     IDs, then it is impossible for them to be related. */
-  if (id_a->private_id.node_id.revision == SVN_INVALID_REVNUM)
+  /* If both node_ids have been created within _different_ transactions
+     (and are still uncommitted), then it is impossible for them to be
+     related.
+
+     Due to our txn-local temporary IDs, however, they might have been
+     given the same temporary node ID.  We need to detect that case.
+   */
+  if (   id_a->private_id.node_id.revision == SVN_INVALID_REVNUM
+      && id_b->private_id.node_id.revision == SVN_INVALID_REVNUM)
     {
-      if (   !svn_fs_fs__id_part_eq(&id_a->private_id.txn_id,
-                                    &id_b->private_id.txn_id)
-          || !svn_fs_fs__id_txn_used(&id_a->private_id.txn_id))
+      if (!svn_fs_fs__id_part_eq(&id_a->private_id.txn_id,
+                                 &id_b->private_id.txn_id))
         return FALSE;
+
+      /* At this point, matching node_ids implies relatedness. */
     }
 
   return svn_fs_fs__id_part_eq(&id_a->private_id.node_id,
@@ -385,7 +392,7 @@ svn_fs_fs__id_compare(const svn_fs_id_t
                       const svn_fs_id_t *b)
 {
   if (svn_fs_fs__id_eq(a, b))
-    return svn_fs_node_same;
+    return svn_fs_node_unchanged;
   return (svn_fs_fs__id_check_related(a, b) ? svn_fs_node_common_ancestor
                                             : svn_fs_node_unrelated);
 }

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/lock.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/lock.c Thu Jun 18 10:35:30 2015
@@ -222,7 +222,7 @@ write_digest_file(apr_hash_t *children,
                                  svn_io_file_del_none, pool, pool));
   if ((err = svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, pool)))
     {
-      svn_error_clear(svn_stream_close(stream));
+      err = svn_error_compose_create(err, svn_stream_close(stream));
       return svn_error_createf(err->apr_err,
                                err,
                                _("Cannot write lock/entries hashfile '%s'"),
@@ -273,7 +273,7 @@ read_digest_file(apr_hash_t **children_p
   hash = apr_hash_make(pool);
   if ((err = svn_hash_read2(hash, stream, SVN_HASH_TERMINATOR, pool)))
     {
-      svn_error_clear(svn_stream_close(stream));
+      err = svn_error_compose_create(err, svn_stream_close(stream));
       return svn_error_createf(err->apr_err,
                                err,
                                _("Can't parse lock/entries hashfile '%s'"),
@@ -715,6 +715,7 @@ check_lock(svn_error_t **fs_err,
            const svn_fs_lock_target_t *target,
            struct lock_baton *lb,
            svn_fs_root_t *root,
+           svn_revnum_t youngest_rev,
            apr_pool_t *pool)
 {
   svn_node_kind_t kind;
@@ -751,6 +752,15 @@ check_lock(svn_error_t **fs_err,
   if (SVN_IS_VALID_REVNUM(target->current_rev))
     {
       svn_revnum_t created_rev;
+
+      if (target->current_rev > youngest_rev)
+        {
+          *fs_err = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                                      _("No such revision %ld"),
+                                      target->current_rev);
+          return SVN_NO_ERROR;
+        }
+
       SVN_ERR(svn_fs_fs__node_created_rev(&created_rev, root, path,
                                           pool));
 
@@ -856,7 +866,7 @@ lock_body(void *baton, apr_pool_t *pool)
       info.fs_err = SVN_NO_ERROR;
 
       SVN_ERR(check_lock(&info.fs_err, info.path, item->value, lb, root,
-                         iterpool));
+                         youngest, iterpool));
 
       /* If no error occurred while pre-checking, schedule the index updates for
          this path. */
@@ -1099,6 +1109,7 @@ svn_fs_fs__lock(svn_fs_t *fs,
   apr_array_header_t *sorted_targets;
   apr_hash_t *canonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
   svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
@@ -1139,11 +1150,13 @@ svn_fs_fs__lock(svn_fs_t *fs,
   lb.steal_lock = steal_lock;
   lb.result_pool = result_pool;
 
-  err = svn_fs_fs__with_write_lock(fs, lock_body, &lb, scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  err = svn_fs_fs__with_write_lock(fs, lock_body, &lb, iterpool);
   for (i = 0; i < lb.infos->nelts; ++i)
     {
       struct lock_info_t *info = &APR_ARRAY_IDX(lb.infos, i,
                                                 struct lock_info_t);
+      svn_pool_clear(iterpool);
       if (!cb_err && lock_callback)
         {
           if (!info->lock && !info->fs_err)
@@ -1152,10 +1165,11 @@ svn_fs_fs__lock(svn_fs_t *fs,
                                              info->path);
 
           cb_err = lock_callback(lock_baton, info->path, info->lock,
-                                 info->fs_err, scratch_pool);
+                                 info->fs_err, iterpool);
         }
       svn_error_clear(info->fs_err);
     }
+  svn_pool_destroy(iterpool);
 
   if (err && cb_err)
     svn_error_compose(err, cb_err);
@@ -1195,6 +1209,7 @@ svn_fs_fs__unlock(svn_fs_t *fs,
   apr_array_header_t *sorted_targets;
   apr_hash_t *canonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
   svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
@@ -1229,11 +1244,13 @@ svn_fs_fs__unlock(svn_fs_t *fs,
   ub.break_lock = break_lock;
   ub.result_pool = result_pool;
 
-  err = svn_fs_fs__with_write_lock(fs, unlock_body, &ub, scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  err = svn_fs_fs__with_write_lock(fs, unlock_body, &ub, iterpool);
   for (i = 0; i < ub.infos->nelts; ++i)
     {
       struct unlock_info_t *info = &APR_ARRAY_IDX(ub.infos, i,
                                                   struct unlock_info_t);
+      svn_pool_clear(iterpool);
       if (!cb_err && lock_callback)
         {
           if (!info->done && !info->fs_err)
@@ -1241,10 +1258,11 @@ svn_fs_fs__unlock(svn_fs_t *fs,
                                              0, _("Failed to unlock '%s'"),
                                              info->path);
           cb_err = lock_callback(lock_baton, info->path, NULL, info->fs_err,
-                                 scratch_pool);
+                                 iterpool);
         }
       svn_error_clear(info->fs_err);
     }
+  svn_pool_destroy(iterpool);
 
   if (err && cb_err)
     svn_error_compose(err, cb_err);

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/low_level.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/low_level.c Thu Jun 18 10:35:30 2015
@@ -189,6 +189,19 @@ svn_fs_fs__unparse_revision_trailer(apr_
                                changes_offset);
 }
 
+/* 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_fs__parse_footer(apr_off_t *l2p_offset,
                         svn_checksum_t **l2p_checksum,
@@ -196,6 +209,7 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
                         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;
@@ -204,17 +218,20 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
   /* 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));
@@ -222,17 +239,33 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
   /* 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));

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/low_level.h?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/low_level.h (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/low_level.h Thu Jun 18 10:35:30 2015
@@ -67,6 +67,8 @@ svn_fs_fs__unparse_revision_trailer(apr_
  * *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.
  */
@@ -77,6 +79,7 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
                         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

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/pack.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/pack.c Thu Jun 18 10:35:30 2015
@@ -384,6 +384,8 @@ close_pack_context(pack_context_t *conte
   SVN_ERR(svn_io_remove_file2(proto_l2p_index_path, FALSE, pool));
   SVN_ERR(svn_io_remove_file2(proto_p2l_index_path, FALSE, pool));
 
+  /* Ensure that packed file is written to disk.*/
+  SVN_ERR(svn_io_file_flush_to_disk(context->pack_file, pool));
   SVN_ERR(svn_io_file_close(context->pack_file, pool));
 
   return SVN_NO_ERROR;
@@ -572,7 +574,7 @@ copy_rep_to_temp(pack_context_t *context
   /* read & parse the representation header */
   stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
   SVN_ERR(svn_fs_fs__read_rep_header(&rep_header, stream, pool, pool));
-  svn_stream_close(stream);
+  SVN_ERR(svn_stream_close(stream));
 
   /* if the representation is a delta against some other rep, link the two */
   if (   rep_header->type == svn_fs_fs__rep_delta
@@ -643,17 +645,18 @@ compare_dir_entries_format6(const svn_so
 apr_array_header_t *
 svn_fs_fs__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,
                      svn_fs_fs__use_log_addressing(fs)
                        ? compare_dir_entries_format7
                        : compare_dir_entries_format6,
-                     pool);
+                     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)
@@ -714,7 +717,7 @@ copy_node_to_temp(pack_context_t *contex
   /* read & parse noderev */
   stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
   SVN_ERR(svn_fs_fs__read_noderev(&noderev, stream, pool, pool));
-  svn_stream_close(stream);
+  SVN_ERR(svn_stream_close(stream));
 
   /* create a copy of ENTRY, make it point to the copy destination and
    * store it in CONTEXT */
@@ -736,9 +739,7 @@ copy_node_to_temp(pack_context_t *contex
     {
       path_order->rep_id.revision = noderev->data_rep->revision;
       path_order->rep_id.number = noderev->data_rep->item_index;
-      path_order->expanded_size = noderev->data_rep->expanded_size
-                                ? noderev->data_rep->expanded_size
-                                : noderev->data_rep->size;
+      path_order->expanded_size = noderev->data_rep->expanded_size;
     }
 
   /* Sort path is the key used for ordering noderevs and associated reps.
@@ -1655,7 +1656,9 @@ pack_phys_addressed(const char *pack_fil
                     apr_pool_t *pool)
 {
   const char *pack_file_path, *manifest_file_path;
-  svn_stream_t *pack_stream, *manifest_stream;
+  apr_file_t *pack_file;
+  apr_file_t *manifest_file;
+  svn_stream_t *manifest_stream;
   svn_revnum_t end_rev, rev;
   apr_off_t next_offset;
   apr_pool_t *iterpool;
@@ -1664,13 +1667,18 @@ pack_phys_addressed(const char *pack_fil
   pack_file_path = svn_dirent_join(pack_file_dir, PATH_PACKED, pool);
   manifest_file_path = svn_dirent_join(pack_file_dir, PATH_MANIFEST, pool);
 
-  /* Create the new directory and pack file. */
-  SVN_ERR(svn_stream_open_writable(&pack_stream, pack_file_path, pool,
-                                    pool));
+  /* Create the new directory and pack file.
+   * Use unbuffered apr_file_t since we're going to write using 16kb
+   * chunks. */
+  SVN_ERR(svn_io_file_open(&pack_file, pack_file_path,
+                           APR_WRITE | APR_CREATE | APR_EXCL,
+                           APR_OS_DEFAULT, pool));
 
   /* Create the manifest file. */
-  SVN_ERR(svn_stream_open_writable(&manifest_stream, manifest_file_path,
-                                   pool, pool));
+  SVN_ERR(svn_io_file_open(&manifest_file, manifest_file_path,
+                           APR_WRITE | APR_BUFFERED | APR_CREATE | APR_EXCL,
+                           APR_OS_DEFAULT, pool));
+  manifest_stream = svn_stream_from_aprfile2(manifest_file, TRUE, pool);
 
   end_rev = start_rev + max_files_per_dir - 1;
   next_offset = 0;
@@ -1697,16 +1705,24 @@ pack_phys_addressed(const char *pack_fil
 
       /* Copy all the bits from the rev file to the end of the pack file. */
       SVN_ERR(svn_stream_open_readonly(&rev_stream, path, iterpool, iterpool));
-      SVN_ERR(svn_stream_copy3(rev_stream, svn_stream_disown(pack_stream,
-                                                             iterpool),
+      SVN_ERR(svn_stream_copy3(rev_stream,
+                               svn_stream_from_aprfile2(pack_file, TRUE, pool),
                                cancel_func, cancel_baton, iterpool));
     }
 
-  /* disallow write access to the manifest file */
+  /* Close stream over APR file. */
   SVN_ERR(svn_stream_close(manifest_stream));
+
+  /* Ensure that pack file is written to disk. */
+  SVN_ERR(svn_io_file_flush_to_disk(manifest_file, pool));
+  SVN_ERR(svn_io_file_close(manifest_file, pool));
+
+  /* disallow write access to the manifest file */
   SVN_ERR(svn_io_set_file_read_only(manifest_file_path, FALSE, iterpool));
 
-  SVN_ERR(svn_stream_close(pack_stream));
+  /* Ensure that pack file is written to disk. */
+  SVN_ERR(svn_io_file_flush_to_disk(pack_file, pool));
+  SVN_ERR(svn_io_file_close(pack_file, pool));
 
   svn_pool_destroy(iterpool);
 

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/pack.h
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/pack.h?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/pack.h (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/pack.h Thu Jun 18 10:35:30 2015
@@ -51,13 +51,14 @@ svn_fs_fs__get_packed_offset(apr_off_t *
                              apr_pool_t *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_fs__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/reuse-ra-session/subversion/libsvn_fs_fs/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/recovery.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/recovery.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/recovery.c Thu Jun 18 10:35:30 2015
@@ -160,6 +160,7 @@ recover_find_max_ids(svn_fs_t *fs,
   apr_hash_index_t *hi;
   apr_pool_t *iterpool;
   node_revision_t *noderev;
+  svn_error_t *err;
 
   baton.stream = rev_file->stream;
   SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
@@ -196,16 +197,23 @@ recover_find_max_ids(svn_fs_t *fs,
      stored in the representation.  Note that this is a directory, i.e.
      represented using the hash format on disk and can never have 0 length. */
   baton.pool = pool;
-  baton.remaining = noderev->data_rep->expanded_size
-                  ? noderev->data_rep->expanded_size
-                  : noderev->data_rep->size;
+  baton.remaining = noderev->data_rep->expanded_size;
   stream = svn_stream_create(&baton, pool);
   svn_stream_set_read2(stream, NULL /* only full read support */,
                        read_handler_recover);
 
   /* Now read the entries from that stream. */
   entries = apr_hash_make(pool);
-  SVN_ERR(svn_hash_read2(entries, stream, SVN_HASH_TERMINATOR, pool));
+  err = svn_hash_read2(entries, stream, SVN_HASH_TERMINATOR, pool);
+  if (err)
+    {
+      svn_string_t *id_str = svn_fs_fs__id_unparse(noderev->id, pool);
+
+      err = svn_error_compose_create(err, svn_stream_close(stream));
+      return svn_error_quick_wrapf(err,
+                _("malformed representation for node-revision '%s'"),
+                id_str->data);
+    }
   SVN_ERR(svn_stream_close(stream));
 
   /* Now check each of the entries in our directory to find new node and

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache-db.sql
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache-db.sql?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache-db.sql (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache-db.sql Thu Jun 18 10:35:30 2015
@@ -63,3 +63,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/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache.c Thu Jun 18 10:35:30 2015
@@ -24,6 +24,7 @@
 
 #include "svn_private_config.h"
 
+#include "cached_data.h"
 #include "fs_fs.h"
 #include "fs.h"
 #include "rep-cache.h"
@@ -273,6 +274,8 @@ svn_fs_fs__get_rep_reference(representat
       (*rep)->item_index = svn_sqlite__column_int64(stmt, 1);
       (*rep)->size = svn_sqlite__column_int64(stmt, 2);
       (*rep)->expanded_size = svn_sqlite__column_int64(stmt, 3);
+
+      SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, *rep, pool));
     }
   else
     *rep = NULL;
@@ -371,9 +374,13 @@ svn_fs_fs__del_rep_reference(svn_fs_t *f
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_fs_fs__lock_rep_cache(svn_fs_t *fs,
-                          apr_pool_t *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)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
 
@@ -384,3 +391,31 @@ svn_fs_fs__lock_rep_cache(svn_fs_t *fs,
 
   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)
+{
+  fs_fs_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_fs__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/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache.h?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache.h (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rep-cache.h Thu Jun 18 10:35:30 2015
@@ -87,10 +87,14 @@ svn_fs_fs__del_rep_reference(svn_fs_t *f
                              apr_pool_t *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_fs__lock_rep_cache(svn_fs_t *fs,
-                          apr_pool_t *pool);
+svn_fs_fs__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
 }

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rev_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rev_file.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rev_file.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/rev_file.c Thu Jun 18 10:35:30 2015
@@ -259,6 +259,7 @@ svn_fs_fs__auto_read_footer(svn_fs_fs__r
       SVN_ERR(svn_fs_fs__parse_footer(&file->l2p_offset, &file->l2p_checksum,
                                       &file->p2l_offset, &file->p2l_checksum,
                                       footer, file->start_revision,
+                                      filesize - footer_length - 1,
                                       file->pool));
       file->footer_offset = filesize - footer_length - 1;
     }

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/revprops.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/revprops.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/revprops.c Thu Jun 18 10:35:30 2015
@@ -36,11 +36,6 @@
 
 #include "svn_private_config.h"
 
-/* Give writing processes 10 seconds to replace an existing revprop
-   file with a new one. After that time, we assume that the writing
-   process got aborted and that we have re-read revprops. */
-#define REVPROP_CHANGE_TIMEOUT (10 * 1000000)
-
 svn_error_t *
 svn_fs_fs__upgrade_pack_revprops(svn_fs_t *fs,
                                  svn_fs_upgrade_notify_t notify_func,
@@ -415,7 +410,8 @@ parse_packed_revprops(svn_fs_t *fs,
    * length header to remove) */
   svn_stringbuf_t *compressed = revprops->packed_revprops;
   svn_stringbuf_t *uncompressed = svn_stringbuf_create_empty(pool);
-  SVN_ERR(svn__decompress(compressed, uncompressed, APR_SIZE_MAX));
+  SVN_ERR(svn__decompress(compressed->data, compressed->len,
+                          uncompressed, APR_SIZE_MAX));
 
   /* read first revision number and number of revisions in the pack */
   stream = svn_stream_from_stringbuf(uncompressed, scratch_pool);
@@ -657,17 +653,23 @@ write_non_packed_revprop(const char **fi
                          apr_hash_t *proplist,
                          apr_pool_t *pool)
 {
+  apr_file_t *file;
   svn_stream_t *stream;
   *final_path = svn_fs_fs__path_revprops(fs, rev, pool);
 
   /* ### do we have a directory sitting around already? we really shouldn't
      ### have to get the dirname here. */
-  SVN_ERR(svn_stream_open_unique(&stream, tmp_path,
-                                 svn_dirent_dirname(*final_path, pool),
-                                 svn_io_file_del_none, pool, pool));
+  SVN_ERR(svn_io_open_unique_file3(&file, tmp_path,
+                                   svn_dirent_dirname(*final_path, pool),
+                                   svn_io_file_del_none, pool, pool));
+  stream = svn_stream_from_aprfile2(file, TRUE, pool);
   SVN_ERR(svn_hash_write2(proplist, stream, SVN_HASH_TERMINATOR, pool));
   SVN_ERR(svn_stream_close(stream));
 
+  /* Flush temporary file to disk and close it. */
+  SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -750,7 +752,7 @@ serialize_revprops_header(svn_stream_t *
   return SVN_NO_ERROR;
 }
 
-/* Writes the a pack file to FILE_STREAM.  It copies the serialized data
+/* Writes the a pack file to FILE.  It copies the serialized data
  * from REVPROPS for the indexes [START,END) except for index CHANGED_INDEX.
  *
  * The data for the latter is taken from NEW_SERIALIZED.  Note, that
@@ -768,7 +770,7 @@ repack_revprops(svn_fs_t *fs,
                 int changed_index,
                 svn_stringbuf_t *new_serialized,
                 apr_off_t new_total_size,
-                svn_stream_t *file_stream,
+                apr_file_t *file,
                 apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -810,15 +812,17 @@ repack_revprops(svn_fs_t *fs,
   SVN_ERR(svn_stream_close(stream));
 
   /* compress / store the data */
-  SVN_ERR(svn__compress(uncompressed,
+  SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
                         compressed,
                         ffd->compress_packed_revprops
                           ? SVN_DELTA_COMPRESSION_LEVEL_DEFAULT
                           : SVN_DELTA_COMPRESSION_LEVEL_NONE));
 
-  /* finally, write the content to the target stream and close it */
-  SVN_ERR(svn_stream_write(file_stream, compressed->data, &compressed->len));
-  SVN_ERR(svn_stream_close(file_stream));
+  /* finally, write the content to the target file, flush and close it */
+  SVN_ERR(svn_io_file_write_full(file, compressed->data, compressed->len,
+                                 NULL, pool));
+  SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
 }
@@ -826,23 +830,22 @@ repack_revprops(svn_fs_t *fs,
 /* Allocate a new pack file name for revisions
  *     [REVPROPS->START_REVISION + START, REVPROPS->START_REVISION + END - 1]
  * of REVPROPS->MANIFEST.  Add the name of old file to FILES_TO_DELETE,
- * auto-create that array if necessary.  Return an open file stream to
- * the new file in *STREAM allocated in POOL.
+ * auto-create that array if necessary.  Return an open file *FILE that is
+ * allocated in POOL.
  */
 static svn_error_t *
-repack_stream_open(svn_stream_t **stream,
-                   svn_fs_t *fs,
-                   packed_revprops_t *revprops,
-                   int start,
-                   int end,
-                   apr_array_header_t **files_to_delete,
-                   apr_pool_t *pool)
+repack_file_open(apr_file_t **file,
+                 svn_fs_t *fs,
+                 packed_revprops_t *revprops,
+                 int start,
+                 int end,
+                 apr_array_header_t **files_to_delete,
+                 apr_pool_t *pool)
 {
   apr_int64_t tag;
   const char *tag_string;
   svn_string_t *new_filename;
   int i;
-  apr_file_t *file;
   int manifest_offset
     = (int)(revprops->start_revision - revprops->manifest_start);
 
@@ -874,12 +877,11 @@ repack_stream_open(svn_stream_t **stream
     APR_ARRAY_IDX(revprops->manifest, i + manifest_offset, const char*)
       = new_filename->data;
 
-  /* create a file stream for the new file */
-  SVN_ERR(svn_io_file_open(&file, svn_dirent_join(revprops->folder,
-                                                  new_filename->data,
-                                                  pool),
+  /* open the file */
+  SVN_ERR(svn_io_file_open(file, svn_dirent_join(revprops->folder,
+                                                 new_filename->data,
+                                                 pool),
                            APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pool));
-  *stream = svn_stream_from_aprfile2(file, FALSE, pool);
 
   return SVN_NO_ERROR;
 }
@@ -903,6 +905,7 @@ write_packed_revprop(const char **final_
   packed_revprops_t *revprops;
   apr_int64_t generation = 0;
   svn_stream_t *stream;
+  apr_file_t *file;
   svn_stringbuf_t *serialized;
   apr_off_t new_total_size;
   int changed_index;
@@ -933,11 +936,11 @@ write_packed_revprop(const char **final_
 
       *final_path = svn_dirent_join(revprops->folder, revprops->filename,
                                     pool);
-      SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
-                                     svn_io_file_del_none, pool, pool));
+      SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
+                                       svn_io_file_del_none, pool, pool));
       SVN_ERR(repack_revprops(fs, revprops, 0, revprops->sizes->nelts,
                               changed_index, serialized, new_total_size,
-                              stream, pool));
+                              file, pool));
     }
   else
     {
@@ -983,50 +986,51 @@ write_packed_revprop(const char **final_
       /* write the new, split files */
       if (left_count)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops, 0,
-                                     left_count, files_to_delete, pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops, 0,
+                                   left_count, files_to_delete, pool));
           SVN_ERR(repack_revprops(fs, revprops, 0, left_count,
                                   changed_index, serialized, new_total_size,
-                                  stream, pool));
+                                  file, pool));
         }
 
       if (left_count + right_count < revprops->sizes->nelts)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops, changed_index,
-                                     changed_index + 1, files_to_delete,
-                                     pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops, changed_index,
+                                   changed_index + 1, files_to_delete,
+                                   pool));
           SVN_ERR(repack_revprops(fs, revprops, changed_index,
                                   changed_index + 1,
                                   changed_index, serialized, new_total_size,
-                                  stream, pool));
+                                  file, pool));
         }
 
       if (right_count)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops,
-                                     revprops->sizes->nelts - right_count,
-                                     revprops->sizes->nelts,
-                                     files_to_delete, pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops,
+                                   revprops->sizes->nelts - right_count,
+                                   revprops->sizes->nelts,
+                                   files_to_delete, pool));
           SVN_ERR(repack_revprops(fs, revprops,
                                   revprops->sizes->nelts - right_count,
                                   revprops->sizes->nelts, changed_index,
-                                  serialized, new_total_size, stream,
+                                  serialized, new_total_size, file,
                                   pool));
         }
 
       /* write the new manifest */
       *final_path = svn_dirent_join(revprops->folder, PATH_MANIFEST, pool);
-      SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
-                                     svn_io_file_del_none, pool, pool));
-
+      SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
+                                       svn_io_file_del_none, pool, pool));
+      stream = svn_stream_from_aprfile2(file, TRUE, pool);
       for (i = 0; i < revprops->manifest->nelts; ++i)
         {
           const char *filename = APR_ARRAY_IDX(revprops->manifest, i,
                                                const char*);
           SVN_ERR(svn_stream_printf(stream, pool, "%s\n", filename));
         }
-
       SVN_ERR(svn_stream_close(stream));
+      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+      SVN_ERR(svn_io_file_close(file, pool));
     }
 
   return SVN_NO_ERROR;
@@ -1165,7 +1169,6 @@ svn_fs_fs__copy_revprops(const char *pac
   apr_file_t *pack_file;
   svn_revnum_t rev;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  svn_stream_t *stream;
 
   /* create empty data buffer and a write stream on top of it */
   svn_stringbuf_t *uncompressed
@@ -1189,6 +1192,7 @@ svn_fs_fs__copy_revprops(const char *pac
   for (rev = start_rev; rev <= end_rev; rev++)
     {
       const char *path;
+      svn_stream_t *stream;
 
       svn_pool_clear(iterpool);
 
@@ -1207,12 +1211,14 @@ svn_fs_fs__copy_revprops(const char *pac
   SVN_ERR(svn_stream_close(pack_stream));
 
   /* compress the content (or just store it for COMPRESSION_LEVEL 0) */
-  SVN_ERR(svn__compress(uncompressed, compressed, compression_level));
+  SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
+                        compressed, compression_level));
 
   /* write the pack file content to disk */
-  stream = svn_stream_from_aprfile2(pack_file, FALSE, scratch_pool);
-  SVN_ERR(svn_stream_write(stream, compressed->data, &compressed->len));
-  SVN_ERR(svn_stream_close(stream));
+  SVN_ERR(svn_io_file_write_full(pack_file, compressed->data, compressed->len,
+                                 NULL, scratch_pool));
+  SVN_ERR(svn_io_file_flush_to_disk(pack_file, scratch_pool));
+  SVN_ERR(svn_io_file_close(pack_file, scratch_pool));
 
   svn_pool_destroy(iterpool);
 
@@ -1231,6 +1237,7 @@ svn_fs_fs__pack_revprops_shard(const cha
                                apr_pool_t *scratch_pool)
 {
   const char *manifest_file_path, *pack_filename = NULL;
+  apr_file_t *manifest_file;
   svn_stream_t *manifest_stream;
   svn_revnum_t start_rev, end_rev, rev;
   apr_off_t total_size;
@@ -1247,8 +1254,12 @@ svn_fs_fs__pack_revprops_shard(const cha
 
   /* Create the new directory and manifest file stream. */
   SVN_ERR(svn_io_dir_make(pack_file_dir, APR_OS_DEFAULT, scratch_pool));
-  SVN_ERR(svn_stream_open_writable(&manifest_stream, manifest_file_path,
-                                   scratch_pool, scratch_pool));
+
+  SVN_ERR(svn_io_file_open(&manifest_file, manifest_file_path,
+                           APR_WRITE | APR_BUFFERED | APR_CREATE | APR_EXCL,
+                           APR_OS_DEFAULT, scratch_pool));
+  manifest_stream = svn_stream_from_aprfile2(manifest_file, TRUE,
+                                             scratch_pool);
 
   /* revisions to handle. Special case: revision 0 */
   start_rev = (svn_revnum_t) (shard * max_files_per_dir);
@@ -1315,8 +1326,10 @@ svn_fs_fs__pack_revprops_shard(const cha
                                      compression_level, cancel_func,
                                      cancel_baton, iterpool));
 
-  /* flush the manifest file and update permissions */
+  /* flush the manifest file to disk and update permissions */
   SVN_ERR(svn_stream_close(manifest_stream));
+  SVN_ERR(svn_io_file_flush_to_disk(manifest_file, iterpool));
+  SVN_ERR(svn_io_file_close(manifest_file, iterpool));
   SVN_ERR(svn_io_copy_perms(shard_path, pack_file_dir, iterpool));
 
   svn_pool_destroy(iterpool);
@@ -1347,7 +1360,7 @@ svn_fs_fs__delete_revprops_shard(const c
                                  apr_psprintf(iterpool, "%d", i),
                                  iterpool);
           if (cancel_func)
-            SVN_ERR((*cancel_func)(cancel_baton));
+            SVN_ERR(cancel_func(cancel_baton));
 
           SVN_ERR(svn_io_remove_file2(path, TRUE, iterpool));
         }

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/stats.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/stats.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/stats.c Thu Jun 18 10:35:30 2015
@@ -176,23 +176,6 @@ typedef struct query_t
   void *cancel_baton;
 } query_t;
 
-/* Return the length of REV_FILE in *FILE_SIZE.
- * Use SCRATCH_POOL for temporary allocations.
- */
-static svn_error_t *
-get_file_size(apr_off_t *file_size,
-              svn_fs_fs__revision_file_t *rev_file,
-              apr_pool_t *scratch_pool)
-{
-  apr_finfo_t finfo;
-
-  SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE, rev_file->file,
-                               scratch_pool));
-
-  *file_size = finfo.size;
-  return SVN_NO_ERROR;
-}
-
 /* Initialize the LARGEST_CHANGES member in STATS with a capacity of COUNT
  * entries.  Allocate the result in RESULT_POOL.
  */
@@ -436,8 +419,7 @@ parse_representation(rep_stats_t **repre
        */
       result = apr_pcalloc(result_pool, sizeof(*result));
       result->revision = rep->revision;
-      result->expanded_size = (rep->expanded_size ? rep->expanded_size
-                                                  : rep->size);
+      result->expanded_size = rep->expanded_size;
       result->offset = (apr_off_t)rep->item_index;
       result->size = rep->size;
 
@@ -729,12 +711,12 @@ read_phys_pack_file(query_t *query,
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   int i;
-  apr_off_t file_size = 0;
+  svn_filesize_t file_size = 0;
   svn_fs_fs__revision_file_t *rev_file;
 
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, query->fs, base,
                                            scratch_pool, scratch_pool));
-  SVN_ERR(get_file_size(&file_size, rev_file, scratch_pool));
+  SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool));
 
   /* process each revision in the pack file */
   for (i = 0; i < query->shard_size; ++i)
@@ -798,7 +780,7 @@ read_phys_revision_file(query_t *query,
                         apr_pool_t *scratch_pool)
 {
   revision_info_t *info = apr_pcalloc(result_pool, sizeof(*info));
-  apr_off_t file_size = 0;
+  svn_filesize_t file_size = 0;
   svn_fs_fs__revision_file_t *rev_file;
 
   /* cancellation support */
@@ -808,7 +790,7 @@ read_phys_revision_file(query_t *query,
   /* read the whole pack file into memory */
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, query->fs, revision,
                                            scratch_pool, scratch_pool));
-  SVN_ERR(get_file_size(&file_size, rev_file, scratch_pool));
+  SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool));
 
   /* create the revision info for the current rev */
   info->representations = apr_array_make(result_pool, 4, sizeof(rep_stats_t*));

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/structure?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/structure Thu Jun 18 10:35:30 2015
@@ -198,9 +198,9 @@ Shard packing:
     (i.e. same min packed revision)
 
 Addressing:
-  Format 1-6: Physical addressing; uses fixed positions within a rev file
+  Format 1+: Physical addressing; uses fixed positions within a rev file
   Format 7+:  Logical addressing; uses item index that will be translated
-    on-the-fly to the actual rev / pack file location
+    on-the-fly to the actual rev / pack file location (default for 7+ created)
 
 Repository IDs:
   Format 1+:  The first line of db/uuid contains the repository UUID
@@ -525,6 +525,7 @@ A revision file contains a concatenation
   * Text and property representations
   * Node-revisions
   * The changed-path data
+  * Two offsets at the very end (physical addressing only)
   * Index data (logical addressing only)
   * Revision / pack file footer (logical addressing only)
 
@@ -578,8 +579,9 @@ defined:
     representations may not be handled correctly by SVN before 1.7.20,
     1.8.12 and 1.9.0, if they have 0 <size> fields for non-empty contents.
     Releases 1.8.0 through 1.8.11 may have falsely created instances of
-    that (see issue #4554).  Finally, 0 <size> fields are NEVER legal for
-    DELTA representations.
+    that (see issue #4554).  Finally, 0 <size> fields are only ever legal
+    for DELTA representations if the reconstructed full-text is actually
+    empty.
 
 The predecessor of a node-rev crosses both soft and true copies;
 together with the count field, it allows efficient determination of
@@ -756,6 +758,9 @@ Format 7 introduces logical addressing t
 to be translated / mapped to physical rev / pack file offsets.
 These indexes are appended to the respective rev / pack file.
 
+The indexes map (revision number, item-index) pairs to absolute file offsets
+and absolute file offsets to (revision number, item-index, item metadata).
+
 Details of the binary format used by these index files can be
 found in structure-indexes.
 

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/structure-indexes
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/structure-indexes?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/structure-indexes (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/structure-indexes Thu Jun 18 10:35:30 2015
@@ -13,10 +13,10 @@ to read and cache any data without trave
 
 Rev and pack files are immutable, so the same is true for index data.
 During a transaction or while packing a file, a proto index file gets
-written (actually, one log-to-phys and one phys-to-log).  Its format is
-a simple concatenation of runtime structs and as such, an implementation
-detail subject to change.  A proto index basically aggregates all the
-information that must later be transformed into the final index.
+written (actually, one log-to-phys and one phys-to-log).  They use a
+simpler, less compact format with fixed record lengths.  A proto index
+basically aggregates all the information that must later be transformed
+into the final index.
 
 
 General design concerns
@@ -192,11 +192,11 @@ at the beginning of the file is optional
 
   <bof>         /* begin of proto index file for revision r and following */
   (0, 0)        /* mark start of revision r, optional for first rev */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   (0, 0)        /* mark start of revision r + 1 */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   (0, 0)        /* mark start of revision r + 2 */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   ...
   <eof>         /* end of file. */
 
@@ -343,10 +343,12 @@ For performance reasons we use a modifie
 
   h0 = fnv_1a([b0 b4 b8 ..]), ..., h3 = fnv_1a([b3 b7 b11 ..])
 
-* combine the big endian representation of these checksums plus the
-  remnant of the original stream into a 12 to 15 byte long intermediate
+* concatenate the big endian representation of these checksums (4 bytes
+  each) plus the remnant of the original stream into a 16 to 19 byte long
+  intermediate:
 
-  [i0 .. iK], 12 <= K+1 <= 15
+  [i0 .. iK] = [big-endian(h0) ... big-endian(h3) remnant ], 16 <= K+1 <= 19
 
-* FNV checksum = fnv_1a([i0 .. iK]) in big endian representation
+* fold the variable-length intermediate into a compact 32 bit checksum:
 
+  FNV checksum = fnv_1a([i0 .. iK])

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/temp_serializer.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/temp_serializer.c Thu Jun 18 10:35:30 2015
@@ -153,6 +153,10 @@ typedef struct dir_data_t
    * (it's int because the directory is an APR array) */
   int count;
 
+  /** Current length of the in-txn in-disk representation of the directory.
+   * SVN_INVALID_FILESIZE if unknown (i.e. committed data). */
+  svn_filesize_t txn_filesize;
+
   /* number of unused dir entry buckets in the index */
   apr_size_t over_provision;
 
@@ -198,15 +202,16 @@ serialize_dir_entry(svn_temp_serializer_
   svn_temp_serializer__pop(context);
 }
 
-/* Utility function to serialize the ENTRIES into a new serialization
+/* Utility function to serialize the DIR into a new serialization
  * context to be returned. Allocation will be made form POOL.
  */
 static svn_temp_serializer__context_t *
-serialize_dir(apr_array_header_t *entries, apr_pool_t *pool)
+serialize_dir(svn_fs_fs__dir_data_t *dir, apr_pool_t *pool)
 {
   dir_data_t dir_data;
   int i = 0;
   svn_temp_serializer__context_t *context;
+  apr_array_header_t *entries = dir->entries;
 
   /* calculate sizes */
   int count = entries->nelts;
@@ -216,6 +221,7 @@ serialize_dir(apr_array_header_t *entrie
 
   /* copy the hash entries to an auxiliary struct of known layout */
   dir_data.count = count;
+  dir_data.txn_filesize = dir->txn_filesize;
   dir_data.over_provision = over_provision;
   dir_data.operations = 0;
   dir_data.entries = apr_palloc(pool, entries_len);
@@ -252,24 +258,29 @@ serialize_dir(apr_array_header_t *entrie
   return context;
 }
 
-/* Utility function to reconstruct a dir entries array from serialized data
+/* Utility function to reconstruct a dir entries struct from serialized data
  * in BUFFER and DIR_DATA. Allocation will be made form POOL.
  */
-static apr_array_header_t *
+static svn_fs_fs__dir_data_t *
 deserialize_dir(void *buffer, dir_data_t *dir_data, apr_pool_t *pool)
 {
-  apr_array_header_t *result
-    = apr_array_make(pool, dir_data->count, sizeof(svn_fs_dirent_t *));
+  svn_fs_fs__dir_data_t *result;
   apr_size_t i;
   apr_size_t count;
   svn_fs_dirent_t *entry;
   svn_fs_dirent_t **entries;
 
+  /* Construct empty directory object. */
+  result = apr_pcalloc(pool, sizeof(*result));
+  result->entries
+    = apr_array_make(pool, dir_data->count, sizeof(svn_fs_dirent_t *));
+  result->txn_filesize = dir_data->txn_filesize;
+
   /* resolve the reference to the entries array */
   svn_temp_deserializer__resolve(buffer, (void **)&dir_data->entries);
   entries = dir_data->entries;
 
-  /* fixup the references within each entry and add it to the hash */
+  /* fixup the references within each entry and add it to the RESULT */
   for (i = 0, count = dir_data->count; i < count; ++i)
     {
       svn_temp_deserializer__resolve(entries, (void **)&entries[i]);
@@ -280,7 +291,7 @@ deserialize_dir(void *buffer, dir_data_t
       svn_fs_fs__id_deserialize(entry, (svn_fs_id_t **)&entry->id);
 
       /* add the entry to the hash */
-      APR_ARRAY_PUSH(result, svn_fs_dirent_t *) = entry;
+      APR_ARRAY_PUSH(result->entries, svn_fs_dirent_t *) = entry;
     }
 
   /* return the now complete hash */
@@ -496,8 +507,7 @@ svn_fs_fs__serialize_manifest(void **dat
   apr_array_header_t *manifest = in;
 
   *data_len = sizeof(apr_off_t) *manifest->nelts;
-  *data = apr_palloc(pool, *data_len);
-  memcpy(*data, manifest->elts, *data_len);
+  *data = apr_pmemdup(pool, manifest->elts, *data_len);
 
   return SVN_NO_ERROR;
 }
@@ -764,7 +774,7 @@ svn_fs_fs__serialize_dir_entries(void **
                                  void *in,
                                  apr_pool_t *pool)
 {
-  apr_array_header_t *dir = in;
+  svn_fs_fs__dir_data_t *dir = in;
 
   /* serialize the dir content into a new serialization context
    * and return the serialized data */
@@ -803,6 +813,20 @@ svn_fs_fs__get_sharded_offset(void **out
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_fs__extract_dir_filesize(void **out,
+                                const void *data,
+                                apr_size_t data_len,
+                                void *baton,
+                                apr_pool_t *pool)
+{
+  const dir_data_t *dir_data = data;
+
+  *(svn_filesize_t *)out = dir_data->txn_filesize;
+
+  return SVN_NO_ERROR;
+}
+
 /* Utility function that returns the lowest index of the first entry in
  * *ENTRIES that points to a dir entry with a name equal or larger than NAME.
  * If an exact match has been found, *FOUND will be set to TRUE. COUNT is
@@ -857,7 +881,7 @@ svn_fs_fs__extract_dir_entry(void **out,
                              apr_pool_t *pool)
 {
   const dir_data_t *dir_data = data;
-  const char* name = baton;
+  const extract_dir_entry_baton_t *entry_baton = baton;
   svn_boolean_t found;
 
   /* resolve the reference to the entries array */
@@ -870,13 +894,14 @@ svn_fs_fs__extract_dir_entry(void **out,
 
   /* binary search for the desired entry by name */
   apr_size_t pos = find_entry((svn_fs_dirent_t **)entries,
-                              name,
+                              entry_baton->name,
                               dir_data->count,
                               &found);
 
-  /* de-serialize that entry or return NULL, if no match has been found */
+  /* de-serialize that entry or return NULL, if no match has been found.
+   * Be sure to check that the directory contents is still up-to-date. */
   *out = NULL;
-  if (found)
+  if (found && dir_data->txn_filesize == entry_baton->txn_filesize)
     {
       const svn_fs_dirent_t *source =
           svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]);
@@ -889,8 +914,7 @@ svn_fs_fs__extract_dir_entry(void **out,
       apr_size_t size = lengths[pos];
 
       /* copy & deserialize the entry */
-      svn_fs_dirent_t *new_entry = apr_palloc(pool, size);
-      memcpy(new_entry, source, size);
+      svn_fs_dirent_t *new_entry = apr_pmemdup(pool, source, size);
 
       svn_temp_deserializer__resolve(new_entry, (void **)&new_entry->name);
       svn_fs_fs__id_deserialize(new_entry, (svn_fs_id_t **)&new_entry->id);
@@ -911,31 +935,34 @@ slowly_replace_dir_entry(void **data,
 {
   replace_baton_t *replace_baton = (replace_baton_t *)baton;
   dir_data_t *dir_data = (dir_data_t *)*data;
-  apr_array_header_t *dir;
+  svn_fs_fs__dir_data_t *dir;
   int idx = -1;
   svn_fs_dirent_t *entry;
+  apr_array_header_t *entries;
 
   SVN_ERR(svn_fs_fs__deserialize_dir_entries((void **)&dir,
                                              *data,
                                              dir_data->len,
                                              pool));
 
-  entry = svn_fs_fs__find_dir_entry(dir, replace_baton->name, &idx);
+  entries = dir->entries;
+  entry = svn_fs_fs__find_dir_entry(entries, replace_baton->name, &idx);
 
   /* Replacement or removal? */
   if (replace_baton->new_entry)
     {
       /* Replace ENTRY with / insert the NEW_ENTRY */
       if (entry)
-        APR_ARRAY_IDX(dir, idx, svn_fs_dirent_t *) = replace_baton->new_entry;
+        APR_ARRAY_IDX(entries, idx, svn_fs_dirent_t *)
+          = replace_baton->new_entry;
       else
-        svn_sort__array_insert(dir, &replace_baton->new_entry, idx);
+        svn_sort__array_insert(entries, &replace_baton->new_entry, idx);
     }
   else
     {
       /* Remove the old ENTRY. */
       if (entry)
-        svn_sort__array_delete(dir, idx, 1);
+        svn_sort__array_delete(entries, idx, 1);
     }
 
   return svn_fs_fs__serialize_dir_entries(data, data_len, dir, pool);
@@ -957,6 +984,12 @@ svn_fs_fs__replace_dir_entry(void **data
 
   svn_temp_serializer__context_t *context;
 
+  /* update the cached file length info.
+   * Because we are writing to the cache, it is fair to assume that the
+   * caller made sure that the current contents is consistent with the
+   * previous state of the directory file. */
+  dir_data->txn_filesize = replace_baton->txn_filesize;
+
   /* after quite a number of operations, let's re-pack everything.
    * This is to limit the number of wasted space as we cannot overwrite
    * existing data but must always append. */

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/temp_serializer.h?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/temp_serializer.h (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/temp_serializer.h Thu Jun 18 10:35:30 2015
@@ -192,7 +192,7 @@ svn_fs_fs__deserialize_node_revision(voi
                                      apr_pool_t *pool);
 
 /**
- * Implements #svn_cache__serialize_func_t for a directory contents array
+ * Implements #svn_cache__serialize_func_t for a #svn_fs_fs__dir_data_t
  */
 svn_error_t *
 svn_fs_fs__serialize_dir_entries(void **data,
@@ -201,7 +201,7 @@ svn_fs_fs__serialize_dir_entries(void **
                                  apr_pool_t *pool);
 
 /**
- * Implements #svn_cache__deserialize_func_t for a directory contents array
+ * Implements #svn_cache__deserialize_func_t for a #svn_fs_fs__dir_data_t
  */
 svn_error_t *
 svn_fs_fs__deserialize_dir_entries(void **out,
@@ -221,9 +221,38 @@ svn_fs_fs__get_sharded_offset(void **out
                               apr_pool_t *pool);
 
 /**
+ * Implements #svn_cache__partial_getter_func_t.
+ * Set (svn_filesize_t) @a *out to the filesize info stored with the
+ * serialized directory in @a data of @a data_len.  @a baton is unused.
+ */
+svn_error_t *
+svn_fs_fs__extract_dir_filesize(void **out,
+                                const void *data,
+                                apr_size_t data_len,
+                                void *baton,
+                                apr_pool_t *pool);
+
+/**
+ * Describes the entry to be found in a directory: Identifies the entry
+ * by @a name and requires the directory file size to be @a filesize.
+ */
+typedef struct extract_dir_entry_baton_t
+{
+  /** name of the directory entry to return */
+  const char *name;
+
+  /** Current length of the in-txn in-disk representation of the directory.
+   * SVN_INVALID_FILESIZE if unknown. */
+  svn_filesize_t txn_filesize;
+} extract_dir_entry_baton_t;
+
+
+/**
  * Implements #svn_cache__partial_getter_func_t for a single
  * #svn_fs_dirent_t within a serialized directory contents hash,
- * identified by its name (const char @a *baton).
+ * identified by its name (in (extract_dir_entry_baton_t *) @a *baton).
+ * If the filesize specified in the baton does not match the cached
+ * value for this directory, @a *out will be NULL as well.
  */
 svn_error_t *
 svn_fs_fs__extract_dir_entry(void **out,
@@ -236,7 +265,10 @@ svn_fs_fs__extract_dir_entry(void **out,
  * Describes the change to be done to a directory: Set the entry
  * identify by @a name to the value @a new_entry. If the latter is
  * @c NULL, the entry shall be removed if it exists. Otherwise it
- * will be replaced or automatically added, respectively.
+ * will be replaced or automatically added, respectively.  The
+ * @a filesize allows readers to identify stale cache data (e.g.
+ * due to concurrent access to txns); writers use it to update the
+ * cached file size info.
  */
 typedef struct replace_baton_t
 {
@@ -245,6 +277,10 @@ typedef struct replace_baton_t
 
   /** directory entry to insert instead */
   svn_fs_dirent_t *new_entry;
+
+  /** Current length of the in-txn in-disk representation of the directory.
+   * SVN_INVALID_FILESIZE if unknown. */
+  svn_filesize_t txn_filesize;
 } replace_baton_t;
 
 /**

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/transaction.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/transaction.c Thu Jun 18 10:35:30 2015
@@ -25,6 +25,7 @@
 #include <assert.h>
 #include <apr_sha1.h>
 
+#include "svn_error_codes.h"
 #include "svn_hash.h"
 #include "svn_props.h"
 #include "svn_sorts.h"
@@ -1127,6 +1128,7 @@ get_txn_proplist(apr_hash_t *proplist,
                  apr_pool_t *pool)
 {
   svn_stream_t *stream;
+  svn_error_t *err;
 
   /* Check for issue #3696. (When we find and fix the cause, we can change
    * this to an assertion.) */
@@ -1140,7 +1142,14 @@ get_txn_proplist(apr_hash_t *proplist,
                                    pool, pool));
 
   /* Read in the property list. */
-  SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
+  err = svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool);
+  if (err)
+    {
+      err = svn_error_compose_create(err, svn_stream_close(stream));
+      return svn_error_quick_wrapf(err,
+               _("malformed property list in transaction '%s'"),
+               path_txn_props(fs, txn_id, pool));
+    }
 
   return svn_stream_close(stream);
 }
@@ -1515,22 +1524,80 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
     }
   else
     {
+      const svn_io_dirent2_t *dirent;
+
       /* The directory rep is already mutable, so just open it for append. */
       SVN_ERR(svn_io_file_open(&file, filename, APR_WRITE | APR_APPEND,
-                               APR_OS_DEFAULT, pool));
-      out = svn_stream_from_aprfile2(file, TRUE, pool);
+                               APR_OS_DEFAULT, subpool));
+      out = svn_stream_from_aprfile2(file, TRUE, subpool);
+
+      /* If the cache contents is stale, drop it.
+       *
+       * Note that the directory file is append-only, i.e. if the size
+       * did not change, the contents didn't either. */
+      if (ffd->txn_dir_cache)
+        {
+          const char *key
+            = svn_fs_fs__id_unparse(parent_noderev->id, subpool)->data;
+          svn_boolean_t found;
+          svn_filesize_t filesize;
+
+          /* Get the file size that corresponds to the cached contents
+           * (if any). */
+          SVN_ERR(svn_cache__get_partial((void **)&filesize, &found,
+                                         ffd->txn_dir_cache, key,
+                                         svn_fs_fs__extract_dir_filesize,
+                                         NULL, subpool));
+
+          /* File size info still matches?
+           * If not, we need to drop the cache entry. */
+          if (found)
+            {
+              SVN_ERR(svn_io_stat_dirent2(&dirent, filename, FALSE, FALSE,
+                                          subpool, subpool));
+
+              if (filesize != dirent->filesize)
+                SVN_ERR(svn_cache__set(ffd->txn_dir_cache, key, NULL,
+                                       subpool));
+            }
+        }
     }
 
+  /* Append an incremental hash entry for the entry change. */
+  if (id)
+    {
+      svn_fs_dirent_t entry;
+      entry.name = name;
+      entry.id = id;
+      entry.kind = kind;
+
+      SVN_ERR(unparse_dir_entry(&entry, out, subpool));
+    }
+  else
+    {
+      SVN_ERR(svn_stream_printf(out, subpool, "D %" APR_SIZE_T_FMT "\n%s\n",
+                                strlen(name), name));
+    }
+
+  /* Flush APR buffers. */
+  SVN_ERR(svn_io_file_close(file, subpool));
+  svn_pool_clear(subpool);
+
   /* if we have a directory cache for this transaction, update it */
   if (ffd->txn_dir_cache)
     {
-      /* build parameters: (name, new entry) pair */
+      /* build parameters: name, new entry, new file size  */
       const char *key =
           svn_fs_fs__id_unparse(parent_noderev->id, subpool)->data;
       replace_baton_t baton;
 
+      const svn_io_dirent2_t *dirent;
+      SVN_ERR(svn_io_stat_dirent2(&dirent, filename, FALSE, FALSE,
+                                  subpool, subpool));
+
       baton.name = name;
       baton.new_entry = NULL;
+      baton.txn_filesize = dirent->filesize;
 
       if (id)
         {
@@ -1545,25 +1612,7 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
                                      svn_fs_fs__replace_dir_entry, &baton,
                                      subpool));
     }
-  svn_pool_clear(subpool);
-
-  /* Append an incremental hash entry for the entry change. */
-  if (id)
-    {
-      svn_fs_dirent_t entry;
-      entry.name = name;
-      entry.id = id;
-      entry.kind = kind;
-
-      SVN_ERR(unparse_dir_entry(&entry, out, subpool));
-    }
-  else
-    {
-      SVN_ERR(svn_stream_printf(out, subpool, "D %" APR_SIZE_T_FMT "\n%s\n",
-                                strlen(name), name));
-    }
 
-  SVN_ERR(svn_io_file_close(file, subpool));
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
@@ -1963,9 +2012,7 @@ choose_delta_base(representation_t **rep
 
       /* Very short rep bases are simply not worth it as we are unlikely
        * to re-coup the deltification space overhead of 20+ bytes. */
-      svn_filesize_t rep_size = (*rep)->expanded_size
-                              ? (*rep)->expanded_size
-                              : (*rep)->size;
+      svn_filesize_t rep_size = (*rep)->expanded_size;
       if (rep_size < 64)
         {
           *rep = NULL;
@@ -2118,7 +2165,7 @@ rep_write_get_baton(struct rep_write_bat
 }
 
 /* For REP->SHA1_CHECKSUM, try to find an already existing representation
-   in FS and return it in *OUT_REP.  If no such representation exists or
+   in FS and return it in *OLD_REP.  If no such representation exists or
    if rep sharing has been disabled for FS, NULL will be returned.  Since
    there may be new duplicate representations within the same uncommitted
    revision, those can be passed in REPS_HASH (maps a sha1 digest onto
@@ -2144,7 +2191,7 @@ get_shared_rep(representation_t **old_re
 
   /* Check and see if we already have a representation somewhere that's
      identical to the one we just wrote out.  Start with the hash lookup
-     because it is cheepest. */
+     because it is cheapest. */
   if (reps_hash)
     *old_rep = apr_hash_get(reps_hash,
                             rep->sha1_digest,
@@ -2213,12 +2260,37 @@ get_shared_rep(representation_t **old_re
   if (!*old_rep)
     return SVN_NO_ERROR;
 
-  /* We don't want 0-length PLAIN representations to replace non-0-length
-     ones (see issue #4554).  Also, this doubles as a simple guard against
-     general rep-cache induced corruption. */
-  if (   ((*old_rep)->expanded_size != rep->expanded_size)
-      || ((*old_rep)->size != rep->size))
+  /* A simple guard against general rep-cache induced corruption. */
+  if ((*old_rep)->expanded_size != rep->expanded_size)
     {
+      /* Make the problem show up in the server log.
+
+         Because not sharing reps is always a safe option,
+         terminating the request would be inappropriate.
+       */
+      svn_checksum_t checksum;
+      checksum.digest = rep->sha1_digest;
+      checksum.kind = svn_checksum_sha1;
+
+      err = svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                              "Rep size %s mismatches rep-cache.db value %s "
+                              "for SHA1 %s.\n"
+                              "You should delete the rep-cache.db and "
+                              "verify the repository. The cached rep will "
+                              "not be shared.",
+                              apr_psprintf(scratch_pool,
+                                           "%" SVN_FILESIZE_T_FMT,
+                                           rep->expanded_size),
+                              apr_psprintf(scratch_pool,
+                                           "%" SVN_FILESIZE_T_FMT,
+                                           (*old_rep)->expanded_size),
+                              svn_checksum_to_cstring_display(&checksum,
+                                                              scratch_pool));
+
+      (fs->warning)(fs->warning_baton, err);
+      svn_error_clear(err);
+
+      /* Ignore the shared rep. */
       *old_rep = NULL;
     }
   else
@@ -2553,6 +2625,7 @@ write_container_rep(representation_t *re
 
   /* Check and see if we already have a representation somewhere that's
      identical to the one we just wrote out. */
+  rep->expanded_size = whb->size;
   SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, scratch_pool,
                          scratch_pool));
 
@@ -2588,7 +2661,6 @@ write_container_rep(representation_t *re
 
       /* update the representation */
       rep->size = whb->size;
-      rep->expanded_size = whb->size;
     }
 
   return SVN_NO_ERROR;
@@ -2692,6 +2764,7 @@ write_container_delta_rep(representation
 
   /* Check and see if we already have a representation somewhere that's
      identical to the one we just wrote out. */
+  rep->expanded_size = whb->size;
   SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, scratch_pool,
                          scratch_pool));
 
@@ -2727,7 +2800,6 @@ write_container_delta_rep(representation
       SVN_ERR(store_p2l_index_entry(fs, &rep->txn_id, &entry, scratch_pool));
 
       /* update the representation */
-      rep->expanded_size = whb->size;
       rep->size = rep_end - delta_start;
     }
 

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/tree.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/tree.c Thu Jun 18 10:35:30 2015
@@ -1328,8 +1328,8 @@ fs_node_relation(svn_fs_node_relation_t
                  apr_pool_t *pool)
 {
   dag_node_t *node;
-  const svn_fs_id_t *id;
-  svn_fs_fs__id_part_t rev_item_a, rev_item_b, node_id_a, node_id_b;
+  const svn_fs_id_t *id_a, *id_b;
+  svn_fs_fs__id_part_t node_id_a, node_id_b;
 
   /* Root paths are a common special case. */
   svn_boolean_t a_is_root_dir
@@ -1337,6 +1337,11 @@ fs_node_relation(svn_fs_node_relation_t
   svn_boolean_t b_is_root_dir
     = (path_b[0] == '\0') || ((path_b[0] == '/') && (path_b[1] == '\0'));
 
+  /* Another useful thing to know: Both are txns but not the same txn. */
+  svn_boolean_t different_txn
+    = root_a->is_txn_root && root_b->is_txn_root
+        && strcmp(root_a->txn, root_b->txn);
+
   /* Path from different repository are always unrelated. */
   if (root_a->fs != root_b->fs)
     {
@@ -1344,20 +1349,15 @@ fs_node_relation(svn_fs_node_relation_t
       return SVN_NO_ERROR;
     }
 
-  /* Nodes from different transactions are never related. */
-  if (root_a->is_txn_root && root_b->is_txn_root
-      && strcmp(root_a->txn, root_b->txn))
-    {
-      *relation = svn_fs_node_unrelated;
-      return SVN_NO_ERROR;
-    }
-
   /* Are both (!) root paths? Then, they are related and we only test how
    * direct the relation is. */
   if (a_is_root_dir && b_is_root_dir)
     {
-      *relation = root_a->rev == root_b->rev
-                ? svn_fs_node_same
+      /* For txn roots, root->REV is the base revision of that TXN. */
+      *relation = (   (root_a->rev == root_b->rev)
+                   && (root_a->is_txn_root == root_b->is_txn_root)
+                   && !different_txn)
+                ? svn_fs_node_unchanged
                 : svn_fs_node_common_ancestor;
       return SVN_NO_ERROR;
     }
@@ -1365,21 +1365,35 @@ fs_node_relation(svn_fs_node_relation_t
   /* We checked for all separations between ID spaces (repos, txn).
    * Now, we can simply test for the ID values themselves. */
   SVN_ERR(get_dag(&node, root_a, path_a, pool));
-  id = svn_fs_fs__dag_get_id(node);
-  rev_item_a = *svn_fs_fs__id_rev_item(id);
-  node_id_a = *svn_fs_fs__id_node_id(id);
+  id_a = svn_fs_fs__dag_get_id(node);
+  node_id_a = *svn_fs_fs__id_node_id(id_a);
 
   SVN_ERR(get_dag(&node, root_b, path_b, pool));
-  id = svn_fs_fs__dag_get_id(node);
-  rev_item_b = *svn_fs_fs__id_rev_item(id);
-  node_id_b = *svn_fs_fs__id_node_id(id);
-
-  if (svn_fs_fs__id_part_eq(&rev_item_a, &rev_item_b))
-    *relation = svn_fs_node_same;
-  else if (svn_fs_fs__id_part_eq(&node_id_a, &node_id_b))
-    *relation = svn_fs_node_common_ancestor;
+  id_b = svn_fs_fs__dag_get_id(node);
+  node_id_b = *svn_fs_fs__id_node_id(id_b);
+
+  /* Noderevs from different nodes are unrelated. */
+  if (!svn_fs_fs__id_part_eq(&node_id_a, &node_id_b))
+    {
+      *relation = svn_fs_node_unrelated;
+      return SVN_NO_ERROR;
+    }
+
+  /* Noderevs have the same node-ID now. So, they *seem* to be related.
+   *
+   * Special case: Different txns may create the same (txn-local) node ID.
+   * These are not related to each other, nor to any other node ID so far. */
+  if (different_txn && node_id_a.revision == SVN_INVALID_REVNUM)
+    {
+      *relation = svn_fs_node_unrelated;
+      return SVN_NO_ERROR;
+    }
+
+  /* The noderevs are actually related.  Are they the same? */
+  if (svn_fs_fs__id_eq(id_a, id_b))
+    *relation = svn_fs_node_unchanged;
   else
-    *relation = svn_fs_node_unrelated;
+    *relation = svn_fs_node_common_ancestor;
 
   return SVN_NO_ERROR;
 }
@@ -1501,6 +1515,19 @@ fs_node_proplist(apr_hash_t **table_p,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+fs_node_has_props(svn_boolean_t *has_props,
+                  svn_fs_root_t *root,
+                  const char *path,
+                  apr_pool_t *scratch_pool)
+{
+  dag_node_t *node;
+
+  SVN_ERR(get_dag(&node, root, path, scratch_pool));
+
+  return svn_error_trace(svn_fs_fs__dag_has_props(has_props, node,
+                                                  scratch_pool));
+}
 
 static svn_error_t *
 increment_mergeinfo_up_tree(parent_path_t *pp,
@@ -2378,9 +2405,11 @@ static svn_error_t *
 fs_dir_optimal_order(apr_array_header_t **ordered_p,
                      svn_fs_root_t *root,
                      apr_hash_t *entries,
-                     apr_pool_t *pool)
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
 {
-  *ordered_p = svn_fs_fs__order_dir_entries(root->fs, entries, pool);
+  *ordered_p = svn_fs_fs__order_dir_entries(root->fs, entries, result_pool,
+                                            scratch_pool);
 
   return SVN_NO_ERROR;
 }
@@ -4222,6 +4251,7 @@ static root_vtable_t root_vtable = {
   fs_closest_copy,
   fs_node_prop,
   fs_node_proplist,
+  fs_node_has_props,
   fs_change_node_prop,
   fs_props_changed,
   fs_dir_entries,

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/util.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/util.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/util.c Thu Jun 18 10:35:30 2015
@@ -637,6 +637,22 @@ svn_fs_fs__move_into_place(const char *o
                            apr_pool_t *pool)
 {
   svn_error_t *err;
+  apr_file_t *file;
+
+#if defined(WIN32) || defined(__OS2__)
+
+  /* APR will *not* error out on Win32 if this requires a copy instead of
+     of a move. */
+  SVN_ERR(svn_io_file_rename(old_filename, new_filename, pool));
+
+  /* Flush the target of the copy to disk. */
+  SVN_ERR(svn_io_file_open(&file, new_filename, APR_WRITE,
+                           APR_OS_DEFAULT, pool));
+  SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
+
+  /* Copying permissions is a no-op on WIN32. */
+#else
 
   SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, pool));
 
@@ -644,8 +660,6 @@ svn_fs_fs__move_into_place(const char *o
   err = svn_io_file_rename(old_filename, new_filename, pool);
   if (err && APR_STATUS_IS_EXDEV(err->apr_err))
     {
-      apr_file_t *file;
-
       /* Can't rename across devices; fall back to copying. */
       svn_error_clear(err);
       err = SVN_NO_ERROR;
@@ -654,26 +668,19 @@ svn_fs_fs__move_into_place(const char *o
       /* Flush the target of the copy to disk. */
       SVN_ERR(svn_io_file_open(&file, new_filename, APR_READ,
                                APR_OS_DEFAULT, pool));
-      /* ### BH: Does this really guarantee a flush of the data written
-         ### via a completely different handle on all operating systems?
-         ###
-         ### Maybe we should perform the copy ourselves instead of making
-         ### apr do that and flush the real handle? */
       SVN_ERR(svn_io_file_flush_to_disk(file, pool));
       SVN_ERR(svn_io_file_close(file, pool));
     }
   if (err)
     return svn_error_trace(err);
 
-#ifdef __linux__
+#if SVN_ON_POSIX
   {
-    /* Linux has the unusual feature that fsync() on a file is not
-       enough to ensure that a file's directory entries have been
-       flushed to disk; you have to fsync the directory as well.
+    /* On POSIX, the file name is stored in the file's directory entry.
+       Hence, we need to fsync() that directory as well.
        On other operating systems, we'd only be asking for trouble
        by trying to open and fsync a directory. */
     const char *dirname;
-    apr_file_t *file;
 
     dirname = svn_dirent_dirname(new_filename, pool);
     SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
@@ -683,6 +690,8 @@ svn_fs_fs__move_into_place(const char *o
   }
 #endif
 
+#endif /*  defined(WIN32) || defined(__OS2__) */
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/verify.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/verify.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/verify.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_fs/verify.c Thu Jun 18 10:35:30 2015
@@ -463,7 +463,8 @@ expect_buffer_nul(apr_file_t *file,
 
   /* read the whole data block; error out on failure */
   data.chunks[(size - 1)/ sizeof(apr_uint64_t)] = 0;
-  SVN_ERR(svn_io_file_read_full2(file, data.buffer, size, NULL, NULL, pool));
+  SVN_ERR(svn_io_file_read_full2(file, data.buffer, (apr_size_t)size, NULL,
+                                 NULL, pool));
 
   /* chunky check */
   for (i = 0; i < size / sizeof(apr_uint64_t); ++i)
@@ -850,13 +851,15 @@ svn_fs_fs__verify(svn_fs_t *fs,
                   apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
-  svn_revnum_t youngest = ffd->youngest_rev_cache; /* cache is current */
 
   /* Input validation. */
   if (! SVN_IS_VALID_REVNUM(start))
     start = 0;
   if (! SVN_IS_VALID_REVNUM(end))
-    end = youngest;
+    {
+      SVN_ERR(svn_fs_fs__youngest_rev(&end, fs, pool));
+    }
+
   SVN_ERR(svn_fs_fs__ensure_revision_exists(start, fs, pool));
   SVN_ERR(svn_fs_fs__ensure_revision_exists(end, fs, pool));
 

Propchange: subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Jun 18 10:35:30 2015
@@ -90,4 +90,4 @@
 /subversion/branches/verify-keep-going/subversion/libsvn_fs_x:1439280-1492639,1546002-1546110
 /subversion/branches/wc-collate-path/subversion/libsvn_fs_x:1402685-1480384
 /subversion/trunk/subversion/libsvn_fs_fs:1415133-1596500,1596567,1597414,1597989,1598273,1599140,1600872,1601633,1603485-1603487,1603499,1603605,1604128,1604188,1604413-1604414,1604416-1604417,1604421,1604442,1604700,1604717,1604720,1604726,1604755,1604794,1604802,1604824,1604836,1604844,1604902-1604903,1604911,1604925,1604933,1604947,1605059-1605060,1605064-1605065,1605068,1605071-1605073,1605075,1605123,1605188-1605189,1605191,1605197,1605444,1605633,1606132,1606142,1606144,1606514,1606526,1606528,1606551,1606554,1606564,1606598-1606599,1606656,1606658,1606662,1606744,1606840,1607085,1607572,1612407,1612810,1613339,1613872,1614611,1615348,1615351-1615352,1615356,1616338-1616339,1616613,1617586,1617688,1618138,1618151,1618153,1618226,1618641,1618653,1618662,1619068,1619358,1619413,1619769,1619774,1620602,1620909,1620912,1620928,1620930,1621275,1621635,1622931,1622937,1622942,1622946,1622959-1622960,1622963,1622987,1623007,1623368,1623373,1623377,1623379,1623381,1623398,1623402,162
 4011,1624265,1624512,1626246,1626871,1626873,1626886,1627497-1627498,1627502,1627947-1627949,1627966,1628083,1628093,1628158-1628159,1628161,1628392-1628393,1628415,1628427,1628676,1628738,1628762,1628764,1629854-1629855,1629857,1629865,1629873,1629875,1629879,1630067,1630070,1631049-1631051,1631075,1631115,1631171,1631180,1631185-1631186,1631196-1631197,1631239-1631240,1631548,1631550,1631563,1631567,1631588,1631598,1632646,1632776,1632849,1632851-1632853,1632856-1632857,1632868,1632908,1632926,1633232,1633617-1633618,1634872,1634875,1634879-1634880,1634920,1636478,1636483,1636629,1636644,1637184,1637186,1637330,1637358,1637363,1637393,1639319,1639322,1639335,1639348,1639352,1639355,1639358,1639414,1639419,1639426,1639430,1639436,1639440,1639549,1640061-1640062,1640197,1640915,1640966,1641013,1643139,1643233,1645567,1646021,1646712,1646716,1647537,1647540-1647541,1647820,1647905,1648230,1648238,1648241-1648243,1648253,1648272,1648532,1648537-1648539,1648542,1648591,1648612,1653608,
 1658482
-/subversion/trunk/subversion/libsvn_fs_x:1414756-1662176
+/subversion/trunk/subversion/libsvn_fs_x:1414756-1686172

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/cached_data.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/cached_data.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/cached_data.c Thu Jun 18 10:35:30 2015
@@ -838,7 +838,7 @@ svn_fs_x__check_rep(svn_fs_x__representa
           && entry->type != SVN_FS_X__ITEM_TYPE_FILE_PROPS
           && entry->type != SVN_FS_X__ITEM_TYPE_DIR_PROPS
           && entry->type != SVN_FS_X__ITEM_TYPE_REPS_CONT))
-    return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                              _("No representation found at offset %s "
                                "for item %s in revision %ld"),
                              apr_off_t_toa(scratch_pool, offset),
@@ -2534,7 +2534,7 @@ read_dir_entries(apr_array_header_t *ent
       /* In incremental mode, update the hash; otherwise, write to the
        * final array. */
       if (incremental)
-        apr_hash_set(hash, entry.key, entry.keylen, dirent);
+        apr_hash_set(hash, dirent->name, entry.keylen, dirent);
       else
         APR_ARRAY_PUSH(entries, svn_fs_x__dirent_t *) = dirent;
     }

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/fs.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/fs.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/fs.c Thu Jun 18 10:35:30 2015
@@ -27,7 +27,6 @@
 #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"
@@ -165,9 +164,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;
 }

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/fs_id.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/fs_id.c?rev=1686174&r1=1686173&r2=1686174&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/fs_id.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_fs_x/fs_id.c Thu Jun 18 10:35:30 2015
@@ -217,13 +217,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



Mime
View raw message