Author: stsp
Date: Tue Mar 31 08:53:55 2020
New Revision: 1875921

URL: http://svn.apache.org/viewvc?rev=1875921&view=rev
Log:
Introduce 'svnadmin build-repcache' command.

Implement the 'svnadmin build-repcache' CLI and add an ioctl API for building
the representation cache.

The implementation iterates over revisions in the specified range and 
recursively
processes the changed nodes, starting from the corresponding revision roots.
For each changed node, it ensures that its data and property representations
exist in the rep-cache. The nodes are processed in the same order as when
committing a transaction (see write_final_rev() function in 
libsvn_fs_fs/transaction.c),
so that the rep-cache.db files are fully consistent.

* subversion/svnadmin/svnadmin.c
  (cmd_table): Add and document the 'build-repcache' command.
  (subcommand_build_repcache,
   build_rep_cache,
   build_rep_cache_progress_func): New.

* subversion/include/svn_error_codes.h
  (SVN_ERR_FS_REP_SHARING_NOT_ALLOWED,
   SVN_ERR_FS_REP_SHARING_NOT_SUPPORTED): New error codes.

* subversion/include/private/svn_fs_fs_private.h
  (svn_fs_fs__ioctl_build_rep_cache_input_t,
   SVN_FS_FS__IOCTL_BUILD_REP_CACHE): New.

* subversion/libsvn_fs_fs/fs.c
  (fs_ioctl): Handle SVN_FS_FS__IOCTL_BUILD_REP_CACHE.

* subversion/libsvn_fs_fs/fs_fs.h
* subversion/libsvn_fs_fs/fs_fs.c
  (): Include 'low_level.h'.
  (svn_fs_fs__build_rep_cache,
   reindex_node,
   ensure_representation_sha1): New. Iterate over revisions and recursively
   process the changed nodes. For each changed node, ensure that its data
   and property representations exist in the rep-cache.

* subversion/tests/cmdline/svnadmin_tests.py
  (build_repcache): New test.
  (test_list): Add the new test.

* subversion/tests/libsvn_fs_fs/fs-fs-private-test.c
  (): Include 'libsvn_fs_fs/rep-cache.h' and 'libsvn_fs/fs-loader.h'.
  (build_rep_cache): New test.
  (test_funcs): Add the new test.

* tools/client-side/bash_completion
  (_svnadmin): Add the 'build-repcache' command.

Patch by: Denis Kovalchuk <[email protected]>

Modified:
    subversion/trunk/subversion/include/private/svn_fs_fs_private.h
    subversion/trunk/subversion/include/svn_error_codes.h
    subversion/trunk/subversion/libsvn_fs_fs/fs.c
    subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c
    subversion/trunk/subversion/libsvn_fs_fs/fs_fs.h
    subversion/trunk/subversion/svnadmin/svnadmin.c
    subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py
    subversion/trunk/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c
    subversion/trunk/tools/client-side/bash_completion

Modified: subversion/trunk/subversion/include/private/svn_fs_fs_private.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_fs_fs_private.h?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_fs_fs_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_fs_fs_private.h Tue Mar 31 
08:53:55 2020
@@ -353,6 +353,17 @@ typedef struct svn_fs_fs__ioctl_revision
 /* See svn_fs_fs__revision_size(). */
 SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_REVISION_SIZE, SVN_FS_TYPE_FSFS, 
1003);
 
+typedef struct svn_fs_fs__ioctl_build_rep_cache_input_t
+{
+  svn_revnum_t start_rev;
+  svn_revnum_t end_rev;
+  svn_fs_progress_notify_func_t progress_func;
+  void *progress_baton;
+} svn_fs_fs__ioctl_build_rep_cache_input_t;
+
+/* See svn_fs_fs__build_rep_cache(). */
+SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_BUILD_REP_CACHE, SVN_FS_TYPE_FSFS, 
1004);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/trunk/subversion/include/svn_error_codes.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_error_codes.h?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_error_codes.h (original)
+++ subversion/trunk/subversion/include/svn_error_codes.h Tue Mar 31 08:53:55 
2020
@@ -893,6 +893,16 @@ SVN_ERROR_START
              SVN_ERR_FS_CATEGORY_START + 68,
              "Unrecognized filesystem I/O control code")
 
