subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From g..@apache.org
Subject svn commit: r1549081 [5/18] - in /subversion/branches/invoke-diff-cmd-feature: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/server-side/ contrib/server-side/svncutter/ subversion/bindings/javahl/native/ subversion/bind...
Date Sun, 08 Dec 2013 17:56:53 GMT
Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/cat.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/cat.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/cat.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/cat.c Sun Dec  8 17:56:46 2013
@@ -176,22 +176,28 @@ svn_client__get_normalized_stream(svn_st
 }
 
 svn_error_t *
-svn_client_cat2(svn_stream_t *out,
+svn_client_cat3(apr_hash_t **props,
+                svn_stream_t *out,
                 const char *path_or_url,
                 const svn_opt_revision_t *peg_revision,
                 const svn_opt_revision_t *revision,
+                svn_boolean_t expand_keywords,
                 svn_client_ctx_t *ctx,
-                apr_pool_t *pool)
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
 {
   svn_ra_session_t *ra_session;
   svn_client__pathrev_t *loc;
   svn_string_t *eol_style;
   svn_string_t *keywords;
-  apr_hash_t *props;
+  apr_hash_t *pprops = NULL;
   const char *repos_root_url;
   svn_stream_t *output = out;
   svn_error_t *err;
 
+  if (!props)
+    props = &pprops;
+
   /* ### Inconsistent default revision logic in this command. */
   if (peg_revision->kind == svn_opt_revision_unspecified)
     {
@@ -213,32 +219,39 @@ svn_client_cat2(svn_stream_t *out,
       const char *local_abspath;
       svn_stream_t *normal_stream;
 
-      SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool));
+      SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url,
+                                      scratch_pool));
       SVN_ERR(svn_client__get_normalized_stream(&normal_stream, ctx->wc_ctx,
-                                            local_abspath, revision, TRUE, FALSE,
+                                            local_abspath, revision,
+                                            expand_keywords, FALSE,
                                             ctx->cancel_func, ctx->cancel_baton,
-                                            pool, pool));
+                                            scratch_pool, scratch_pool));
 
       /* We don't promise to close output, so disown it to ensure we don't. */
-      output = svn_stream_disown(output, pool);
+      output = svn_stream_disown(output, scratch_pool);
+
+      if (props)
+        SVN_ERR(svn_wc_prop_list2(props, ctx->wc_ctx, local_abspath,
+                                  result_pool, scratch_pool));
 
       return svn_error_trace(svn_stream_copy3(normal_stream, output,
                                               ctx->cancel_func,
-                                              ctx->cancel_baton, pool));
+                                              ctx->cancel_baton, scratch_pool));
     }
 
   /* Get an RA plugin for this filesystem object. */
   SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
                                             path_or_url, NULL,
                                             peg_revision,
-                                            revision, ctx, pool));
+                                            revision, ctx, scratch_pool));
 
   /* Find the repos root URL */
-  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, pool));
+  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, scratch_pool));
 
   /* Grab some properties we need to know in order to figure out if anything
      special needs to be done with this file. */
-  err = svn_ra_get_file(ra_session, "", loc->rev, NULL, NULL, &props, pool);
+  err = svn_ra_get_file(ra_session, "", loc->rev, NULL, NULL, props,
+                        result_pool);
   if (err)
     {
       if (err->apr_err == SVN_ERR_FS_NOT_FILE)
@@ -253,8 +266,8 @@ svn_client_cat2(svn_stream_t *out,
         }
     }
 
-  eol_style = svn_hash_gets(props, SVN_PROP_EOL_STYLE);
-  keywords = svn_hash_gets(props, SVN_PROP_KEYWORDS);
+  eol_style = svn_hash_gets(*props, SVN_PROP_EOL_STYLE);
+  keywords = svn_hash_gets(*props, SVN_PROP_KEYWORDS);
 
   if (eol_style || keywords)
     {
@@ -272,33 +285,36 @@ svn_client_cat2(svn_stream_t *out,
         }
 
 
-      if (keywords)
+      if (keywords && expand_keywords)
         {
           svn_string_t *cmt_rev, *cmt_date, *cmt_author;
           apr_time_t when = 0;
 
-          cmt_rev = svn_hash_gets(props, SVN_PROP_ENTRY_COMMITTED_REV);
-          cmt_date = svn_hash_gets(props, SVN_PROP_ENTRY_COMMITTED_DATE);
-          cmt_author = svn_hash_gets(props, SVN_PROP_ENTRY_LAST_AUTHOR);
+          cmt_rev = svn_hash_gets(*props, SVN_PROP_ENTRY_COMMITTED_REV);
+          cmt_date = svn_hash_gets(*props, SVN_PROP_ENTRY_COMMITTED_DATE);
+          cmt_author = svn_hash_gets(*props, SVN_PROP_ENTRY_LAST_AUTHOR);
           if (cmt_date)
-            SVN_ERR(svn_time_from_cstring(&when, cmt_date->data, pool));
+            SVN_ERR(svn_time_from_cstring(&when, cmt_date->data, scratch_pool));
 
           SVN_ERR(svn_subst_build_keywords3(&kw, keywords->data,
                                             cmt_rev->data, loc->url,
                                             repos_root_url, when,
                                             cmt_author ?
                                               cmt_author->data : NULL,
-                                            pool));
+                                            scratch_pool));
         }
       else
         kw = NULL;
 
       /* Interject a translating stream */
-      output = svn_subst_stream_translated(svn_stream_disown(out, pool),
-                                           eol_str, FALSE, kw, TRUE, pool);
+      output = svn_subst_stream_translated(svn_stream_disown(out,
+                                                             scratch_pool),
+                                           eol_str, FALSE, kw, TRUE,
+                                           scratch_pool);
     }
 
-  SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev, output, NULL, NULL, pool));
+  SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev, output, NULL, NULL,
+                          scratch_pool));
 
   if (out != output)
     /* Close the interjected stream */

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/cleanup.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/cleanup.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/cleanup.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/cleanup.c Sun Dec  8 17:56:46 2013
@@ -46,9 +46,13 @@
 
 struct cleanup_status_walk_baton
 {
-  svn_boolean_t include_externals;
+  svn_boolean_t break_locks;
+  svn_boolean_t fix_timestamps;
+  svn_boolean_t clear_dav_cache;
+  svn_boolean_t vacuum_pristines;
   svn_boolean_t remove_unversioned_items;
   svn_boolean_t remove_ignored_items;
+  svn_boolean_t include_externals;
   svn_client_ctx_t *ctx;
 };
 
