subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cmpil...@apache.org
Subject svn commit: r1186392 - in /subversion/trunk/subversion: include/svn_repos.h libsvn_repos/deprecated.c libsvn_repos/load-fs-vtable.c svnadmin/main.c tests/cmdline/svnadmin_tests.py
Date Wed, 19 Oct 2011 18:44:37 GMT
Author: cmpilato
Date: Wed Oct 19 18:44:36 2011
New Revision: 1186392

URL: http://svn.apache.org/viewvc?rev=1186392&view=rev
Log:
Finish issue #3734 ('Add revision-based filtering to the dumpstream
load functionality').  Add support for the --revision (-r) option for
'svnadmin load' to facilitate incremental loads.

* subversion/include/svn_repos.h
  (svn_repos_notify_action_t): Add 'svn_repos_notify_load_skipped_rev'
    enum value.
  (svn_repos_load_fs4, svn_repos_get_fs_build_parser4): New versions
    of these APIs which add 'start_rev' and 'end_rev' parameters.
  (svn_repos_load_fs3, svn_repos_get_fs_build_parser3): Deprecate.

* subversion/libsvn_repos/load-fs-vtable.c
  (struct parse_baton): Add 'start_rev' and 'end_rev' members.
  (struct revision_baton): Add 'skipped' member.
  (new_revision_record): Don't create a transaction when skipping
    revisions, but do notify about the skip.
  (new_node_record, set_revision_property, set_node_property,
    delete_node_property, remove_node_props, apply_textdelta,
    set_fulltext, close_node, close_revision): Don't make any real FS
    changes if we're skipping the current revision.
  (svn_repos_load_fs4): Was svn_repos_load_fs3().  Add 'start_rev' and
    'end_rev' parameters.  Update call to svn_repos_get_fs_build_parser4().
  (svn_repos_get_fs_build_parser4): Was svn_repos_get_fs_build_parser3(). 
    Add 'start_rev' and 'end_rev' parameters, which are validated and
    then stuff into the parse_baton.

* subversion/libsvn_repos/deprecated.c
  (svn_repos_load_fs3): New wrapper around svn_repos_load_fs4().
  (svn_repos_get_fs_build_parser3): New wrapper around
    svn_repos_get_fs_build_parser4().

* subversion/svnadmin/main.c
  (cmd_table): Cause the 'load' command to also accept the --revision (-r)
    option.
  (repos_notify_handler): Handle the svn_repos_notify_load_skipped_rev
    notification, too.
  (optrev_to_revnum): New helper function.
  (subcommand_load): Handle revision options now with an updated call
    to svn_fs_load_fs4().

* subversion/tests/cmdline/svnadmin_tests.py
  (load_ranges): New test.
  (test_list): Add reference to new test.

Modified:
    subversion/trunk/subversion/include/svn_repos.h
    subversion/trunk/subversion/libsvn_repos/deprecated.c
    subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c
    subversion/trunk/subversion/svnadmin/main.c
    subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py

Modified: subversion/trunk/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_repos.h?rev=1186392&r1=1186391&r2=1186392&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_repos.h (original)
+++ subversion/trunk/subversion/include/svn_repos.h Wed Oct 19 18:44:36 2011
@@ -242,7 +242,10 @@ typedef enum svn_repos_notify_action_t
   svn_repos_notify_recover_start,
 
   /** Upgrade has started. */
-  svn_repos_notify_upgrade_start
+  svn_repos_notify_upgrade_start,
+
+  /** A revision was skipped during loading. @since New in 1.8. */
+  svn_repos_notify_load_skipped_rev
 
 } svn_repos_notify_action_t;
 
@@ -2547,6 +2550,13 @@ svn_repos_dump_fs(svn_repos_t *repos,
  * If the dumpstream contains no UUID, then @a uuid_action is
  * ignored and the repository UUID is not touched.
  *
+ * @a start_rev and @a end_rev act as filters, the lower and upper
+ * (inclusive) range values of revisions in @a dumpstream which will
+ * be loaded.  Either both of these values are #SVN_INVALID_REVNUM (in
+ * which case no revision-based filtering occurs at all), or both are
+ * valid revisions (where @a start_rev is older than or equivalent to
+ * @a end_rev).
+ *
  * If @a parent_dir is not NULL, then the parser will reparent all the
  * loaded nodes, from root to @a parent_dir.  The directory @a parent_dir
  * must be an existing directory in the repository.