+  /** @since New in 1.14. */
+  SVN_ERRDEF(SVN_ERR_FS_REP_SHARING_NOT_ALLOWED,
+             SVN_ERR_FS_CATEGORY_START + 69,
+             "Rep-sharing is not allowed.")
+
+  /** @since New in 1.14. */
+  SVN_ERRDEF(SVN_ERR_FS_REP_SHARING_NOT_SUPPORTED,
+             SVN_ERR_FS_CATEGORY_START + 70,
+             "Rep-sharing is not supported.")
+
   /* repos errors */
 
   SVN_ERRDEF(SVN_ERR_REPOS_LOCKED,

Modified: subversion/trunk/subversion/libsvn_fs_fs/fs.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/fs.c?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/fs.c Tue Mar 31 08:53:55 2020
@@ -312,6 +312,22 @@ fs_ioctl(svn_fs_t *fs, svn_fs_ioctl_code
           *output_p = output;
           return SVN_NO_ERROR;
         }
+      else if (ctlcode.code == SVN_FS_FS__IOCTL_BUILD_REP_CACHE.code)
+        {
+          svn_fs_fs__ioctl_build_rep_cache_input_t *input = input_void;
+
+          SVN_ERR(svn_fs_fs__build_rep_cache(fs,
+                                             input->start_rev,
+                                             input->end_rev,
+                                             input->progress_func,
+                                             input->progress_baton,
+                                             cancel_func,
+                                             cancel_baton,
+                                             scratch_pool));
+
+          *output_p = NULL;
+          return SVN_NO_ERROR;
+        }
     }
 
   return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL);

Modified: subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c Tue Mar 31 08:53:55 2020
@@ -37,6 +37,7 @@
 #include "cached_data.h"
 #include "id.h"
 #include "index.h"
+#include "low_level.h"
 #include "rep-cache.h"
 #include "revprops.h"
 #include "transaction.h"
@@ -2343,3 +2344,168 @@ svn_fs_fs__info_config_files(apr_array_h
                                                          result_pool);
   return SVN_NO_ERROR;
 }
