subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1442344 [11/39] - in /subversion/branches/fsfs-format7: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ doc/...
Date Mon, 04 Feb 2013 20:48:13 GMT
Modified: subversion/branches/fsfs-format7/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_diff/diff_file.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_diff/diff_file.c Mon Feb  4 20:48:05 2013
@@ -122,6 +122,9 @@ datasource_to_index(svn_diff_datasource_
  * whatsoever.  If there is a number someone comes up with that has some
  * argumentation, let's use that.
  */
+/* If you change this number, update test_norm_offset(),
+ * test_identical_suffix() and and test_token_compare()  in diff-diff3-test.c.
+ */
 #define CHUNK_SHIFT 17
 #define CHUNK_SIZE (1 << CHUNK_SHIFT)
 
@@ -418,7 +421,7 @@ find_identical_prefix(svn_boolean_t *rea
         }
 
       is_match = TRUE;
-      for (delta = 0; delta < max_delta && is_match; delta += sizeof(apr_uintptr_t))
+      for (delta = 0; delta < max_delta; delta += sizeof(apr_uintptr_t))
         {
           apr_uintptr_t chunk = *(const apr_uintptr_t *)(file[0].curp + delta);
           if (contains_eol(chunk))
@@ -428,18 +431,25 @@ find_identical_prefix(svn_boolean_t *rea
             if (chunk != *(const apr_uintptr_t *)(file[i].curp + delta))
               {
                 is_match = FALSE;
-                delta -= sizeof(apr_uintptr_t);
                 break;
               }
+
+          if (! is_match)
+            break;
         }
 
-      /* We either found a mismatch or an EOL at or shortly behind curp+delta
-       * or we cannot proceed with chunky ops without exceeding endp.
-       * In any way, everything up to curp + delta is equal and not an EOL.
-       */
-      for (i = 0; i < file_len; i++)
-        file[i].curp += delta;
+      if (delta /* > 0*/)
+        {
+          /* We either found a mismatch or an EOL at or shortly behind curp+delta
+           * or we cannot proceed with chunky ops without exceeding endp.
+           * In any way, everything up to curp + delta is equal and not an EOL.
+           */
+          for (i = 0; i < file_len; i++)
+            file[i].curp += delta;
 
+          /* Skipped data without EOL markers, so last char was not a CR. */
+          had_cr = FALSE; 
+        }
 #endif
 
       *reached_one_eof = is_one_at_eof(file, file_len);
@@ -496,6 +506,7 @@ find_identical_prefix(svn_boolean_t *rea
  * The number 50 is more or less arbitrary, based on some real-world tests
  * with big files (and then doubling the required number to be on the safe
  * side). This has a negligible effect on the power of the optimization. */
+/* If you change this number, update test_identical_suffix() in diff-diff3-test.c */
 #ifndef SUFFIX_LINES_TO_KEEP
 #define SUFFIX_LINES_TO_KEEP 50
 #endif
@@ -518,7 +529,6 @@ find_identical_suffix(apr_off_t *suffix_
   apr_off_t min_file_size;
   int suffix_lines_to_keep = SUFFIX_LINES_TO_KEEP;
   svn_boolean_t is_match;
-  svn_boolean_t reached_prefix;
   apr_off_t lines = 0;
   svn_boolean_t had_cr;
   svn_boolean_t had_nl;
@@ -580,6 +590,7 @@ find_identical_suffix(apr_off_t *suffix_
   had_nl = FALSE;
   while (is_match)
     {
+      svn_boolean_t reached_prefix;
 #if SVN_UNALIGNED_ACCESS_IS_OK
       /* Initialize the minimum pointer positions. */
       const char *min_curp[4];
@@ -606,44 +617,60 @@ find_identical_suffix(apr_off_t *suffix_
       DECREMENT_POINTERS(file_for_suffix, file_len, pool);
 
 #if SVN_UNALIGNED_ACCESS_IS_OK
+      for (i = 0; i < file_len; i++)
+        min_curp[i] = file_for_suffix[i].buffer;
 
-      min_curp[0] = file_for_suffix[0].chunk == suffix_min_chunk0
-                  ? file_for_suffix[0].buffer + suffix_min_offset0 + 1
-                  : file_for_suffix[0].buffer + 1;
-      for (i = 1; i < file_len; i++)
-        min_curp[i] = file_for_suffix[i].buffer + 1;
+      /* If we are in the same chunk that contains the last part of the common
+         prefix, use the min_curp[0] pointer to make sure we don't get a
+         suffix that overlaps the already determined common prefix. */
+      if (file_for_suffix[0].chunk == suffix_min_chunk0)
+        min_curp[0] += suffix_min_offset0;
 
       /* Scan quickly by reading with machine-word granularity. */
       for (i = 0, can_read_word = TRUE; i < file_len; i++)
         can_read_word = can_read_word
-                        && (   file_for_suffix[i].curp - sizeof(apr_uintptr_t)
-                            >= min_curp[i]);
-      if (can_read_word)
-        {
-          do
-            {
-              apr_uintptr_t chunk;
-              for (i = 0; i < file_len; i++)
-                file_for_suffix[i].curp -= sizeof(apr_uintptr_t);
+                        && (  (file_for_suffix[i].curp + 1
+                                 - sizeof(apr_uintptr_t))
+                            > min_curp[i]);
+      while (can_read_word)
+        {
+          apr_uintptr_t chunk;
+
+          /* For each file curp is positioned at the current byte, but we
+             want to examine the current byte and the ones before the current
+             location as one machine word. */
 
-              chunk = *(const apr_uintptr_t *)(file_for_suffix[0].curp + 1);
-              if (contains_eol(chunk))
-                break;
+          chunk = *(const apr_uintptr_t *)(file_for_suffix[0].curp + 1
+                                             - sizeof(apr_uintptr_t));
+          if (contains_eol(chunk))
+            break;
 
-              for (i = 0, can_read_word = TRUE; i < file_len; i++)
-                can_read_word = can_read_word
-                                && (   file_for_suffix[i].curp - sizeof(apr_uintptr_t)
-                                    >= min_curp[i]);
-              for (i = 1, is_match = TRUE; i < file_len; i++)
-                is_match = is_match
-                           && (   chunk
-                               == *(const apr_uintptr_t *)(file_for_suffix[i].curp + 1));
-            } while (can_read_word && is_match);
+          for (i = 1, is_match = TRUE; i < file_len; i++)
+            is_match = is_match
+                       && (   chunk
+                           == *(const apr_uintptr_t *)
+                                    (file_for_suffix[i].curp + 1
+                                       - sizeof(apr_uintptr_t)));
+
+          if (! is_match)
+            break;
+
+          for (i = 0; i < file_len; i++)
+            {
+              file_for_suffix[i].curp -= sizeof(apr_uintptr_t);
+              can_read_word = can_read_word
+                              && (  (file_for_suffix[i].curp + 1
+                                       - sizeof(apr_uintptr_t))
+                                  > min_curp[i]);
+            }
 
-            for (i = 0; i < file_len; i++)
-              file_for_suffix[i].curp += sizeof(apr_uintptr_t);
+          /* We skipped some bytes, so there are no closing EOLs */
+          had_nl = FALSE;
+          had_cr = FALSE;
         }
 
+      /* The > min_curp[i] check leaves at least one final byte for checking
+         in the non block optimized case below. */
 #endif
 
       reached_prefix = file_for_suffix[0].chunk == suffix_min_chunk0
@@ -652,7 +679,8 @@ find_identical_suffix(apr_off_t *suffix_
       if (reached_prefix || is_one_at_bof(file_for_suffix, file_len))
         break;
 
-      for (i = 1, is_match = TRUE; i < file_len; i++)
+      is_match = TRUE;
+      for (i = 1; i < file_len; i++)
         is_match = is_match
                    && *file_for_suffix[0].curp == *file_for_suffix[i].curp;
     }
@@ -734,7 +762,9 @@ datasources_open(void *baton,
   struct file_info files[4];
   apr_finfo_t finfo[4];
   apr_off_t length[4];
+#ifndef SVN_DISABLE_PREFIX_SUFFIX_SCANNING
   svn_boolean_t reached_one_eof;
+#endif
   apr_size_t i;
 
   /* Make sure prefix_lines and suffix_lines are set correctly, even if we
@@ -828,17 +858,24 @@ datasource_get_next_token(apr_uint32_t *
 
   last_chunk = offset_to_chunk(file->size);
 
-  if (curp == endp
-      && last_chunk == file->chunk)
+  /* Are we already at the end of a chunk? */
+  if (curp == endp)
     {
-      return SVN_NO_ERROR;
+      /* Are we at EOF */
+      if (last_chunk == file->chunk)
+        return SVN_NO_ERROR; /* EOF */
+
+      /* Or right before an identical suffix in the next chunk? */
+      if (file->chunk + 1 == file->suffix_start_chunk
+          && file->suffix_offset_in_chunk == 0)
+        return SVN_NO_ERROR;
     }
 
   /* Stop when we encounter the identical suffix. If suffix scanning was not
    * performed, suffix_start_chunk will be -1, so this condition will never
    * be true. */
   if (file->chunk == file->suffix_start_chunk
-      && curp - file->buffer == file->suffix_offset_in_chunk)
+      && (curp - file->buffer) == file->suffix_offset_in_chunk)
     return SVN_NO_ERROR;
 
   /* Allocate a new token, or fetch one from the "reusable tokens" list. */
@@ -855,6 +892,7 @@ datasource_get_next_token(apr_uint32_t *
   file_token->datasource = datasource;
   file_token->offset = chunk_to_offset(file->chunk)
                        + (curp - file->buffer);
+  file_token->norm_offset = file_token->offset;
   file_token->raw_length = 0;
   file_token->length = 0;
 
@@ -883,11 +921,21 @@ datasource_get_next_token(apr_uint32_t *
 
       length = endp - curp;
       file_token->raw_length += length;
-      svn_diff__normalize_buffer(&curp, &length,
-                                 &file->normalize_state,
-                                 curp, file_baton->options);
-      file_token->length += length;
-      h = svn__adler32(h, curp, length);
+      {
+        char *c = curp;
+
+        svn_diff__normalize_buffer(&c, &length,
+                                   &file->normalize_state,
+                                   curp, file_baton->options);
+        if (file_token->length == 0)
+          {
+            /* When we are reading the first part of the token, move the
+               normalized offset past leading ignored characters, if any. */
+            file_token->norm_offset += (c - curp);
+          }
+        file_token->length += length;
+        h = svn__adler32(h, c, length);
+      }
 
       curp = endp = file->buffer;
       file->chunk++;
@@ -896,6 +944,14 @@ datasource_get_next_token(apr_uint32_t *
       endp += length;
       file->endp = endp;
 
+      /* Issue #4283: Normally we should have checked for reaching the skipped
+         suffix here, but because we assume that a suffix always starts on a
+         line and token boundary we rely on catching the suffix earlier in this
+         function.
+
+         When changing things here, make sure the whitespace settings are
+         applied, or we mught not reach the exact suffix boundary as token
+         boundary. */
       SVN_ERR(read_chunk(file->file, file->path,
                          curp, length,
                          chunk_to_offset(file->chunk),
@@ -926,11 +982,12 @@ datasource_get_next_token(apr_uint32_t *
       svn_diff__normalize_buffer(&c, &length,
                                  &file->normalize_state,
                                  curp, file_baton->options);
-
-      file_token->norm_offset = file_token->offset;
       if (file_token->length == 0)
-        /* move past leading ignored characters */
-        file_token->norm_offset += (c - curp);
+        {
+          /* When we are reading the first part of the token, move the
+             normalized offset past leading ignored characters, if any. */
+          file_token->norm_offset += (c - curp);
+        }
 
       file_token->length += length;
 
@@ -1002,8 +1059,15 @@ token_compare(void *baton, void *token1,
         }
       else
         {
+          apr_off_t skipped;
+
           length[i] = 0;
-          raw_length[i] = file_token[i]->raw_length;
+
+          /* When we skipped the first part of the token via the whitespace
+             normalization we must reduce the raw length of the token */
+          skipped = (file_token[i]->norm_offset - file_token[i]->offset);
+
+          raw_length[i] = file_token[i]->raw_length - skipped;
         }
     }
 
@@ -1039,6 +1103,8 @@ token_compare(void *baton, void *token1,
                  so, overwriting it isn't a problem */
               svn_diff__normalize_buffer(&bufp[i], &length[i], &state[i],
                                          bufp[i], file_baton->options);
+
+              /* assert(length[i] == file_token[i]->length); */
             }
         }
 
@@ -1502,12 +1568,26 @@ output_unified_line(svn_diff__file_outpu
   return SVN_NO_ERROR;
 }
 
+static APR_INLINE svn_error_t *
+output_unified_diff_range(svn_diff__file_output_baton_t *output_baton,
+                          int source,
+                          svn_diff__file_output_unified_type_e type,
+                          apr_off_t until)
+{
+  while (output_baton->current_line[source] < until)
+    {
+      SVN_ERR(output_unified_line(output_baton, type, source));
+    }
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 output_unified_flush_hunk(svn_diff__file_output_baton_t *baton)
 {
   apr_off_t target_line;
   apr_size_t hunk_len;
-  int i;
+  apr_off_t old_start;
+  apr_off_t new_start;
 
   if (svn_stringbuf_isempty(baton->hunk))
     {
@@ -1519,25 +1599,25 @@ output_unified_flush_hunk(svn_diff__file
                 + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
 
   /* Add trailing context to the hunk */
-  while (baton->current_line[0] < target_line)
-    {
-      SVN_ERR(output_unified_line
-              (baton, svn_diff__file_output_unified_context, 0));
-    }
+  SVN_ERR(output_unified_diff_range(baton, 0 /* original */,
+                                    svn_diff__file_output_unified_context,
+                                    target_line));
+
+  old_start = baton->hunk_start[0];
+  new_start = baton->hunk_start[1];
 
   /* If the file is non-empty, convert the line indexes from
      zero based to one based */
-  for (i = 0; i < 2; i++)
-    {
-      if (baton->hunk_length[i] > 0)
-        baton->hunk_start[i]++;
-    }
+  if (baton->hunk_length[0])
+    old_start++;
+  if (baton->hunk_length[1])
+    new_start++;
 
   /* Write the hunk header */
   SVN_ERR(svn_diff__unified_write_hunk_header(
             baton->output_stream, baton->header_encoding, "@@",
-            baton->hunk_start[0], baton->hunk_length[0],
-            baton->hunk_start[1], baton->hunk_length[1],
+            old_start, baton->hunk_length[0],
+            new_start, baton->hunk_length[1],
             baton->hunk_extra_context,
             baton->pool));
 
@@ -1549,6 +1629,8 @@ output_unified_flush_hunk(svn_diff__file
   /* Prepare for the next hunk */
   baton->hunk_length[0] = 0;
   baton->hunk_length[1] = 0;
+  baton->hunk_start[0] = 0;
+  baton->hunk_start[1] = 0;
   svn_stringbuf_setempty(baton->hunk);
 
   return SVN_NO_ERROR;
@@ -1561,95 +1643,120 @@ output_unified_diff_modified(void *baton
   apr_off_t latest_start, apr_off_t latest_length)
 {
   svn_diff__file_output_baton_t *output_baton = baton;
-  apr_off_t target_line[2];
-  int i;
+  apr_off_t context_prefix_length;
+  apr_off_t prev_context_end;
+  svn_boolean_t init_hunk = FALSE;
 
-  target_line[0] = original_start >= SVN_DIFF__UNIFIED_CONTEXT_SIZE
-                   ? original_start - SVN_DIFF__UNIFIED_CONTEXT_SIZE : 0;
-  target_line[1] = modified_start;
-
-  /* If the changed ranges are far enough apart (no overlapping or connecting
-     context), flush the current hunk, initialize the next hunk and skip the
-     lines not in context.  Also do this when this is the first hunk.
-   */
-  if (output_baton->current_line[0] < target_line[0]
-      && (output_baton->hunk_start[0] + output_baton->hunk_length[0]
-          + SVN_DIFF__UNIFIED_CONTEXT_SIZE < target_line[0]
-          || output_baton->hunk_length[0] == 0))
-    {
-      SVN_ERR(output_unified_flush_hunk(output_baton));
-
-      output_baton->hunk_start[0] = target_line[0];
-      output_baton->hunk_start[1] = target_line[1] + target_line[0]
-                                    - original_start;
-
-      /* Skip lines until we are at the beginning of the context we want to
-         display */
-      while (output_baton->current_line[0] < target_line[0])
-        {
-          SVN_ERR(output_unified_line(output_baton,
-                                      svn_diff__file_output_unified_skip, 0));
-        }
-
-      if (output_baton->show_c_function)
-        {
-          apr_size_t p;
-          const char *invalid_character;
-
-          /* Save the extra context for later use.
-           * Note that the last byte of the hunk_extra_context array is never
-           * touched after it is zero-initialized, so the array is always
-           * 0-terminated. */
-          strncpy(output_baton->hunk_extra_context,
-                  output_baton->extra_context->data,
-                  SVN_DIFF__EXTRA_CONTEXT_LENGTH);
-          /* Trim whitespace at the end, most notably to get rid of any
-           * newline characters. */
-          p = strlen(output_baton->hunk_extra_context);
-          while (p > 0
-                 && svn_ctype_isspace(output_baton->hunk_extra_context[p - 1]))
-            {
-              output_baton->hunk_extra_context[--p] = '\0';
-            }
-          invalid_character =
-            svn_utf__last_valid(output_baton->hunk_extra_context,
-                                SVN_DIFF__EXTRA_CONTEXT_LENGTH);
-          for (p = invalid_character - output_baton->hunk_extra_context;
-               p < SVN_DIFF__EXTRA_CONTEXT_LENGTH; p++)
-            {
-              output_baton->hunk_extra_context[p] = '\0';
-            }
-        }
-    }
+  if (original_start > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
+    context_prefix_length = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+  else
+    context_prefix_length = original_start;
 
-  /* Skip lines until we are at the start of the changed range */
-  while (output_baton->current_line[1] < target_line[1])
-    {
-      SVN_ERR(output_unified_line(output_baton,
-                                  svn_diff__file_output_unified_skip, 1));
+  /* Calculate where the previous hunk will end if we would write it now
+     (including the necessary context at the end) */
+  if (output_baton->hunk_length[0] > 0 || output_baton->hunk_length[1] > 0)
+    {
+      prev_context_end = output_baton->hunk_start[0]
+                         + output_baton->hunk_length[0]
+                         + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
     }
-
-  /* Output the context preceding the changed range */
-  while (output_baton->current_line[0] < original_start)
+  else
     {
-      SVN_ERR(output_unified_line(output_baton,
-                                  svn_diff__file_output_unified_context, 0));
-    }
+      prev_context_end = -1;
 
-  target_line[0] = original_start + original_length;
-  target_line[1] = modified_start + modified_length;
-
-  /* Output the changed range */
-  for (i = 0; i < 2; i++)
-    {
-      while (output_baton->current_line[i] < target_line[i])
-        {
-          SVN_ERR(output_unified_line
-                          (output_baton,
-                           i == 0 ? svn_diff__file_output_unified_delete
-                                  : svn_diff__file_output_unified_insert, i));
-        }
-    }
+      if (output_baton->hunk_start[0] == 0
+          && (original_length > 0 || modified_length > 0))
+        init_hunk = TRUE;
+    }
+
+  /* If the changed range is far enough from the previous range, flush the current
+     hunk. */
+  {
+    apr_off_t new_hunk_start = (original_start - context_prefix_length);
+
+    if (output_baton->current_line[0] < new_hunk_start
+          && prev_context_end <= new_hunk_start)
+      {
+        SVN_ERR(output_unified_flush_hunk(output_baton));
+        init_hunk = TRUE;
+      }
+    else if (output_baton->hunk_length[0] > 0
+             || output_baton->hunk_length[1] > 0)
+      {
+        /* We extend the current hunk */
+
+
+        /* Original: Output the context preceding the changed range */
+        SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
+                                          svn_diff__file_output_unified_context,
+                                          original_start));
+      }
+  }
+
+  /* Original: Skip lines until we are at the beginning of the context we want
+     to display */
+  SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
+                                    svn_diff__file_output_unified_skip,
+                                    original_start - context_prefix_length));
+
+  /* Note that the above skip stores data for the show_c_function support below */
+
+  if (init_hunk)
+    {
+      SVN_ERR_ASSERT(output_baton->hunk_length[0] == 0
+                     && output_baton->hunk_length[1] == 0);
+
+      output_baton->hunk_start[0] = original_start - context_prefix_length;
+      output_baton->hunk_start[1] = modified_start - context_prefix_length;
+    }
+
+  if (init_hunk && output_baton->show_c_function)
+    {
+      apr_size_t p;
+      const char *invalid_character;
+
+      /* Save the extra context for later use.
+       * Note that the last byte of the hunk_extra_context array is never
+       * touched after it is zero-initialized, so the array is always
+       * 0-terminated. */
+      strncpy(output_baton->hunk_extra_context,
+              output_baton->extra_context->data,
+              SVN_DIFF__EXTRA_CONTEXT_LENGTH);
+      /* Trim whitespace at the end, most notably to get rid of any
+       * newline characters. */
+      p = strlen(output_baton->hunk_extra_context);
+      while (p > 0
+             && svn_ctype_isspace(output_baton->hunk_extra_context[p - 1]))
+        {
+          output_baton->hunk_extra_context[--p] = '\0';
+        }
+      invalid_character =
+        svn_utf__last_valid(output_baton->hunk_extra_context,
+                            SVN_DIFF__EXTRA_CONTEXT_LENGTH);
+      for (p = invalid_character - output_baton->hunk_extra_context;
+           p < SVN_DIFF__EXTRA_CONTEXT_LENGTH; p++)
+        {
+          output_baton->hunk_extra_context[p] = '\0';
+        }
+    }
+
+  /* Modified: Skip lines until we are at the start of the changed range */
+  SVN_ERR(output_unified_diff_range(output_baton, 1 /* modified */,
+                                    svn_diff__file_output_unified_skip,
+                                    modified_start));
+
+  /* Original: Output the context preceding the changed range */
+  SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
+                                    svn_diff__file_output_unified_context,
+                                    original_start));
+
+  /* Both: Output the changed range */
+  SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
+                                    svn_diff__file_output_unified_delete,
+                                    original_start + original_length));
+  SVN_ERR(output_unified_diff_range(output_baton, 1 /* modified */,
+                                    svn_diff__file_output_unified_insert,
+                                    modified_start + modified_length));
 
   return SVN_NO_ERROR;
 }
@@ -1703,7 +1810,6 @@ svn_diff_file_output_unified3(svn_stream
   if (svn_diff_contains_diffs(diff))
     {
       svn_diff__file_output_baton_t baton;
-      const char **c;
       int i;
 
       memset(&baton, 0, sizeof(baton));
@@ -1715,14 +1821,15 @@ svn_diff_file_output_unified3(svn_stream
       baton.hunk = svn_stringbuf_create_empty(pool);
       baton.show_c_function = show_c_function;
       baton.extra_context = svn_stringbuf_create_empty(pool);
-      baton.extra_skip_match = apr_array_make(pool, 3, sizeof(char **));
 
-      c = apr_array_push(baton.extra_skip_match);
-      *c = "public:*";
-      c = apr_array_push(baton.extra_skip_match);
-      *c = "private:*";
-      c = apr_array_push(baton.extra_skip_match);
-      *c = "protected:*";
+      if (show_c_function)
+        {
+          baton.extra_skip_match = apr_array_make(pool, 3, sizeof(char **));
+
+          APR_ARRAY_PUSH(baton.extra_skip_match, const char *) = "public:*";
+          APR_ARRAY_PUSH(baton.extra_skip_match, const char *) = "private:*";
+          APR_ARRAY_PUSH(baton.extra_skip_match, const char *) = "protected:*";
+        }
 
       SVN_ERR(svn_utf_cstring_from_utf8_ex2(&baton.context_str, " ",
                                             header_encoding, pool));
@@ -1746,7 +1853,7 @@ svn_diff_file_output_unified3(svn_stream
               else
                 return svn_error_createf(
                                    SVN_ERR_BAD_RELATIVE_PATH, NULL,
-                                   _("Path '%s' must be an immediate child of "
+                                   _("Path '%s' must be inside "
                                      "the directory '%s'"),
                                    svn_dirent_local_style(original_path, pool),
                                    svn_dirent_local_style(relative_to_dir,
@@ -1762,7 +1869,7 @@ svn_diff_file_output_unified3(svn_stream
               else
                 return svn_error_createf(
                                    SVN_ERR_BAD_RELATIVE_PATH, NULL,
-                                   _("Path '%s' must be an immediate child of "
+                                   _("Path '%s' must be inside "
                                      "the directory '%s'"),
                                    svn_dirent_local_style(modified_path, pool),
                                    svn_dirent_local_style(relative_to_dir,
@@ -1778,19 +1885,19 @@ svn_diff_file_output_unified3(svn_stream
 
       if (original_header == NULL)
         {
-          SVN_ERR(output_unified_default_hdr
-                  (&original_header, original_path, pool));
+          SVN_ERR(output_unified_default_hdr(&original_header, original_path,
+                                             pool));
         }
 
       if (modified_header == NULL)
         {
-          SVN_ERR(output_unified_default_hdr
-                  (&modified_header, modified_path, pool));
+          SVN_ERR(output_unified_default_hdr(&modified_header, modified_path,
+                                             pool));
         }
 
-      SVN_ERR(svn_diff__unidiff_write_header(
-                output_stream, header_encoding,
-                original_header, modified_header, pool));
+      SVN_ERR(svn_diff__unidiff_write_header(output_stream, header_encoding,
+                                             original_header, modified_header,
+                                             pool));
 
       SVN_ERR(svn_diff_output(diff, &baton,
                               &svn_diff__file_output_unified_vtable));

Modified: subversion/branches/fsfs-format7/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_diff/diff_memory.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_diff/diff_memory.c Mon Feb  4 20:48:05 2013
@@ -27,6 +27,8 @@
 #include <apr_want.h>
 #include <apr_tables.h>
 
+#include <assert.h>
+
 #include "svn_diff.h"
 #include "svn_pools.h"
 #include "svn_types.h"
@@ -342,7 +344,8 @@ typedef enum unified_output_e
 {
   unified_output_context = 0,
   unified_output_delete,
-  unified_output_insert
+  unified_output_insert,
+  unified_output_skip
 } unified_output_e;
 
 /* Baton for generating unified diffs */
@@ -351,7 +354,7 @@ typedef struct unified_output_baton_t
   svn_stream_t *output_stream;
   const char *header_encoding;
   source_tokens_t sources[2]; /* 0 == original; 1 == modified */
-  apr_off_t next_token; /* next token in original source */
+  apr_off_t current_token[2]; /* current token per source */
 
   /* Cached markers, in header_encoding,
      indexed using unified_output_e */
@@ -382,31 +385,28 @@ static svn_error_t *
 output_unified_token_range(output_baton_t *btn,
                            int tokens,
                            unified_output_e type,
-                           apr_off_t first,
-                           apr_off_t past_last)
+                           apr_off_t until)
 {
   source_tokens_t *source = &btn->sources[tokens];
-  apr_off_t idx;
-
-  past_last = (past_last > source->tokens->nelts)
-    ? source->tokens->nelts : past_last;
 
-  if (tokens == 0)
-    /* We get context from the original source, don't expect
-       to be asked to output a block which starts before
-       what we already have written. */
-    first = (first < btn->next_token) ? btn->next_token : first;
+  if (until > source->tokens->nelts)
+    until = source->tokens->nelts;
 
-  if (first >= past_last)
+  if (until <= btn->current_token[tokens])
     return SVN_NO_ERROR;
 
   /* Do the loop with prefix and token */
-  for (idx = first; idx < past_last; idx++)
+  while (TRUE)
     {
-      svn_string_t *token
-        = APR_ARRAY_IDX(source->tokens, idx, svn_string_t *);
-      svn_stringbuf_appendcstr(btn->hunk, btn->prefix_str[type]);
-      svn_stringbuf_appendbytes(btn->hunk, token->data, token->len);
+      svn_string_t *token =
+        APR_ARRAY_IDX(source->tokens, btn->current_token[tokens],
+                      svn_string_t *);
+
+      if (type != unified_output_skip)
+        {
+          svn_stringbuf_appendcstr(btn->hunk, btn->prefix_str[type]);
+          svn_stringbuf_appendbytes(btn->hunk, token->data, token->len);
+        }
 
       if (type == unified_output_context)
         {
@@ -415,11 +415,18 @@ output_unified_token_range(output_baton_
         }
       else if (type == unified_output_delete)
         btn->hunk_length[0]++;
-      else
+      else if (type == unified_output_insert)
         btn->hunk_length[1]++;
 
+      /* ### TODO: Add skip processing for -p handling? */
+
+      btn->current_token[tokens]++;
+      if (btn->current_token[tokens] == until)
+        break;
     }
-  if (past_last == source->tokens->nelts && source->ends_without_eol)
+
+  if (btn->current_token[tokens] == source->tokens->nelts 
+      && source->ends_without_eol)
     {
       const char *out_str;
 
@@ -429,8 +436,7 @@ output_unified_token_range(output_baton_
       svn_stringbuf_appendcstr(btn->hunk, out_str);
     }
 
-  if (tokens == 0)
-    btn->next_token = past_last;
+  
 
   return SVN_NO_ERROR;
 }
@@ -445,6 +451,8 @@ output_unified_flush_hunk(output_baton_t
 {
   apr_off_t target_token;
   apr_size_t hunk_len;
+  apr_off_t old_start;
+  apr_off_t new_start;
 
   if (svn_stringbuf_isempty(baton->hunk))
     return SVN_NO_ERROR;
@@ -453,24 +461,28 @@ output_unified_flush_hunk(output_baton_t
 
   /* Write the trailing context */
   target_token = baton->hunk_start[0] + baton->hunk_length[0]
-    + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+                 + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
   SVN_ERR(output_unified_token_range(baton, 0 /*original*/,
                                      unified_output_context,
-                                     baton->next_token, target_token));
+                                     target_token));
   if (hunk_delimiter == NULL)
     hunk_delimiter = "@@";
 
-  /* Convert our 0-based line numbers into unidiff 1-based numbers */
-  if (baton->hunk_length[0] > 0)
-    baton->hunk_start[0]++;
-  if (baton->hunk_length[1] > 0)
-    baton->hunk_start[1]++;
+  old_start = baton->hunk_start[0];
+  new_start = baton->hunk_start[1];
+
+  /* If the file is non-empty, convert the line indexes from
+     zero based to one based */
+  if (baton->hunk_length[0])
+    old_start++;
+  if (baton->hunk_length[1])
+    new_start++;
 
   /* Write the hunk header */
   SVN_ERR(svn_diff__unified_write_hunk_header(
             baton->output_stream, baton->header_encoding, hunk_delimiter,
-            baton->hunk_start[0], baton->hunk_length[0],
-            baton->hunk_start[1], baton->hunk_length[1],
+            old_start, baton->hunk_length[0],
+            new_start, baton->hunk_length[1],
             NULL /* hunk_extra_context */,
             baton->pool));
 
@@ -478,7 +490,11 @@ output_unified_flush_hunk(output_baton_t
   SVN_ERR(svn_stream_write(baton->output_stream,
                            baton->hunk->data, &hunk_len));
 
-  baton->hunk_length[0] = baton->hunk_length[1] = 0;
+  /* Prepare for the next hunk */
+  baton->hunk_length[0] = 0;
+  baton->hunk_length[1] = 0;
+  baton->hunk_start[0] = 0;
+  baton->hunk_start[1] = 0;
   svn_stringbuf_setempty(baton->hunk);
 
   return SVN_NO_ERROR;
@@ -494,38 +510,91 @@ output_unified_diff_modified(void *baton
                              apr_off_t latest_start,
                              apr_off_t latest_length)
 {
-  output_baton_t *btn = baton;
-  apr_off_t targ_orig, targ_mod;
+  output_baton_t *output_baton = baton;
+  apr_off_t context_prefix_length;
+  apr_off_t prev_context_end;
+  svn_boolean_t init_hunk = FALSE;
+
+  if (original_start > SVN_DIFF__UNIFIED_CONTEXT_SIZE)
+    context_prefix_length = SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+  else
+    context_prefix_length = original_start;
 
-  targ_orig = original_start - SVN_DIFF__UNIFIED_CONTEXT_SIZE;
-  targ_orig = (targ_orig < 0) ? 0 : targ_orig;
-  targ_mod = modified_start;
-
-  /* If the changed ranges are far enough apart (no overlapping or
-   * connecting context), flush the current hunk. */
-  if (btn->next_token + SVN_DIFF__UNIFIED_CONTEXT_SIZE < targ_orig)
-    SVN_ERR(output_unified_flush_hunk(btn, btn->hunk_delimiter));
-  /* Adjust offset if it's not the first hunk. */
-  else if (btn->hunk_length[0] != 0)
-    targ_orig = btn->next_token;
+  /* Calculate where the previous hunk will end if we would write it now
+     (including the necessary context at the end) */
+  if (output_baton->hunk_length[0] > 0 || output_baton->hunk_length[1] > 0)
+    {
+      prev_context_end = output_baton->hunk_start[0]
+                         + output_baton->hunk_length[0]
+                         + SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+    }
+  else
+    {
+      prev_context_end = -1;
+
+      if (output_baton->hunk_start[0] == 0
+          && (original_length > 0 || modified_length > 0))
+        init_hunk = TRUE;
+    }
 
-  if (btn->hunk_length[0] == 0
-      && btn->hunk_length[1] == 0)
+  /* If the changed range is far enough from the previous range, flush the current
+     hunk. */
+  {
+    apr_off_t new_hunk_start = (original_start - context_prefix_length);
+
+    if (output_baton->current_token[0] < new_hunk_start
+          && prev_context_end <= new_hunk_start)
+      {
+        SVN_ERR(output_unified_flush_hunk(output_baton,
+                                          output_baton->hunk_delimiter));
+        init_hunk = TRUE;
+      }
+    else if (output_baton->hunk_length[0] > 0
+             || output_baton->hunk_length[1] > 0)
+      {
+        /* We extend the current hunk */
+
+        /* Original: Output the context preceding the changed range */
+        SVN_ERR(output_unified_token_range(output_baton, 0 /* original */,
+                                           unified_output_context,
+                                           original_start));
+      }
+  }
+
+  /* Original: Skip lines until we are at the beginning of the context we want
+     to display */
+  SVN_ERR(output_unified_token_range(output_baton, 0 /* original */,
+                                     unified_output_skip,
+                                     original_start - context_prefix_length));
+
+  if (init_hunk)
     {
-      btn->hunk_start[0] = targ_orig;
-      btn->hunk_start[1] = targ_mod + targ_orig - original_start;
+      SVN_ERR_ASSERT(output_baton->hunk_length[0] == 0
+                     && output_baton->hunk_length[1] == 0);
+
+      output_baton->hunk_start[0] = original_start - context_prefix_length;
+      output_baton->hunk_start[1] = modified_start - context_prefix_length;
     }
 
-  SVN_ERR(output_unified_token_range(btn, 0/*original*/,
-                                     unified_output_context,
-                                     targ_orig, original_start));
-  SVN_ERR(output_unified_token_range(btn, 0/*original*/,
+  /* Modified: Skip lines until we are at the start of the changed range */
+  SVN_ERR(output_unified_token_range(output_baton, 1 /* modified */,
+                                     unified_output_skip,
+                                     modified_start));
+
+  /* Original: Output the context preceding the changed range */
+  SVN_ERR(output_unified_token_range(output_baton, 0 /* original */,
+                                    unified_output_context,
+                                    original_start));
+
+  /* Both: Output the changed range */
+  SVN_ERR(output_unified_token_range(output_baton, 0 /* original */,
                                      unified_output_delete,
-                                     original_start,
                                      original_start + original_length));
-  return output_unified_token_range(btn, 1/*modified*/, unified_output_insert,
-                                    modified_start,
-                                    modified_start + modified_length);
+  SVN_ERR(output_unified_token_range(output_baton, 1 /* modified */,
+                                     unified_output_insert,
+                                     modified_start + modified_length));
+
+  return SVN_NO_ERROR;
 }
 
 static const svn_diff_output_fns_t mem_output_unified_vtable =
@@ -656,7 +725,7 @@ typedef struct merge_output_baton_t
 
   /* Tokenized source text */
   source_tokens_t sources[3];
-  apr_off_t next_token;
+  apr_off_t next_token[3];
 
   /* Markers for marking conflicted sections */
   const char *markers[4]; /* 0 = original, 1 = modified,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_diff/parse-diff.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_diff/parse-diff.c Mon Feb  4 20:48:05 2013
@@ -1147,8 +1147,8 @@ svn_diff_open_patch_file(svn_patch_file_
   svn_patch_file_t *p;
 
   p = apr_palloc(result_pool, sizeof(*p));
-  SVN_ERR(svn_io_file_open(&p->apr_file, local_abspath,
-                           APR_READ | APR_BINARY, 0, result_pool));
+  SVN_ERR(svn_io_file_open(&p->apr_file, local_abspath, APR_READ,
+                           APR_OS_DEFAULT, result_pool));
   p->next_patch_offset = 0;
   *patch_file = p;
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs/editor.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs/editor.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs/editor.c Mon Feb  4 20:48:05 2013
@@ -26,7 +26,6 @@
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_pools.h"
-#include "svn_editor.h"
 #include "svn_fs.h"
 #include "svn_props.h"
 
@@ -35,6 +34,8 @@
 #include "fs-loader.h"
 
 #include "private/svn_fspath.h"
+#include "private/svn_fs_private.h"
+#include "private/svn_editor.h"
 
 
 struct edit_baton {
@@ -474,7 +475,8 @@ alter_directory_cb(void *baton,
   SVN_ERR(get_root(&root, eb));
   SVN_ERR(can_modify(root, fspath, revision, scratch_pool));
 
-  SVN_ERR(alter_props(root, fspath, props, scratch_pool));
+  if (props)
+    SVN_ERR(alter_props(root, fspath, props, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -731,14 +733,14 @@ make_editor(svn_editor_t **editor,
 
 
 svn_error_t *
-svn_fs_editor_create(svn_editor_t **editor,
-                     const char **txn_name,
-                     svn_fs_t *fs,
-                     apr_uint32_t flags,
-                     svn_cancel_func_t cancel_func,
-                     void *cancel_baton,
-                     apr_pool_t *result_pool,
-                     apr_pool_t *scratch_pool)
+svn_fs__editor_create(svn_editor_t **editor,
+                      const char **txn_name,
+                      svn_fs_t *fs,
+                      apr_uint32_t flags,
+                      svn_cancel_func_t cancel_func,
+                      void *cancel_baton,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
 {
   svn_revnum_t revision;
   svn_fs_txn_t *txn;
@@ -753,13 +755,13 @@ svn_fs_editor_create(svn_editor_t **edit
 
 
 svn_error_t *
-svn_fs_editor_create_for(svn_editor_t **editor,
-                         svn_fs_t *fs,
-                         const char *txn_name,
-                         svn_cancel_func_t cancel_func,
-                         void *cancel_baton,
-                         apr_pool_t *result_pool,
-                         apr_pool_t *scratch_pool)
+svn_fs__editor_create_for(svn_editor_t **editor,
+                          svn_fs_t *fs,
+                          const char *txn_name,
+                          svn_cancel_func_t cancel_func,
+                          void *cancel_baton,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
 {
   svn_fs_txn_t *txn;
 
@@ -771,12 +773,12 @@ svn_fs_editor_create_for(svn_editor_t **
 
 
 svn_error_t *
-svn_fs_editor_commit(svn_revnum_t *revision,
-                     svn_error_t **post_commit_err,
-                     const char **conflict_path,
-                     svn_editor_t *editor,
-                     apr_pool_t *result_pool,
-                     apr_pool_t *scratch_pool)
+svn_fs__editor_commit(svn_revnum_t *revision,
+                      svn_error_t **post_commit_err,
+                      const char **conflict_path,
+                      svn_editor_t *editor,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
 {
   struct edit_baton *eb = svn_editor_get_baton(editor);
   const char *inner_conflict_path;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs/fs-loader.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs/fs-loader.c Mon Feb  4 20:48:05 2013
@@ -120,8 +120,8 @@ load_module(fs_init_func_t *initfunc, co
                                  _("Invalid name for FS type '%s'"),
                                  name);
 
-    libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.0",
-                           name, SVN_VER_MAJOR);
+    libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.%d",
+                           name, SVN_VER_MAJOR, SVN_SOVERSION);
     funcname = apr_psprintf(pool, "svn_fs_%s__init", name);
 
     /* Find/load the specified library.  If we get an error, assume
@@ -483,10 +483,12 @@ svn_fs_upgrade(const char *path, apr_poo
 
 svn_error_t *
 svn_fs_verify(const char *path,
-              svn_cancel_func_t cancel_func,
-              void *cancel_baton,
               svn_revnum_t start,
               svn_revnum_t end,
+              svn_fs_progress_notify_func_t notify_func,
+              void *notify_baton,
+              svn_cancel_func_t cancel_func,
+              void *cancel_baton,
               apr_pool_t *pool)
 {
   fs_library_vtable_t *vtable;
@@ -496,8 +498,10 @@ svn_fs_verify(const char *path,
   fs = fs_new(NULL, pool);
 
   SVN_MUTEX__WITH_LOCK(common_pool_lock,
-                       vtable->verify_fs(fs, path, cancel_func, cancel_baton,
-                                         start, end, pool, common_pool));
+                       vtable->verify_fs(fs, path, start, end,
+                                         notify_func, notify_baton,
+                                         cancel_func, cancel_baton,
+                                         pool, common_pool));
   return SVN_NO_ERROR;
 }
 
@@ -625,6 +629,16 @@ svn_fs_recover(const char *path,
 }
 
 svn_error_t *
+svn_fs_verify_rev(svn_fs_t *fs,
+                  svn_revnum_t revision,
+                  apr_pool_t *scratch_pool)
+{
+  SVN_ERR(fs->vtable->verify_rev(fs, revision, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_fs_freeze(svn_fs_t *fs,
               svn_error_t *(*freeze_body)(void *baton, apr_pool_t *pool),
               void *baton,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs/fs-loader.h?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs/fs-loader.h Mon Feb  4 20:48:05 2013
@@ -88,10 +88,12 @@ typedef struct fs_library_vtable_t
   svn_error_t *(*upgrade_fs)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
                              apr_pool_t *common_pool);
   svn_error_t *(*verify_fs)(svn_fs_t *fs, const char *path,
-                            /* ### notification? */
-                            svn_cancel_func_t cancel_func, void *cancel_baton,
                             svn_revnum_t start,
                             svn_revnum_t end,
+                            svn_fs_progress_notify_func_t notify_func,
+                            void *notify_baton,
+                            svn_cancel_func_t cancel_func,
+                            void *cancel_baton,
                             apr_pool_t *pool,
                             apr_pool_t *common_pool);
   svn_error_t *(*delete_fs)(const char *path, apr_pool_t *pool);
@@ -202,6 +204,9 @@ typedef struct fs_vtable_t
                             svn_fs_get_locks_callback_t get_locks_func,
                             void *get_locks_baton,
                             apr_pool_t *pool);
+  svn_error_t *(*verify_rev)(svn_fs_t *fs,
+                             svn_revnum_t revision,
+                             apr_pool_t *pool);
   svn_error_t *(*freeze)(svn_fs_t *fs,
                          svn_error_t *(*freeze_body)(void *, apr_pool_t *),
                          void *baton, apr_pool_t *pool);

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_base/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_base/dag.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_base/dag.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_base/dag.c Mon Feb  4 20:48:05 2013
@@ -579,7 +579,7 @@ svn_fs_base__dag_get_proplist(apr_hash_t
 
 svn_error_t *
 svn_fs_base__dag_set_proplist(dag_node_t *node,
-                              apr_hash_t *proplist,
+                              const apr_hash_t *proplist,
                               const char *txn_id,
                               trail_t *trail,
                               apr_pool_t *pool)

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_base/dag.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_base/dag.h?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_base/dag.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_base/dag.h Mon Feb  4 20:48:05 2013
@@ -150,7 +150,7 @@ svn_error_t *svn_fs_base__dag_get_propli
    node being changed must be mutable.  TXN_ID is the Subversion
    transaction under which this occurs.  */
 svn_error_t *svn_fs_base__dag_set_proplist(dag_node_t *node,
-                                           apr_hash_t *proplist,
+                                           const apr_hash_t *proplist,
                                            const char *txn_id,
                                            trail_t *trail,
                                            apr_pool_t *pool);

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_base/fs.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_base/fs.c Mon Feb  4 20:48:05 2013
@@ -472,6 +472,15 @@ bdb_write_config(svn_fs_t *fs)
 }
 
 static svn_error_t *
+base_bdb_verify_rev(svn_fs_t *fs,
+                    svn_revnum_t revision,
+                    apr_pool_t *scratch_pool)
+{
+  /* Verifying is currently a no op for BDB. */
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 base_bdb_freeze(svn_fs_t *fs,
                 svn_error_t *(*freeze_body)(void *, apr_pool_t *),
                 void *baton,
@@ -500,6 +509,7 @@ static fs_vtable_t fs_vtable = {
   svn_fs_base__unlock,
   svn_fs_base__get_lock,
   svn_fs_base__get_locks,
+  base_bdb_verify_rev,
   base_bdb_freeze,
   base_bdb_set_errcall,
 };
@@ -892,10 +902,12 @@ base_upgrade(svn_fs_t *fs, const char *p
 
 static svn_error_t *
 base_verify(svn_fs_t *fs, const char *path,
-            svn_cancel_func_t cancel_func,
-            void *cancel_baton,
             svn_revnum_t start,
             svn_revnum_t end,
+            svn_fs_progress_notify_func_t notify_func,
+            void *notify_baton,
+            svn_cancel_func_t cancel_func,
+            void *cancel_baton,
             apr_pool_t *pool,
             apr_pool_t *common_pool)
 {
@@ -1016,7 +1028,7 @@ svn_fs_base__clean_logs(const char *live
                                                  sub_pool));
 
           /* If log files do not match, go to the next log file. */
-          if (files_match == FALSE)
+          if (!files_match)
             continue;
         }
 
@@ -1124,7 +1136,7 @@ copy_db_file_safely(const char *src_dir,
   /* Open source file.  If it's missing and that's allowed, there's
      nothing more to do here. */
   err = svn_io_file_open(&s, file_src_path,
-                         (APR_READ | APR_LARGEFILE | APR_BINARY),
+                         (APR_READ | APR_LARGEFILE),
                          APR_OS_DEFAULT, pool);
   if (err && APR_STATUS_IS_ENOENT(err->apr_err) && allow_missing)
     {
@@ -1135,7 +1147,7 @@ copy_db_file_safely(const char *src_dir,
 
   /* Open destination file. */
   SVN_ERR(svn_io_file_open(&d, file_dst_path, (APR_WRITE | APR_CREATE |
-                                               APR_LARGEFILE | APR_BINARY),
+                                               APR_LARGEFILE),
                            APR_OS_DEFAULT, pool));
 
   /* Allocate our read/write buffer. */

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c Mon Feb  4 20:48:05 2013
@@ -137,7 +137,7 @@ get_cached_node_revision_body(node_revis
     }
   else
     {
-      pair_cache_key_t key;
+      pair_cache_key_t key = { 0 };
 
       key.revision = svn_fs_fs__id_rev(id);
       key.second = svn_fs_fs__id_item(id);
@@ -166,7 +166,7 @@ set_cached_node_revision_body(node_revis
 
   if (ffd->node_revision_cache && !svn_fs_fs__id_txn_id(id))
     {
-      pair_cache_key_t key;
+      pair_cache_key_t key = { 0 };
 
       key.revision = svn_fs_fs__id_rev(id);
       key.second = svn_fs_fs__id_item(id);
@@ -228,10 +228,6 @@ get_node_revision_body(node_revision_t *
                                   svn_stream_from_aprfile2(revision_file, FALSE,
                                                            pool),
                                   pool));
-  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
-  if (svn_fs_fs__id_txn_id(id) == NULL)
-    (*noderev_p)->is_fresh_txn_root = FALSE;
-
 
   /* The noderev is not in cache, yet. Add it, if caching has been enabled. */
   return set_cached_node_revision_body(*noderev_p, fs, id, pool);
@@ -490,7 +486,7 @@ create_rep_state_body(rep_state_t **rep_
   *rep_state = rs;
   *rep_header = rh;
 
-  if (rh->is_delta == FALSE)
+  if (!rh->is_delta)
     /* This is a plaintext, so just return the current rep_state. */
     return SVN_NO_ERROR;
 
@@ -858,7 +854,7 @@ build_rep_list(apr_array_header_t **list
           return SVN_NO_ERROR;
         }
 
-      if (rep_header->is_delta == FALSE)
+      if (!rep_header->is_delta)
         {
           /* This is a plaintext, so just return the current rep_state. */
           *src_state = rs;
@@ -1256,7 +1252,7 @@ svn_fs_fs__get_contents(svn_stream_t **c
   else
     {
       fs_fs_data_t *ffd = fs->fsap_data;
-      pair_cache_key_t fulltext_cache_key;
+      pair_cache_key_t fulltext_cache_key = { 0 };
       svn_filesize_t len = rep->expanded_size ? rep->expanded_size : rep->size;
       struct rep_read_baton *rb;
 
@@ -1334,7 +1330,7 @@ svn_fs_fs__try_process_file_contents(svn
   if (rep)
     {
       fs_fs_data_t *ffd = fs->fsap_data;
-      pair_cache_key_t fulltext_cache_key;
+      pair_cache_key_t fulltext_cache_key = { 0 };
 
       fulltext_cache_key.revision = rep->revision;
       fulltext_cache_key.second = rep->item_index;
@@ -1684,7 +1680,7 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
     {
       fs_fs_data_t *ffd = fs->fsap_data;
       representation_t *rep = noderev->prop_rep;
-      pair_cache_key_t key;
+      pair_cache_key_t key = { 0 };
 
       key.revision = rep->revision;
       key.second = rep->item_index;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/dag.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/dag.c Mon Feb  4 20:48:05 2013
@@ -1099,7 +1099,7 @@ svn_fs_fs__dag_serialize(void **data,
   svn_temp_serializer__context_t *context =
       svn_temp_serializer__init(node,
                                 sizeof(*node),
-                                503,
+                                1007,
                                 pool);
 
   /* for mutable nodes, we will _never_ cache the noderev */

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs.c Mon Feb  4 20:48:05 2013
@@ -189,6 +189,7 @@ static fs_vtable_t fs_vtable = {
   svn_fs_fs__unlock,
   svn_fs_fs__get_lock,
   svn_fs_fs__get_locks,
+  svn_fs_fs__verify_rev,
   fs_freeze,
   fs_set_errcall
 };
@@ -288,10 +289,12 @@ fs_upgrade(svn_fs_t *fs, const char *pat
 
 static svn_error_t *
 fs_verify(svn_fs_t *fs, const char *path,
-          svn_cancel_func_t cancel_func,
-          void *cancel_baton,
           svn_revnum_t start,
           svn_revnum_t end,
+          svn_fs_progress_notify_func_t notify_func,
+          void *notify_baton,
+          svn_cancel_func_t cancel_func,
+          void *cancel_baton,
           apr_pool_t *pool,
           apr_pool_t *common_pool)
 {
@@ -300,7 +303,8 @@ fs_verify(svn_fs_t *fs, const char *path
   SVN_ERR(svn_fs_fs__open(fs, path, pool));
   SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
   SVN_ERR(fs_serialized_init(fs, common_pool, pool));
-  return svn_fs_fs__verify(fs, cancel_func, cancel_baton, start, end, pool);
+  return svn_fs_fs__verify(fs, start, end, notify_func, notify_baton,
+                           cancel_func, cancel_baton, pool);
 }
 
 static svn_error_t *

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c Mon Feb  4 20:48:05 2013
@@ -1331,6 +1331,37 @@ svn_fs_fs__change_rev_prop(svn_fs_t *fs,
 
 /** Verifying. **/
 
+/* Baton type expected by verify_walker().  The purpose is to reuse open
+ * rev / pack file handles between calls.  Its contents need to be cleaned
+ * periodically to limit resource usage.
+ */
+typedef struct verify_walker_baton_t
+{
+  /* number of calls to verify_walker() since the last clean */
+  int iteration_count;
+  
+  /* number of files opened since the last clean */
+  int file_count;
+
+  /* progress notification callback to invoke periodically (may be NULL) */
+  svn_fs_progress_notify_func_t notify_func;
+
+  /* baton to use with NOTIFY_FUNC */
+  void *notify_baton;
+
+  /* remember the last revision for which we called notify_func */
+  svn_revnum_t last_notified_revision;
+
+  /* current file handle (or NULL) */
+  apr_file_t *file_hint;
+
+  /* corresponding revision (or SVN_INVALID_REVNUM) */
+  svn_revnum_t rev_hint;
+
+  /* pool to use for the file handles etc. */
+  apr_pool_t *pool;
+} verify_walker_baton_t;
+
 /* Used by svn_fs_fs__verify().
    Implements svn_fs_fs__walk_rep_reference().walker.  */
 static svn_error_t *
@@ -1339,24 +1370,69 @@ verify_walker(representation_t *rep,
               svn_fs_t *fs,
               apr_pool_t *scratch_pool)
 {
-  /* ### Should this be using read_rep_line() directly? */
-  SVN_ERR(svn_fs_fs__check_rep(rep, fs, scratch_pool));
+  struct rep_state *rs;
+  struct rep_args *rep_args;
+
+  if (baton)
+    {
+      verify_walker_baton_t *walker_baton = baton;
+      apr_file_t * previous_file;
+
+      /* notify and free resources periodically */
+      if (   walker_baton->iteration_count > 1000
+          || walker_baton->file_count > 16)
+        {
+          if (   walker_baton->notify_func
+              && rep->revision != walker_baton->last_notified_revision)
+            {
+              walker_baton->notify_func(rep->revision,
+                                        walker_baton->notify_baton,
+                                        scratch_pool);
+              walker_baton->last_notified_revision = rep->revision;
+            }
+
+          svn_pool_clear(walker_baton->pool);
+          
+          walker_baton->iteration_count = 0;
+          walker_baton->file_count = 0;
+          walker_baton->file_hint = NULL;
+          walker_baton->rev_hint = SVN_INVALID_REVNUM;
+        }
+
+      /* access the repo data */
+      previous_file = walker_baton->file_hint;
+      SVN_ERR(create_rep_state(&rs, &rep_args, &walker_baton->file_hint,
+                               &walker_baton->rev_hint, rep, fs,
+                               walker_baton->pool));
+
+      /* update resource usage counters */
+      walker_baton->iteration_count++;
+      if (previous_file != walker_baton->file_hint)
+        walker_baton->file_count++;
+    }
+  else
+    {
+      /* ### Should this be using read_rep_line() directly? */
+      SVN_ERR(create_rep_state(&rs, &rep_args, NULL, NULL, rep, fs,
+                               scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
 svn_fs_fs__verify(svn_fs_t *fs,
-                  svn_cancel_func_t cancel_func,
-                  void *cancel_baton,
                   svn_revnum_t start,
                   svn_revnum_t end,
+                  svn_fs_progress_notify_func_t notify_func,
+                  void *notify_baton,
+                  svn_cancel_func_t cancel_func,
+                  void *cancel_baton,
                   apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_boolean_t exists;
   svn_revnum_t youngest = ffd->youngest_rev_cache; /* cache is current */
-  apr_pool_t *iterpool = svn_pool_create(pool);
 
   if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT)
     return SVN_NO_ERROR;
@@ -1366,40 +1442,62 @@ svn_fs_fs__verify(svn_fs_t *fs,
     start = 0;
   if (! SVN_IS_VALID_REVNUM(end))
     end = youngest;
-  SVN_ERR(ensure_revision_exists(fs, start, iterpool));
-  SVN_ERR(ensure_revision_exists(fs, end, iterpool));
+  SVN_ERR(ensure_revision_exists(fs, start, pool));
+  SVN_ERR(ensure_revision_exists(fs, end, pool));
 
   /* rep-cache verification. */
   SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, fs, pool));
   if (exists)
-    /* Do not attempt to walk the rep-cache database if its file does not exist,
-       since doing so would create it --- which may confuse the administrator.
-       Don't take any lock. */
-    SVN_ERR(svn_fs_fs__walk_rep_reference(fs, verify_walker, NULL,
-                                          cancel_func, cancel_baton,
-                                          start, end,
-                                          pool));
+    {
+      /* provide a baton to allow the reuse of open file handles between
+         iterations (saves 2/3 of OS level file operations). */
+      verify_walker_baton_t *baton = apr_pcalloc(pool, sizeof(*baton));
+      baton->rev_hint = SVN_INVALID_REVNUM;
+      baton->pool = svn_pool_create(pool);
+      baton->last_notified_revision = SVN_INVALID_REVNUM;
+      baton->notify_func = notify_func;
+      baton->notify_baton = notify_baton;
+      
+      /* tell the user that we are now read to do *something* */
+      if (notify_func)
+        notify_func(SVN_INVALID_REVNUM, notify_baton, baton->pool);
+
+      /* Do not attempt to walk the rep-cache database if its file does
+         not exist,  since doing so would create it --- which may confuse
+         the administrator.   Don't take any lock. */
+      SVN_ERR(svn_fs_fs__walk_rep_reference(fs, start, end,
+                                            verify_walker, baton,
+                                            cancel_func, cancel_baton,
+                                            pool));
+
+      /* walker resource cleanup */
+      svn_pool_destroy(baton->pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__verify_rev(svn_fs_t *fs,
+                      svn_revnum_t revision,
+                      apr_pool_t *pool)
+{
+  svn_fs_root_t *root;
 
   /* Issue #4129: bogus pred-counts and minfo-cnt's on the root node-rev
      (and elsewhere).  This code makes more thorough checks than the
      commit-time checks in validate_root_noderev(). */
-  {
-    svn_revnum_t i;
-    for (i = start; i <= end; i++)
-      {
-        svn_fs_root_t *root;
-
-        svn_pool_clear(iterpool);
-
-        /* ### TODO: Make sure caches are disabled.
-
-           When this code is called in the library, we want to ensure we
-           use the on-disk data --- rather than some data that was read
-           in the possibly-distance past and cached since. */
-        SVN_ERR(svn_fs_fs__revision_root(&root, fs, i, iterpool));
-        SVN_ERR(svn_fs_fs__verify_root(root, iterpool));
-      }
-  }
+
+  /* ### TODO: Make sure caches are disabled.
+
+     When this code is called in the library, we want to ensure we
+     use the on-disk data --- rather than some data that was read
+     in the possibly-distance past and cached since. */
+  SVN_ERR(svn_fs_fs__revision_root(&root, fs, revision, pool));
+  SVN_ERR(svn_fs_fs__verify_root(root, pool));
+
+  return SVN_NO_ERROR;
+}
 
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.h?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.h Mon Feb  4 20:48:05 2013
@@ -38,14 +38,27 @@ svn_error_t *svn_fs_fs__open(svn_fs_t *f
 svn_error_t *svn_fs_fs__upgrade(svn_fs_t *fs,
                                 apr_pool_t *pool);
 
-/* Verify the fsfs filesystem FS.  Use POOL for temporary allocations. */
+/* Verify metadata in fsfs filesystem FS.  Limit the checks to revisions
+ * START to END where possible.  Indicate progress via the optional
+ * NOTIFY_FUNC callback using NOTIFY_BATON.  The optional CANCEL_FUNC
+ * will periodically be called with CANCEL_BATON to allow for preemption.
+ * Use POOL for temporary allocations. */
 svn_error_t *svn_fs_fs__verify(svn_fs_t *fs,
-                               svn_cancel_func_t cancel_func,
-                               void *cancel_baton,
                                svn_revnum_t start,
                                svn_revnum_t end,
+                               svn_fs_progress_notify_func_t notify_func,
+                               void *notify_baton,
+                               svn_cancel_func_t cancel_func,
+                               void *cancel_baton,
                                apr_pool_t *pool);
 
+/* Verify metadata of REVISION in filesystem FS.
+ * Use POOL for temporary allocations. */
+svn_error_t *
+svn_fs_fs__verify_rev(svn_fs_t *fs,
+                      svn_revnum_t revision,
+                      apr_pool_t *pool);
+
 /* Set *YOUNGEST to the youngest revision in filesystem FS.  Do any
    temporary allocation in POOL. */
 svn_error_t *svn_fs_fs__youngest_rev(svn_revnum_t *youngest,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/low_level.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/low_level.c Mon Feb  4 20:48:05 2013
@@ -525,7 +525,7 @@ svn_fs_fs__unparse_representation(repres
     return svn_stringbuf_ncreate("-1", 2, pool);
 
 #define DISPLAY_MAYBE_NULL_CHECKSUM(checksum)          \
-  ((may_be_corrupt == FALSE || (checksum) != NULL)     \
+  ((!may_be_corrupt || (checksum) != NULL)     \
    ? svn_checksum_to_cstring_display((checksum), pool) \
    : "(null)")
 
@@ -689,7 +689,7 @@ svn_fs_fs__write_rep_header(svn_fs_fs__r
 {
   const char *text;
   
-  if (header->is_delta == FALSE)
+  if (!header->is_delta)
     {
       text = REP_PLAIN "\n";
     }

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache-db.sql
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache-db.sql?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache-db.sql (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache-db.sql Mon Feb  4 20:48:05 2013
@@ -22,7 +22,6 @@
  */
 
 -- STMT_CREATE_SCHEMA
-PRAGMA AUTO_VACUUM = 1;
 PRAGMA PAGE_SIZE = 4096;
 
 /* A table mapping representation hashes to locations in a rev file. */

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache.c Mon Feb  4 20:48:05 2013
@@ -76,26 +76,30 @@ open_rep_cache(void *baton,
 {
   svn_fs_t *fs = baton;
   fs_fs_data_t *ffd = fs->fsap_data;
+  svn_sqlite__db_t *sdb;
   const char *db_path;
   int version;
 
   /* Open (or create) the sqlite database.  It will be automatically
      closed when fs->pool is destoyed. */
   db_path = path_rep_cache_db(fs->path, pool);
-  SVN_ERR(svn_sqlite__open(&ffd->rep_cache_db, db_path,
+  SVN_ERR(svn_sqlite__open(&sdb, db_path,
                            svn_sqlite__mode_rwcreate, statements,
                            0, NULL,
                            fs->pool, pool));
 
-  SVN_ERR(svn_sqlite__read_schema_version(&version, ffd->rep_cache_db, pool));
+  SVN_ERR(svn_sqlite__read_schema_version(&version, sdb, pool));
   if (version < REP_CACHE_SCHEMA_FORMAT)
     {
       /* Must be 0 -- an uninitialized (no schema) database. Create
          the schema. Results in schema version of 1.  */
-      SVN_ERR(svn_sqlite__exec_statements(ffd->rep_cache_db,
-                                          STMT_CREATE_SCHEMA));
+      SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_SCHEMA));
     }
 
+  /* This is used as a flag that the database is available so don't
+     set it earlier. */
+  ffd->rep_cache_db = sdb;
+
   return SVN_NO_ERROR;
 }
 
@@ -124,6 +128,8 @@ svn_fs_fs__exists_rep_cache(svn_boolean_
 
 svn_error_t *
 svn_fs_fs__walk_rep_reference(svn_fs_t *fs,
+                              svn_revnum_t start,
+                              svn_revnum_t end,
                               svn_error_t *(*walker)(representation_t *,
                                                      void *,
                                                      svn_fs_t *,
@@ -131,8 +137,6 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
                               void *walker_baton,
                               svn_cancel_func_t cancel_func,
                               void *cancel_baton,
-                              svn_revnum_t start,
-                              svn_revnum_t end,
                               apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -151,16 +155,15 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
   /* Check global invariants. */
   if (start == 0)
     {
-      svn_sqlite__stmt_t *stmt2;
       svn_revnum_t max;
 
-      SVN_ERR(svn_sqlite__get_statement(&stmt2, ffd->rep_cache_db,
+      SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db,
                                         STMT_GET_MAX_REV));
-      SVN_ERR(svn_sqlite__step(&have_row, stmt2));
-      max = svn_sqlite__column_revnum(stmt2, 0);
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      max = svn_sqlite__column_revnum(stmt, 0);
+      SVN_ERR(svn_sqlite__reset(stmt));
       if (SVN_IS_VALID_REVNUM(max))  /* The rep-cache could be empty. */
         SVN_ERR(svn_fs_fs__ensure_revision_exists(max, fs, iterpool));
-      SVN_ERR(svn_sqlite__reset(stmt2));
     }
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db,
@@ -174,6 +177,7 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
     {
       representation_t *rep;
       const char *sha1_digest;
+      svn_error_t *err;
 
       /* Clear ITERPOOL occasionally. */
       if (iterations++ % 16 == 0)
@@ -181,21 +185,29 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
 
       /* Check for cancellation. */
       if (cancel_func)
-        SVN_ERR(cancel_func(cancel_baton));
+        {
+          err = cancel_func(cancel_baton);
+          if (err)
+            return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+        }
 
       /* Construct a representation_t. */
       rep = apr_pcalloc(iterpool, sizeof(*rep));
       sha1_digest = svn_sqlite__column_text(stmt, 0, iterpool);
-      SVN_ERR(svn_checksum_parse_hex(&rep->sha1_checksum,
-                                     svn_checksum_sha1, sha1_digest,
-                                     iterpool));
+      err = svn_checksum_parse_hex(&rep->sha1_checksum,
+                                   svn_checksum_sha1, sha1_digest,
+                                   iterpool);
+      if (err)
+        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
       rep->revision = svn_sqlite__column_revnum(stmt, 1);
       rep->item_index = svn_sqlite__column_int64(stmt, 2);
       rep->size = svn_sqlite__column_int64(stmt, 3);
       rep->expanded_size = svn_sqlite__column_int64(stmt, 4);
 
       /* Walk. */
-      SVN_ERR(walker(rep, walker_baton, fs, iterpool));
+      err = walker(rep, walker_baton, fs, iterpool);
+      if (err)
+        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
@@ -247,10 +259,12 @@ svn_fs_fs__get_rep_reference(representat
   else
     *rep = NULL;
 
+  SVN_ERR(svn_sqlite__reset(stmt));
+
   if (*rep)
     SVN_ERR(rep_has_been_born(*rep, fs, pool));
 
-  return svn_sqlite__reset(stmt);
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache.h?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/rep-cache.h Mon Feb  4 20:48:05 2013
@@ -48,6 +48,8 @@ svn_fs_fs__exists_rep_cache(svn_boolean_
 /* Iterate all representations currently in FS's cache. */
 svn_error_t *
 svn_fs_fs__walk_rep_reference(svn_fs_t *fs,
+                              svn_revnum_t start,
+                              svn_revnum_t end,
                               svn_error_t *(*walker)(representation_t *rep,
                                                      void *walker_baton,
                                                      svn_fs_t *fs,
@@ -55,8 +57,6 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
                               void *walker_baton,
                               svn_cancel_func_t cancel_func,
                               void *cancel_baton,
-                              svn_revnum_t start,
-                              svn_revnum_t end,
                               apr_pool_t *pool);
 
 /* Return the representation REP in FS which has fulltext CHECKSUM.

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/revprops.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/revprops.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/revprops.c Mon Feb  4 20:48:05 2013
@@ -578,7 +578,7 @@ parse_revprop(apr_hash_t **properties,
   if (has_revprop_cache(fs, pool))
     {
       fs_fs_data_t *ffd = fs->fsap_data;
-      pair_cache_key_t key;
+      pair_cache_key_t key = { 0 };
 
       key.revision = revision;
       key.second = generation;
@@ -881,7 +881,7 @@ get_revision_proplist(apr_hash_t **propl
   if (has_revprop_cache(fs, pool))
     {
       svn_boolean_t is_cached;
-      pair_cache_key_t key;
+      pair_cache_key_t key = { 0 };
 
       SVN_ERR(read_revprop_generation(&generation, fs, pool));
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/temp_serializer.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/temp_serializer.c Mon Feb  4 20:48:05 2013
@@ -738,7 +738,7 @@ svn_fs_fs__serialize_node_revision(void 
 
   /* create an (empty) serialization context with plenty of buffer space */
   svn_temp_serializer__context_t *context =
-      svn_temp_serializer__init(NULL, 0, 503, pool);
+      svn_temp_serializer__init(NULL, 0, 1007, pool);
 
   /* serialize the noderev */
   svn_fs_fs__noderev_serialize(context, &noderev);

Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c Mon Feb  4 20:48:05 2013
@@ -60,6 +60,12 @@ static txn_vtable_t txn_vtable = {
   svn_fs_fs__change_txn_props
 };
 
+static svn_error_t *
+verify_walker(representation_t *rep,
+              void *baton,
+              svn_fs_t *fs,
+              apr_pool_t *scratch_pool);
+
 /* Functions for working with shared transaction data. */
 
 /* Return the transaction object for transaction TXN_ID from the
@@ -1771,6 +1777,7 @@ choose_delta_base(representation_t **rep
   int walk;
   node_revision_t *base;
   fs_fs_data_t *ffd = fs->fsap_data;
+  svn_boolean_t maybe_shared_rep = FALSE;
 
   /* If we have no predecessors, then use the empty stream as a
      base. */
@@ -1810,12 +1817,83 @@ choose_delta_base(representation_t **rep
      walk back two predecessors.) */
   base = noderev;
   while ((count++) < noderev->predecessor_count)
-    SVN_ERR(svn_fs_fs__get_node_revision(&base, fs,
-                                         base->predecessor_id, pool));
+    {
+      SVN_ERR(svn_fs_fs__get_node_revision(&base, fs,
+                                           base->predecessor_id, pool));
+
+      /* If there is a shared rep along the way, we need to limit the
+       * length of the deltification chain.
+       * 
+       * Please note that copied nodes - such as branch directories - will
+       * look the same (false positive) while reps shared within the same
+       * revision will not be caught (false negative).
+       */
+      if (props)
+        {
+          if (   base->prop_rep
+              && svn_fs_fs__id_rev(base->id) > base->prop_rep->revision)
+            maybe_shared_rep = TRUE;
+        }
+      else
+        {
+          if (   base->data_rep
+              && svn_fs_fs__id_rev(base->id) > base->data_rep->revision)
+            maybe_shared_rep = TRUE;
+        }
+    }
 
   /* return a suitable base representation */
   *rep = props ? base->prop_rep : base->data_rep;
 
+  /* if we encountered a shared rep, it's parent chain may be different
+   * from the node-rev parent chain. */
+  if (*rep && maybe_shared_rep)
+    {
+      /* Check whether the length of the deltification chain is acceptable.
+       * Otherwise, shared reps may form a non-skipping delta chain in
+       * extreme cases. */
+      apr_pool_t *sub_pool = svn_pool_create(pool);
+      representation_t base_rep = **rep;
+      
+      /* Some reasonable limit, depending on how acceptable longer linear
+       * chains are in this repo.  Also, allow for some minimal chain. */
+      int max_chain_length = 2 * (int)ffd->max_linear_deltification + 2;
+
+      /* re-use open files between iterations */
+      svn_revnum_t rev_hint = SVN_INVALID_REVNUM;
+      apr_file_t *file_hint = NULL;
+
+      /* follow the delta chain towards the end but for at most
+       * MAX_CHAIN_LENGTH steps. */
+      for (; max_chain_length; --max_chain_length)
+        {
+          struct rep_state *rep_state;
+          struct rep_args *rep_args;
+
+          SVN_ERR(create_rep_state_body(&rep_state,
+                                        &rep_args,
+                                        &file_hint,
+                                        &rev_hint,
+                                        &base_rep,
+                                        fs,
+                                        sub_pool));
+          if (!rep_args->is_delta  || !rep_args->base_revision)
+            break;
+
+          base_rep.revision = rep_args->base_revision;
+          base_rep.offset = rep_args->base_offset;
+          base_rep.size = rep_args->base_length;
+          base_rep.txn_id = NULL;
+        }
+
+      /* start new delta chain if the current one has grown too long */
+      if (max_chain_length == 0)
+        *rep = NULL;
+
+      svn_pool_destroy(sub_pool);
+    }
+
+  /* verify that the reps don't form a degenerated '*/
   return SVN_NO_ERROR;
 }
 
@@ -1969,10 +2047,14 @@ get_shared_rep(representation_t **old_re
       err = svn_fs_fs__get_rep_reference(old_rep, fs, rep->sha1_checksum,
                                          pool);
       /* ### Other error codes that we shouldn't mask out? */
-      if (err == SVN_NO_ERROR
-          || err->apr_err == SVN_ERR_FS_CORRUPT
-          || SVN_ERROR_IN_CATEGORY(err->apr_err,
-                                   SVN_ERR_MALFUNC_CATEGORY_START))
+      if (err == SVN_NO_ERROR)
+        {
+          if (*old_rep)
+            SVN_ERR(verify_walker(*old_rep, NULL, fs, pool));
+        }
+      else if (err->apr_err == SVN_ERR_FS_CORRUPT
+               || SVN_ERROR_IN_CATEGORY(err->apr_err,
+                                        SVN_ERR_MALFUNC_CATEGORY_START))
         {
           /* Fatal error; don't mask it.
 
@@ -2785,9 +2867,13 @@ write_final_rev(const svn_fs_id_t **new_
   if (noderev->prop_rep)
     noderev->prop_rep->sha1_checksum = NULL;
 
+  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
+  noderev->is_fresh_txn_root = FALSE;
+
   /* Write out our new node-revision. */
   if (at_root)
     SVN_ERR(validate_root_noderev(fs, noderev, rev, pool));
+
   SVN_ERR(svn_fs_fs__write_noderev(svn_stream_from_aprfile2(file, TRUE, pool),
                                    noderev, ffd->format,
                                    svn_fs_fs__fs_supports_mergeinfo(fs),
@@ -3199,23 +3285,6 @@ write_reps_to_cache(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
-/* Implements svn_sqlite__transaction_callback_t. */
-static svn_error_t *
-commit_sqlite_txn_callback(void *baton, svn_sqlite__db_t *db,
-                           apr_pool_t *scratch_pool)
-{
-  struct commit_baton *cb = baton;
-
-  /* Write new entries to the rep-sharing database.
-   *
-   * We use an sqlite transcation to speed things up;
-   * see <http://www.sqlite.org/faq.html#q19>.
-   */
-  SVN_ERR(write_reps_to_cache(cb->fs, cb->reps_to_cache, scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_fs_fs__commit(svn_revnum_t *new_rev_p,
                   svn_fs_t *fs,
@@ -3250,9 +3319,15 @@ svn_fs_fs__commit(svn_revnum_t *new_rev_
   if (ffd->rep_sharing_allowed)
     {
       SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool));
-      SVN_ERR(svn_sqlite__with_transaction(ffd->rep_cache_db,
-                                           commit_sqlite_txn_callback,
-                                           &cb, pool));
+
+      /* Write new entries to the rep-sharing database.
+       *
+       * We use an sqlite transaction to speed things up;
+       * see <http://www.sqlite.org/faq.html#q19>.
+       */
+      SVN_SQLITE__WITH_TXN(
+        write_reps_to_cache(fs, cb.reps_to_cache, pool),
+        ffd->rep_cache_db);
     }
 
   return SVN_NO_ERROR;



Mime
View raw message