You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2014/03/09 11:08:53 UTC

svn commit: r1575685 [6/13] - in /subversion/branches/fsfs-ucsnorm: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/cgi/ contrib/client-side/emacs/ contrib/client-side/svn2cl/ contrib/hook-scripts/ contrib/server-side/svn...

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff_memory.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/diff_memory.c Sun Mar  9 10:08:46 2014
@@ -949,6 +949,25 @@ output_conflict(void *baton,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+output_conflict_with_context_marker(merge_output_baton_t *btn,
+                                    const char *label,
+                                    apr_off_t start,
+                                    apr_off_t length)
+{
+  if (length == 1)
+    SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
+                              "%s (%" APR_OFF_T_FMT ")",
+                              label, start + 1));
+  else
+    SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
+                              "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")",
+                              label, start + 1, length));
+
+  SVN_ERR(output_marker_eol(btn));
+
+  return SVN_NO_ERROR;
+}
 
 static svn_error_t *
 output_conflict_with_context(void *baton,
@@ -975,36 +994,24 @@ output_conflict_with_context(void *baton
   btn->output_stream = btn->real_output_stream;
 
   /* Output the conflict itself. */
-  SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
-                            (modified_length == 1
-                             ? "%s (%" APR_OFF_T_FMT ")"
-                             : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
-                            btn->markers[1],
-                            modified_start + 1, modified_length));
-  SVN_ERR(output_marker_eol(btn));
+  SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[1],
+                                              modified_start,
+                                              modified_length));
   SVN_ERR(output_merge_token_range(NULL, btn, 1/*modified*/,
                                    modified_start, modified_length));
 
-  SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
-                            (original_length == 1
-                             ? "%s (%" APR_OFF_T_FMT ")"
-                             : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
-                            btn->markers[0],
-                            original_start + 1, original_length));
-  SVN_ERR(output_marker_eol(btn));
+  SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[0],
+                                              original_start,
+                                              original_length));
   SVN_ERR(output_merge_token_range(NULL, btn, 0/*original*/,
                                    original_start, original_length));
 
   SVN_ERR(output_merge_marker(btn, 2/*separator*/));
   SVN_ERR(output_merge_token_range(NULL, btn, 2/*latest*/,
                                    latest_start, latest_length));
-  SVN_ERR(svn_stream_printf(btn->output_stream, btn->pool,
-                            (latest_length == 1
-                             ? "%s (%" APR_OFF_T_FMT ")"
-                             : "%s (%" APR_OFF_T_FMT ",%" APR_OFF_T_FMT ")"),
-                            btn->markers[3],
-                            latest_start + 1, latest_length));
-  SVN_ERR(output_marker_eol(btn));
+  SVN_ERR(output_conflict_with_context_marker(btn, btn->markers[3],
+                                              latest_start,
+                                              latest_length));
 
   /* Go into print-trailing-context mode instead. */
   make_trailing_context_printer(btn);

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/util.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/util.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_diff/util.c Sun Mar  9 10:08:46 2014
@@ -75,9 +75,11 @@ svn_diff_contains_diffs(svn_diff_t *diff
 }
 
 svn_error_t *