+
+static svn_error_t *
+ensure_representation_sha1(svn_fs_t *fs,
+                           representation_t *rep,
+                           apr_pool_t *pool)
+{
+  if (!rep->has_sha1)
+    {
+      svn_stream_t *contents;
+      svn_checksum_t *checksum;
+
+      SVN_ERR(svn_fs_fs__get_contents(&contents, fs, rep, FALSE, pool));
+      SVN_ERR(svn_stream_contents_checksum(&checksum, contents,
+                                           svn_checksum_sha1, pool, pool));
+
+      memcpy(rep->sha1_digest, checksum->digest, APR_SHA1_DIGESTSIZE);
+      rep->has_sha1 = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+reindex_node(svn_fs_t *fs,
+             const svn_fs_id_t *id,
+             svn_revnum_t rev,
+             svn_fs_fs__revision_file_t *rev_file,
+             svn_cancel_func_t cancel_func,
+             void *cancel_baton,
+             apr_pool_t *pool)
+{
+  node_revision_t *noderev;
+  apr_off_t offset;
+
+  if (svn_fs_fs__id_rev(id) != rev)
+    {
+      return SVN_NO_ERROR;
+    }
+
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
+
+  SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, rev, NULL,
+                                 svn_fs_fs__id_item(id), pool));
+
+  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
+  SVN_ERR(svn_fs_fs__read_noderev(&noderev, rev_file->stream,
+                                  pool, pool));
+
+  /* First reindex sub-directory to match write_final_rev() behavior. */
+  if (noderev->kind == svn_node_dir)
+    {
+      apr_array_header_t *entries;
+
+      SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, noderev, pool, pool));
+
+      if (entries->nelts > 0)
+        {
+          int i;
+          apr_pool_t *iterpool;
+
+          iterpool = svn_pool_create(pool);
+          for (i = 0; i < entries->nelts; i++)
+            {
+              const svn_fs_dirent_t *dirent;
+
+              svn_pool_clear(iterpool);
+
+              dirent = APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *);
+
+              SVN_ERR(reindex_node(fs, dirent->id, rev, rev_file,
+                                   cancel_func, cancel_baton, iterpool));
+            }
+          svn_pool_destroy(iterpool);
+        }
+    }
+
+  if (noderev->data_rep && noderev->data_rep->revision == rev &&
+      noderev->kind == svn_node_file)
+    {
+      SVN_ERR(ensure_representation_sha1(fs, noderev->data_rep, pool));
+      SVN_ERR(svn_fs_fs__set_rep_reference(fs, noderev->data_rep, pool));
+    }
+
+  if (noderev->prop_rep && noderev->prop_rep->revision == rev)
+    {
+      SVN_ERR(ensure_representation_sha1(fs, noderev->prop_rep, pool));
+      SVN_ERR(svn_fs_fs__set_rep_reference(fs, noderev->prop_rep, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__build_rep_cache(svn_fs_t *fs,
+                           svn_revnum_t start_rev,
+                           svn_revnum_t end_rev,
+                           svn_fs_progress_notify_func_t progress_func,
+                           void *progress_baton,
+                           svn_cancel_func_t cancel_func,
+                           void *cancel_baton,
+                           apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  apr_pool_t *iterpool;
+  svn_revnum_t rev;
+
+  if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT)
+    {
+      return svn_error_createf(SVN_ERR_FS_REP_SHARING_NOT_SUPPORTED, NULL,
+                               _("FSFS format (%d) too old for rep-sharing; "
+                                 "please upgrade the filesystem."),
+                               ffd->format);
+    }
+
+  if (!ffd->rep_sharing_allowed)
+    {
+      return svn_error_create(SVN_ERR_FS_REP_SHARING_NOT_ALLOWED, NULL,
+                              _("Filesystem does not allow rep-sharing."));
+    }
+
+  /* Do not build rep-cache for revision zero to match
+   * svn_fs_fs__create() behavior. */
+  if (start_rev == SVN_INVALID_REVNUM)
+    start_rev = 1;
+
+  if (end_rev == SVN_INVALID_REVNUM)
+    SVN_ERR(svn_fs_fs__youngest_rev(&end_rev, fs, pool));
+
+  /* Do nothing for empty FS. */
+  if (start_rev > end_rev)
+    {
+      return SVN_NO_ERROR;
+    }
+
+  if (!ffd->rep_cache_db)
+    SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool));
+
+  iterpool = svn_pool_create(pool);
+  for (rev = start_rev; rev <= end_rev; rev++)
+    {
+      svn_fs_id_t *root_id;
+      svn_fs_fs__revision_file_t *file;
+      svn_error_t *err;
+
+      svn_pool_clear(iterpool);
+
+      if (progress_func)
+        progress_func(rev, progress_baton, iterpool);
+
+      SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&file, fs, rev,
+                                               iterpool, iterpool));
+      SVN_ERR(svn_fs_fs__rev_get_root(&root_id, fs, rev, iterpool, iterpool));
+
+      SVN_ERR(svn_sqlite__begin_transaction(ffd->rep_cache_db));
+      err = reindex_node(fs, root_id, rev, file, cancel_func, cancel_baton, 
iterpool);
+      SVN_ERR(svn_sqlite__finish_transaction(ffd->rep_cache_db, err));
+
+      SVN_ERR(svn_fs_fs__close_revision_file(file));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/trunk/subversion/libsvn_fs_fs/fs_fs.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/fs_fs.h?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/fs_fs.h Tue Mar 31 08:53:55 2020
@@ -356,4 +356,23 @@ svn_fs_fs__revision_size(apr_off_t *rev_
                          svn_revnum_t revision,
                          apr_pool_t *scratch_pool);
 