@@ -61,64 +65,46 @@ cleanup_status_walk(void *baton,
 
 static svn_error_t *
 do_cleanup(const char *local_abspath,
-           svn_boolean_t include_externals,
+           svn_boolean_t break_locks,
+           svn_boolean_t fix_timestamps,
+           svn_boolean_t clear_dav_cache,
+           svn_boolean_t vacuum_pristines,
            svn_boolean_t remove_unversioned_items,
            svn_boolean_t remove_ignored_items,
+           svn_boolean_t include_externals,
            svn_client_ctx_t *ctx,
            apr_pool_t *scratch_pool)
 {
-  svn_error_t *err;
-
-  if (remove_unversioned_items || remove_ignored_items)
-    {
-      svn_boolean_t is_locked_here;
-      svn_boolean_t is_locked;
-      svn_boolean_t sqlite_exclusive;
-      svn_config_t *cfg = ctx->config
-                          ? svn_hash_gets(ctx->config,
-                                          SVN_CONFIG_CATEGORY_CONFIG)
-                          : NULL;
-
-      /* Check if someone else owns a lock for LOCAL_ABSPATH. */
-      SVN_ERR(svn_wc_locked2(&is_locked_here, &is_locked, ctx->wc_ctx,
-                             local_abspath, scratch_pool));
-      if (is_locked && !is_locked_here)
-        return svn_error_createf(SVN_ERR_WC_LOCKED, NULL,
-                                 _("Working copy at '%s' is already locked."),
-                                 svn_dirent_local_style(local_abspath,
-                                                        scratch_pool));
-
-      SVN_ERR(svn_config_get_bool(cfg, &sqlite_exclusive,
-                                  SVN_CONFIG_SECTION_WORKING_COPY,
-                                  SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE,
-                                  FALSE));
-      if (sqlite_exclusive)
-        {
-          /* Close the db because svn_wc_cleanup3() will try to open it again,
-           * which doesn't work if exclusive sqlite locking mode is enabled. */
-          SVN_ERR(svn_wc__close_db(local_abspath, ctx->wc_ctx, scratch_pool));
-        }
-    }
+  SVN_ERR(svn_wc_cleanup4(ctx->wc_ctx,
+                          local_abspath,
+                          break_locks,
+                          fix_timestamps,
+                          clear_dav_cache,
+                          vacuum_pristines,
+                          ctx->cancel_func, ctx->cancel_baton,
+                          scratch_pool));
 
-  err = svn_wc_cleanup3(ctx->wc_ctx, local_abspath, ctx->cancel_func,
-                        ctx->cancel_baton, scratch_pool);
-  svn_io_sleep_for_timestamps(local_abspath, scratch_pool);
-  if (err)
-    return svn_error_trace(err);
+  if (fix_timestamps)
+    svn_io_sleep_for_timestamps(local_abspath, scratch_pool);
 
   if (remove_unversioned_items || remove_ignored_items || include_externals)
     {
       struct cleanup_status_walk_baton b;
       apr_array_header_t *ignores;
 
-      b.include_externals = include_externals;
+      b.break_locks = break_locks;
+      b.fix_timestamps = fix_timestamps;
+      b.clear_dav_cache = clear_dav_cache;
+      b.vacuum_pristines = vacuum_pristines;
       b.remove_unversioned_items = remove_unversioned_items;
       b.remove_ignored_items = remove_ignored_items;
       b.include_externals = include_externals;
       b.ctx = ctx;
 
       SVN_ERR(svn_wc_get_default_ignores(&ignores, ctx->config, scratch_pool));
-      SVN_ERR(svn_wc_walk_status(ctx->wc_ctx, local_abspath,
+
+      SVN_WC__CALL_WITH_WRITE_LOCK(
+              svn_wc_walk_status(ctx->wc_ctx, local_abspath,
                                  svn_depth_infinity,
                                  TRUE,  /* get all */
                                  remove_ignored_items,
@@ -127,7 +113,11 @@ do_cleanup(const char *local_abspath,
                                  cleanup_status_walk, &b,
                                  ctx->cancel_func,
                                  ctx->cancel_baton,
-                                 scratch_pool));
+                                 scratch_pool),
+              ctx->wc_ctx,
+              local_abspath,
+              FALSE /* lock_anchor */,
+              scratch_pool);
     }
 
   return SVN_NO_ERROR;
@@ -161,10 +151,15 @@ cleanup_status_walk(void *baton,
                                       scratch_pool);
             }
 
-          err = do_cleanup(local_abspath, b->include_externals,
-                            b->remove_unversioned_items,
-                            b->remove_ignored_items,
-                            b->ctx, scratch_pool);
+          err = do_cleanup(local_abspath,
+                           b->break_locks,
+                           b->fix_timestamps,
+                           b->clear_dav_cache,
+                           b->vacuum_pristines,
+                           b->remove_unversioned_items,
+                           b->remove_ignored_items,
+                           TRUE /* include_externals */,
+                           b->ctx, scratch_pool);
           if (err && err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
             {
               svn_error_clear(err);
@@ -219,22 +214,50 @@ cleanup_status_walk(void *baton,
 }
 
 svn_error_t *
-svn_client_cleanup2(const char *path,
+svn_client_cleanup2(const char *dir_abspath,
+                    svn_boolean_t break_locks,
+                    svn_boolean_t fix_recorded_timestamps,
+                    svn_boolean_t clear_dav_cache,
+                    svn_boolean_t vacuum_pristines,
                     svn_boolean_t include_externals,
-                    svn_boolean_t remove_unversioned_items,
-                    svn_boolean_t remove_ignored_items,
                     svn_client_ctx_t *ctx,
                     apr_pool_t *scratch_pool)
 {
-  const char *local_abspath;
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
+
+  SVN_ERR(do_cleanup(dir_abspath,
+                     break_locks,
+                     fix_recorded_timestamps,
+                     clear_dav_cache,
+                     vacuum_pristines,
+                     FALSE /* remove_unversioned_items */,
+                     FALSE /* remove_ignored_items */,
+                     include_externals,
+                     ctx, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_vacuum(const char *dir_abspath,
+                  svn_boolean_t remove_unversioned_items,
+                  svn_boolean_t remove_ignored_items,
+                  svn_boolean_t fix_recorded_timestamps,
+                  svn_boolean_t vacuum_pristines,
+                  svn_boolean_t include_externals,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *scratch_pool)
+{
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
 
-  if (svn_path_is_url(path))
-    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-                             _("'%s' is not a local path"), path);
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
-  SVN_ERR(do_cleanup(local_abspath, include_externals,
-                     remove_unversioned_items, remove_ignored_items,
+  SVN_ERR(do_cleanup(dir_abspath,
+                     FALSE /* break_locks */,
+                     fix_recorded_timestamps,
+                     FALSE /* clear_dav_cache */,
+                     vacuum_pristines,
+                     remove_unversioned_items,
+                     remove_ignored_items,
+                     include_externals,
                      ctx, scratch_pool));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/deprecated.c Sun Dec  8 17:56:46 2013
@@ -2555,6 +2555,21 @@ svn_client_switch(svn_revnum_t *result_r
 
 /*** From cat.c ***/
 svn_error_t *
+svn_client_cat2(svn_stream_t *out,
+                const char *path_or_url,
+                const svn_opt_revision_t *peg_revision,
+                const svn_opt_revision_t *revision,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *pool)
+{
+  return svn_client_cat3(NULL /* props */,
+                         out, path_or_url, peg_revision, revision,
+                         TRUE /* expand_keywords */,
+                         ctx, pool, pool);
+}
+
+
+svn_error_t *
 svn_client_cat(svn_stream_t *out,
                const char *path_or_url,
                const svn_opt_revision_t *revision,
@@ -3085,6 +3100,19 @@ svn_client_cleanup(const char *path,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *scratch_pool)
 {
-  return svn_error_trace(svn_client_cleanup2(path, FALSE, FALSE, FALSE, ctx,
-                                             scratch_pool));
+  const char *local_abspath;
+
+  if (svn_path_is_url(path))
+    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                             _("'%s' is not a local path"), path);
+
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
+
+  return svn_error_trace(svn_client_cleanup2(local_abspath,
+                                             TRUE /* break_locks */,
+                                             TRUE /* fix_recorded_timestamps */,
+                                             TRUE /* clear_dav_cache */,
+                                             TRUE /* vacuum_pristines */,
+                                             FALSE /* include_externals */,
+                                             ctx, scratch_pool));
 }

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/merge.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/merge.c Sun Dec  8 17:56:46 2013
@@ -12681,7 +12681,8 @@ svn_client_get_merging_summary(svn_boole
 
   target_is_wc = (! svn_path_is_url(target_path_or_url))
                  && (target_revision->kind == svn_opt_revision_unspecified
-                     || target_revision->kind == svn_opt_revision_working);
+                     || target_revision->kind == svn_opt_revision_working
+                     || target_revision->kind == svn_opt_revision_base);
   if (target_is_wc)
     {
       const char *target_abspath;

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/update.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/update.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_client/update.c Sun Dec  8 17:56:46 2013
@@ -383,7 +383,7 @@ update_internal(svn_revnum_t *result_rev
       SVN_ERR(svn_ra_get_repos_root2(ra_session, &new_repos_root_url, pool));
 
       /* svn_client_relocate2() will check the uuid */
-      SVN_ERR(svn_client_relocate2(anchor_abspath, anchor_url,
+      SVN_ERR(svn_client_relocate2(anchor_abspath, repos_root_url,
                                    new_repos_root_url, ignore_externals,
                                    ctx, pool));
 

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_diff/parse-diff.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_diff/parse-diff.c Sun Dec  8 17:56:46 2013
@@ -386,7 +386,6 @@ svn_diff_hunk_readline_diff_text(svn_dif
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
 {
-  svn_diff_hunk_t dummy;
   svn_stringbuf_t *line;
   apr_size_t max_len;
   apr_off_t pos;
@@ -416,33 +415,10 @@ svn_diff_hunk_readline_diff_text(svn_dif
 
   if (hunk->patch->reverse)
     {
-      if (parse_hunk_header(line->data, &dummy, "@@", scratch_pool))
-        {
-          /* Line is a hunk header, reverse it. */
-          line = svn_stringbuf_createf(result_pool,
-                                       "@@ -%lu,%lu +%lu,%lu @@",
-                                       hunk->modified_start,
-                                       hunk->modified_length,
-                                       hunk->original_start,
-                                       hunk->original_length);
-        }
-      else if (parse_hunk_header(line->data, &dummy, "##", scratch_pool))
-        {
-          /* Line is a hunk header, reverse it. */
-          line = svn_stringbuf_createf(result_pool,
-                                       "## -%lu,%lu +%lu,%lu ##",
-                                       hunk->modified_start,
-                                       hunk->modified_length,
-                                       hunk->original_start,
-                                       hunk->original_length);
-        }
-      else
-        {
-          if (line->data[0] == '+')
-            line->data[0] = '-';
-          else if (line->data[0] == '-')
-            line->data[0] = '+';
-        }
+      if (line->data[0] == '+')
+        line->data[0] = '-';
+      else if (line->data[0] == '-')
+        line->data[0] = '+';
     }
 
   *stringbuf = line;

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs/editor.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs/editor.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs/editor.c Sun Dec  8 17:56:46 2013
@@ -789,10 +789,11 @@ svn_fs__editor_commit(svn_revnum_t *revi
      it placed into RESULT_POOL.  */
 
   if (!err)
-    err = svn_fs_commit_txn(&inner_conflict_path,
-                            revision,
-                            eb->txn,
-                            scratch_pool);
+    err = svn_fs_commit_txn2(&inner_conflict_path,
+                             revision,
+                             eb->txn,
+                             TRUE,
+                             scratch_pool);
   if (SVN_IS_VALID_REVNUM(*revision))
     {
       if (err)

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs/fs-loader.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs/fs-loader.c Sun Dec  8 17:56:46 2013
@@ -44,6 +44,7 @@
 #include "svn_string.h"
 #include "svn_sorts.h"
 
+#include "private/svn_atomic.h"
 #include "private/svn_fs_private.h"
 #include "private/svn_fs_util.h"
 #include "private/svn_utf_private.h"
@@ -62,8 +63,9 @@
 
 /* A pool common to all FS objects.  See the documentation on the
    open/create functions in fs-loader.h and for svn_fs_initialize(). */
-static apr_pool_t *common_pool;
-svn_mutex__t *common_pool_lock;
+static apr_pool_t *common_pool = NULL;
+static svn_mutex__t *common_pool_lock = NULL;
+static svn_atomic_t common_pool_initialized = FALSE;
 
 
 /* --- Utility functions for the loader --- */
@@ -196,8 +198,7 @@ get_library_vtable_direct(fs_library_vta
        unloaded.  This function makes a best effort by creating the
        common pool as a child of the global pool; the window of failure
        due to thread collision is small. */
-    if (!common_pool)
-      SVN_ERR(svn_fs_initialize(NULL));
+    SVN_ERR(svn_fs_initialize(NULL));
 
     /* Invoke the FS module's initfunc function with the common
        pool protected by a lock. */
@@ -280,8 +281,8 @@ get_library_vtable(fs_library_vtable_t *
   if (!known)
     {
       fst = &(*fst)->next;
-      if (!common_pool)  /* Best-effort init, see get_library_vtable_direct. */
-        SVN_ERR(svn_fs_initialize(NULL));
+      /* Best-effort init, see get_library_vtable_direct. */
+      SVN_ERR(svn_fs_initialize(NULL));
       SVN_MUTEX__WITH_LOCK(common_pool_lock,
                            get_or_allocate_third(fst, fs_type));
       known = TRUE;
@@ -371,16 +372,15 @@ write_fs_type(const char *path, const ch
 static apr_status_t uninit(void *data)
 {
   common_pool = NULL;
+  common_pool_lock = NULL;
+  common_pool_initialized = 0;
+
   return APR_SUCCESS;
 }
 
-svn_error_t *
-svn_fs_initialize(apr_pool_t *pool)
+static svn_error_t *
+synchronized_initialize(void *baton, apr_pool_t *pool)
 {
-  /* Protect against multiple calls. */
-  if (common_pool)
-    return SVN_NO_ERROR;
-
   common_pool = svn_pool_create(pool);
   base_defn.next = NULL;
   SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool));
@@ -395,6 +395,15 @@ svn_fs_initialize(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_initialize(apr_pool_t *pool)
+{
+  /* Protect against multiple calls. */
+  return svn_error_trace(svn_atomic__init_once(&common_pool_initialized,
+                                               synchronized_initialize,
+                                               NULL, pool));
+}
+
 /* A default warning handling function.  */
 static void
 default_warning_func(void *baton, svn_error_t *err)
@@ -1518,10 +1527,10 @@ svn_fs_lock(svn_lock_t **lock, svn_fs_t 
                                  token, "opaquelocktoken");
 
       for (c = token; *c; c++)
-        if (! svn_ctype_isascii(*c))
+        if (! svn_ctype_isascii(*c) || svn_ctype_iscntrl(*c))
           return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
-                                   _("Lock token '%s' is not ASCII "
-                                     "at byte %u"),
+                                   _("Lock token '%s' is not ASCII or is a "
+                                     "control character at byte %u"),
                                    token, (unsigned)(c - token));
 
       /* strlen(token) == c - token. */

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_base/fs.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_base/fs.c Sun Dec  8 17:56:46 2013
@@ -741,12 +741,27 @@ base_create(svn_fs_t *fs,
   /* See if compatibility with older versions was explicitly requested. */
   if (fs->config)
     {
-      if (svn_hash_gets(fs->config, SVN_FS_CONFIG_PRE_1_4_COMPATIBLE))
-        format = 1;
-      else if (svn_hash_gets(fs->config, SVN_FS_CONFIG_PRE_1_5_COMPATIBLE))
-        format = 2;
-      else if (svn_hash_gets(fs->config, SVN_FS_CONFIG_PRE_1_6_COMPATIBLE))
-        format = 3;
+      svn_version_t *compatible_version;
+      SVN_ERR(svn_fs__compatible_version(&compatible_version, fs->config,
+                                         pool));
+
+      /* select format number */
+      switch(compatible_version->minor)
+        {
+          case 0:
+          case 1:
+          case 2:
+          case 3: format = 1;
+                  break;
+
+          case 4: format = 2;
+                  break;
+
+          case 5: format = 3;
+                  break;
+
+          default:format = SVN_FS_BASE__FORMAT_NUMBER;
+        }
     }
 
   /* Create the environment and databases. */

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_base/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_base/fs.h?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_base/fs.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_base/fs.h Sun Dec  8 17:56:46 2013
@@ -43,7 +43,11 @@ extern "C" {
    repository format number, and independent of any other FS back
    ends.  See the SVN_FS_BASE__MIN_*_FORMAT defines to get a sense of
    what changes and features were added in which versions of this
-   back-end's format.  */
+   back-end's format.
+
+   Note: If you bump this, please update the switch statement in
+         base_create() as well.
+ */
 #define SVN_FS_BASE__FORMAT_NUMBER                4
 
 /* Minimum format number that supports representation sharing.  This

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_fs/cached_data.c?rev=1549081&r1=1549080&r2=1549081&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_fs_fs/cached_data.c Sun Dec  8 17:56:46 2013
@@ -26,10 +26,12 @@
 
 #include "svn_hash.h"
 #include "svn_ctype.h"
+#include "private/svn_io_private.h"
 #include "private/svn_temp_serializer.h"
 
 #include "fs_fs.h"
 #include "id.h"
+#include "index.h"
 #include "low_level.h"
 #include "pack.h"
 #include "util.h"
@@ -39,16 +41,21 @@
 
 #include "svn_private_config.h"
 
+/* forward-declare. See implementation for the docstring */
+static svn_error_t *
+block_read(void **result,
+           svn_fs_t *fs,
+           svn_revnum_t revision,
+           apr_uint64_t item_index,
+           svn_fs_fs__revision_file_t *revision_file,
+           apr_pool_t *result_pool,
+           apr_pool_t *scratch_pool);
+
+
 /* Defined this to enable access logging via dgb__log_access
 #define SVN_FS_FS__LOG_ACCESS
  */
 
-/* Data / item types.
- */
-#define SVN_FS_FS__ITEM_TYPE_ANY_REP    1  /* item is a representation. */
-#define SVN_FS_FS__ITEM_TYPE_NODEREV    2  /* item is a noderev */
-#define SVN_FS_FS__ITEM_TYPE_CHANGES    3  /* item is a changed paths list */
-
 /* When SVN_FS_FS__LOG_ACCESS has been defined, write a line to console
  * showing where REVISION, ITEM_INDEX is located in FS and use ITEM to
  * show details on it's contents if not NULL.  To support format 6 and
@@ -60,7 +67,7 @@
 static svn_error_t *
 dbg_log_access(svn_fs_t *fs,
                svn_revnum_t revision,
-               apr_off_t offset,
+               apr_uint64_t item_index,
                void *item,
                int item_type,
                apr_pool_t *scratch_pool)
@@ -68,14 +75,17 @@ dbg_log_access(svn_fs_t *fs,
   /* no-op if this macro is not defined */
 #ifdef SVN_FS_FS__LOG_ACCESS
   fs_fs_data_t *ffd = fs->fsap_data;
-  static const char *types[] = {"<n/a>", "rep ", "node ", "chgs "};
+  apr_off_t end_offset = 0;
+  svn_fs_fs__p2l_entry_t *entry = NULL;
+  static const char *types[] = {"<n/a>", "frep ", "drep ", "fprop", "dprop",
+                                "node ", "chgs ", "rep  "};
   const char *description = "";
   const char *type = types[item_type];
   const char *pack = "";
-  apr_off_t offset_in_rev = offset;
+  apr_off_t offset;
 
   /* determine rev / pack file offset */
-  SVN_ERR(svn_fs_fs__item_offset(&offset, fs, revision, offset,
+  SVN_ERR(svn_fs_fs__item_offset(&offset, fs, revision, NULL, item_index,
                                  scratch_pool));
 
   /* constructing the pack file description */
@@ -91,13 +101,13 @@ dbg_log_access(svn_fs_t *fs,
         = node->data_rep
         ? apr_psprintf(scratch_pool, " d=%ld/%" APR_UINT64_T_FMT,
                        node->data_rep->revision,
-                       node->data_rep->offset)
+                       node->data_rep->item_index)
         : "";
       const char *prop_rep
         = node->prop_rep
         ? apr_psprintf(scratch_pool, " p=%ld/%" APR_UINT64_T_FMT,
                        node->prop_rep->revision,
-                       node->prop_rep->offset)
+                       node->prop_rep->item_index)
         : "";
       description = apr_psprintf(scratch_pool, "%s   (pc=%d%s%s)",
                                  node->created_path,
@@ -118,7 +128,7 @@ dbg_log_access(svn_fs_t *fs,
         description = apr_psprintf(scratch_pool,
                                    "  DELTA against %ld/%" APR_UINT64_T_FMT,
                                    header->base_revision,
-                                   header->base_offset);
+                                   header->base_item_index);
     }
   else if (item_type == SVN_FS_FS__ITEM_TYPE_CHANGES && item != NULL)
     {
@@ -134,23 +144,53 @@ dbg_log_access(svn_fs_t *fs,
         }
     }
 
-  printf("%5s%10" APR_UINT64_T_HEX_FMT " %s %7ld %7" APR_UINT64_T_FMT \
-          "   %s\n",
-          pack, (apr_uint64_t)(offset), type, revision, offset_in_rev,
-          description);
+  /* some info is only available in format7 repos */
+  if (svn_fs_fs__use_log_addressing(fs, revision))
+    {
+      /* reverse index lookup: get item description in ENTRY */
+      SVN_ERR(svn_fs_fs__p2l_entry_lookup(&entry, fs, revision, offset,
+                                          scratch_pool));
+      if (entry)
+        {
+          /* more details */
+          end_offset = offset + entry->size;
+          type = types[entry->type];
+        }
+
+      /* line output */
+      printf("%5s%4lx:%04lx -%4lx:%04lx %s %7ld %5"APR_UINT64_T_FMT"   %s\n",
+             pack, (long)(offset / ffd->block_size),
+             (long)(offset % ffd->block_size),
+             (long)(end_offset / ffd->block_size),
+             (long)(end_offset % ffd->block_size),
+             type, revision, item_index, description);
+    }
+  else
+    {
+      /* reduced logging for format 6 and earlier */
+      printf("%5s%10" APR_UINT64_T_HEX_FMT " %s %7ld %7" APR_UINT64_T_FMT \
+             "   %s\n",
+             pack, (apr_uint64_t)(offset), type, revision, item_index,
+             description);
+    }
 
 #endif
 
   return SVN_NO_ERROR;
 }
 
-/* Convenience wrapper around svn_io_file_aligned_seek. */
+/* Convenience wrapper around svn_io_file_aligned_seek, taking filesystem
+   FS instead of a block size. */
 static svn_error_t *
-aligned_seek(apr_file_t *file,
+aligned_seek(svn_fs_t *fs,
+             apr_file_t *file,
+             apr_off_t *buffer_start,
              apr_off_t offset,
              apr_pool_t *pool)
 {
-  return svn_error_trace(svn_io_file_aligned_seek(file, 0, NULL, offset,
+  fs_fs_data_t *ffd = fs->fsap_data;
+  return svn_error_trace(svn_io_file_aligned_seek(file, ffd->block_size,
+                                                  buffer_start, offset,
                                                   pool));
 }
 
@@ -158,19 +198,22 @@ aligned_seek(apr_file_t *file,
    the newly opened file in FILE.  Seek to location OFFSET before
    returning.  Perform temporary allocations in POOL. */
 static svn_error_t *
-open_and_seek_revision(apr_file_t **file,
+open_and_seek_revision(svn_fs_fs__revision_file_t **file,
                        svn_fs_t *fs,
                        svn_revnum_t rev,
-                       apr_off_t offset,
+                       apr_uint64_t item,
                        apr_pool_t *pool)
 {
-  apr_file_t *rev_file;
+  svn_fs_fs__revision_file_t *rev_file;
+  apr_off_t offset = -1;
 
   SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, pool));
 
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, rev, pool));
-  SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev, offset, pool));
-  SVN_ERR(aligned_seek(rev_file, offset, pool));
+  SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, rev, NULL, item,
+                                 pool));
+
+  SVN_ERR(aligned_seek(fs, rev_file->file, NULL, offset, pool));
 
   *file = rev_file;
 
@@ -181,21 +224,18 @@ open_and_seek_revision(apr_file_t **file
    to its position and store the newly opened file in FILE.  Perform
    temporary allocations in POOL. */
 static svn_error_t *
-open_and_seek_transaction(apr_file_t **file,
+open_and_seek_transaction(svn_fs_fs__revision_file_t **file,
                           svn_fs_t *fs,
                           representation_t *rep,
                           apr_pool_t *pool)
 {
-  apr_file_t *rev_file;
-
-  SVN_ERR(svn_io_file_open(&rev_file,
-                           svn_fs_fs__path_txn_proto_rev(fs, &rep->txn_id,
-                                                         pool),
-                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
+  apr_off_t offset;
 
-  SVN_ERR(aligned_seek(rev_file, rep->offset, pool));
+  SVN_ERR(svn_fs_fs__open_proto_rev_file(file, fs, &rep->txn_id, pool));
 
-  *file = rev_file;
+  SVN_ERR(svn_fs_fs__item_offset(&offset, fs, NULL, SVN_INVALID_REVNUM,
+                                 &rep->txn_id, rep->item_index, pool));
+  SVN_ERR(aligned_seek(fs, (*file)->file, NULL, offset, pool));
 
   return SVN_NO_ERROR;
 }
@@ -204,13 +244,13 @@ open_and_seek_transaction(apr_file_t **f
    the correct file and seek to the correction location.  Store this
    file in *FILE_P.  Perform any allocations in POOL. */
 static svn_error_t *
-open_and_seek_representation(apr_file_t **file_p,
+open_and_seek_representation(svn_fs_fs__revision_file_t **file_p,
                              svn_fs_t *fs,
                              representation_t *rep,
                              apr_pool_t *pool)
 {
   if (! svn_fs_fs__id_txn_used(&rep->txn_id))
-    return open_and_seek_revision(file_p, fs, rep->revision, rep->offset,
+    return open_and_seek_revision(file_p, fs, rep->revision, rep->item_index,
                                   pool);
   else
     return open_and_seek_transaction(file_p, fs, rep, pool);
@@ -238,16 +278,17 @@ get_node_revision_body(node_revision_t *
                        const svn_fs_id_t *id,
                        apr_pool_t *pool)
 {
-  apr_file_t *revision_file;
   svn_error_t *err;
   svn_boolean_t is_cached = FALSE;
   fs_fs_data_t *ffd = fs->fsap_data;
 
   if (svn_fs_fs__id_is_txn(id))
     {
+      apr_file_t *file;
+
       /* This is a transaction node-rev.  Its storage logic is very
          different from that of rev / pack files. */
-      err = svn_io_file_open(&revision_file,
+      err = svn_io_file_open(&file,
                              svn_fs_fs__path_txn_node_rev(fs, id, pool),
                              APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
       if (err)
@@ -262,15 +303,17 @@ get_node_revision_body(node_revision_t *
         }
 
       SVN_ERR(svn_fs_fs__read_noderev(noderev_p,
-                                      svn_stream_from_aprfile2(revision_file,
+                                      svn_stream_from_aprfile2(file,
                                                                FALSE,
                                                                pool),
                                       pool));
     }
   else
     {
+      svn_fs_fs__revision_file_t *revision_file;
+
       /* noderevs in rev / pack files can be cached */
-      const svn_fs_fs__id_part_t *rev_item = svn_fs_fs__id_rev_offset(id);
+      const svn_fs_fs__id_part_t *rev_item = svn_fs_fs__id_rev_item(id);
       pair_cache_key_t key = { 0 };
       key.revision = rev_item->revision;
       key.second = rev_item->number;
@@ -293,21 +336,36 @@ get_node_revision_body(node_revision_t *
                                      rev_item->revision,
                                      rev_item->number,
                                      pool));
-      SVN_ERR(svn_fs_fs__read_noderev(noderev_p,
-                                      svn_stream_from_aprfile2(revision_file,
-                                                                FALSE,
-                                                                pool),
-                                      pool));
 
-      /* Workaround issue #4031: is-fresh-txn-root in revision files. */
-      (*noderev_p)->is_fresh_txn_root = FALSE;
+      if (svn_fs_fs__use_log_addressing(fs, rev_item->revision))
+        {
+          /* block-read will parse the whole block and will also return
+             the one noderev that we need right now. */
+          SVN_ERR(block_read((void **)noderev_p, fs,
+                             rev_item->revision,
+                             rev_item->number,
+                             revision_file,
+                             pool,
+                             pool));
+          SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
+        }
+      else
+        {
+          /* physical addressing mode reading, parsing and caching */
+          SVN_ERR(svn_fs_fs__read_noderev(noderev_p,
+                                          revision_file->stream,
+                                          pool));
+
+          /* Workaround issue #4031: is-fresh-txn-root in revision files. */
+          (*noderev_p)->is_fresh_txn_root = FALSE;
 
-      /* The noderev is not in cache, yet. Add it, if caching has been enabled. */
-      if (ffd->node_revision_cache)
-        SVN_ERR(svn_cache__set(ffd->node_revision_cache,
-                                &key,
-                                *noderev_p,
-                                pool));
+          /* The noderev is not in cache, yet. Add it, if caching has been enabled. */
+          if (ffd->node_revision_cache)
+            SVN_ERR(svn_cache__set(ffd->node_revision_cache,
+                                   &key,
+                                   *noderev_p,
+                                   pool));
+        }
     }
 
   return SVN_NO_ERROR;
@@ -319,7 +377,7 @@ svn_fs_fs__get_node_revision(node_revisi
                              const svn_fs_id_t *id,
                              apr_pool_t *pool)
 {
-  const svn_fs_fs__id_part_t *rev_offset = svn_fs_fs__id_rev_offset(id);
+  const svn_fs_fs__id_part_t *rev_item = svn_fs_fs__id_rev_item(id);
 
   svn_error_t *err = get_node_revision_body(noderev_p, fs, id, pool);
   if (err && err->apr_err == SVN_ERR_FS_CORRUPT)
@@ -331,8 +389,8 @@ svn_fs_fs__get_node_revision(node_revisi
     }
 
   SVN_ERR(dbg_log_access(fs,
-                         rev_offset->revision,
-                         rev_offset->number,
+                         rev_item->revision,
+                         rev_item->number,
                          *noderev_p,
                          SVN_FS_FS__ITEM_TYPE_NODEREV,
                          pool));
@@ -346,7 +404,7 @@ svn_fs_fs__get_node_revision(node_revisi
    temporary variables from POOL. */
 static svn_error_t *
 get_fs_id_at_offset(svn_fs_id_t **id_p,
-                    apr_file_t *rev_file,
+                    svn_fs_fs__revision_file_t *rev_file,
                     svn_fs_t *fs,
                     svn_revnum_t rev,
                     apr_off_t offset,
@@ -354,10 +412,9 @@ get_fs_id_at_offset(svn_fs_id_t **id_p,
 {
   node_revision_t *noderev;
 
-  SVN_ERR(aligned_seek(rev_file, offset, pool));
+  SVN_ERR(aligned_seek(fs, rev_file->file, NULL, offset, pool));
   SVN_ERR(svn_fs_fs__read_noderev(&noderev,
-                                  svn_stream_from_aprfile2(rev_file, TRUE,
-                                                           pool),
+                                  rev_file->stream,
                                   pool));
 
   /* noderev->id is const, get rid of that */
@@ -434,7 +491,7 @@ get_root_changes_offset(apr_off_t *root_
   SVN_ERR(svn_io_file_seek(rev_file, seek_relative, &offset, pool));
 
   trailer->len = trailer->blocksize-1;
-  SVN_ERR(aligned_seek(rev_file, offset - trailer->len, pool));
+  SVN_ERR(aligned_seek(fs, rev_file, NULL, offset - trailer->len, pool));
 
   /* Read in this last block, from which we will identify the last line. */
   SVN_ERR(svn_io_file_read(rev_file, trailer->data, &trailer->len, pool));
@@ -462,30 +519,37 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro
                         apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
+  SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, pool));
 
-  apr_file_t *revision_file;
-  apr_off_t root_offset;
-  svn_fs_id_t *root_id = NULL;
-  svn_boolean_t is_cached;
+  if (svn_fs_fs__use_log_addressing(fs, rev))
+    {
+      *root_id_p = svn_fs_fs__id_create_root(rev, pool);
+    }
+  else
+    {
+      svn_fs_fs__revision_file_t *revision_file;
+      apr_off_t root_offset;
+      svn_fs_id_t *root_id = NULL;
+      svn_boolean_t is_cached;
 
-  SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, pool));
-  SVN_ERR(svn_cache__get((void **) root_id_p, &is_cached,
-                         ffd->rev_root_id_cache, &rev, pool));
-  if (is_cached)
-    return SVN_NO_ERROR;
+      SVN_ERR(svn_cache__get((void **) root_id_p, &is_cached,
+                            ffd->rev_root_id_cache, &rev, pool));
+      if (is_cached)
+        return SVN_NO_ERROR;
 
-  SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&revision_file, fs, rev, pool));
-  SVN_ERR(get_root_changes_offset(&root_offset, NULL, revision_file, fs, rev,
-                                  pool));
+      SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&revision_file, fs, rev, pool));
+      SVN_ERR(get_root_changes_offset(&root_offset, NULL,
+                                      revision_file->file, fs, rev, pool));
 
-  SVN_ERR(get_fs_id_at_offset(&root_id, revision_file, fs, rev,
-                              root_offset, pool));
+      SVN_ERR(get_fs_id_at_offset(&root_id, revision_file, fs, rev,
+                                  root_offset, pool));
 
-  SVN_ERR(svn_io_file_close(revision_file, pool));
+      SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
 
-  SVN_ERR(svn_cache__set(ffd->rev_root_id_cache, &rev, root_id, pool));
+      SVN_ERR(svn_cache__set(ffd->rev_root_id_cache, &rev, root_id, pool));
 
-  *root_id_p = root_id;
+      *root_id_p = root_id;
+    }
 
   return SVN_NO_ERROR;
 }
@@ -495,10 +559,7 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro
 typedef struct shared_file_t
 {
   /* The opened file. NULL while file is not open, yet. */
-  apr_file_t *file;
-
-  /* Stream wrapper around FILE. NULL while file is not open, yet. */
-  svn_stream_t *stream;
+  svn_fs_fs__revision_file_t *rfile;
 
   /* file system to open the file in */
   svn_fs_t *fs;
@@ -518,15 +579,15 @@ typedef struct shared_file_t
 typedef struct rep_state_t
 {
                     /* shared lazy-open rev/pack file structure */
-  shared_file_t *file;
+  shared_file_t *sfile;
                     /* The txdelta window cache to use or NULL. */
   svn_cache__t *window_cache;
                     /* Caches un-deltified windows. May be NULL. */
   svn_cache__t *combined_cache;
                     /* revision containing the representation */
   svn_revnum_t revision;
-                    /* representation's offset in REVISION */
-  apr_uint64_t offset;
+                    /* representation's item index in REVISION */
+  apr_uint64_t item_index;
                     /* length of the header at the start of the rep.
                        0 iff this is rep is stored in a container
                        (i.e. does not have a header) */
@@ -541,16 +602,38 @@ typedef struct rep_state_t
   int chunk_index;  /* number of the window to read */
 } rep_state_t;
 
+/* Simple wrapper around svn_fs_fs__get_file_offset to simplify callers. */
+static svn_error_t *
+get_file_offset(apr_off_t *offset,
+                rep_state_t *rs,
+                apr_pool_t *pool)
+{
+  return svn_error_trace(svn_fs_fs__get_file_offset(offset,
+                                                    rs->sfile->rfile->file,
+                                                    pool));
+}
+
+/* Simple wrapper around svn_io_file_aligned_seek to simplify callers. */
+static svn_error_t *
+rs_aligned_seek(rep_state_t *rs,
+                apr_off_t *buffer_start,
+                apr_off_t offset,
+                apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = rs->sfile->fs->fsap_data;
+  return svn_error_trace(svn_io_file_aligned_seek(rs->sfile->rfile->file,
+                                                  ffd->block_size,
+                                                  buffer_start, offset,
+                                                  pool));
+}
+
 /* Open FILE->FILE and FILE->STREAM if they haven't been opened, yet. */
 static svn_error_t*
 auto_open_shared_file(shared_file_t *file)
 {
-  if (file->file == NULL)
-    {
-      SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&file->file, file->fs,
-                                               file->revision, file->pool));
-      file->stream = svn_stream_from_aprfile2(file->file, TRUE, file->pool);
-    }
+  if (file->rfile == NULL)
+    SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&file->rfile, file->fs,
+                                             file->revision, file->pool));
 
   return SVN_NO_ERROR;
 }
@@ -562,8 +645,9 @@ auto_set_start_offset(rep_state_t *rs, a
 {
   if (rs->start == -1)
     {
-      SVN_ERR(svn_fs_fs__item_offset(&rs->start, rs->file->fs, rs->revision,
-                                     rs->offset, pool));
+      SVN_ERR(svn_fs_fs__item_offset(&rs->start, rs->sfile->fs,
+                                     rs->sfile->rfile, rs->revision, NULL,
+                                     rs->item_index, pool));
       rs->start += rs->header_size;
     }
 
@@ -579,9 +663,9 @@ auto_read_diff_version(rep_state_t *rs, 
   if (rs->ver == -1)
     {
       char buf[4];
-      SVN_ERR(aligned_seek(rs->file->file, rs->start, pool));
-      SVN_ERR(svn_io_file_read_full2(rs->file->file, buf, sizeof(buf),
-                                     NULL, NULL, pool));
+      SVN_ERR(rs_aligned_seek(rs, NULL, rs->start, pool));
+      SVN_ERR(svn_io_file_read_full2(rs->sfile->rfile->file, buf,
+                                     sizeof(buf), NULL, NULL, pool));
 
       /* ### Layering violation */
       if (! ((buf[0] == 'S') && (buf[1] == 'V') && (buf[2] == 'N')))
@@ -620,7 +704,7 @@ create_rep_state_body(rep_state_t **rep_
    * we can re-use the same, already open file object
    */
   svn_boolean_t reuse_shared_file
-    =    shared_file && *shared_file && (*shared_file)->file
+    =    shared_file && *shared_file && (*shared_file)->rfile
       && SVN_IS_VALID_REVNUM((*shared_file)->revision)
       && (*shared_file)->revision < ffd->min_unpacked_rev
       && rep->revision < ffd->min_unpacked_rev
@@ -630,12 +714,12 @@ create_rep_state_body(rep_state_t **rep_
   representation_cache_key_t key;
   key.revision = rep->revision;
   key.is_packed = rep->revision < ffd->min_unpacked_rev;
-  key.offset = rep->offset;
+  key.item_index = rep->item_index;
 
   /* continue constructing RS and RA */
   rs->size = rep->size;
   rs->revision = rep->revision;
-  rs->offset = rep->offset;
+  rs->item_index = rep->item_index;
   rs->window_cache = ffd->txdelta_window_cache;
   rs->combined_cache = ffd->combined_window_cache;
   rs->ver = -1;
@@ -649,7 +733,7 @@ create_rep_state_body(rep_state_t **rep_
   /* initialize the (shared) FILE member in RS */
   if (reuse_shared_file)
     {
-      rs->file = *shared_file;
+      rs->sfile = *shared_file;
     }
   else
     {
@@ -657,7 +741,7 @@ create_rep_state_body(rep_state_t **rep_
       file->revision = rep->revision;
       file->pool = pool;
       file->fs = fs;
-      rs->file = file;
+      rs->sfile = file;
 
       /* remember the current file, if suggested by the caller */
       if (shared_file)
@@ -675,35 +759,39 @@ create_rep_state_body(rep_state_t **rep_
           /* ... we can re-use the same, already open file object.
            * This implies that we don't read from a txn.
            */
-          rs->file = *shared_file;
-          SVN_ERR(auto_open_shared_file(rs->file));
-          SVN_ERR(svn_fs_fs__get_packed_offset(&offset, fs, rep->revision,
-                                               pool));
-          SVN_ERR(aligned_seek((*shared_file)->file, offset + rep->offset,
-                               pool));
+          rs->sfile = *shared_file;
+          SVN_ERR(auto_open_shared_file(rs->sfile));
+          SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rs->sfile->rfile,
+                                         rep->revision, NULL, rep->item_index,
+                                         pool));
+          SVN_ERR(rs_aligned_seek(rs, NULL, offset, pool));
         }
       else
         {
           /* otherwise, create a new file object.  May or may not be
            * an in-txn file.
            */
-          SVN_ERR(open_and_seek_representation(&rs->file->file, fs, rep,
+          SVN_ERR(open_and_seek_representation(&rs->sfile->rfile, fs, rep,
                                                pool));
-          rs->file->stream = svn_stream_from_aprfile2(rs->file->file, TRUE,
-                                                      rs->file->pool);
         }
 
-      SVN_ERR(svn_fs_fs__read_rep_header(&rh, rs->file->stream, pool));
-      SVN_ERR(svn_fs_fs__get_file_offset(&rs->start, rs->file->file, pool));
+      SVN_ERR(svn_fs_fs__read_rep_header(&rh, rs->sfile->rfile->stream, pool));
+      SVN_ERR(get_file_offset(&rs->start, rs, pool));
 
-      /* cache the rep header if appropriate */
+      /* populate the cache if appropriate */
       if (! svn_fs_fs__id_txn_used(&rep->txn_id))
-        if (ffd->rep_header_cache)
-          SVN_ERR(svn_cache__set(ffd->rep_header_cache, &key, rh, pool));
+        {
+          if (svn_fs_fs__use_log_addressing(fs, rep->revision))
+            SVN_ERR(block_read(NULL, fs, rep->revision, rep->item_index,
+                               rs->sfile->rfile, pool, pool));
+          else
+            if (ffd->rep_header_cache)
+              SVN_ERR(svn_cache__set(ffd->rep_header_cache, &key, rh, pool));
+        }
     }
 
   /* finalize */
-  SVN_ERR(dbg_log_access(fs, rep->revision, rep->offset, rh,
+  SVN_ERR(dbg_log_access(fs, rep->revision, rep->item_index, rh,
                          SVN_FS_FS__ITEM_TYPE_ANY_REP, pool));
 
   rs->header_size = rh->header_size;
@@ -769,12 +857,52 @@ svn_fs_fs__check_rep(representation_t *r
                      void **hint,
                      apr_pool_t *pool)
 {
-  rep_state_t *rs;
-  svn_fs_fs__rep_header_t *rep_header;
+  if (svn_fs_fs__use_log_addressing(fs, rep->revision))
+    {
+      svn_error_t *err;
+      apr_off_t offset;
+      svn_fs_fs__p2l_entry_t *entry;
+      svn_boolean_t is_packed;
+
+      svn_fs_fs__revision_file_t rev_file;
+      svn_fs_fs__init_revision_file(&rev_file, fs, rep->revision, pool);
+      SVN_ERR(svn_fs_fs__item_offset(&offset, fs, &rev_file, rep->revision,
+                                     NULL, rep->item_index, pool));
+
+      is_packed = rev_file.is_packed;
+      err = svn_fs_fs__p2l_entry_lookup(&entry, fs, &rev_file, rep->revision,
+                                        offset, pool);
+
+      /* retry if the packing state has changed */
+      if (is_packed != rev_file.is_packed)
+        {
+          svn_error_clear(err);
+          return svn_error_trace(svn_fs_fs__check_rep(rep, fs, hint, pool));
+        }
+      else
+        {
+          SVN_ERR(err);
+        }
 
-  /* ### Should this be using read_rep_line() directly? */
-  SVN_ERR(create_rep_state(&rs, &rep_header, (shared_file_t**)hint, rep,
-                           fs, pool));
+      if (   entry == NULL
+          || entry->type < SVN_FS_FS__ITEM_TYPE_FILE_REP
+          || entry->type > SVN_FS_FS__ITEM_TYPE_DIR_PROPS)
+        return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+                                 _("No representation found at offset %s "
+                                   "for item %" APR_UINT64_T_FMT
+                                   " in revision %ld"),
+                                 apr_off_t_toa(pool, entry->offset),
+                                 rep->item_index, rep->revision);
+    }
+  else
+    {
+      rep_state_t *rs;
+      svn_fs_fs__rep_header_t *rep_header;
+
+      /* ### Should this be using read_rep_line() directly? */
+      SVN_ERR(create_rep_state(&rs, &rep_header, (shared_file_t**)hint,
+                               rep, fs, pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -812,7 +940,7 @@ svn_fs_fs__rep_chain_length(int *chain_l
                                     sub_pool));
 
       base_rep.revision = header->base_revision;
-      base_rep.offset = header->base_offset;
+      base_rep.item_index = header->base_item_index;
       base_rep.size = header->base_length;
       svn_fs_fs__id_txn_reset(&base_rep.txn_id);
       is_delta = header->type == svn_fs_fs__rep_delta;
@@ -891,7 +1019,7 @@ get_window_key(window_cache_key_t *key, 
 {
   assert(rs->revision <= APR_UINT32_MAX);
   key->revision = (apr_uint32_t)rs->revision;
-  key->offset = rs->offset;
+  key->item_index = rs->item_index;
   key->chunk_index = rs->chunk_index;
 
   return key;
@@ -1111,7 +1239,7 @@ build_rep_list(apr_array_header_t **list
         }
 
       rep.revision = rep_header->base_revision;
-      rep.offset = rep_header->base_offset;
+      rep.item_index = rep_header->base_item_index;
       rep.size = rep_header->base_length;
       svn_fs_fs__id_txn_reset(&rep.txn_id);
 
@@ -1177,7 +1305,7 @@ read_delta_window(svn_txdelta_window_t *
   apr_off_t end_offset;
   SVN_ERR_ASSERT(rs->chunk_index <= this_chunk);
 
-  SVN_ERR(dbg_log_access(rs->file->fs, rs->revision, rs->offset,
+  SVN_ERR(dbg_log_access(rs->sfile->fs, rs->revision, rs->item_index,
                          NULL, SVN_FS_FS__ITEM_TYPE_ANY_REP, pool));
 
   /* Read the next window.  But first, try to find it in the cache. */
@@ -1186,23 +1314,42 @@ read_delta_window(svn_txdelta_window_t *
     return SVN_NO_ERROR;
 
   /* someone has to actually read the data from file.  Open it */
-  SVN_ERR(auto_open_shared_file(rs->file));
+  SVN_ERR(auto_open_shared_file(rs->sfile));
+
+  /* invoke the 'block-read' feature for non-txn data.
+     However, don't do that if we are in the middle of some representation,
+     because the block is unlikely to contain other data. */
+  if (   rs->chunk_index == 0
+      && SVN_IS_VALID_REVNUM(rs->revision)
+      && svn_fs_fs__use_log_addressing(rs->sfile->fs, rs->revision))
+    {
+      SVN_ERR(block_read(NULL, rs->sfile->fs, rs->revision, rs->item_index,
+                         rs->sfile->rfile, pool, pool));
+
+      /* reading the whole block probably also provided us with the
+         desired txdelta window */
+      SVN_ERR(get_cached_window(nwin, rs, this_chunk, &is_cached, pool));
+      if (is_cached)
+        return SVN_NO_ERROR;
+    }
+
+  /* data is still not cached -> we need to read it.
+     Make sure we have all the necessary info. */
   SVN_ERR(auto_set_start_offset(rs, pool));
   SVN_ERR(auto_read_diff_version(rs, pool));
 
   /* RS->FILE may be shared between RS instances -> make sure we point
    * to the right data. */
   start_offset = rs->start + rs->current;
-  SVN_ERR(aligned_seek(rs->file->file, start_offset, pool));
+  SVN_ERR(rs_aligned_seek(rs, NULL, start_offset, pool));
 
   /* Skip windows to reach the current chunk if we aren't there yet. */
   while (rs->chunk_index < this_chunk)
     {
-      SVN_ERR(svn_txdelta_skip_svndiff_window(rs->file->file, rs->ver,
-                                              pool));
+      SVN_ERR(svn_txdelta_skip_svndiff_window(rs->sfile->rfile->file,
+                                              rs->ver, pool));
       rs->chunk_index++;
-      SVN_ERR(svn_fs_fs__get_file_offset(&start_offset, rs->file->file,
-                                         pool));
+      SVN_ERR(get_file_offset(&start_offset, rs, pool));
       rs->current = start_offset - rs->start;
       if (rs->current >= rs->size)
         return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -1212,9 +1359,9 @@ read_delta_window(svn_txdelta_window_t *
     }
 
   /* Actually read the next window. */
-  SVN_ERR(svn_txdelta_read_svndiff_window(nwin, rs->file->stream, rs->ver,
-                                          pool));
-  SVN_ERR(svn_fs_fs__get_file_offset(&end_offset, rs->file->file, pool));
+  SVN_ERR(svn_txdelta_read_svndiff_window(nwin, rs->sfile->rfile->stream,
+                                          rs->ver, pool));
+  SVN_ERR(get_file_offset(&end_offset, rs, pool));
   rs->current = end_offset - rs->start;
   if (rs->current > rs->size)
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -1238,15 +1385,15 @@ read_plain_window(svn_stringbuf_t **nwin
   
   /* RS->FILE may be shared between RS instances -> make sure we point
    * to the right data. */
-  SVN_ERR(auto_open_shared_file(rs->file));
+  SVN_ERR(auto_open_shared_file(rs->sfile));
   SVN_ERR(auto_set_start_offset(rs, pool));
 
   offset = rs->start + rs->current;
-  SVN_ERR(aligned_seek(rs->file->file, offset, pool));
+  SVN_ERR(rs_aligned_seek(rs, NULL, offset, pool));
 
   /* Read the plain data. */
   *nwin = svn_stringbuf_create_ensure(size, pool);
-  SVN_ERR(svn_io_file_read_full2(rs->file->file, (*nwin)->data, size,
+  SVN_ERR(svn_io_file_read_full2(rs->sfile->rfile->file, (*nwin)->data, size,
                                  NULL, NULL, pool));
   (*nwin)->data[size] = 0;
 
@@ -1399,13 +1546,13 @@ get_contents(struct rep_read_baton *rb,
           if (((apr_off_t) copy_len) > rs->size - rs->current)
             copy_len = (apr_size_t) (rs->size - rs->current);
 
-          SVN_ERR(auto_open_shared_file(rs->file));
+          SVN_ERR(auto_open_shared_file(rs->sfile));
           SVN_ERR(auto_set_start_offset(rs, rb->pool));
 
           offset = rs->start + rs->current;
-          SVN_ERR(aligned_seek(rs->file->file, offset, rb->pool));
-          SVN_ERR(svn_io_file_read_full2(rs->file->file, cur, copy_len,
-                                         NULL, NULL, rb->pool));
+          SVN_ERR(rs_aligned_seek(rs, NULL, offset, rb->pool));
+          SVN_ERR(svn_io_file_read_full2(rs->sfile->rfile->file, cur,
+                                         copy_len, NULL, NULL, rb->pool));
         }
 
       rs->current += copy_len;
@@ -1532,7 +1679,7 @@ svn_fs_fs__get_contents(svn_stream_t **c
       struct rep_read_baton *rb;
 
       fulltext_cache_key.revision = rep->revision;
-      fulltext_cache_key.second = rep->offset;
+      fulltext_cache_key.second = rep->item_index;
       if (ffd->fulltext_cache && SVN_IS_VALID_REVNUM(rep->revision)
           && fulltext_size_is_cachable(ffd, len))
         {
@@ -1607,7 +1754,7 @@ svn_fs_fs__try_process_file_contents(svn
       pair_cache_key_t fulltext_cache_key = { 0 };
 
       fulltext_cache_key.revision = rep->revision;
-      fulltext_cache_key.second = rep->offset;
+      fulltext_cache_key.second = rep->item_index;
       if (ffd->fulltext_cache && SVN_IS_VALID_REVNUM(rep->revision)
           && fulltext_size_is_cachable(ffd, rep->expanded_size))
         {
@@ -1685,7 +1832,7 @@ svn_fs_fs__get_file_delta_stream(svn_txd
       if (rep_header->type == svn_fs_fs__rep_self_delta
           || (rep_header->type == svn_fs_fs__rep_delta
               && rep_header->base_revision == source->data_rep->revision
-              && rep_header->base_offset == source->data_rep->offset))
+              && rep_header->base_item_index == source->data_rep->item_index))
         {
           /* Create the delta read baton. */
           struct delta_read_baton *drb = apr_pcalloc(pool, sizeof(*drb));
@@ -1696,9 +1843,11 @@ svn_fs_fs__get_file_delta_stream(svn_txd
                                                 delta_read_md5_digest, pool);
           return SVN_NO_ERROR;
         }
-      else
-        if (rep_state->file->file)
-          SVN_ERR(svn_io_file_close(rep_state->file->file, pool));
+      else if (rep_state->sfile->rfile)
+        {
+          SVN_ERR(svn_fs_fs__close_revision_file(rep_state->sfile->rfile));
+          rep_state->sfile->rfile = NULL;
+        }
     }
 
   /* Read both fulltexts and construct a delta. */
@@ -1855,7 +2004,7 @@ locate_dir_cache(svn_fs_t *fs,
       if (noderev->data_rep)
         {
           pair_key->revision = noderev->data_rep->revision;
-          pair_key->second = noderev->data_rep->offset;
+          pair_key->second = noderev->data_rep->item_index;
           *key = pair_key;
         }
       else
@@ -1985,7 +2134,7 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
       pair_cache_key_t key = { 0 };
 
       key.revision = rep->revision;
-      key.second = rep->offset;
+      key.second = rep->item_index;
       if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
         {
           svn_boolean_t is_cached;
@@ -2014,53 +2163,543 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
   return SVN_NO_ERROR;
 }
 
-/* Fetch the list of change in revision REV in FS and return it in *CHANGES.
- * Allocate the result in POOL.
- */
 svn_error_t *
 svn_fs_fs__get_changes(apr_array_header_t **changes,
                        svn_fs_t *fs,
                        svn_revnum_t rev,
                        apr_pool_t *pool)
 {
-  apr_off_t changes_offset;
-  apr_file_t *revision_file;
+  apr_off_t changes_offset = -1;
+  svn_fs_fs__revision_file_t *revision_file;
+  svn_boolean_t found;
   fs_fs_data_t *ffd = fs->fsap_data;
 
   /* try cache lookup first */
 
   if (ffd->changes_cache)
+    SVN_ERR(svn_cache__get((void **) changes, &found, ffd->changes_cache,
+                           &rev, pool));
+
+  if (!found)
     {
-      svn_boolean_t found;
-      SVN_ERR(svn_cache__get((void **) changes, &found, ffd->changes_cache,
-                             &rev, pool));
-      if (found)
+      /* read changes from revision file */
+
+      SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, pool));
+      SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&revision_file, fs, rev,
+                                               pool));
+
+      if (svn_fs_fs__use_log_addressing(fs, rev))
+        {
+          /* 'block-read' will also provide us with the desired data */
+          SVN_ERR(block_read((void **)changes, fs,
+                             rev, SVN_FS_FS__ITEM_INDEX_CHANGES,
+                             revision_file, pool, pool));
+        }
+      else
+        {
+          /* physical addressing mode code path */
+          SVN_ERR(get_root_changes_offset(NULL, &changes_offset,
+                                          revision_file->file, fs, rev,
+                                          pool));
+
+          SVN_ERR(aligned_seek(fs, revision_file->file, NULL, changes_offset,
+                               pool));
+          SVN_ERR(svn_fs_fs__read_changes(changes, revision_file->stream,
+                                          pool));
+
+          /* cache for future reference */
+
+          if (ffd->changes_cache)
+            SVN_ERR(svn_cache__set(ffd->changes_cache, &rev, *changes, pool));
+        }
+
+      SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
+    }
+
+  SVN_ERR(dbg_log_access(fs, rev, changes_offset, *changes,
+                         SVN_FS_FS__ITEM_TYPE_CHANGES, pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Inialize the representation read state RS for the given REP_HEADER and
+ * p2l index ENTRY.  If not NULL, assign FILE and STREAM to RS.
+ * Use POOL for allocations.
+ */
+static svn_error_t *
+init_rep_state(rep_state_t *rs,
+               svn_fs_fs__rep_header_t *rep_header,
+               svn_fs_t *fs,
+               svn_fs_fs__revision_file_t *file,
+               svn_fs_fs__p2l_entry_t* entry,
+               apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  shared_file_t *shared_file = apr_pcalloc(pool, sizeof(*shared_file));
+
+  /* this function does not apply to representation containers */
+  SVN_ERR_ASSERT(entry->type >= SVN_FS_FS__ITEM_TYPE_FILE_REP
+                 && entry->type <= SVN_FS_FS__ITEM_TYPE_DIR_PROPS);
+  
+  shared_file->rfile = file;
+  shared_file->fs = fs;
+  shared_file->revision = entry->item.revision;
+  shared_file->pool = pool;
+
+  rs->sfile = shared_file;
+  rs->revision = entry->item.revision;
+  rs->item_index = entry->item.number;
+  rs->header_size = rep_header->header_size;
+  rs->start = entry->offset + rs->header_size;
+  rs->current = rep_header->type == svn_fs_fs__rep_plain ? 0 : 4;
+  rs->size = entry->size - rep_header->header_size - 7;
+  rs->ver = 1;
+  rs->chunk_index = 0;
+  rs->window_cache = ffd->txdelta_window_cache;
+  rs->combined_cache = ffd->combined_window_cache;
+
+  return SVN_NO_ERROR;
+}
+
+/* Walk through all windows in the representation addressed by RS in FS
+ * (excluding the delta bases) and put those not already cached into the
+ * window caches.  As a side effect, return the total sum of all expanded
+ * window sizes in *FULLTEXT_LEN.  Use POOL for temporary allocations.
+ */
+static svn_error_t *
+cache_windows(svn_filesize_t *fulltext_len,
+              svn_fs_t *fs,
+              rep_state_t *rs,
+              apr_pool_t *pool)
+{
+  *fulltext_len = 0;
+
+  while (rs->current < rs->size)
+    {
+      svn_txdelta_window_t *window;
+      apr_off_t start_offset = rs->start + rs->current;
+      apr_off_t end_offset;
+
+      /* navigate to & read the current window */
+      SVN_ERR(rs_aligned_seek(rs, NULL, start_offset, pool));
+      SVN_ERR(svn_txdelta_read_svndiff_window(&window,
+                                              rs->sfile->rfile->stream,
+                                              rs->ver, pool));
+
+      /* aggregate expanded window size */
+      *fulltext_len += window->tview_len;
+
+      /* determine on-disk window size */
+      SVN_ERR(get_file_offset(&end_offset, rs, pool));
+      rs->current = end_offset - rs->start;
+      if (rs->current > rs->size)
+        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                      _("Reading one svndiff window read beyond "
+                                  "the end of the representation"));
+
+      /* cache the window now */
+      SVN_ERR(set_cached_window(window, rs, pool));
+
+      rs->chunk_index++;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Read all txdelta / plain windows following REP_HEADER in FS as described
+ * by ENTRY.  Read the data from the already open FILE and the wrapping
+ * STREAM object.  Use POOL for allocations.
+ * If caching is not enabled, this is a no-op.
+ */
+static svn_error_t *
+block_read_windows(svn_fs_fs__rep_header_t *rep_header,
+                   svn_fs_t *fs,
+                   svn_fs_fs__revision_file_t *rev_file,
+                   svn_fs_fs__p2l_entry_t* entry,
+                   apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  rep_state_t rs = { 0 };
+  apr_off_t offset;
+  window_cache_key_t key = { 0 };
+
+  if (   (rep_header->type != svn_fs_fs__rep_plain
+          && !ffd->txdelta_window_cache)
+      || (rep_header->type == svn_fs_fs__rep_plain
+          && !ffd->combined_window_cache))
+    return SVN_NO_ERROR;
+
+  SVN_ERR(init_rep_state(&rs, rep_header, fs, rev_file, entry, pool));
+  
+  /* RS->FILE may be shared between RS instances -> make sure we point
+   * to the right data. */
+  offset = rs.start + rs.current;
+  if (rep_header->type == svn_fs_fs__rep_plain)
+    {
+      svn_stringbuf_t *plaintext;
+      svn_boolean_t is_cached;
+
+      /* already in cache? */
+      SVN_ERR(svn_cache__has_key(&is_cached, rs.combined_cache,
+                                 get_window_key(&key, &rs), pool));
+      if (is_cached)
         return SVN_NO_ERROR;
+
+      /* for larger reps, the header may have crossed a block boundary.
+       * make sure we still read blocks properly aligned, i.e. don't use
+       * plain seek here. */
+      SVN_ERR(aligned_seek(fs, rev_file->file, NULL, offset, pool));
+
+      plaintext = svn_stringbuf_create_ensure(rs.size, pool);
+      SVN_ERR(svn_io_file_read_full2(rev_file->file, plaintext->data,
+                                     rs.size, &plaintext->len, NULL, pool));
+      plaintext->data[plaintext->len] = 0;
+      rs.current += rs.size;
+
+      SVN_ERR(set_cached_combined_window(plaintext, &rs, pool));
+    }
+  else
+    {
+      svn_filesize_t fulltext_len;
+      SVN_ERR(cache_windows(&fulltext_len, fs, &rs, pool));
     }
 
-  /* read changes from revision file */
+  return SVN_NO_ERROR;
+}
 
-  SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, pool));
-  SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&revision_file, fs, rev, pool));
+/* Try to get the representation header identified by KEY from FS's cache.
+ * If it has not been cached, read it from the current position in STREAM
+ * and put it into the cache (if caching has been enabled for rep headers).
+ * Return the result in *REP_HEADER.  Use POOL for allocations.
+ */
+static svn_error_t *
+read_rep_header(svn_fs_fs__rep_header_t **rep_header,
+                svn_fs_t *fs,
+                svn_stream_t *stream,
+                representation_cache_key_t *key,
+                apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  svn_boolean_t is_cached = FALSE;
+  
+  if (ffd->rep_header_cache)
+    {
+      SVN_ERR(svn_cache__get((void**)rep_header, &is_cached,
+                             ffd->rep_header_cache, key, pool));
+      if (is_cached)
+        return SVN_NO_ERROR;
+    }
 
-  SVN_ERR(get_root_changes_offset(NULL, &changes_offset, revision_file, fs,
-                                  rev, pool));
+  SVN_ERR(svn_fs_fs__read_rep_header(rep_header, stream, pool));
 
-  SVN_ERR(aligned_seek(revision_file, changes_offset, pool));
-  SVN_ERR(svn_fs_fs__read_changes(changes,
-                      svn_stream_from_aprfile2(revision_file, TRUE, pool),
-                                  pool));
+  if (ffd->rep_header_cache)
+    SVN_ERR(svn_cache__set(ffd->rep_header_cache, key, *rep_header, pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Fetch the representation data (header, txdelta / plain windows)
+ * addressed by ENTRY->ITEM in FS and cache it if caches are enabled.
+ * Read the data from the already open FILE and the wrapping
+ * STREAM object.  Use POOL for allocations.
+ */
+static svn_error_t *
+block_read_contents(svn_fs_t *fs,
+                    svn_fs_fs__revision_file_t *rev_file,
+                    svn_fs_fs__p2l_entry_t* entry,
+                    apr_pool_t *pool)
+{
+  representation_cache_key_t header_key = { 0 };
+  svn_fs_fs__rep_header_t *rep_header;
+
+  header_key.revision = (apr_int32_t)entry->item.revision;
+  header_key.is_packed = svn_fs_fs__is_packed_rev(fs, header_key.revision);
+  header_key.item_index = entry->item.number;
+
+  SVN_ERR(read_rep_header(&rep_header, fs, rev_file->stream, &header_key,
+                          pool));
+  SVN_ERR(block_read_windows(rep_header, fs, rev_file, entry, pool));
+
+  return SVN_NO_ERROR;
+}
 
-  SVN_ERR(svn_io_file_close(revision_file, pool));
+/* For the given FILE in FS and wrapping FILE_STREAM return the stream
+ * object in *STREAM that has the lowest performance overhead for reading
+ * and parsing the item addressed by ENTRY.  Use POOL for allocations.
+ */
+static svn_error_t *
+auto_select_stream(svn_stream_t **stream,
+                   svn_fs_t *fs,
+                   svn_fs_fs__revision_file_t *rev_file,
+                   svn_fs_fs__p2l_entry_t* entry,
+                   apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  /* Item parser might be crossing block boundaries? */
+  if (((entry->offset + entry->size + SVN__LINE_CHUNK_SIZE) ^ entry->offset)
+      >= ffd->block_size)
+    {
+      /* Parsing items that cross block boundaries will cause the file
+         buffer to be re-read and misaligned.  So, read the whole block
+         into memory - it must fit anyways since the parsed object will
+         be even larger.
+       */
+      svn_stringbuf_t *text = svn_stringbuf_create_ensure(entry->size, pool);
+      text->len = entry->size;
+      text->data[text->len] = 0;
+      SVN_ERR(svn_io_file_read_full2(rev_file->file, text->data, text->len,
+                                     NULL, NULL, pool));
+      *stream = svn_stream_from_stringbuf(text, pool);
+    }
+  else
+    {
+      *stream = rev_file->stream;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* If not already cached or if MUST_READ is set, read the changed paths
+ * list addressed by ENTRY in FS and retúrn it in *CHANGES.  Cache the
+ * result if caching is enabled.  Read the data from the already open
+ * FILE and wrapping FILE_STREAM.  Use POOL for allocations.
+ */
+static svn_error_t *
+block_read_changes(apr_array_header_t **changes,
+                   svn_fs_t *fs,
+                   svn_fs_fs__revision_file_t *rev_file,
+                   svn_fs_fs__p2l_entry_t *entry,
+                   svn_boolean_t must_read,
+                   apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  svn_stream_t *stream;
+  if (!must_read && !ffd->changes_cache)
+    return SVN_NO_ERROR;
+
+  /* already in cache? */
+  if (!must_read && ffd->changes_cache)
+    {
+      svn_boolean_t is_cached;
+      SVN_ERR(svn_cache__has_key(&is_cached, ffd->changes_cache,
+                                 &entry->item.revision, pool));
+      if (is_cached)
+        return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(auto_select_stream(&stream, fs, rev_file, entry, pool));
+
+  /* read changes from revision file */
+
+  SVN_ERR(svn_fs_fs__read_changes(changes, stream, pool));
 
   /* cache for future reference */
 
   if (ffd->changes_cache)
-    SVN_ERR(svn_cache__set(ffd->changes_cache, &rev, *changes, pool));
+    SVN_ERR(svn_cache__set(ffd->changes_cache, &entry->item.revision,
+                           *changes, pool));
 
-  SVN_ERR(dbg_log_access(fs, rev, changes_offset, *changes,
-                         SVN_FS_FS__ITEM_TYPE_CHANGES, pool));
+  return SVN_NO_ERROR;
+}
+
+/* If not already cached or if MUST_READ is set, read the nod revision
+ * addressed by ENTRY in FS and retúrn it in *NODEREV_P.  Cache the
+ * result if caching is enabled.  Read the data from the already open
+ * FILE and wrapping FILE_STREAM.  Use POOL for allocations.
+ */
+static svn_error_t *
+block_read_noderev(node_revision_t **noderev_p,
+                   svn_fs_t *fs,
+                   svn_fs_fs__revision_file_t *rev_file,
+                   svn_fs_fs__p2l_entry_t *entry,
+                   svn_boolean_t must_read,
+                   apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  svn_stream_t *stream;
+
+  pair_cache_key_t key = { 0 };
+  key.revision = entry->item.revision;
+  key.second = entry->item.number;
+
+  if (!must_read && !ffd->node_revision_cache)
+    return SVN_NO_ERROR;
+
+  /* already in cache? */
+  if (!must_read && ffd->node_revision_cache)
+    {
+      svn_boolean_t is_cached;
+      SVN_ERR(svn_cache__has_key(&is_cached, ffd->node_revision_cache,
+                                 &key, pool));
+      if (is_cached)
+        return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(auto_select_stream(&stream, fs, rev_file, entry, pool));
+
+  /* read node rev from revision file */
+
+  SVN_ERR(svn_fs_fs__read_noderev(noderev_p, stream, pool));
+
+  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
+  (*noderev_p)->is_fresh_txn_root = FALSE;
+
+  if (ffd->node_revision_cache)
+    SVN_ERR(svn_cache__set(ffd->node_revision_cache, &key, *noderev_p,
+                           pool));
 
   return SVN_NO_ERROR;
 }
 
+/* Read the whole (e.g. 64kB) block containing ITEM_INDEX of REVISION in FS
+ * and put all data into cache.  If necessary and depending on heuristics,
+ * neighboring blocks may also get read.  The data is being read from
+ * already open REVISION_FILE, which must be the correct rev / pack file
+ * w.r.t. REVISION.
+ *
+ * For noderevs and changed path lists, the item fetched can be allocated
+ * RESULT_POOL and returned in *RESULT.  Otherwise, RESULT must be NULL.
+ */
+static svn_error_t *
+block_read(void **result,
+           svn_fs_t *fs,
+           svn_revnum_t revision,
+           apr_uint64_t item_index,
+           svn_fs_fs__revision_file_t *revision_file,
+           apr_pool_t *result_pool,
+           apr_pool_t *scratch_pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  apr_off_t offset, wanted_offset = 0;
+  apr_off_t block_start = 0;
+  apr_array_header_t *entries;
+  int run_count = 0;
+  int i;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  /* don't try this on transaction protorev files */
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
+  
+  /* index lookup: find the OFFSET of the item we *must* read plus (in the
+   * "do-while" block) the list of items in the same block. */
+  SVN_ERR(svn_fs_fs__item_offset(&wanted_offset, fs, revision_file,
+                                 revision, NULL, item_index, iterpool));
+
+  offset = wanted_offset;
+
+  /* Heuristics:
+   *
+   * Read this block.  If the last item crosses the block boundary, read
+   * the next block but stop there.  Because cross-boundary items cause
+   * blocks to be read twice, this heuristics will limit this effect to
+   * approx. 50% of blocks, probably less, while providing a sensible
+   * amount of read-ahead.
+   */
+  do
+    {
+      /* fetch list of items in the block surrounding OFFSET */
+      svn_error_t *err
+        = svn_fs_fs__p2l_index_lookup(&entries, fs, revision_file,
+                                      revision, offset, scratch_pool);
+
+      /* if the revision got packed in the meantime and we still need need
+       * to actually read some item, we retry the whole process */
+      if (err &&
+          revision_file->is_packed != svn_fs_fs__is_packed_rev(fs, revision))
+        {
+          if (result && !*result)
+            {
+              SVN_ERR(svn_fs_fs__reopen_revision_file(revision_file, fs, 
+                                                      revision));
+              SVN_ERR(block_read(result, fs, revision, item_index,
+                                  revision_file, result_pool, scratch_pool));
+            }
+
+          return SVN_NO_ERROR;
+        }
+
+      SVN_ERR(err);
+      SVN_ERR(aligned_seek(fs, revision_file->file, &block_start, offset,
+                           iterpool));
+
+      /* read all items from the block */
+      for (i = 0; i < entries->nelts; ++i)
+        {
+          svn_boolean_t is_result;
+          apr_pool_t *pool;
+          svn_fs_fs__p2l_entry_t* entry;
+
+          svn_pool_clear(iterpool);
+
+          /* skip empty sections */
+          entry = &APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t);
+          if (entry->type == SVN_FS_FS__ITEM_TYPE_UNUSED)
+            continue;
+
+          /* the item / container we were looking for? */
+          is_result =    result
+                      && entry->offset == wanted_offset
+                      && entry->item.revision == revision
+                      && entry->item.number == item_index;
+
+          /* select the pool that we want the item to be allocated in */
+          pool = is_result ? result_pool : iterpool;
+
+          /* handle all items that start within this block and are relatively
+           * small (i.e. < block size).  Always read the item we need to return.
+           */
+          if (is_result || (   entry->offset >= block_start
+                            && entry->size < ffd->block_size))
+            {
+              void *item = NULL;
+              SVN_ERR(svn_io_file_seek(revision_file->file, SEEK_SET,
+                                       &entry->offset, iterpool));
+              switch (entry->type)
+                {
+                  case SVN_FS_FS__ITEM_TYPE_FILE_REP:
+                  case SVN_FS_FS__ITEM_TYPE_DIR_REP:
+                  case SVN_FS_FS__ITEM_TYPE_FILE_PROPS:
+                  case SVN_FS_FS__ITEM_TYPE_DIR_PROPS:
+                    SVN_ERR(block_read_contents(fs, revision_file, entry,
+                                                pool));
+                    break;
+
+                  case SVN_FS_FS__ITEM_TYPE_NODEREV:
+                    if (ffd->node_revision_cache || is_result)
+                      SVN_ERR(block_read_noderev((node_revision_t **)&item,
+                                                 fs, revision_file,
+                                                 entry, is_result, pool));
+                    break;
+
+                  case SVN_FS_FS__ITEM_TYPE_CHANGES:
+                    SVN_ERR(block_read_changes((apr_array_header_t **)&item,
+                                               fs, revision_file,
+                                               entry, is_result, pool));
+                    break;
+
+                  default:
+                    break;
+                }
+
+              if (is_result)
+                *result = item;
+
+              /* if we crossed a block boundary, read the remainder of
+               * the last block as well */
+              offset = entry->offset + entry->size;
+              if (offset > block_start + ffd->block_size)
+                ++run_count;
+            }
+        }
+
+    }
+  while(run_count++ == 1); /* can only be true once and only if a block
+                            * boundary got crossed */
+
+  /* if the caller requested a result, we must have provided one by now */
+  assert(!result || *result);
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}



Mime
View raw message