-svn_diff_output(svn_diff_t *diff,
-                void *output_baton,
-                const svn_diff_output_fns_t *vtable)
+svn_diff_output2(svn_diff_t *diff,
+                 void *output_baton,
+                 const svn_diff_output_fns_t *vtable,
+                 svn_cancel_func_t cancel_func,
+                 void *cancel_baton)
 {
   svn_error_t *(*output_fn)(void *,
                             apr_off_t, apr_off_t,
@@ -86,6 +88,9 @@ svn_diff_output(svn_diff_t *diff,
 
   while (diff != NULL)
     {
+      if (cancel_func)
+        SVN_ERR(cancel_func(cancel_baton));
+
       switch (diff->type)
         {
         case svn_diff__type_common:
@@ -570,7 +575,7 @@ svn_diff__display_prop_diffs(svn_stream_
          * from the diff header. But there usually are no files which
          * UNIX patch could apply the property diff to, so we use "##"
          * instead of "@@" as the default hunk delimiter for property diffs.
-         * We also supress the diff header. */
+         * We also suppress the diff header. */
         SVN_ERR(svn_diff_mem_string_output_unified2(
                   outstream, diff, FALSE /* no header */, "##", NULL, NULL,
                   encoding, orig, val, iterpool));

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Mar  9 10:08:46 2014
@@ -8,4 +8,5 @@ Release
 *~
 .*~
 libsvn_fs.def
-
+libsvn_fs.pc.in
+libsvn_fs.pc

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/editor.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/editor.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/editor.c Sun Mar  9 10:08:46 2014
@@ -177,7 +177,7 @@ can_modify(svn_fs_root_t *txn_root,
   SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, fspath,
                                   scratch_pool));
 
-  /* Uncommitted nodes (eg. a descendent of a copy/move destination)
+  /* Uncommitted nodes (eg. a descendant of a copy/move destination)
      have no (committed) revision number. Let the caller go ahead and
      modify these nodes.
 
@@ -195,7 +195,7 @@ can_modify(svn_fs_root_t *txn_root,
      have supplied a valid revision number [that they expect to change].
      The checks further below will determine the out-of-dateness of the
      specified revision.  */
-  /* ### ugh. descendents of copy/move destinations carry along
+  /* ### ugh. descendants of copy/move destinations carry along
      ### their original immutable state and (thus) a valid CREATED_REV.
      ### but they are logically uncommitted, so the caller will pass
      ### SVN_INVALID_REVNUM. (technically, the caller could provide
@@ -203,7 +203,7 @@ can_modify(svn_fs_root_t *txn_root,
      ### API).
      ###
      ### for now, we will assume the caller knows what they are doing
-     ### and an invalid revision implies such a descendent. in the
+     ### and an invalid revision implies such a descendant. in the
      ### future, we could examine the ancestor chain looking for a
      ### copy/move-here node and allow the modification (and the
      ### converse: if no such ancestor, the caller must specify the
@@ -810,7 +810,7 @@ svn_fs__editor_commit(svn_revnum_t *revi
           /* Copy this into the correct pool (see note above).  */
           *conflict_path = apr_pstrdup(result_pool, inner_conflict_path);
 
-          /* Return sucess. The caller should inspect CONFLICT_PATH to
+          /* Return success. The caller should inspect CONFLICT_PATH to
              determine this particular case.  */
           svn_error_clear(err);
           err = SVN_NO_ERROR;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/fs-loader.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/fs-loader.c Sun Mar  9 10:08:46 2014
@@ -1106,7 +1106,7 @@ svn_fs_node_relation(svn_fs_node_relatio
                      apr_pool_t *pool)
 {
   /* Different repository types? */
-  if (root_a->vtable != root_b->vtable)
+  if (root_a->fs != root_b->fs)
     {
       *relation = svn_fs_node_unrelated;
       return SVN_NO_ERROR;
@@ -1167,6 +1167,17 @@ svn_fs_change_node_prop(svn_fs_root_t *r
 }
 
 svn_error_t *
+svn_fs_props_different(svn_boolean_t *changed_p, svn_fs_root_t *root1,
+                       const char *path1, svn_fs_root_t *root2,
+                       const char *path2, apr_pool_t *pool)
+{
+  return svn_error_trace(root1->vtable->props_changed(changed_p,
+                                                      root1, path1,
+                                                      root2, path2,
+                                                      TRUE, pool));
+}
+
+svn_error_t *
 svn_fs_props_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
                      const char *path1, svn_fs_root_t *root2,
                      const char *path2, apr_pool_t *pool)
@@ -1174,7 +1185,7 @@ svn_fs_props_changed(svn_boolean_t *chan
   return svn_error_trace(root1->vtable->props_changed(changed_p,
                                                       root1, path1,
                                                       root2, path2,
-                                                      pool));
+                                                      FALSE, pool));
 }
 
 svn_error_t *
@@ -1223,6 +1234,30 @@ svn_fs_get_mergeinfo(svn_mergeinfo_catal
 }
 
 svn_error_t *
+svn_fs__get_mergeinfo_for_path(svn_mergeinfo_t *mergeinfo,
+                               svn_fs_root_t *root,
+                               const char *path,
+                               svn_mergeinfo_inheritance_t inherit,
+                               svn_boolean_t adjust_inherited_mergeinfo,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *paths
+    = apr_array_make(scratch_pool, 1, sizeof(const char *));
+  svn_mergeinfo_catalog_t catalog;
+
+  APR_ARRAY_PUSH(paths, const char *) = path;
+
+  SVN_ERR(svn_fs_get_mergeinfo2(&catalog, root, paths,
+                                inherit, FALSE /*include_descendants*/,
+                                adjust_inherited_mergeinfo,
+                                result_pool, scratch_pool));
+  *mergeinfo = svn_hash_gets(catalog, path);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_fs_merge(const char **conflict_p, svn_fs_root_t *source_root,
              const char *source_path, svn_fs_root_t *target_root,
              const char *target_path, svn_fs_root_t *ancestor_root,
@@ -1418,6 +1453,17 @@ svn_fs_apply_text(svn_stream_t **content
 }
 
 svn_error_t *
+svn_fs_contents_different(svn_boolean_t *changed_p, svn_fs_root_t *root1,
+                          const char *path1, svn_fs_root_t *root2,
+                          const char *path2, apr_pool_t *pool)
+{
+  return svn_error_trace(root1->vtable->contents_changed(changed_p,
+                                                         root1, path1,
+                                                         root2, path2,
+                                                         TRUE, pool));
+}
+
+svn_error_t *
 svn_fs_contents_changed(svn_boolean_t *changed_p, svn_fs_root_t *root1,
                         const char *path1, svn_fs_root_t *root2,
                         const char *path2, apr_pool_t *pool)
@@ -1425,7 +1471,7 @@ svn_fs_contents_changed(svn_boolean_t *c
   return svn_error_trace(root1->vtable->contents_changed(changed_p,
                                                          root1, path1,
                                                          root2, path2,
-                                                         pool));
+                                                         FALSE, pool));
 }
 
 svn_error_t *
@@ -1679,13 +1725,21 @@ svn_fs_unparse_id(const svn_fs_id_t *id,
 svn_boolean_t
 svn_fs_check_related(const svn_fs_id_t *a, const svn_fs_id_t *b)
 {
-  return (a->vtable->compare(a, b) != -1);
+  return (a->vtable->compare(a, b) != svn_fs_node_unrelated);
 }
 
 int
 svn_fs_compare_ids(const svn_fs_id_t *a, const svn_fs_id_t *b)
 {
-  return a->vtable->compare(a, b);
+  switch (a->vtable->compare(a, b))
+    {
+    case svn_fs_node_same:
+      return 0;
+    case svn_fs_node_common_ancestor:
+      return 1;
+    default:
+      return -1;
+    }
 }
 
 svn_error_t *

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/fs-loader.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs/fs-loader.h Sun Mar  9 10:08:46 2014
@@ -29,6 +29,7 @@
 #include "svn_fs.h"
 #include "svn_props.h"
 #include "private/svn_mutex.h"
+#include <apr_poll.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -343,7 +344,8 @@ typedef struct root_vtable_t
                                    apr_pool_t *pool);
   svn_error_t *(*props_changed)(int *changed_p, svn_fs_root_t *root1,
                                 const char *path1, svn_fs_root_t *root2,
-                                const char *path2, apr_pool_t *pool);
+                                const char *path2, svn_boolean_t strict,
+                                apr_pool_t *pool);
 
   /* Directories */
   svn_error_t *(*dir_entries)(apr_hash_t **entries_p, svn_fs_root_t *root,
@@ -383,7 +385,8 @@ typedef struct root_vtable_t
                              apr_pool_t *pool);
   svn_error_t *(*contents_changed)(int *changed_p, svn_fs_root_t *root1,
                                    const char *path1, svn_fs_root_t *root2,
-                                   const char *path2, apr_pool_t *pool);
+                                   const char *path2, svn_boolean_t strict,
+                                   apr_pool_t *pool);
   svn_error_t *(*get_file_delta_stream)(svn_txdelta_stream_t **stream_p,
                                         svn_fs_root_t *source_root,
                                         const char *source_path,
@@ -424,8 +427,10 @@ typedef struct history_vtable_t
 
 typedef struct id_vtable_t
 {
-  svn_string_t *(*unparse)(const svn_fs_id_t *id, apr_pool_t *pool);
-  int (*compare)(const svn_fs_id_t *a, const svn_fs_id_t *b);
+  svn_string_t *(*unparse)(const svn_fs_id_t *id,
+                           apr_pool_t *pool);
+  svn_fs_node_relation_t (*compare)(const svn_fs_id_t *a,
+                                    const svn_fs_id_t *b);
 } id_vtable_t;
 
 

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Mar  9 10:08:46 2014
@@ -7,4 +7,5 @@ Release
 *.o
 *~
 .*~
-
+libsvn_fs_base.pc
+libsvn_fs_base.pc.in

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/dag.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/dag.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/dag.c Sun Mar  9 10:08:46 2014
@@ -1654,14 +1654,8 @@ svn_fs_base__things_different(svn_boolea
 
   /* Compare contents keys and their (optional) uniquifiers. */
   if (contents_changed != NULL)
-    *contents_changed =
-      (! (svn_fs_base__same_keys(noderev1->data_key,
-                                 noderev2->data_key)
-          /* Technically, these uniquifiers aren't used and "keys",
-             but keys are base-36 stringified numbers, so we'll take
-             this liberty. */
-          && (svn_fs_base__same_keys(noderev1->data_key_uniquifier,
-                                     noderev2->data_key_uniquifier))));
+    *contents_changed = (! svn_fs_base__same_keys(noderev1->data_key,
+                                                  noderev2->data_key));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/id.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/id.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/id.c Sun Mar  9 10:08:46 2014
@@ -108,13 +108,14 @@ svn_fs_base__id_check_related(const svn_
 }
 
 
-int
+svn_fs_node_relation_t
 svn_fs_base__id_compare(const svn_fs_id_t *a,
                         const svn_fs_id_t *b)
 {
   if (svn_fs_base__id_eq(a, b))
-    return 0;
-  return (svn_fs_base__id_check_related(a, b) ? 1 : -1);
+    return svn_fs_node_same;
+  return (svn_fs_base__id_check_related(a, b) ? svn_fs_node_common_ancestor
+                                              : svn_fs_node_unrelated);
 }
 
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/id.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/id.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/id.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/id.h Sun Mar  9 10:08:46 2014
@@ -53,9 +53,9 @@ svn_boolean_t svn_fs_base__id_eq(const s
 svn_boolean_t svn_fs_base__id_check_related(const svn_fs_id_t *a,
                                             const svn_fs_id_t *b);
 
-/* Return 0 if A and B are equal, 1 if they are related, -1 otherwise. */
-int svn_fs_base__id_compare(const svn_fs_id_t *a,
-                            const svn_fs_id_t *b);
+/* Return the noderev relationship between A and B. */
+svn_fs_node_relation_t svn_fs_base__id_compare(const svn_fs_id_t *a,
+                                               const svn_fs_id_t *b);
 
 /* Create an ID based on NODE_ID, COPY_ID, and TXN_ID, allocated in
    POOL. */

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/key-gen.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/key-gen.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/key-gen.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/key-gen.c Sun Mar  9 10:08:46 2014
@@ -39,20 +39,19 @@ void
 svn_fs_base__next_key(const char *this, apr_size_t *len, char *next)
 {
   apr_size_t olen = *len;     /* remember the first length */
-  int i = olen - 1;           /* initial index; we work backwards */
+  apr_size_t i;               /* current index */
   char c;                     /* current char */
   svn_boolean_t carry = TRUE; /* boolean: do we have a carry or not?
                                  We start with a carry, because we're
                                  incrementing the number, after all. */
 
-  /* Leading zeros are not allowed, except for the string "0". */
-  if ((*len > 1) && (this[0] == '0'))
-    {
-      *len = 0;
-      return;
-    }
+  /* Empty strings and leading zeros (except for the string "0") are not
+   * allowed.  Run our malfunction handler to prevent possible db corruption
+   * from being propagated further. */
+  SVN_ERR_ASSERT_NO_RETURN(olen != 0 && (olen == 1 || this[0] != '0'));
 
-  for (i = (olen - 1); i >= 0; i--)
+  i = olen - 1; /* initial index: we work backwords */
+  while (1729)
     {
       c = this[i];
 
@@ -79,6 +78,11 @@ svn_fs_base__next_key(const char *this, 
         }
       else
         next[i] = c;
+
+      if (i == 0)
+        break;
+
+      i--;
     }
 
   /* The new length is OLEN, plus 1 if there's a carry out of the
@@ -102,22 +106,6 @@ svn_fs_base__next_key(const char *this, 
 }
 
 
-int
-svn_fs_base__key_compare(const char *a, const char *b)
-{
-  int a_len = strlen(a);
-  int b_len = strlen(b);
-  int cmp;
-
-  if (a_len > b_len)
-    return 1;
-  if (b_len > a_len)
-    return -1;
-  cmp = strcmp(a, b);
-  return (cmp ? (cmp / abs(cmp)) : 0);
-}
-
-
 svn_boolean_t
 svn_fs_base__same_keys(const char *a, const char *b)
 {

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/key-gen.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/key-gen.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/key-gen.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/key-gen.h Sun Mar  9 10:08:46 2014
@@ -78,13 +78,6 @@ extern "C" {
 void svn_fs_base__next_key(const char *this, apr_size_t *len, char *next);
 
 
-/* Compare two strings A and B as base-36 alphanumeric keys.
- *
- * Return -1, 0, or 1 if A is less than, equal to, or greater than B,
- * respectively.
- */
-int svn_fs_base__key_compare(const char *a, const char *b);
-
 /* Compare two strings A and B as base-36 alphanumber keys.
  *
  * Return TRUE iff both keys are NULL or both keys have the same

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/revs-txns.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/revs-txns.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/revs-txns.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/revs-txns.c Sun Mar  9 10:08:46 2014
@@ -912,7 +912,7 @@ delete_txn_tree(svn_fs_t *fs,
   svn_error_t *err;
 
   /* If this sucker isn't mutable, there's nothing to do. */
-  if (svn_fs_base__key_compare(svn_fs_base__id_txn_id(id), txn_id) != 0)
+  if (strcmp(svn_fs_base__id_txn_id(id), txn_id) != 0)
     return SVN_NO_ERROR;
 
   /* See if the thing has dirents that need to be recursed upon.  If

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/tree.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_base/tree.c Sun Mar  9 10:08:46 2014
@@ -544,7 +544,7 @@ get_copy_inheritance(copy_id_inherit_t *
   parent_copy_id = svn_fs_base__id_copy_id(parent_id);
 
   /* Easy out: if this child is already mutable, we have nothing to do. */
-  if (svn_fs_base__key_compare(svn_fs_base__id_txn_id(child_id), txn_id) == 0)
+  if (strcmp(svn_fs_base__id_txn_id(child_id), txn_id) == 0)
     return SVN_NO_ERROR;
 
   /* If the child and its parent are on the same branch, then the
@@ -561,7 +561,7 @@ get_copy_inheritance(copy_id_inherit_t *
      target of any copy, and therefore must be on the same branch as
      its parent.  */
   if ((strcmp(child_copy_id, "0") == 0)
-      || (svn_fs_base__key_compare(child_copy_id, parent_copy_id) == 0))
+      || (strcmp(child_copy_id, parent_copy_id) == 0))
     {
       *inherit_p = copy_id_inherit_parent;
       return SVN_NO_ERROR;
@@ -570,7 +570,8 @@ get_copy_inheritance(copy_id_inherit_t *
     {
       copy_t *copy;
       SVN_ERR(svn_fs_bdb__get_copy(&copy, fs, child_copy_id, trail, pool));
-      if (svn_fs_base__id_compare(copy->dst_noderev_id, child_id) == -1)
+      if (   svn_fs_base__id_compare(copy->dst_noderev_id, child_id)
+          == svn_fs_node_unrelated)
         {
           *inherit_p = copy_id_inherit_parent;
           return SVN_NO_ERROR;
@@ -1047,15 +1048,7 @@ base_node_relation(svn_fs_node_relation_
   SVN_ERR(base_node_id(&id_a, root_a, path_a, pool));
   SVN_ERR(base_node_id(&id_b, root_b, path_b, pool));
 
-  switch (svn_fs_base__id_compare(id_a, id_b))
-    {
-      case 0:  *relation = svn_fs_node_same;
-               break;
-      case 1:  *relation = svn_fs_node_common_anchestor;
-               break;
-      default: *relation = svn_fs_node_unrelated;
-               break;
-    }
+  *relation = svn_fs_base__id_compare(id_a, id_b);
 
   return SVN_NO_ERROR;
 }
@@ -1402,6 +1395,7 @@ struct things_changed_args
   svn_fs_root_t *root2;
   const char *path1;
   const char *path2;
+  svn_boolean_t strict;
   apr_pool_t *pool;
 };
 
@@ -1411,11 +1405,26 @@ txn_body_props_changed(void *baton, trai
 {
   struct things_changed_args *args = baton;
   dag_node_t *node1, *node2;
+  apr_hash_t *proplist1, *proplist2;
 
   SVN_ERR(get_dag(&node1, args->root1, args->path1, trail, trail->pool));
   SVN_ERR(get_dag(&node2, args->root2, args->path2, trail, trail->pool));
-  return svn_fs_base__things_different(args->changed_p, NULL,
-                                       node1, node2, trail, trail->pool);
+  SVN_ERR(svn_fs_base__things_different(args->changed_p, NULL,
+                                        node1, node2, trail, trail->pool));
+
+  /* Is there a potential false positive and do we want to correct it? */
+  if (!args->strict || !*args->changed_p)
+    return SVN_NO_ERROR;
+
+  /* Different representations. They might still have equal contents. */
+  SVN_ERR(svn_fs_base__dag_get_proplist(&proplist1, node1,
+                                        trail, trail->pool));
+  SVN_ERR(svn_fs_base__dag_get_proplist(&proplist2, node2,
+                                        trail, trail->pool));
+
+  *args->changed_p = !svn_fs__prop_lists_equal(proplist1, proplist2,
+                                               trail->pool);
+  return SVN_NO_ERROR;
 }
 
 
@@ -1425,6 +1434,7 @@ base_props_changed(svn_boolean_t *change
                    const char *path1,
                    svn_fs_root_t *root2,
                    const char *path2,
+                   svn_boolean_t strict,
                    apr_pool_t *pool)
 {
   struct things_changed_args args;
@@ -1441,6 +1451,7 @@ base_props_changed(svn_boolean_t *change
   args.path2      = path2;
   args.changed_p  = changed_p;
   args.pool       = pool;
+  args.strict     = strict;
 
   return svn_fs_base__retry_txn(root1->fs, txn_body_props_changed, &args,
                                 TRUE, pool);
@@ -3154,7 +3165,7 @@ txn_body_copy(void *baton,
   if ((to_parent_path->node)
       && (svn_fs_base__id_compare(svn_fs_base__dag_get_id(from_node),
                                   svn_fs_base__dag_get_id
-                                  (to_parent_path->node)) == 0))
+                                  (to_parent_path->node)) == svn_fs_node_same))
     return SVN_NO_ERROR;
 
   if (! from_root->is_txn_root)
@@ -3354,8 +3365,8 @@ txn_body_copied_from(void *baton, trail_
     return SVN_NO_ERROR;
 
   /* If NODE's copy-ID is the same as that of its predecessor... */
-  if (svn_fs_base__key_compare(svn_fs_base__id_copy_id(node_id),
-                               svn_fs_base__id_copy_id(pred_id)) != 0)
+  if (strcmp(svn_fs_base__id_copy_id(node_id),
+             svn_fs_base__id_copy_id(pred_id)) != 0)
     {
       /* ... then NODE was either the target of a copy operation,
          a copied subtree item.  We examine the actual copy record
@@ -4004,11 +4015,53 @@ txn_body_contents_changed(void *baton, t
 {
   struct things_changed_args *args = baton;
   dag_node_t *node1, *node2;
+  svn_checksum_t *checksum1, *checksum2;
+  svn_stream_t *stream1, *stream2;
+  svn_boolean_t same;
 
   SVN_ERR(get_dag(&node1, args->root1, args->path1, trail, trail->pool));
   SVN_ERR(get_dag(&node2, args->root2, args->path2, trail, trail->pool));
-  return svn_fs_base__things_different(NULL, args->changed_p,
-                                       node1, node2, trail, trail->pool);
+  SVN_ERR(svn_fs_base__things_different(NULL, args->changed_p,
+                                        node1, node2, trail, trail->pool));
+
+  /* Is there a potential false positive and do we want to correct it? */
+  if (!args->strict || !*args->changed_p)
+    return SVN_NO_ERROR;
+
+  /* Different representations. They might still have equal contents. */
+
+  /* Compare MD5 checksums.  These should be readily accessible. */
+  SVN_ERR(svn_fs_base__dag_file_checksum(&checksum1, svn_checksum_md5,
+                                         node1, trail, trail->pool));
+  SVN_ERR(svn_fs_base__dag_file_checksum(&checksum2, svn_checksum_md5,
+                                         node2, trail, trail->pool));
+
+  /* Different MD5 checksums -> different contents */
+  if (!svn_checksum_match(checksum1, checksum2))
+    return SVN_NO_ERROR;
+
+  /* Paranoia. Compare SHA1 checksums because that's the level of
+     confidence we require for e.g. the working copy. */
+  SVN_ERR(svn_fs_base__dag_file_checksum(&checksum1, svn_checksum_sha1,
+                                         node1, trail, trail->pool));
+  SVN_ERR(svn_fs_base__dag_file_checksum(&checksum2, svn_checksum_sha1,
+                                         node2, trail, trail->pool));
+
+  /* Different SHA1 checksums -> different contents */
+  if (checksum1 && checksum2)
+    {
+      *args->changed_p = !svn_checksum_match(checksum1, checksum2);
+      return SVN_NO_ERROR;
+    }
+
+  /* SHA1 checksums are not available for very old reps / repositories. */
+  SVN_ERR(svn_fs_base__dag_get_contents(&stream1, node1, trail, trail->pool));
+  SVN_ERR(svn_fs_base__dag_get_contents(&stream2, node2, trail, trail->pool));
+  SVN_ERR(svn_stream_contents_same2(&same, stream1, stream2, trail->pool));
+
+  /* Now, it's definitive. */
+  *args->changed_p = !same;
+  return SVN_NO_ERROR;
 }
 
 
@@ -4020,6 +4073,7 @@ base_contents_changed(svn_boolean_t *cha
                       const char *path1,
                       svn_fs_root_t *root2,
                       const char *path2,
+                      svn_boolean_t strict,
                       apr_pool_t *pool)
 {
   struct things_changed_args args;
@@ -4051,6 +4105,7 @@ base_contents_changed(svn_boolean_t *cha
   args.path2      = path2;
   args.changed_p  = changed_p;
   args.pool       = pool;
+  args.strict     = strict;
 
   return svn_fs_base__retry_txn(root1->fs, txn_body_contents_changed, &args,
                                 TRUE, pool);
@@ -4360,8 +4415,7 @@ txn_body_history_prev(void *baton, trail
      (which is either a real predecessor, or is the node itself
      playing the predecessor role to an imaginary mutable successor),
      then we need to report a copy.  */
-  if (svn_fs_base__key_compare(svn_fs_base__id_copy_id(node_id),
-                               end_copy_id) != 0)
+  if (strcmp(svn_fs_base__id_copy_id(node_id), end_copy_id) != 0)
     {
       const char *remainder;
       dag_node_t *dst_node;

Propchange: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Mar  9 10:08:46 2014
@@ -9,3 +9,5 @@ Release
 .*~
 rep-cache-db.h
 revprops-db.h
+libsvn_fs_fs.pc.in
+libsvn_fs_fs.pc

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/cached_data.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/cached_data.c Sun Mar  9 10:08:46 2014
@@ -462,10 +462,13 @@ get_root_changes_offset(apr_off_t *root_
                         apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
-  apr_off_t offset;
   apr_off_t rev_offset;
   apr_seek_where_t seek_relative;
-  svn_stringbuf_t *trailer = svn_stringbuf_create_ensure(64, pool);
+  svn_stringbuf_t *trailer;
+  char buffer[64];
+  apr_off_t start;
+  apr_off_t end;
+  apr_size_t len;
 
   /* Determine where to seek to in the file.
 
@@ -479,13 +482,13 @@ get_root_changes_offset(apr_off_t *root_
   if (svn_fs_fs__is_packed_rev(fs, rev)
       && ((rev + 1) % ffd->max_files_per_dir != 0))
     {
-      SVN_ERR(svn_fs_fs__get_packed_offset(&offset, fs, rev + 1, pool));
+      SVN_ERR(svn_fs_fs__get_packed_offset(&end, fs, rev + 1, pool));
       seek_relative = APR_SET;
     }
   else
     {
       seek_relative = APR_END;
-      offset = 0;
+      end = 0;
     }
 
   /* Offset of the revision from the start of the pack file, if applicable. */
@@ -496,16 +499,25 @@ get_root_changes_offset(apr_off_t *root_
 
   /* We will assume that the last line containing the two offsets
      will never be longer than 64 characters. */
-  SVN_ERR(svn_io_file_seek(rev_file, seek_relative, &offset, pool));
+  SVN_ERR(svn_io_file_seek(rev_file, seek_relative, &end, pool));
 
-  trailer->len = trailer->blocksize-1;
-  SVN_ERR(aligned_seek(fs, rev_file, NULL, offset - trailer->len, pool));
+  if (end < sizeof(buffer))
+    {
+      len = (apr_size_t)end;
+      start = 0;
+    }
+  else
+    {
+      len = sizeof(buffer);
+      start = end - sizeof(buffer);
+    }
 
   /* 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));
-  trailer->data[trailer->len] = 0;
+  SVN_ERR(aligned_seek(fs, rev_file, NULL, start, pool));
+  SVN_ERR(svn_io_file_read_full2(rev_file, buffer, len, NULL, NULL, pool));
 
   /* Parse the last line. */
+  trailer = svn_stringbuf_ncreate(buffer, len, pool);
   SVN_ERR(svn_fs_fs__parse_revision_trailer(root_offset,
                                             changes_offset,
                                             trailer,
@@ -719,10 +731,9 @@ create_rep_state_body(rep_state_t **rep_
       && (   ((*shared_file)->revision / ffd->max_files_per_dir)
           == (rep->revision / ffd->max_files_per_dir));
 
-  representation_cache_key_t key;
+  pair_cache_key_t key;
   key.revision = rep->revision;
-  key.is_packed = rep->revision < ffd->min_unpacked_rev;
-  key.item_index = rep->item_index;
+  key.second = rep->item_index;
 
   /* continue constructing RS and RA */
   rs->size = rep->size;
@@ -1130,7 +1141,7 @@ set_cached_window(svn_txdelta_window_t *
  * cache. This will be a no-op and IS_CACHED will be set to FALSE if no
  * cache has been given. If a cache is available IS_CACHED will inform
  * the caller about the success of the lookup. Allocations (of the window
- * in particualar) will be made from POOL.
+ * in particular) will be made from POOL.
  */
 static svn_error_t *
 get_cached_combined_window(svn_stringbuf_t **window_p,
@@ -1346,7 +1357,8 @@ read_delta_window(svn_txdelta_window_t *
      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_fs_fs__use_log_addressing(rs->sfile->fs, rs->revision)
+      && rs->window_cache)
     {
       SVN_ERR(block_read(NULL, rs->sfile->fs, rs->revision, rs->item_index,
                          rs->sfile->rfile, pool, pool));
@@ -2051,9 +2063,10 @@ read_dir_entries(apr_array_header_t *ent
       dirent->dirent.id = svn_fs_fs__id_parse(str, strlen(str), result_pool);
 
       /* In incremental mode, update the hash; otherwise, write to the
-       * final array. */
+       * final array.  Be sure to use hash keys that survive this iteration.
+       */
       if (incremental)
-        apr_hash_set(hash, entry.key, entry.keylen, dirent);
+        apr_hash_set(hash, dirent->name, entry.keylen, dirent);
       else
         APR_ARRAY_PUSH(entries, svn_fs_fs__dirent_t *) = dirent;
     }
@@ -2440,62 +2453,83 @@ init_rep_state(rep_state_t *rs,
   return SVN_NO_ERROR;
 }
 
+/* Implement svn_cache__partial_getter_func_t for txdelta windows.
+ * Instead of the whole window data, return only the
+ * svn_fs_fs__txdelta_cached_window_t wrapper containing the end-offset.
+ */
+static svn_error_t *
+get_window_header(void **out,
+                  const void *data,
+                  apr_size_t data_len,
+                  void *baton,
+                  apr_pool_t *result_pool)
+{
+  *out = apr_pmemdup(result_pool, data,
+                     sizeof(svn_fs_fs__txdelta_cached_window_t));
+
+  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.
+ * window caches.  If MAX_OFFSET is not -1, don't read windows that start
+ * at or beyond that offset.  Use POOL for temporary allocations.
  */
 static svn_error_t *
-cache_windows(svn_filesize_t *fulltext_len,
-              svn_fs_t *fs,
+cache_windows(svn_fs_t *fs,
               rep_state_t *rs,
+              apr_off_t max_offset,
               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;
+      svn_fs_fs__txdelta_cached_window_t *cached_window;
       svn_boolean_t found = FALSE;
 
-      /* We don't need to read the data again, if it is already in cache.
+      if (max_offset != -1 && rs->start + rs->current >= max_offset)
+        return SVN_NO_ERROR;
+
+      /* We don't need to read the data again if it is already in cache.
        */
       if (rs->window_cache)
         {
-          window_cache_key_t key = {0};
-          SVN_ERR(svn_cache__has_key(&found, rs->window_cache,
-                                     get_window_key(&key, rs), pool));
+          window_cache_key_t key = { 0 };
+          SVN_ERR(svn_cache__get_partial((void **) &cached_window, &found,
+                                         rs->window_cache,
+                                         get_window_key(&key, rs),
+                                         get_window_header, NULL, pool));
         }
 
-      /* navigate to the current window */
-      SVN_ERR(rs_aligned_seek(rs, NULL, start_offset, pool));
-
-      /* Skip or actually read the window - depending on cache status. */
       if (found)
-        SVN_ERR(svn_txdelta__read_svndiff_window_sizes(&window,
-                                                rs->sfile->rfile->stream,
-                                                rs->ver, pool));
+        {
+          /* Skip this window; we already have it. */
+          rs->current = cached_window->end_offset;
+        }
       else
-        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;
+        {
+          /* Read, decode and cache the window. */
+          svn_txdelta_window_t *window;
+          apr_off_t start_offset = rs->start + rs->current;
+          apr_off_t end_offset;
+
+          /* navigate to 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));
+
+          /* determine on-disk window size */
+          SVN_ERR(get_file_offset(&end_offset, rs, pool));
+          rs->current = end_offset - rs->start;
+
+          /* cache the window now */
+          SVN_ERR(set_cached_window(window, rs, pool));
+        }
+
       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 */
-      if (!found)
-        SVN_ERR(set_cached_window(window, rs, pool));
+                                _("Reading one svndiff window read beyond "
+                                            "the end of the representation"));
 
       rs->chunk_index++;
     }
@@ -2505,7 +2539,8 @@ cache_windows(svn_filesize_t *fulltext_l
 
 /* 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.
+ * STREAM object.  If MAX_OFFSET is not -1, don't read windows that start
+ * at or beyond that offset.  Use POOL for allocations.
  * If caching is not enabled, this is a no-op.
  */
 static svn_error_t *
@@ -2513,6 +2548,7 @@ block_read_windows(svn_fs_fs__rep_header
                    svn_fs_t *fs,
                    svn_fs_fs__revision_file_t *rev_file,
                    svn_fs_fs__p2l_entry_t* entry,
+                   apr_off_t max_offset,
                    apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -2557,8 +2593,7 @@ block_read_windows(svn_fs_fs__rep_header
     }
   else
     {
-      svn_filesize_t fulltext_len;
-      SVN_ERR(cache_windows(&fulltext_len, fs, &rs, pool));
+      SVN_ERR(cache_windows(fs, &rs, max_offset, pool));
     }
 
   return SVN_NO_ERROR;
@@ -2573,7 +2608,7 @@ 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,
+                pair_cache_key_t *key,
                 apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -2598,24 +2633,26 @@ read_rep_header(svn_fs_fs__rep_header_t 
 /* 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.
+ * STREAM object.  If MAX_OFFSET is not -1, don't read windows that start
+ * at or beyond that offset.  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_off_t max_offset,
                     apr_pool_t *pool)
 {
-  representation_cache_key_t header_key = { 0 };
+  pair_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;
+  header_key.second = 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));
+  SVN_ERR(block_read_windows(rep_header, fs, rev_file, entry, max_offset,
+                             pool));
 
   return SVN_NO_ERROR;
 }
@@ -2800,7 +2837,7 @@ block_read(void **result,
         = 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
+      /* if the revision got packed in the meantime and we still 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))
@@ -2823,7 +2860,7 @@ block_read(void **result,
       /* read all items from the block */
       for (i = 0; i < entries->nelts; ++i)
         {
-          svn_boolean_t is_result;
+          svn_boolean_t is_result, is_wanted;
           apr_pool_t *pool;
           svn_fs_fs__p2l_entry_t* entry;
 
@@ -2835,10 +2872,10 @@ block_read(void **result,
             continue;
 
           /* the item / container we were looking for? */
-          is_result =    result
-                      && entry->offset == wanted_offset
+          is_wanted =    entry->offset == wanted_offset
                       && entry->item.revision == revision
                       && entry->item.number == item_index;
+          is_result = result && is_wanted;
 
           /* select the pool that we want the item to be allocated in */
           pool = is_result ? result_pool : iterpool;
@@ -2859,6 +2896,9 @@ block_read(void **result,
                   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,
+                                                is_wanted
+                                                  ? -1
+                                                  : block_start + ffd->block_size,
                                                 pool));
                     break;
 

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/caching.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/caching.c Sun Mar  9 10:08:46 2014
@@ -510,9 +510,9 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
                        1, 1000, /* ~8 bytes / entry; 1k entries total */
                        svn_fs_fs__serialize_rep_header,
                        svn_fs_fs__deserialize_rep_header,
-                       sizeof(representation_cache_key_t),
+                       sizeof(pair_cache_key_t),
                        apr_pstrcat(pool, prefix, "REPHEADER", SVN_VA_NULL),
-                       SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+                       SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
                        fs,
                        no_handler,
                        fs->pool));

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/dag.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/dag.c Sun Mar  9 10:08:46 2014
@@ -1276,29 +1276,40 @@ svn_error_t *
 svn_fs_fs__dag_things_different(svn_boolean_t *props_changed,
                                 svn_boolean_t *contents_changed,
                                 dag_node_t *node1,
-                                dag_node_t *node2)
+                                dag_node_t *node2,
+                                svn_boolean_t strict,
+                                apr_pool_t *pool)
 {
   node_revision_t *noderev1, *noderev2;
+  svn_fs_t *fs;
+  svn_boolean_t same;
 
   /* If we have no place to store our results, don't bother doing
      anything. */
   if (! props_changed && ! contents_changed)
     return SVN_NO_ERROR;
 
+  fs = svn_fs_fs__dag_get_fs(node1);
+
   /* The node revision skels for these two nodes. */
   SVN_ERR(get_node_revision(&noderev1, node1));
   SVN_ERR(get_node_revision(&noderev2, node2));
 
   /* Compare property keys. */
   if (props_changed != NULL)
-    *props_changed = (! svn_fs_fs__noderev_same_rep_key(noderev1->prop_rep,
-                                                        noderev2->prop_rep));
+    {
+      SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, noderev1, noderev2,
+                                        strict, pool));
+      *props_changed = !same;
+    }
 
   /* Compare contents keys. */
   if (contents_changed != NULL)
-    *contents_changed =
-      (! svn_fs_fs__noderev_same_rep_key(noderev1->data_rep,
-                                         noderev2->data_rep));
+    {
+      SVN_ERR(svn_fs_fs__file_text_rep_equal(&same, fs, noderev1, noderev2,
+                                             strict, pool));
+      *contents_changed = !same;
+    }
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/dag.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/dag.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/dag.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/dag.h Sun Mar  9 10:08:46 2014
@@ -567,27 +567,25 @@ svn_error_t *svn_fs_fs__dag_copy(dag_nod
 
 /* Comparison */
 
-/* Find out what is the same between two nodes.
+/* Find out what is the same between two nodes.  If STRICT is FALSE,
+   this function may report false positives, i.e. report changes even
+   if the resulting contents / props are equal.
 
    If PROPS_CHANGED is non-null, set *PROPS_CHANGED to 1 if the two
    nodes have different property lists, or to 0 if same.
 
    If CONTENTS_CHANGED is non-null, set *CONTENTS_CHANGED to 1 if the
-   two nodes have different contents, or to 0 if same.  For files,
-   file contents are compared; for directories, the entries lists are
-   compared.  If one is a file and the other is a directory, the one's
-   contents will be compared to the other's entries list.  (Not
-   terribly useful, I suppose, but that's the caller's business.)
-
-   ### todo: This function only compares rep keys at the moment.  This
-   may leave us with a slight chance of a false positive, though I
-   don't really see how that would happen in practice.  Nevertheless,
-   it should probably be fixed.
+   two nodes have different contents, or to 0 if same.  NODE1 and NODE2
+   must refer to files from the same filesystem.
+
+   Use POOL for temporary allocations.
  */
 svn_error_t *svn_fs_fs__dag_things_different(svn_boolean_t *props_changed,
                                              svn_boolean_t *contents_changed,
                                              dag_node_t *node1,
-                                             dag_node_t *node2);
+                                             dag_node_t *node2,
+                                             svn_boolean_t strict,
+                                             apr_pool_t *pool);
 
 
 /* Set *REV and *PATH to the copyroot revision and path of node NODE, or

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs.c Sun Mar  9 10:08:46 2014
@@ -103,8 +103,11 @@ fs_serialized_init(svn_fs_t *fs, apr_poo
       SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock,
                               SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
 
+      /* We also need a mutex for synchronizing access to the active
+         transaction list and free transaction pointer.  This one is
+         enabled unconditionally. */
       SVN_ERR(svn_mutex__init(&ffsd->txn_list_lock,
-                              SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
+                              TRUE, common_pool));
 
       key = apr_pstrdup(common_pool, key);
       status = apr_pool_userdata_set(ffsd, key, NULL, common_pool);

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs.h Sun Mar  9 10:08:46 2014
@@ -55,6 +55,7 @@ extern "C" {
 #define PATH_UUID             "uuid"             /* Contains UUID */
 #define PATH_CURRENT          "current"          /* Youngest revision */
 #define PATH_LOCK_FILE        "write-lock"       /* Revision lock file */
+#define PATH_PACK_LOCK_FILE   "pack-lock"        /* Pack lock file */
 #define PATH_REVS_DIR         "revs"             /* Directory of revisions */
 #define PATH_REVPROPS_DIR     "revprops"         /* Directory of revprops */
 #define PATH_TXNS_DIR         "transactions"     /* Directory of transactions */
@@ -172,6 +173,9 @@ extern "C" {
 /* The minimum format number that supports packed revprops. */
 #define SVN_FS_FS__MIN_LOG_ADDRESSING_FORMAT 7
 
+/* Minimum format number that providing a separate lock file for pack ops */
+#define SVN_FS_FS__MIN_PACK_LOCK_FORMAT 7
+
 /* Minimum format number that stores mergeinfo-mode flag in changed paths */
 #define SVN_FS_FS__MIN_MERGEINFO_IN_CHANGES_FORMAT 7
 
@@ -255,37 +259,27 @@ typedef struct fs_fs_dag_cache_t fs_fs_d
 
 /* Key type for all caches that use revision + offset / counter as key.
 
-   NOTE: always initialize this using calloc() or '= {0};'!  This is used
-   as a cache key and the padding bytes on 32 bit archs should be zero for
-   cache effectiveness. */
+   Note: Cache keys should be 16 bytes for best performance and there
+         should be no padding. */
 typedef struct pair_cache_key_t
 {
-  svn_revnum_t revision;
+  /* The object's revision.  Use the 64 data type to prevent padding. */
+  apr_int64_t revision;
 
+  /* Sub-address: item index, revprop generation, packed flag, etc. */
   apr_int64_t second;
 } pair_cache_key_t;
 
-/* Key type that identifies a representation / rep header. */
-typedef struct representation_cache_key_t
-{
-  /* Revision that contains the representation */
-  apr_uint32_t revision;
-
-  /* Packed or non-packed representation? */
-  svn_boolean_t is_packed;
-
-  /* Item index of the representation */
-  apr_uint64_t item_index;
-} representation_cache_key_t;
+/* Key type that identifies a txdelta window.
 
-/* Key type that identifies a txdelta window. */
+   Note: Cache keys should require no padding. */
 typedef struct window_cache_key_t
 {
-  /* Revision that contains the representation */
-  apr_uint32_t revision;
+  /* The object's revision.  Use the 64 data type to prevent padding. */
+  apr_int64_t revision;
 
-  /* Window number within that representation */
-  apr_int32_t chunk_index;
+  /* Window number within that representation. */
+  apr_int64_t chunk_index;
 
   /* Item index of the representation */
   apr_uint64_t item_index;

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs_fs.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs_fs.c Sun Mar  9 10:08:46 2014
@@ -114,9 +114,9 @@ path_lock(svn_fs_t *fs, apr_pool_t *pool
 
 
 /* Get a lock on empty file LOCK_FILENAME, creating it in POOL. */
-static svn_error_t *
-get_lock_on_filesystem(const char *lock_filename,
-                       apr_pool_t *pool)
+svn_error_t *
+svn_fs_fs__get_lock_on_filesystem(const char *lock_filename,
+                                  apr_pool_t *pool)
 {
   svn_error_t *err = svn_io_file_lock2(lock_filename, TRUE, FALSE, pool);
 
@@ -160,7 +160,8 @@ with_some_lock_file(svn_fs_t *fs,
                     apr_pool_t *pool)
 {
   apr_pool_t *subpool = svn_pool_create(pool);
-  svn_error_t *err = get_lock_on_filesystem(lock_filename, subpool);
+  svn_error_t *err = svn_fs_fs__get_lock_on_filesystem(lock_filename,
+                                                       subpool);
 
   if (!err)
     {
@@ -1089,25 +1090,131 @@ svn_fs_fs__file_length(svn_filesize_t *l
   return SVN_NO_ERROR;
 }
 
-svn_boolean_t
-svn_fs_fs__noderev_same_rep_key(representation_t *a,
-                                representation_t *b)
-{
-  if (a == b)
-    return TRUE;
+svn_error_t *
+svn_fs_fs__file_text_rep_equal(svn_boolean_t *equal,
+                               svn_fs_t *fs,
+                               node_revision_t *a,
+                               node_revision_t *b,
+                               svn_boolean_t strict,
+                               apr_pool_t *scratch_pool)
+{
+  svn_stream_t *contents_a, *contents_b;
+  representation_t *rep_a = a->data_rep;
+  representation_t *rep_b = b->data_rep;
+  svn_boolean_t a_empty = !rep_a || rep_a->expanded_size == 0;
+  svn_boolean_t b_empty = !rep_b || rep_b->expanded_size == 0;
+
+  /* This makes sure that neither rep will be NULL later on */
+  if (a_empty && b_empty)
+    {
+      *equal = TRUE;
+      return SVN_NO_ERROR;
+    }
+
+  if (a_empty != b_empty)
+    {
+      *equal = FALSE;
+      return SVN_NO_ERROR;
+    }
+
+  /* File text representations always know their checksums - even in a txn. */
+  if (memcmp(rep_a->md5_digest, rep_b->md5_digest, sizeof(rep_a->md5_digest)))
+    {
+      *equal = FALSE;
+      return SVN_NO_ERROR;
+    }
+
+  /* Paranoia. Compare SHA1 checksums because that's the level of
+     confidence we require for e.g. the working copy. */
+  if (rep_a->has_sha1 && rep_b->has_sha1)
+    {
+      *equal = memcmp(rep_a->sha1_digest, rep_b->sha1_digest,
+                      sizeof(rep_a->sha1_digest)) == 0;
+      return SVN_NO_ERROR;
+    }
+
+  /* Same path in same rev or txn? */
+  if (svn_fs_fs__id_eq(a->id, b->id))
+    {
+      *equal = TRUE;
+      return SVN_NO_ERROR;
+    }
+
+  /* Old repositories may not have the SHA1 checksum handy.
+     This check becomes expensive.  Skip it unless explicitly required. */
+  if (!strict)
+    {
+      *equal = TRUE;
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(svn_fs_fs__get_contents(&contents_a, fs, rep_a, TRUE,
+                                  scratch_pool));
+  SVN_ERR(svn_fs_fs__get_contents(&contents_b, fs, rep_b, TRUE,
+                                  scratch_pool));
+  SVN_ERR(svn_stream_contents_same2(equal, contents_a, contents_b,
+                                   scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__prop_rep_equal(svn_boolean_t *equal,
+                          svn_fs_t *fs,
+                          node_revision_t *a,
+                          node_revision_t *b,
+                          svn_boolean_t strict,
+                          apr_pool_t *scratch_pool)
+{
+  representation_t *rep_a = a->prop_rep;
+  representation_t *rep_b = b->prop_rep;
+  apr_hash_t *proplist_a;
+  apr_hash_t *proplist_b;
+
+  /* Mainly for a==b==NULL */
+  if (rep_a == rep_b)
+    {
+      *equal = TRUE;
+      return SVN_NO_ERROR;
+    }
 
-  if (a == NULL || b == NULL)
-    return FALSE;
+  /* Committed property lists can be compared quickly */
+  if (   rep_a && rep_b
+      && !svn_fs_fs__id_txn_used(&rep_a->txn_id)
+      && !svn_fs_fs__id_txn_used(&rep_b->txn_id))
+    {
+      /* MD5 must be given. Having the same checksum is good enough for
+         accepting the prop lists as equal. */
+      *equal = memcmp(rep_a->md5_digest, rep_b->md5_digest,
+                      sizeof(rep_a->md5_digest)) == 0;
+      return SVN_NO_ERROR;
+    }
 
-  if (a->item_index != b->item_index)
-    return FALSE;
+  /* Same path in same txn? */
+  if (svn_fs_fs__id_eq(a->id, b->id))
+    {
+      *equal = TRUE;
+      return SVN_NO_ERROR;
+    }
 
-  if (a->revision != b->revision)
-    return FALSE;
+  /* Skip the expensive bits unless we are in strict mode.
+     Simply assume that there is a difference. */
+  if (!strict)
+    {
+      *equal = FALSE;
+      return SVN_NO_ERROR;
+    }
 
-  return memcmp(&a->uniquifier, &b->uniquifier, sizeof(a->uniquifier)) == 0;
+  /* At least one of the reps has been modified in a txn.
+     Fetch and compare them. */
+  SVN_ERR(svn_fs_fs__get_proplist(&proplist_a, fs, a, scratch_pool));
+  SVN_ERR(svn_fs_fs__get_proplist(&proplist_b, fs, b, scratch_pool));
+
+  *equal = svn_fs__prop_lists_equal(proplist_a, proplist_b, scratch_pool);
+  return SVN_NO_ERROR;
 }
 
+
 svn_error_t *
 svn_fs_fs__file_checksum(svn_checksum_t **checksum,
                          node_revision_t *noderev,
@@ -1207,9 +1314,9 @@ write_revision_zero(svn_fs_t *fs)
                   "\x80\x80\4\1\x1D"    /* 64k pages, 1 page using 29 bytes */
                   "\0"                  /* offset entry 0 page 1 */
                                         /* len, item & type, rev, checksum */
-                  "\x11\x34\0\xe0\xc6\xac\xa9\x07"
-                  "\x59\x09\0\xc0\xfa\xf8\xc5\x04"
-                  "\1\x0d\0\xf2\x95\xbe\xea\x01"
+                  "\x11\x34\0\xf5\xd6\x8c\x81\x06"
+                  "\x59\x09\0\xc8\xfc\xf6\x81\x04"
+                  "\1\x0d\0\x9d\x9e\xa9\x94\x0f" 
                   "\x95\xff\3\x1b\0\0", /* last entry fills up 64k page */
                   38,
                   fs->pool));

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs_fs.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/fs_fs.h Sun Mar  9 10:08:46 2014
@@ -65,10 +65,29 @@ svn_error_t *svn_fs_fs__file_length(svn_
                                     node_revision_t *noderev,
                                     apr_pool_t *pool);
 
-/* Return TRUE if the representation keys in A and B both point to the
-   same representation, else return FALSE. */
-svn_boolean_t svn_fs_fs__noderev_same_rep_key(representation_t *a,
-                                              representation_t *b);
+/* Set *EQUAL to TRUE if the text representations in A and B within FS
+   have equal contents, else set it to FALSE.  If STRICT is not set, allow
+   for false negatives.
+   Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *
+svn_fs_fs__file_text_rep_equal(svn_boolean_t *equal,
+                               svn_fs_t *fs,
+                               node_revision_t *a,
+                               node_revision_t *b,
+                               svn_boolean_t strict,
+                               apr_pool_t *scratch_pool);
+
+/* Set *EQUAL to TRUE if the property representations in A and B within FS
+   have equal contents, else set it to FALSE.  If STRICT is not set, allow
+   for false negatives.
+   Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *
+svn_fs_fs__prop_rep_equal(svn_boolean_t *equal,
+                          svn_fs_t *fs,
+                          node_revision_t *a,
+                          node_revision_t *b,
+                          svn_boolean_t strict,
+                          apr_pool_t *scratch_pool);
 
 
 /* Return a copy of the representation REP allocated from POOL. */
@@ -117,6 +136,12 @@ svn_fs_fs__write_format(svn_fs_t *fs,
                         svn_boolean_t overwrite,
                         apr_pool_t *pool);
 
+/* Get a lock on empty file LOCK_FILENAME, creating it in POOL;
+   releasing the lock upon POOL cleanup. */
+svn_error_t *
+svn_fs_fs__get_lock_on_filesystem(const char *lock_filename,
+                                  apr_pool_t *pool);
+
 /* Obtain a write lock on the filesystem FS in a subpool of POOL, call
    BODY with BATON and that subpool, destroy the subpool (releasing the write
    lock) and return what BODY returned. */

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/hotcopy.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/hotcopy.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/hotcopy.c Sun Mar  9 10:08:46 2014
@@ -382,12 +382,6 @@ hotcopy_update_current(svn_revnum_t *dst
   /* If necessary, get new current next_node and next_copy IDs. */
   if (dst_ffd->format < SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT)
     {
-      /* Make sure NEW_YOUNGEST is a valid revision in DST_FS.
-         Because a crash in hotcopy requires at least a full recovery run,
-         it is safe to temporarily reset the max IDs to 0. */
-      SVN_ERR(svn_fs_fs__write_current(dst_fs, new_youngest, next_node_id,
-                                      next_copy_id, scratch_pool));
-
       SVN_ERR(svn_fs_fs__find_max_ids(dst_fs, new_youngest,
                                       &next_node_id, &next_copy_id,
                                       scratch_pool));
@@ -586,7 +580,7 @@ struct hotcopy_body_baton {
   svn_boolean_t incremental;
   svn_cancel_func_t cancel_func;
   void *cancel_baton;
-} hotcopy_body_baton;
+};
 
 /* Perform a hotcopy, either normal or incremental.
  *

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/id.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/id.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/id.c Sun Mar  9 10:08:46 2014
@@ -317,13 +317,14 @@ svn_fs_fs__id_check_related(const svn_fs
 }
 
 
-int
+svn_fs_node_relation_t
 svn_fs_fs__id_compare(const svn_fs_id_t *a,
                       const svn_fs_id_t *b)
 {
   if (svn_fs_fs__id_eq(a, b))
-    return 0;
-  return (svn_fs_fs__id_check_related(a, b) ? 1 : -1);
+    return svn_fs_node_same;
+  return (svn_fs_fs__id_check_related(a, b) ? svn_fs_node_common_ancestor
+                                            : svn_fs_node_unrelated);
 }
 
 int

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/id.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/id.h?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/id.h (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/id.h Sun Mar  9 10:08:46 2014
@@ -114,9 +114,9 @@ svn_boolean_t svn_fs_fs__id_eq(const svn
 svn_boolean_t svn_fs_fs__id_check_related(const svn_fs_id_t *a,
                                           const svn_fs_id_t *b);
 
-/* Return 0 if A and B are equal, 1 if they are related, -1 otherwise. */
-int svn_fs_fs__id_compare(const svn_fs_id_t *a,
-                          const svn_fs_id_t *b);
+/* Return the noderev relationship between A and B. */
+svn_fs_node_relation_t svn_fs_fs__id_compare(const svn_fs_id_t *a,
+                                             const svn_fs_id_t *b);
 
 /* Return 0 if A and B are equal, 1 if A is "greater than" B, -1 otherwise. */
 int svn_fs_fs__id_part_compare(const svn_fs_fs__id_part_t *a,

Modified: subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/index.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/index.c?rev=1575685&r1=1575684&r2=1575685&view=diff
==============================================================================
--- subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/index.c (original)
+++ subversion/branches/fsfs-ucsnorm/subversion/libsvn_fs_fs/index.c Sun Mar  9 10:08:46 2014
@@ -71,7 +71,7 @@ typedef struct l2p_header_t
   apr_size_t revision_count;
 
   /* (max) number of entries per page */
-  apr_size_t page_size;
+  apr_uint32_t page_size;
 
   /* indexes into PAGE_TABLE that mark the first page of the respective
    * revision.  PAGE_TABLE_INDEX[REVISION_COUNT] points to the end of
@@ -96,7 +96,7 @@ typedef struct l2p_page_t
   apr_uint64_t *offsets;
 } l2p_page_t;
 
-/* All of the log-to-phys proto index file consist of entires of this type.
+/* All of the log-to-phys proto index file consist of entries of this type.
  */
 typedef struct l2p_proto_entry_t
 {
@@ -297,7 +297,7 @@ packed_stream_read(svn_fs_fs__packed_num
   stream->current = 0;
 
   return SVN_NO_ERROR;
-};
+}
 
 /* Create and open a packed number stream reading from FILE_NAME and
  * return it in *STREAM.  Access the file in chunks of BLOCK_SIZE bytes.
@@ -587,6 +587,14 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs
   svn_spillbuf_t *buffer
     = svn_spillbuf__create(0x10000, 0x1000000, local_pool);
 
+  /* Paranoia check that makes later casting to int32 safe.
+   * The current implementation is limited to 2G entries per page. */
+  if (ffd->l2p_page_size > APR_INT32_MAX)
+    return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                            _("L2P index page size  %" APR_UINT64_T_FMT
+                              " exceeds current limit of 2G entries"),
+                            ffd->l2p_page_size);
+
   /* start at the beginning of the source file */
   SVN_ERR(svn_io_file_open(&proto_index, proto_file_name,
                            APR_READ | APR_CREATE | APR_BUFFERED,
@@ -617,7 +625,9 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs
 
               svn_pool_clear(iterpool);
 
-              entry_count = MIN(entries->nelts - i, ffd->l2p_page_size);
+              entry_count = ffd->l2p_page_size < entries->nelts - i
+                          ? (int)ffd->l2p_page_size
+                          : entries->nelts - i;
               SVN_ERR(encode_l2p_page(entries, i, i + entry_count,
                                       buffer, iterpool));
 
@@ -636,8 +646,18 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs
         }
       else
         {
+          int idx;
+
           /* store the mapping in our array */
-          int idx = (apr_size_t)proto_entry.item_index;
+          if (proto_entry.item_index > APR_INT32_MAX)
+            return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                                    _("Item index %" APR_UINT64_T_FMT
+                                      " too large in l2p proto index for"
+                                      " revision %ld"),
+                                    proto_entry.item_index,
+                                    revision + page_counts->nelts);
+
+          idx = (int)proto_entry.item_index;
           while (idx >= entries->nelts)
             APR_ARRAY_PUSH(entries, apr_uint64_t) = 0;
 
@@ -651,6 +671,14 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs
   /* create the target file */
   SVN_ERR(index_create(&index_file, file_name, local_pool));
 
+  /* Paranoia check that makes later casting to int32 safe.
+   * The current implementation is limited to 2G pages per index. */
+  if (page_counts->nelts > APR_INT32_MAX)
+    return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                            _("L2P index page count  %d"
+                              " exceeds current limit of 2G pages"),
+                            page_counts->nelts);
+
   /* write header info */
   SVN_ERR(svn_io_file_write_full(index_file, encoded,
                                  encode_uint(encoded, revision),
@@ -782,7 +810,7 @@ get_l2p_header_body(l2p_header_t **heade
   SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
   result->first_revision = (svn_revnum_t)value;
   SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
-  result->page_size = (apr_size_t)value;
+  result->page_size = (apr_uint32_t)value;
   SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
   result->revision_count = (int)value;
   SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
@@ -851,7 +879,7 @@ typedef struct l2p_page_info_baton_t
   l2p_page_table_entry_t entry;
 
   /* page number within the pages for REVISION (not l2p index global!) */
-  apr_size_t page_no;
+  apr_uint32_t page_no;
 
   /* offset of ITEM_INDEX within that page */
   apr_uint32_t page_offset;
@@ -882,7 +910,7 @@ l2p_page_info_copy(l2p_page_info_baton_t
   if (baton->item_index < header->page_size)
     {
       /* most revs fit well into a single page */
-      baton->page_offset = (apr_size_t)baton->item_index;
+      baton->page_offset = (apr_uint32_t)baton->item_index;
       baton->page_no = 0;
       baton->entry = page_table[page_table_index[rel_revision]];
     }
@@ -890,29 +918,28 @@ l2p_page_info_copy(l2p_page_info_baton_t
     {
       const l2p_page_table_entry_t *first_entry;
       const l2p_page_table_entry_t *last_entry;
-      
-      /* all pages are of the same size and full, except for the last one */
-      baton->page_offset = (apr_size_t)(baton->item_index % header->page_size);
-      baton->page_no = (apr_uint32_t)(baton->item_index / header->page_size);
+      apr_uint64_t max_item_index;
 
       /* range of pages for this rev */
       first_entry = page_table + page_table_index[rel_revision];
       last_entry = page_table + page_table_index[rel_revision + 1];
 
-      if (last_entry - first_entry > baton->page_no)
-        {
-          baton->entry = first_entry[baton->page_no];
-        }
-      else
-        {
-          /* limit page index to the valid range */
-          baton->entry = last_entry[-1];
+      /* do we hit a valid index page? */
+      max_item_index =   (apr_uint64_t)header->page_size
+                       * (last_entry - first_entry);
+      if (baton->item_index >= max_item_index)
+        return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                                _("Item index %" APR_UINT64_T_FMT
+                                  " exceeds l2p limit of %" APR_UINT64_T_FMT
+                                  " for revision %ld"),
+                                baton->item_index, max_item_index,
+                                baton->revision);
 
-          /* cause index overflow further down the road */
-          baton->page_offset = header->page_size + 1;
-        }
+      /* all pages are of the same size and full, except for the last one */
+      baton->page_offset = (apr_uint32_t)(baton->item_index % header->page_size);
+      baton->page_no = (apr_uint32_t)(baton->item_index / header->page_size);
     }
-    
+
   baton->first_revision = header->first_revision;
 
   return SVN_NO_ERROR;