+/* Add missing entries to the rep-cache on the filesystem FS. Process data
+ * in revisions START_REV through END_REV inclusive. If START_REV is
+ * SVN_INVALID_REVNUM, start at revision 1; if END_REV is SVN_INVALID_REVNUM,
+ * end at the head revision. If the rep-cache does not exist, then create it.
+ *
+ * Indicate progress via the optional PROGRESS_FUNC callback using
+ * PROGRESS_BATON. The optional CANCEL_FUNC will periodically be called with
+ * CANCEL_BATON to allow cancellation. Use POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__build_rep_cache(svn_fs_t *fs,
+                           svn_revnum_t start_rev,
+                           svn_revnum_t end_rev,
+                           svn_fs_progress_notify_func_t progress_func,
+                           void *progress_baton,
+                           svn_cancel_func_t cancel_func,
+                           void *cancel_baton,
+                           apr_pool_t *pool);
+
 #endif

Modified: subversion/trunk/subversion/svnadmin/svnadmin.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnadmin/svnadmin.c?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/subversion/svnadmin/svnadmin.c (original)
+++ subversion/trunk/subversion/svnadmin/svnadmin.c Tue Mar 31 08:53:55 2020
@@ -97,6 +97,7 @@ check_lib_versions(void)
 /** Subcommands. **/
 
 static svn_opt_subcommand_t
+  subcommand_build_repcache,
   subcommand_crashtest,
   subcommand_create,
   subcommand_delrevprop,
