Bert Huijben <b...@qqmail.nl> writes:

> Noting everything as a change even if there is no actual delta... still
> looks like a bug we should fix (and we did) instead of something that we
> should restore.
>
> For the reasoning on why:
>
> For blame we are really interested if there are deltas... and if there
> aren't any changes the revision is not 'interesting'. (See docs of the api).

The place where we define "interesting" revisions is svn_fs_history_prev2():

  /** Set @a *prev_history_p to an opaque node history object which
   * represents the previous (or "next oldest") interesting history
   * location for the filesystem node represented by @a history, or @c
   * NULL if no such previous history exists.  If @a cross_copies is @c
   * FALSE, also return @c NULL if stepping backwards in history to @a
   * *prev_history_p would cross a filesystem copy operation.
   *
   * @note If this is the first call to svn_fs_history_prev() for the @a
   * history object, it could return a history object whose location is
   * the same as the original.  This will happen if the original
   * location was an interesting one (where the node was modified, or
   * took place in a copy event).  This behavior allows looping callers
   * to avoid the calling svn_fs_history_location() on the object
   * returned by svn_fs_node_history(), and instead go ahead and begin
   * calling svn_fs_history_prev().
   ...

Functions like svn_ra_get_file_revs2() that you mentioned just link to it:

  /**
   * Retrieve a subset of the interesting revisions of a file @a path
   * as seen in revision @a end (see svn_fs_history_prev() for a
   * definition of "interesting revisions").
   ...

The svn_fs_history_prev2() function reports revisions with empty deltas as
interesting, and has been doing that for years (see the attached patch with
a test).  This behavior did not change in 1.9.

This means that after r1572363 and r1573111, svn_ra_get_file_revs2() and
svn_repos_get_file_revs2() were skipping some of the "interesting" revisions,
according to the FS API defining the concept.  Moreover, this behavior could
be inconsistent even within a single function like svn_ra_get_file_revs2()
that calls svn_ra_get_log2() for old servers, as get-log notices revisions
with empty deltas.

I think that it's another example of where r1572363 and r1573111 introduce an
inconsistent and unwanted behavior change.

Stefan Fuhrmann <stefan.fuhrm...@wandisco.com> writes:

>> As for /trunk, I think that we could do that, so I sketched this option in
>> the attached patch.
>
> The patch looks o.k.

Thanks for giving this patch a look.

I examined the differences between these functions, svn_repos__compare_files()
and svn_fs_contents_different(), and I think that we also have a problem in
FSFS's implementation of the new svn_fs_contents_different() API in 1.9.x.
The implementation relies on representation_t.expanded_size value when doing
the comparison.  If this value is zero, a representation is considered empty,
and two empty representations are considered equal.

The problem is that the expanded_size can be zero for empty files and also for
some of the PLAIN representations, which are not empty.  If I am not mistaken,
we have a workaround for this in /trunk — r1673875 [1] and follow-ups, but not
in Subversion 1.9.  Hence, the new svn_fs_contents_different() API can fail to
distinguish different contents in 1.9.x under the circumstances described in
issue 4554 [2].

So, we can use it in trunk, but this API may produce invalid results in 1.9.x.

I'll commit the patch, and then I am going to prepare the nomination consisting
of r1709388 and the new dump_no_op_change() test.

[1] https://svn.apache.org/r1673875
[2] https://issues.apache.org/jira/browse/SVN-4554


Regards,
Evgeny Kotkov
Index: subversion/tests/libsvn_fs/fs-test.c
===================================================================
--- subversion/tests/libsvn_fs/fs-test.c        (revision 1710620)
+++ subversion/tests/libsvn_fs/fs-test.c        (working copy)
@@ -6971,6 +6971,47 @@ freeze_and_commit(const svn_test_opts_t *opts,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+history_with_empty_delta(const svn_test_opts_t *opts,
+                         apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  svn_revnum_t head_rev = 0;
+  svn_fs_root_t *root;
+  svn_fs_txn_t *txn;
+  svn_fs_history_t *history;
+  const char *path;
+  svn_revnum_t revision;
+
+  SVN_ERR(svn_test__create_fs(&fs, "test-history-with-empty-delta",
+                              opts, pool));
+
+  /* r1: Create the greek tree. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, head_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_test__create_greek_tree(root, pool));
+  SVN_ERR(test_commit_txn(&head_rev, txn, NULL, pool));
+
+  /* r2: Commit an empty delta for /iota. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, head_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&root, txn, pool));
+  SVN_ERR(svn_test__set_file_contents(root, "/iota",
+                                      "This is the file 'iota'.\n", pool));
+  SVN_ERR(test_commit_txn(&head_rev, txn, NULL, pool));
+
+  /* Get the first real point of interesting history. */
+  SVN_ERR(svn_fs_revision_root(&root, fs, head_rev, pool));
+  SVN_ERR(svn_fs_node_history2(&history, root, "/iota", pool, pool));
+  SVN_ERR(svn_fs_history_prev2(&history, history, FALSE, pool, pool));
+
+  /* The revision with empty delta is reported as "interesting". */
+  SVN_ERR(svn_fs_history_location(&path, &revision, history, pool));
+  SVN_TEST_STRING_ASSERT(path, "/iota");
+  SVN_TEST_ASSERT(revision == 2);
+
+  return SVN_NO_ERROR;
+}
+
 /* ------------------------------------------------------------------------ */
 
 /* The test table.  */
@@ -7105,6 +7146,8 @@ static struct svn_test_descriptor_t test_funcs[] =
                        "test svn_fs_check_related for transactions"),
     SVN_TEST_OPTS_PASS(freeze_and_commit,
                        "freeze and commit"),
+    SVN_TEST_OPTS_PASS(history_with_empty_delta,
+                       "test node history with empty delta"),
     SVN_TEST_NULL
   };
 

Reply via email to