@@ -2568,8 +2578,38 @@ svn_repos_dump_fs(svn_repos_t *repos,
  * @a cancel_baton as argument to see if the client wishes to cancel
  * the load.
  *
+ * @note If @a start_rev and @end_rev are valid revisions, this
+ * function presumes the revisions as numbered in @a dumpstream only
+ * increase from the beginning of the stream to the end.  Gaps in the
+ * number sequence are ignored, but upon finding a revision number
+ * younger than the specified range, this function may stop loading
+ * new revisions regardless of their number.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_repos_load_fs4(svn_repos_t *repos,
+                   svn_stream_t *dumpstream,
+                   svn_revnum_t start_rev,
+                   svn_revnum_t end_rev,
+                   enum svn_repos_load_uuid uuid_action,
+                   const char *parent_dir,
+                   svn_boolean_t use_pre_commit_hook,
+                   svn_boolean_t use_post_commit_hook,
+                   svn_boolean_t validate_props,
+                   svn_repos_notify_func_t notify_func,
+                   void *notify_baton,
+                   svn_cancel_func_t cancel_func,
+                   void *cancel_baton,
+                   apr_pool_t *pool);
+
+/** Similar to svn_repos_load_fs4(), but with @a start_rev and @a
+ * end_rev always passed as #SVN_INVALID_REVNUM.
+ *
  * @since New in 1.7.
+ * @deprecated Provided for backward compatibility with the 1.7 API.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_repos_load_fs3(svn_repos_t *repos,
                    svn_stream_t *dumpstream,
@@ -2758,6 +2798,13 @@ svn_repos_parse_dumpstream2(svn_stream_t
  * UUID records in a manner consistent with @a uuid_action.  Use @a pool
  * to operate on the fs.
  *
+ * @a start_rev and @a end_rev act as filters, the lower and upper
+ * (inclusive) range values of revisions in @a dumpstream which will
+ * be loaded.  Either both of these values are #SVN_INVALID_REVNUM (in
+ * which case no revision-based filtering occurs at all), or both are
+ * valid revisions (where @a start_rev is older than or equivalent to
+ * @a end_rev).
+ *
  * If @a use_history is set, then the parser will require relative
  * 'copyfrom' history to exist in the repository when it encounters
  * nodes that are added-with-history.
@@ -2770,10 +2817,37 @@ svn_repos_parse_dumpstream2(svn_stream_t
  * loaded nodes, from root to @a parent_dir.  The directory @a parent_dir
  * must be an existing directory in the repository.
  *
- * Print all parsing feedback to @a outstream (if non-@c NULL).
+ * @note If @a start_rev and @end_rev are valid revisions, this
+ * function presumes the revisions as numbered in @a dumpstream only
+ * increase from the beginning of the stream to the end.  Gaps in the
+ * number sequence are ignored, but upon finding a revision number
+ * younger than the specified range, this function may stop loading
+ * new revisions regardless of their number.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_repos_get_fs_build_parser4(const svn_repos_parse_fns2_t **parser,
+                               void **parse_baton,
+                               svn_repos_t *repos,
+                               svn_revnum_t start_rev,
+                               svn_revnum_t end_rev,
+                               svn_boolean_t use_history,
+                               svn_boolean_t validate_props,
+                               enum svn_repos_load_uuid uuid_action,
+                               const char *parent_dir,
+                               svn_repos_notify_func_t notify_func,
+                               void *notify_baton,
+                               apr_pool_t *pool);
+
+/**
+ * Similar to svn_repos_get_fs_build_parser4(), but with @a start_rev
+ * and @a end_rev always passed as #SVN_INVALID_REVNUM.
  *
+ * @deprecated Provided for backward compatibility with the 1.7 API.
  * @since New in 1.7.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_repos_get_fs_build_parser3(const svn_repos_parse_fns2_t **parser,
                                void **parse_baton,

Modified: subversion/trunk/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/deprecated.c?rev=1186392&r1=1186391&r2=1186392&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/trunk/subversion/libsvn_repos/deprecated.c Wed Oct 19 18:44:36 2011
@@ -715,6 +715,28 @@ svn_repos_verify_fs(svn_repos_t *repos,
 /*** From load.c ***/
 
 svn_error_t *
+svn_repos_load_fs3(svn_repos_t *repos,
+                   svn_stream_t *dumpstream,
+                   enum svn_repos_load_uuid uuid_action,
+                   const char *parent_dir,
+                   svn_boolean_t use_pre_commit_hook,
+                   svn_boolean_t use_post_commit_hook,
+                   svn_boolean_t validate_props,
+                   svn_repos_notify_func_t notify_func,
+                   void *notify_baton,
+                   svn_cancel_func_t cancel_func,
+                   void *cancel_baton,
+                   apr_pool_t *pool)
+{
+  return svn_repos_load_fs4(repos, dumpstream,
+                            SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+                            uuid_action, parent_dir,
+                            use_pre_commit_hook, use_post_commit_hook,
+                            validate_props, notify_func, notify_baton,
+                            cancel_func, cancel_baton, pool);
+}
+
+svn_error_t *
 svn_repos_load_fs2(svn_repos_t *repos,
                    svn_stream_t *dumpstream,
                    svn_stream_t *feedback_stream,
@@ -803,6 +825,25 @@ svn_repos_load_fs(svn_repos_t *repos,
 }
 
 svn_error_t *
+svn_repos_get_fs_build_parser3(const svn_repos_parse_fns2_t **callbacks,
+                               void **parse_baton,
+                               svn_repos_t *repos,
+                               svn_boolean_t use_history,
+                               svn_boolean_t validate_props,
+                               enum svn_repos_load_uuid uuid_action,
+                               const char *parent_dir,
+                               svn_repos_notify_func_t notify_func,
+                               void *notify_baton,
+                               apr_pool_t *pool)
+{
+  return svn_repos_get_fs_build_parser4(callbacks, parse_baton, repos,
+                                        SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+                                        use_history, validate_props,
+                                        uuid_action, parent_dir,
+                                        notify_func, notify_baton, pool);
+}
+
+svn_error_t *
 svn_repos_get_fs_build_parser2(const svn_repos_parse_fns2_t **parser,
                                void **parse_baton,
                                svn_repos_t *repos,

Modified: subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c?rev=1186392&r1=1186391&r2=1186392&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/trunk/subversion/libsvn_repos/load-fs-vtable.c Wed Oct 19 18:44:36 2011
@@ -63,6 +63,12 @@ struct parse_baton
   svn_repos_notify_t *notify;
   apr_pool_t *pool;
 
+  /* Start and end (inclusive) of revision range we'll pay attention
+     to, or a pair of SVN_INVALID_REVNUMs if we're not filtering by
+     revisions. */
+  svn_revnum_t start_rev;
+  svn_revnum_t end_rev;
+
   /* A hash mapping copy-from revisions and mergeinfo range revisions
      (svn_revnum_t *) in the dump stream to their corresponding revisions
      (svn_revnum_t *) in the loaded repository.  The hash and its
@@ -84,13 +90,13 @@ struct parse_baton
 struct revision_baton
 {
   svn_revnum_t rev;
-
   svn_fs_txn_t *txn;
   svn_fs_root_t *txn_root;
 
   const svn_string_t *datestamp;
 
   apr_int32_t rev_offset;
+  svn_boolean_t skipped;
 
   struct parse_baton *pb;
   apr_pool_t *pool;
@@ -451,7 +457,14 @@ make_revision_baton(apr_hash_t *headers,
 
   if ((val = apr_hash_get(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER,
                           APR_HASH_KEY_STRING)))
-    rb->rev = SVN_STR_TO_REV(val);
+    {
+      rb->rev = SVN_STR_TO_REV(val);
+
+      /* If we're filtering revisions, is this one we'll skip? */
+      rb->skipped = (SVN_IS_VALID_REVNUM(pb->start_rev)
+                     && ((rb->rev < pb->start_rev) ||
+                         (rb->rev > pb->end_rev)));
+    }
 
   return rb;
 }
@@ -476,7 +489,7 @@ new_revision_record(void **revision_bato
      It might be positive or negative. */
   rb->rev_offset = (apr_int32_t) (rb->rev) - (head_rev + 1);
 
-  if (rb->rev > 0)
+  if ((rb->rev > 0) && (! rb->skipped))
     {
       /* Create a new fs txn. */
       SVN_ERR(svn_fs_begin_txn2(&(rb->txn), pb->fs, head_rev, 0, pool));
@@ -493,6 +506,14 @@ new_revision_record(void **revision_bato
       if (!SVN_IS_VALID_REVNUM(pb->oldest_old_rev))
         pb->oldest_old_rev = rb->rev;
     }
+  
+  /* If we're skipping this revision, try to notify someone. */
+  if (rb->skipped && pb->notify_func)
+    {
+      pb->notify->action = svn_repos_notify_load_skipped_rev;
+      pb->notify->old_revision = rb->rev;
+      pb->notify_func(pb->notify_baton, pb->notify, rb->pool);
+    }
 
   /* If we're parsing revision 0, only the revision are (possibly)
      interesting to us: when loading the stream into an empty
@@ -607,6 +628,13 @@ new_node_record(void **node_baton,
 
   SVN_ERR(make_node_baton(&nb, headers, rb, pool));
 
+  /* If we're skipping this revision, we're done here. */
+  if (rb->skipped)
+    {
+      *node_baton = nb;
+      return SVN_NO_ERROR;
+    }
+
   /* Make sure we have an action we recognize. */
   if (nb->action < svn_node_action_change
         || nb->action > svn_node_action_replace)
@@ -652,6 +680,10 @@ set_revision_property(void *baton,
 {
   struct revision_baton *rb = baton;
 
+  /* If we're skipping this revision, we're done here. */
+  if (rb->skipped)
+    return SVN_NO_ERROR;
+
   if (rb->rev > 0)
     {
       if (rb->pb->validate_props)
@@ -691,6 +723,10 @@ set_node_property(void *baton,
   struct revision_baton *rb = nb->rb;
   struct parse_baton *pb = rb->pb;
 
+  /* If we're skipping this revision, we're done here. */
+  if (rb->skipped)
+    return SVN_NO_ERROR;
+
   if (strcmp(name, SVN_PROP_MERGEINFO) == 0)
     {
       svn_string_t *renumbered_mergeinfo;
@@ -764,6 +800,10 @@ remove_node_props(void *baton)
   apr_hash_t *proplist;
   apr_hash_index_t *hi;
 
+  /* If we're skipping this revision, we're done here. */
+  if (rb->skipped)
+    return SVN_NO_ERROR;
+
   SVN_ERR(svn_fs_node_proplist(&proplist,
                                rb->txn_root, nb->path, nb->pool));
 
@@ -788,6 +828,10 @@ apply_textdelta(svn_txdelta_window_handl
   struct node_baton *nb = node_baton;
   struct revision_baton *rb = nb->rb;
 
+  /* If we're skipping this revision, we're done here. */
+  if (rb->skipped)
+    return SVN_NO_ERROR;
+
   return svn_fs_apply_textdelta(handler, handler_baton,
                                 rb->txn_root, nb->path,
                                 svn_checksum_to_cstring(nb->base_checksum,
@@ -805,6 +849,10 @@ set_fulltext(svn_stream_t **stream,
   struct node_baton *nb = node_baton;
   struct revision_baton *rb = nb->rb;
 
+  /* If we're skipping this revision, we're done here. */
+  if (rb->skipped)
+    return SVN_NO_ERROR;
+
   return svn_fs_apply_text(stream,
                            rb->txn_root, nb->path,
                            svn_checksum_to_cstring(nb->result_checksum,
@@ -820,6 +868,10 @@ close_node(void *baton)
   struct revision_baton *rb = nb->rb;
   struct parse_baton *pb = rb->pb;
 
+  /* If we're skipping this revision, we're done here. */
+  if (rb->skipped)
+    return SVN_NO_ERROR;
+
   if (pb->notify_func)
     {
       pb->notify->action = svn_repos_notify_load_node_done;
@@ -839,7 +891,9 @@ close_revision(void *baton)
   svn_revnum_t committed_rev;
   svn_error_t *err;
 
-  if (rb->rev <= 0)
+  /* If we're skipping this revision or it has an invalid revision
+     number, we're done here. */
+  if (rb->skipped || (rb->rev <= 0))
     return SVN_NO_ERROR;
 
   /* Run the pre-commit hook, if so commanded. */
@@ -943,9 +997,11 @@ close_revision(void *baton)
 
 
 svn_error_t *
-svn_repos_get_fs_build_parser3(const svn_repos_parse_fns2_t **callbacks,
+svn_repos_get_fs_build_parser4(const svn_repos_parse_fns2_t **callbacks,
                                void **parse_baton,
                                svn_repos_t *repos,
+                               svn_revnum_t start_rev,
+                               svn_revnum_t end_rev,
                                svn_boolean_t use_history,
                                svn_boolean_t validate_props,
                                enum svn_repos_load_uuid uuid_action,
@@ -960,6 +1016,13 @@ svn_repos_get_fs_build_parser3(const svn
   if (parent_dir)
     parent_dir = svn_relpath_canonicalize(parent_dir, pool);
 
+  SVN_ERR_ASSERT((SVN_IS_VALID_REVNUM(start_rev) &&
+                  SVN_IS_VALID_REVNUM(end_rev))
+                 || ((! SVN_IS_VALID_REVNUM(start_rev)) &&
+                     (! SVN_IS_VALID_REVNUM(end_rev))));
+  if (SVN_IS_VALID_REVNUM(start_rev))
+    SVN_ERR_ASSERT(start_rev <= end_rev);
+
   parser->new_revision_record = new_revision_record;
   parser->new_node_record = new_node_record;
   parser->uuid_record = uuid_record;
@@ -985,6 +1048,8 @@ svn_repos_get_fs_build_parser3(const svn
   pb->rev_map = apr_hash_make(pool);
   pb->oldest_old_rev = SVN_INVALID_REVNUM;
   pb->last_rev_mapped = SVN_INVALID_REVNUM;
+  pb->start_rev = start_rev;
+  pb->end_rev = end_rev;
 
   *callbacks = parser;
   *parse_baton = pb;
@@ -994,8 +1059,10 @@ svn_repos_get_fs_build_parser3(const svn
 
 
 svn_error_t *
-svn_repos_load_fs3(svn_repos_t *repos,
+svn_repos_load_fs4(svn_repos_t *repos,
                    svn_stream_t *dumpstream,
+                   svn_revnum_t start_rev,
+                   svn_revnum_t end_rev,
                    enum svn_repos_load_uuid uuid_action,
                    const char *parent_dir,
                    svn_boolean_t use_pre_commit_hook,
@@ -1013,8 +1080,9 @@ svn_repos_load_fs3(svn_repos_t *repos,
 
   /* This is really simple. */
 
-  SVN_ERR(svn_repos_get_fs_build_parser3(&parser, &parse_baton,
+  SVN_ERR(svn_repos_get_fs_build_parser4(&parser, &parse_baton,
                                          repos,
+                                         start_rev, end_rev,
                                          TRUE, /* look for copyfrom revs */
                                          validate_props,
                                          uuid_action,

Modified: subversion/trunk/subversion/svnadmin/main.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnadmin/main.c?rev=1186392&r1=1186391&r2=1186392&view=diff
==============================================================================
--- subversion/trunk/subversion/svnadmin/main.c (original)
+++ subversion/trunk/subversion/svnadmin/main.c Wed Oct 19 18:44:36 2011
@@ -352,8 +352,10 @@ static const svn_opt_subcommand_desc2_t 
     "Read a 'dumpfile'-formatted stream from stdin, committing\n"
     "new revisions into the repository's filesystem.  If the repository\n"
     "was previously empty, its UUID will, by default, be changed to the\n"
-    "one specified in the stream.  Progress feedback is sent to stdout.\n"),
-   {'q', svnadmin__ignore_uuid, svnadmin__force_uuid,
+    "one specified in the stream.  Progress feedback is sent to stdout.\n"
+    "If --revision is specified, limit the loaded revisions to only those\n"
+    "in the dump stream whose revision numbers match the specified range.\n"),
+   {'q', 'r', svnadmin__ignore_uuid, svnadmin__force_uuid,
     svnadmin__use_pre_commit_hook, svnadmin__use_post_commit_hook,
     svnadmin__parent_dir, svnadmin__bypass_prop_validation, 'M'} },
 
@@ -790,6 +792,12 @@ repos_notify_handler(void *baton,
                                 notify->old_revision));
       return;
 
+    case svn_repos_notify_load_skipped_rev:
+      svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
+                                _("<<< Skipped original revision %ld\n"),
+                                notify->old_revision));
+      return;
+
     case svn_repos_notify_load_normalized_mergeinfo:
       svn_error_clear(svn_stream_printf(feedback_stream, scratch_pool,
                                 _(" removing '\\r' from %s ..."),
@@ -947,6 +955,32 @@ subcommand_help(apr_getopt_t *os, void *
 }
 
 
+/* Set *REVNUM to the revision number of a numeric REV, or to
+   SVN_INVALID_REVNUM if REV is unspecified. */
+static svn_error_t *
+optrev_to_revnum(svn_revnum_t *revnum, const svn_opt_revision_t *opt_rev)
+{
+  if (opt_rev->kind == svn_opt_revision_number)
+    {
+      *revnum = opt_rev->value.number;
+      if (! SVN_IS_VALID_REVNUM(*revnum))
+        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                 _("Invalid revision number (%ld) specified"),
+                                 *revnum);
+    }
+  else if (opt_rev->kind == svn_opt_revision_unspecified)
+    {
+      *revnum = SVN_INVALID_REVNUM;
+    }
+  else
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("Non-numeric revision specified"));
+    }
+  return SVN_NO_ERROR;
+}
+
+
 /* This implements `svn_opt_subcommand_t'. */
 static svn_error_t *
 subcommand_load(apr_getopt_t *os, void *baton, apr_pool_t *pool)
@@ -954,11 +988,34 @@ subcommand_load(apr_getopt_t *os, void *
   svn_error_t *err;
   struct svnadmin_opt_state *opt_state = baton;
   svn_repos_t *repos;
+  svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM;
   svn_stream_t *stdin_stream, *stdout_stream = NULL;
 
   /* Expect no more arguments. */
   SVN_ERR(parse_args(NULL, os, 0, 0, pool));
 
+  /* Find the revision numbers at which to start and end.  We only
+     support a limited set of revision kinds: number and unspecified. */
+  SVN_ERR(optrev_to_revnum(&lower, &opt_state->start_revision));
+  SVN_ERR(optrev_to_revnum(&upper, &opt_state->end_revision));
+
+  /* Fill in implied revisions if necessary. */
+  if ((upper == SVN_INVALID_REVNUM) && (lower != SVN_INVALID_REVNUM))
+    {
+      upper = lower;
+    }
+  else if ((upper != SVN_INVALID_REVNUM) && (lower == SVN_INVALID_REVNUM))
+    {
+      lower = upper;
+    }
+  
+  /* Ensure correct range ordering. */
+  if (lower > upper)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("First revision cannot be higher than second"));
+    }
+
   SVN_ERR(open_repos(&repos, opt_state->repository_path, pool));
 
   /* Read the stream from STDIN.  Users can redirect a file. */
@@ -968,7 +1025,7 @@ subcommand_load(apr_getopt_t *os, void *
   if (! opt_state->quiet)
     stdout_stream = recode_stream_create(stdout, pool);
 
-  err = svn_repos_load_fs3(repos, stdin_stream,
+  err = svn_repos_load_fs4(repos, stdin_stream, lower, upper,
                            opt_state->uuid_action, opt_state->parent_dir,
                            opt_state->use_pre_commit_hook,
                            opt_state->use_post_commit_hook,

Modified: subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py?rev=1186392&r1=1186391&r2=1186392&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py Wed Oct 19 18:44:36 2011
@@ -1478,6 +1478,39 @@ def test_lslocks_and_rmlocks(sbox):
     "Unexpected output while running 'svnadmin rmlocks'.",
     output, [], expected_output, None)
 
+#----------------------------------------------------------------------
+@Issue(3734)
+def load_ranges(sbox):
+  "'svnadmin load --revision X:Y'"
+
+  ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3734. ##
+  test_create(sbox)
+
+  dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]),
+                                   'svnadmin_tests_data',
+                                   'skeleton_repos.dump')
+  dumpdata = open(dumpfile_location).read()
+
+  # Load our dumpfile, 2 revisions at a time, verifying that we have
+  # the correct youngest revision after each load.
+  load_and_verify_dumpstream(sbox, [], [], None, dumpdata, '-r0:2')
+  svntest.actions.run_and_verify_svnlook("Unexpected output", ['2\n'],
+                                         None, 'youngest', sbox.repo_dir)
+  load_and_verify_dumpstream(sbox, [], [], None, dumpdata, '-r3:4')
+  svntest.actions.run_and_verify_svnlook("Unexpected output", ['4\n'],
+                                         None, 'youngest', sbox.repo_dir)
+  load_and_verify_dumpstream(sbox, [], [], None, dumpdata, '-r5:6')
+  svntest.actions.run_and_verify_svnlook("Unexpected output", ['6\n'],
+                                         None, 'youngest', sbox.repo_dir)
+
+  ### Would prefer to do a dump comparison such as the following, by
+  ### there are ordering differences, it seems, in the property
+  ### blocks.
+  #dumpdata = open(dumpfile_location).readlines()
+  #new_dumpdata = svntest.actions.run_and_verify_dump(sbox.repo_dir)
+  #svntest.verify.compare_and_display_lines("Dump files", "DUMP",
+  #                                         dumpdata, new_dumpdata)
+
 ########################################################################
 # Run the tests
 
@@ -1508,6 +1541,7 @@ test_list = [ None,
               load_bad_props,
               verify_non_utf8_paths,
               test_lslocks_and_rmlocks,
+              load_ranges,
              ]
 
 if __name__ == '__main__':



Mime
View raw message