@@ -306,6 +307,16 @@ static const apr_getopt_option_t options
  */
 static const svn_opt_subcommand_desc3_t cmd_table[] =
 {
+  {"build-repcache", subcommand_build_repcache, {0}, {N_(
+    "usage: svnadmin build-repcache REPOS_PATH [-r LOWER[:UPPER]]\n"
+    "\n"), N_(
+    "Add missing entries to the representation cache for the repository\n"
+    "at REPOS_PATH. Process data in revisions LOWER through UPPER.\n"
+    "If no revision arguments are given, process all revisions. If only\n"
+    "LOWER revision argument is given, process only that single revision.\n"
+   )},
+   {'r', 'q', 'M'} },
+
   {"crashtest", subcommand_crashtest, {0}, {N_(
     "usage: svnadmin crashtest REPOS_PATH\n"
     "\n"), N_(
@@ -2922,6 +2933,107 @@ subcommand_rev_size(apr_getopt_t *os, vo
 
   return SVN_NO_ERROR;
 }
+
+static void
+build_rep_cache_progress_func(svn_revnum_t revision,
+                              void *baton,
+                              apr_pool_t *pool)
+{
+  svn_error_clear(svn_cmdline_printf(pool,
+                                     _("* Processed revision %ld.\n"),
+                                     revision));
+}
+
+static svn_error_t *
+build_rep_cache(svn_fs_t *fs,
+                svn_revnum_t start_rev,
+                svn_revnum_t end_rev,
+                struct svnadmin_opt_state *opt_state,
+                apr_pool_t *pool)
+{
+  svn_fs_fs__ioctl_build_rep_cache_input_t input = {0};
+  svn_error_t *err;
+
+  input.start_rev = start_rev;
+  input.end_rev = end_rev;
+
+  if (opt_state->quiet)
+    {
+      input.progress_func = NULL;
+      input.progress_baton = NULL;
+    }
+  else
+    {
+      input.progress_func = build_rep_cache_progress_func;
+      input.progress_baton = NULL;
+    }
+
+  err = svn_fs_ioctl(fs, SVN_FS_FS__IOCTL_BUILD_REP_CACHE,
+                     &input, NULL,
+                     check_cancel, NULL, pool, pool);
+  if (err && err->apr_err == SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE)
+    {
+      return svn_error_quick_wrapf(err,
+                                   _("Building rep-cache is not implemented "
+                                     "for the filesystem type found in '%s'"),
+                                   svn_fs_path(fs, pool));
+    }
+  else if (err && err->apr_err == SVN_ERR_FS_REP_SHARING_NOT_ALLOWED)
+    {
+      svn_error_clear(err);
+      SVN_ERR(svn_cmdline_printf(pool,
+                                 _("svnadmin: Warning - this repository has 
rep-sharing disabled."
+                                   " Building rep-cache has no effect.\n")));
+      return SVN_NO_ERROR;
+    }
+  else
+    {
+      return err;
+    }
+}
+
+/* This implements `svn_opt_subcommand_t'. */
+static svn_error_t *
+subcommand_build_repcache(apr_getopt_t *os, void *baton, apr_pool_t *pool)
+{
+  struct svnadmin_opt_state *opt_state = baton;
+  svn_repos_t *repos;
+  svn_fs_t *fs;
+  svn_revnum_t youngest;
+  svn_revnum_t lower;
+  svn_revnum_t upper;
+
+  /* Expect no more arguments. */
+  SVN_ERR(parse_args(NULL, os, 0, 0, pool));
+
+  SVN_ERR(open_repos(&repos, opt_state->repository_path, opt_state, pool));
+  fs = svn_repos_fs(repos);
+  SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
+
+  SVN_ERR(get_revnum(&lower, &opt_state->start_revision,
+                     youngest, repos, pool));
+  SVN_ERR(get_revnum(&upper, &opt_state->end_revision,
+                     youngest, repos, pool));
+
+  if (SVN_IS_VALID_REVNUM(lower) && SVN_IS_VALID_REVNUM(upper))
+    {
+      if (lower > upper)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("First revision cannot be higher than 
second"));
+    }
+  else if (SVN_IS_VALID_REVNUM(lower))
+    {
+      upper = lower;
+    }
+  else
+    {
+      upper = youngest;
+    }
+
+  SVN_ERR(build_rep_cache(fs, lower, upper, opt_state, pool));
+
+  return SVN_NO_ERROR;
+}
 
 
 /** Main. **/

Modified: subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py Tue Mar 31 
08:53:55 2020
@@ -4036,6 +4036,27 @@ PROPS-END
   if output != ['\n', '\n']:
     raise svntest.Failure("Unexpected property value %s" % output)
 
+@SkipUnless(svntest.main.is_fs_type_fsfs)
+@SkipUnless(svntest.main.fs_has_rep_sharing)
+def build_repcache(sbox):
+  "svnadmin build-repcache"
+
+  sbox.build(create_wc = False)
+
+  # Remember and remove the existing rep-cache.
+  rep_cache = read_rep_cache(sbox.repo_dir)
+  rep_cache_path = os.path.join(sbox.repo_dir, 'db', 'rep-cache.db')
+  os.remove(rep_cache_path)
+
+  # Build a new rep-cache and compare with the original one.
+  expected_output = ["* Processed revision 1.\n"]
+  svntest.actions.run_and_verify_svnadmin(expected_output, [],
+                                          "build-repcache", sbox.repo_dir)
+
+  new_rep_cache = read_rep_cache(sbox.repo_dir)
+  if new_rep_cache != rep_cache:
+    raise svntest.Failure
+
 
 ########################################################################
 # Run the tests
@@ -4116,6 +4137,7 @@ test_list = [ None,
               recover_prunes_rep_cache_when_disabled,
               dump_include_copied_directory,
               load_normalize_node_props,
+              build_repcache,
              ]
 
 if __name__ == '__main__':

Modified: subversion/trunk/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c 
(original)
+++ subversion/trunk/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c Tue Mar 
31 08:53:55 2020
@@ -35,6 +35,8 @@
 #include "private/svn_subr_private.h"
 
 #include "../../libsvn_fs_fs/index.h"
+#include "../../libsvn_fs_fs/rep-cache.h"
+#include "../../libsvn_fs/fs-loader.h"
 
 #include "../svn_test_fs.h"
 
@@ -440,6 +442,63 @@ load_index(const svn_test_opts_t *opts,
 
 #undef REPO_NAME
 
+/* ------------------------------------------------------------------------ */
+
+static svn_error_t *
+build_rep_cache(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  fs_fs_data_t *ffd;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root;
+  svn_revnum_t rev;
+  svn_boolean_t exists;
+  const char *fs_path;
+  svn_fs_fs__ioctl_build_rep_cache_input_t input = {0};
+
+  /* Bail (with success) on known-untestable scenarios */
+  if (strcmp(opts->fs_type, "fsfs") != 0)
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
+                            "this will test FSFS repositories only");
+
+  if (opts->server_minor_version && (opts->server_minor_version < 6))
+    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
+                            "pre-1.6 SVN doesn't support FSFS rep-sharing");
+
+  /* Create a filesystem and explicitly disable rep-sharing. */
+  fs_path = "test-repo-build-rep-cache-test";
+  SVN_ERR(svn_test__create_fs2(&fs, fs_path, opts, NULL, pool));
+  ffd = fs->fsap_data;
+  ffd->rep_sharing_allowed = FALSE;
+
+  /* Add the Greek tree. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
+  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
+  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(rev));
+
+  /* Make sure the rep-cache does not exist. */
+  SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, fs, pool));
+  SVN_TEST_ASSERT(!exists);
+
+  /* Build and verify the rep-cache. */
+  ffd->rep_sharing_allowed = TRUE;
+
+  input.start_rev = rev;
+  input.end_rev = rev;
+  SVN_ERR(svn_fs_ioctl(fs, SVN_FS_FS__IOCTL_BUILD_REP_CACHE,
+                       &input, NULL, NULL, NULL, pool, pool));
+
+  SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, fs, pool));
+  SVN_TEST_ASSERT(exists);
+
+  SVN_ERR(svn_fs_verify(fs_path, NULL, 0, SVN_INVALID_REVNUM,
+                        NULL, NULL, NULL, NULL, pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 
 /* The test table.  */
@@ -455,6 +514,8 @@ static struct svn_test_descriptor_t test
                        "dump the P2L index"),
     SVN_TEST_OPTS_PASS(load_index,
                        "load the P2L index"),
+    SVN_TEST_OPTS_PASS(build_rep_cache,
+                       "build the representation cache"),
     SVN_TEST_NULL
   };
 

Modified: subversion/trunk/tools/client-side/bash_completion
URL: 
http://svn.apache.org/viewvc/subversion/trunk/tools/client-side/bash_completion?rev=1875921&r1=1875920&r2=1875921&view=diff
==============================================================================
--- subversion/trunk/tools/client-side/bash_completion (original)
+++ subversion/trunk/tools/client-side/bash_completion Tue Mar 31 08:53:55 2020
@@ -1137,7 +1137,7 @@ _svnadmin ()
        cur=${COMP_WORDS[COMP_CWORD]}
 
        # Possible expansions, without pure-prefix abbreviations such as "h".
-       cmds='crashtest create delrevprop deltify dump dump-revprops freeze \
+       cmds='build-repcache crashtest create delrevprop deltify dump 
dump-revprops freeze \
              help hotcopy info list-dblogs list-unused-dblogs \
              load load-revprops lock lslocks lstxns pack recover rev-size 
rmlocks \
              rmtxns setlog setrevprop setuuid unlock upgrade verify --version'
@@ -1163,6 +1163,9 @@ _svnadmin ()
 
        cmdOpts=
        case ${COMP_WORDS[1]} in
+       build-repcache)
+               cmdOpts="-r --revision -q --quiet -M --memory-cache-size"
+               ;;
        create)
                cmdOpts="--bdb-txn-nosync --bdb-log-keep --config-dir \
                         --fs-type --compatible-version"


Reply via email to