You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2012/03/06 18:50:31 UTC

svn commit: r1297604 [4/12] - in /subversion/branches/reintegrate-keep-alive: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ notes/ notes/api-errata/1.7/ subversion/bindings/javahl/native/ subversion/bindings/javahl...

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/compat.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/compat.c Tue Mar  6 17:50:23 2012
@@ -85,8 +85,8 @@ svn_compat_wrap_file_rev_handler(svn_fil
 /* The following code maps the calls to a traditional delta editor to an
  * Editorv2 editor.  It does this by keeping track of a lot of state, and
  * then communicating that state to Ev2 upon closure of the file or dir (or
- * edit).  Note that Ev2 calls add_symlink() and set_target() are not present
- * in the delta editor paradigm, so we never call them.
+ * edit).  Note that Ev2 calls add_symlink() and alter_symlink() are not
+ * present in the delta editor paradigm, so we never call them.
  *
  * The general idea here is that we have to see *all* the actions on a node's
  * parent before we can process that node, which means we need to buffer a
@@ -118,7 +118,7 @@ typedef svn_error_t *(*unlock_func_t)(
     const char *path,
     apr_pool_t *scratch_pool);
 
-/* svn_editor__See insert_shims() for more information. */
+/* See svn_editor__insert_shims() for more information. */
 struct extra_baton
 {
   start_edit_func_t start_edit;
@@ -129,9 +129,14 @@ struct extra_baton
 struct ev2_edit_baton
 {
   svn_editor_t *editor;
+
   apr_hash_t *paths;
+  apr_array_header_t *path_order;
+  int paths_processed;
+
   apr_pool_t *edit_pool;
   struct extra_baton *exb;
+  svn_boolean_t closed;
 
   svn_boolean_t *found_abs_paths; /* Did we strip an incoming '/' from the
                                      paths?  */
@@ -189,6 +194,7 @@ struct prop_args
   const char *name;
   svn_revnum_t base_revision;
   const svn_string_t *value;
+  svn_kind_t kind;
 };
 
 struct copy_args
@@ -201,7 +207,6 @@ struct path_checksum_args
 {
   const char *path;
   svn_revnum_t base_revision;
-  svn_checksum_t *checksum;
 };
 
 static svn_error_t *
@@ -220,10 +225,12 @@ add_action(struct ev2_edit_baton *eb,
 
   if (action_list == NULL)
     {
+      const char *path_dup = apr_pstrdup(eb->edit_pool, path);
+
       action_list = apr_array_make(eb->edit_pool, 1,
                                    sizeof(struct path_action *));
-      apr_hash_set(eb->paths, apr_pstrdup(eb->edit_pool, path),
-                   APR_HASH_KEY_STRING, action_list);
+      apr_hash_set(eb->paths, path_dup, APR_HASH_KEY_STRING, action_list);
+      APR_ARRAY_PUSH(eb->path_order, const char *) = path_dup;
     }
 
   APR_ARRAY_PUSH(action_list, struct path_action *) = p_action;
@@ -231,6 +238,42 @@ add_action(struct ev2_edit_baton *eb,
   return SVN_NO_ERROR;
 }
 
+/* Find all the paths which are immediate children of PATH and return their
+   basenames in a list. */
+static apr_array_header_t *
+get_children(struct ev2_edit_baton *eb,
+             const char *path,
+             apr_pool_t *pool)
+{
+  apr_array_header_t *children = apr_array_make(pool, 1, sizeof(const char *));
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(pool, eb->paths); hi; hi = apr_hash_next(hi))
+    {
+      const char *p = svn__apr_hash_index_key(hi);
+      const char *child;
+
+      /* Sanitize our paths. */
+      if (*p == '/')
+        p++;
+
+      /* Find potential children. */
+      child = svn_relpath_skip_ancestor(path, p);
+      if (!child || !*child)
+        continue;
+
+      /* If we have a path separator, it's a deep child, so just ignore it.
+         ### Is there an API we should be using for this? */
+      if (strchr(child, '/') != NULL)
+        continue;
+
+      APR_ARRAY_PUSH(children, const char *) = child;
+    }
+
+  return children;
+}
+
+
 static svn_error_t *
 process_actions(void *edit_baton,
                 const char *path,
@@ -244,13 +287,13 @@ process_actions(void *edit_baton,
   svn_boolean_t need_copy = FALSE;
   const char *copyfrom_path;
   svn_revnum_t copyfrom_rev;
-  apr_array_header_t *children;
+  apr_array_header_t *children = NULL;
   svn_stream_t *contents = NULL;
   svn_checksum_t *checksum = NULL;
   svn_revnum_t delete_revnum = SVN_INVALID_REVNUM;
   svn_revnum_t props_base_revision = SVN_INVALID_REVNUM;
   svn_revnum_t text_base_revision = SVN_INVALID_REVNUM;
-  svn_kind_t kind;
+  svn_kind_t kind = svn_kind_unknown;
   int i;
 
   if (*path == '/')
@@ -272,6 +315,8 @@ process_actions(void *edit_baton,
             {
               const struct prop_args *p_args = action->args;
 
+              kind = p_args->kind;
+
               if (!SVN_IS_VALID_REVNUM(props_base_revision))
                 props_base_revision = p_args->base_revision;
               else
@@ -283,6 +328,12 @@ process_actions(void *edit_baton,
                      the modifications to it.  */
                   if (need_delete && need_add)
                     props = apr_hash_make(scratch_pool);
+                  else if (need_copy)
+                    SVN_ERR(eb->fetch_props_func(&props,
+                                                 eb->fetch_props_baton,
+                                                 copyfrom_path,
+                                                 copyfrom_rev,
+                                                 scratch_pool, scratch_pool));
                   else
                     SVN_ERR(eb->fetch_props_func(&props,
                                                  eb->fetch_props_baton,
@@ -310,8 +361,7 @@ process_actions(void *edit_baton,
 
               if (kind == svn_kind_dir)
                 {
-                  children = apr_array_make(scratch_pool, 1,
-                                            sizeof(const char *));
+                  children = get_children(eb, path, scratch_pool);
                 }
               else
                 {
@@ -327,9 +377,13 @@ process_actions(void *edit_baton,
             {
               struct path_checksum_args *pca = action->args;
 
+              /* We can only set text on files. */
+              kind = svn_kind_file;
+
+              SVN_ERR(svn_io_file_checksum2(&checksum, pca->path,
+                                            svn_checksum_sha1, scratch_pool));
               SVN_ERR(svn_stream_open_readonly(&contents, pca->path,
                                                scratch_pool, scratch_pool));
-              checksum = pca->checksum;
 
               if (!SVN_IS_VALID_REVNUM(text_base_revision))
                 text_base_revision = pca->base_revision;
@@ -375,10 +429,14 @@ process_actions(void *edit_baton,
     {
       /* If we're only doing a delete, do it here. */
       SVN_ERR(svn_editor_delete(eb->editor, path, delete_revnum));
+      return SVN_NO_ERROR;
     }
 
   if (need_add)
     {
+      if (props == NULL)
+        props = apr_hash_make(scratch_pool);
+
       if (kind == svn_kind_dir)
         {
           SVN_ERR(svn_editor_add_directory(eb->editor, path, children,
@@ -399,19 +457,29 @@ process_actions(void *edit_baton,
                               delete_revnum));
     }
 
-  if (props)
+  if (props || contents)
     {
-      /* We fetched and modified the props in some way. Apply 'em now that
-         we have the new set.  */
-      SVN_ERR(svn_editor_set_props(eb->editor, path, props_base_revision,
-                                   props, contents == NULL));
-    }
+      /* We fetched and modified the props or content in some way. Apply 'em
+         now.  */
+      svn_revnum_t base_revision;
+
+      if (SVN_IS_VALID_REVNUM(props_base_revision)
+            && SVN_IS_VALID_REVNUM(text_base_revision))
+        SVN_ERR_ASSERT(props_base_revision == text_base_revision);
+
+      if (SVN_IS_VALID_REVNUM(props_base_revision))
+        base_revision = props_base_revision;
+      else if (SVN_IS_VALID_REVNUM(text_base_revision))
+        base_revision = text_base_revision;
+      else
+        base_revision = SVN_INVALID_REVNUM;
 
-  if (contents)
-    {
-      /* If we have an content for this node, set it now. */
-      SVN_ERR(svn_editor_set_text(eb->editor, path, text_base_revision,
-                                  checksum, contents));
+      if (kind == svn_kind_dir)
+        SVN_ERR(svn_editor_alter_directory(eb->editor, path, base_revision,
+                                           props));
+      else
+        SVN_ERR(svn_editor_alter_file(eb->editor, path, base_revision, props,
+                                      checksum, contents));
     }
 
   return SVN_NO_ERROR;
@@ -422,29 +490,21 @@ run_ev2_actions(void *edit_baton,
                 apr_pool_t *scratch_pool)
 {
   struct ev2_edit_baton *eb = edit_baton;
-  apr_array_header_t *sorted_hash;
   apr_pool_t *iterpool;
-  int i;
-
-  /* Sort the paths touched by this edit.
-   * Ev2 doesn't really have any particular need for depth-first-ness, but
-   * we want to ensure all parent directories are handled before children in
-   * the case of adds (which does introduce an element of depth-first-ness). */
-  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
-                               scratch_pool);
 
   iterpool = svn_pool_create(scratch_pool);
-  for (i = 0; i < sorted_hash->nelts; i++)
-    {
-      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
-      apr_array_header_t *actions = item->value;
-      const char *path = item->key;
+
+  /* Possibly pick up where we left off. Ocassionally, we do some of these
+     as part of close_edit() and then some more as part of abort_edit()  */
+  for (; eb->paths_processed < eb->path_order->nelts; ++eb->paths_processed)
+    {
+      const char *path = APR_ARRAY_IDX(eb->path_order, eb->paths_processed,
+                                       const char *);
+      apr_array_header_t *actions = apr_hash_get(eb->paths, path,
+                                                 APR_HASH_KEY_STRING);
 
       svn_pool_clear(iterpool);
       SVN_ERR(process_actions(edit_baton, path, actions, iterpool));
-
-      /* Remove this item from the hash. */
-      apr_hash_set(eb->paths, path, APR_HASH_KEY_STRING, NULL);
     }
   svn_pool_destroy(iterpool);
 
@@ -589,6 +649,7 @@ ev2_change_dir_prop(void *dir_baton,
   p_args->name = apr_pstrdup(db->eb->edit_pool, name);
   p_args->value = value ? svn_string_dup(value, db->eb->edit_pool) : NULL;
   p_args->base_revision = db->base_revision;
+  p_args->kind = svn_kind_dir;
 
   SVN_ERR(add_action(db->eb, db->path, ACTION_PROPSET, p_args));
 
@@ -609,7 +670,7 @@ ev2_absent_directory(const char *path,
 {
   struct ev2_dir_baton *pb = parent_baton;
   svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
-  
+
   *kind = svn_kind_dir;
   SVN_ERR(add_action(pb->eb, path, ACTION_ADD_ABSENT, kind));
 
@@ -705,6 +766,8 @@ struct handler_baton
   svn_txdelta_window_handler_t apply_handler;
   void *apply_baton;
 
+  svn_stream_t *source;
+
   apr_pool_t *pool;
 };
 
@@ -718,6 +781,8 @@ window_handler(svn_txdelta_window_t *win
   if (window != NULL && !err)
     return SVN_NO_ERROR;
 
+  SVN_ERR(svn_stream_close(hb->source));
+
   svn_pool_destroy(hb->pool);
 
   return svn_error_trace(err);
@@ -734,7 +799,6 @@ ev2_apply_textdelta(void *file_baton,
   struct ev2_file_baton *fb = file_baton;
   apr_pool_t *handler_pool = svn_pool_create(fb->eb->edit_pool);
   struct handler_baton *hb = apr_pcalloc(handler_pool, sizeof(*hb));
-  svn_stream_t *source;
   svn_stream_t *target;
   struct path_checksum_args *pca = apr_pcalloc(fb->eb->edit_pool,
                                                sizeof(*pca));
@@ -742,27 +806,22 @@ ev2_apply_textdelta(void *file_baton,
   pca->base_revision = fb->base_revision;
 
   if (! fb->delta_base)
-    source = svn_stream_empty(handler_pool);
+    hb->source = svn_stream_empty(handler_pool);
   else
-    SVN_ERR(svn_stream_open_readonly(&source, fb->delta_base, handler_pool,
+    SVN_ERR(svn_stream_open_readonly(&hb->source, fb->delta_base, handler_pool,
                                      result_pool));
 
   SVN_ERR(svn_stream_open_unique(&target, &pca->path, NULL,
                                  svn_io_file_del_on_pool_cleanup,
                                  fb->eb->edit_pool, result_pool));
 
-  /* Wrap our target with a checksum'ing stream. */
-  target = svn_stream_checksummed2(target, NULL, &pca->checksum,
-                                   svn_checksum_sha1, TRUE,
-                                   fb->eb->edit_pool);
-
-  svn_txdelta_apply(source, target,
+  svn_txdelta_apply(hb->source, target,
                     NULL, NULL,
                     handler_pool,
                     &hb->apply_handler, &hb->apply_baton);
 
   hb->pool = handler_pool;
-                    
+
   *handler_baton = hb;
   *handler = window_handler;
 
@@ -792,6 +851,7 @@ ev2_change_file_prop(void *file_baton,
   p_args->name = apr_pstrdup(fb->eb->edit_pool, name);
   p_args->value = value ? svn_string_dup(value, fb->eb->edit_pool) : NULL;
   p_args->base_revision = fb->base_revision;
+  p_args->kind = svn_kind_file;
 
   SVN_ERR(add_action(fb->eb, fb->path, ACTION_PROPSET, p_args));
 
@@ -813,7 +873,7 @@ ev2_absent_file(const char *path,
 {
   struct ev2_dir_baton *pb = parent_baton;
   svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
-  
+
   *kind = svn_kind_file;
   SVN_ERR(add_action(pb->eb, path, ACTION_ADD_ABSENT, kind));
 
@@ -827,6 +887,7 @@ ev2_close_edit(void *edit_baton,
   struct ev2_edit_baton *eb = edit_baton;
 
   SVN_ERR(run_ev2_actions(edit_baton, scratch_pool));
+  eb->closed = TRUE;
   return svn_error_trace(svn_editor_complete(eb->editor));
 }
 
@@ -837,7 +898,10 @@ ev2_abort_edit(void *edit_baton,
   struct ev2_edit_baton *eb = edit_baton;
 
   SVN_ERR(run_ev2_actions(edit_baton, scratch_pool));
-  return svn_error_trace(svn_editor_abort(eb->editor));
+  if (!eb->closed)
+    return svn_error_trace(svn_editor_abort(eb->editor));
+  else
+    return SVN_NO_ERROR;
 }
 
 /* Return a svn_delta_editor_t * in DEDITOR, with an accompanying baton in
@@ -859,7 +923,7 @@ ev2_abort_edit(void *edit_baton,
  *  - EXB: An 'extra baton' which is used to communicate between the shims.
  *         Its callbacks should be invoked at the appropriate time by this
  *         shim.
- */ 
+ */
 static svn_error_t *
 delta_from_editor(const svn_delta_editor_t **deditor,
                   void **dedit_baton,
@@ -897,6 +961,7 @@ delta_from_editor(const svn_delta_editor
 
   eb->editor = editor;
   eb->paths = apr_hash_make(pool);
+  eb->path_order = apr_array_make(pool, 1, sizeof(const char *));
   eb->edit_pool = pool;
   eb->found_abs_paths = found_abs_paths;
   *eb->found_abs_paths = FALSE;
@@ -1055,19 +1120,15 @@ build(struct editor_baton *eb,
       apr_hash_t *current_props;
       apr_array_header_t *propdiffs;
 
-      /* Only fetch the kind if operating on something other than the root,
-         as we already know the kind on the root. */
-      if (operation->path)
-        {
-          if (kind == svn_kind_unknown)
-            SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
-                                        relpath, rev, scratch_pool));
-          else
-            operation->kind = kind;
-        }
+      operation->kind = kind;
 
       if (operation->operation == OP_REPLACE)
         current_props = apr_hash_make(scratch_pool);
+      else if (operation->copyfrom_url)
+        SVN_ERR(eb->fetch_props_func(&current_props, eb->fetch_props_baton,
+                                     operation->copyfrom_url,
+                                     operation->copyfrom_revision,
+                                     scratch_pool, scratch_pool));
       else
         SVN_ERR(eb->fetch_props_func(&current_props, eb->fetch_props_baton,
                                      relpath, rev, scratch_pool,
@@ -1081,7 +1142,7 @@ build(struct editor_baton *eb,
              actual structures, not pointers to them. */
           svn_prop_t *prop = &APR_ARRAY_IDX(propdiffs, i, svn_prop_t);
           if (!prop->value)
-            APR_ARRAY_PUSH(operation->prop_dels, const char *) = 
+            APR_ARRAY_PUSH(operation->prop_dels, const char *) =
                                         apr_pstrdup(eb->edit_pool, prop->name);
           else
             apr_hash_set(operation->prop_mods,
@@ -1285,68 +1346,89 @@ add_absent_cb(void *baton,
   return SVN_NO_ERROR;
 }
 
-/* This implements svn_editor_cb_set_props_t */
+/* This implements svn_editor_cb_alter_directory_t */
 static svn_error_t *
-set_props_cb(void *baton,
-             const char *relpath,
-             svn_revnum_t revision,
-             apr_hash_t *props,
-             svn_boolean_t complete,
-             apr_pool_t *scratch_pool)
+alter_directory_cb(void *baton,
+                   const char *relpath,
+                   svn_revnum_t revision,
+                   apr_hash_t *props,
+                   apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_unknown,
+  /* ### should we verify the kind is truly a directory?  */
+
+  SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_dir,
                 NULL, SVN_INVALID_REVNUM,
                 props, NULL, NULL, revision, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
-/* This implements svn_editor_cb_set_text_t */
+/* This implements svn_editor_cb_alter_file_t */
 static svn_error_t *
-set_text_cb(void *baton,
-            const char *relpath,
-            svn_revnum_t revision,
-            const svn_checksum_t *checksum,
-            svn_stream_t *contents,
-            apr_pool_t *scratch_pool)
+alter_file_cb(void *baton,
+              const char *relpath,
+              svn_revnum_t revision,
+              apr_hash_t *props,
+              const svn_checksum_t *checksum,
+              svn_stream_t *contents,
+              apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
   const char *tmp_filename;
   svn_stream_t *tmp_stream;
   svn_checksum_t *md5_checksum;
 
-  /* We may need to re-checksum these contents */
-  if (!(checksum && checksum->kind == svn_checksum_md5))
-    contents = svn_stream_checksummed2(contents, &md5_checksum, NULL,
-                                       svn_checksum_md5, TRUE, scratch_pool);
-  else
-    md5_checksum = (svn_checksum_t *)checksum;
+  /* ### should we verify the kind is truly a file?  */
 
-  /* Spool the contents to a tempfile, and provide that to the driver. */
-  SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_filename, NULL,
-                                 svn_io_file_del_on_pool_cleanup,
-                                 eb->edit_pool, scratch_pool));
-  SVN_ERR(svn_stream_copy3(contents, tmp_stream, NULL, NULL, scratch_pool));
+  if (contents)
+    {
+      /* We may need to re-checksum these contents */
+      if (!(checksum && checksum->kind == svn_checksum_md5))
+        contents = svn_stream_checksummed2(contents, &md5_checksum, NULL,
+                                           svn_checksum_md5, TRUE,
+                                           scratch_pool);
+      else
+        md5_checksum = (svn_checksum_t *)checksum;
 
-  SVN_ERR(build(eb, ACTION_PUT, relpath, svn_kind_file,
-                NULL, SVN_INVALID_REVNUM,
-                NULL, tmp_filename, md5_checksum, revision, scratch_pool));
+      /* Spool the contents to a tempfile, and provide that to the driver. */
+      SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_filename, NULL,
+                                     svn_io_file_del_on_pool_cleanup,
+                                     eb->edit_pool, scratch_pool));
+      SVN_ERR(svn_stream_copy3(contents, tmp_stream, NULL, NULL,
+                               scratch_pool));
+
+      SVN_ERR(build(eb, ACTION_PUT, relpath, svn_kind_file,
+                    NULL, SVN_INVALID_REVNUM,
+                    NULL, tmp_filename, md5_checksum, revision, scratch_pool));
+    }
+
+  if (props)
+    {
+      SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_file,
+                    NULL, SVN_INVALID_REVNUM,
+                    props, NULL, NULL, revision, scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
 
-/* This implements svn_editor_cb_set_target_t */
+/* This implements svn_editor_cb_alter_symlink_t */
 static svn_error_t *
-set_target_cb(void *baton,
-              const char *relpath,
-              svn_revnum_t revision,
-              const char *target,
-              apr_pool_t *scratch_pool)
+alter_symlink_cb(void *baton,
+                 const char *relpath,
+                 svn_revnum_t revision,
+                 apr_hash_t *props,
+                 const char *target,
+                 apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
 
+  /* ### should we verify the kind is truly a symlink?  */
+
+  /* ### do something  */
+
   return SVN_NO_ERROR;
 }
 
@@ -1489,7 +1571,8 @@ drive_tree(struct operation *op,
     {
       /* Open or create our baton. */
       if (op->operation == OP_OPEN || op->operation == OP_PROPSET)
-        SVN_ERR(editor->open_directory(path, parent_op->baton, op->base_revision,
+        SVN_ERR(editor->open_directory(path, parent_op->baton,
+                                       op->base_revision,
                                        scratch_pool, &op->baton));
 
       else if (op->operation == OP_ADD || op->operation == OP_REPLACE)
@@ -1529,7 +1612,7 @@ drive_tree(struct operation *op,
          I don't know that that's a valid assumption... */
 
       void *file_baton = NULL;
-      
+
       /* Open or create our baton. */
       if (op->operation == OP_OPEN || op->operation == OP_PROPSET)
         SVN_ERR(editor->open_file(path, parent_op->baton, op->base_revision,
@@ -1604,7 +1687,7 @@ drive_root(struct operation *root,
       svn_pool_clear(iterpool);
       SVN_ERR(drive_tree(child, root, editor, make_abs_paths, iterpool));
     }
-  
+
   /* We need to close the root directory, but leave it to our caller to call
      close_ or abort_edit(). */
   SVN_ERR(editor->close_directory(root->baton, scratch_pool));
@@ -1767,9 +1850,9 @@ editor_from_delta(svn_editor_t **editor_
       add_file_cb,
       add_symlink_cb,
       add_absent_cb,
-      set_props_cb,
-      set_text_cb,
-      set_target_cb,
+      alter_directory_cb,
+      alter_file_cb,
+      alter_symlink_cb,
       delete_cb,
       copy_cb,
       move_cb,
@@ -1865,6 +1948,10 @@ svn_editor__insert_shims(const svn_delta
   unlock_func_t unlock_func;
   void *unlock_baton;
 
+  SVN_ERR_ASSERT(shim_callbacks->fetch_kind_func != NULL);
+  SVN_ERR_ASSERT(shim_callbacks->fetch_props_func != NULL);
+  SVN_ERR_ASSERT(shim_callbacks->fetch_base_func != NULL);
+
   SVN_ERR(editor_from_delta(&editor, &exb, &unlock_func, &unlock_baton,
                             deditor_in, dedit_baton_in,
                             found_abs_paths, NULL, NULL,

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c Tue Mar  6 17:50:23 2012
@@ -33,7 +33,7 @@
 /* This enables runtime checks of the editor API constraints.  This may
    introduce additional memory and runtime overhead, and should not be used
    in production builds.
-   
+
    ### Remove before release? */
 #define ENABLE_ORDERING_CHECK
 #endif
@@ -57,13 +57,129 @@ struct svn_editor_t
 #ifdef ENABLE_ORDERING_CHECK
   apr_hash_t *pending_incomplete_children;
   apr_hash_t *completed_nodes;
-  apr_hash_t *needs_text_or_target;
   svn_boolean_t finished;
 
   apr_pool_t *result_pool;
 #endif
 };
 
+#ifdef ENABLE_ORDERING_CHECK
+
+/* Marker to indicate no further changes are allowed on this node.  */
+static const int marker_done;
+#define MARKER_DONE (&marker_done)
+
+/* Marker indicating that add_* may be called for this path, or that it
+   can be the destination of a copy or move. For copy/move, the path
+   will switch to MARKER_ALLOW_ALTER, to enable further tweaks.  */
+static const int marker_allow_add;
+#define MARKER_ALLOW_ADD (&marker_allow_add)
+
+/* Marker indicating that alter_* may be called for this path.  */
+static const int marker_allow_alter;
+#define MARKER_ALLOW_ALTER (&marker_allow_alter)
+
+/* Just like MARKER_DONE, but also indicates that the node was created
+   via add_directory(). This allows us to verify that the CHILDREN param
+   was comprehensive.  */
+static const int marker_added_dir;
+#define MARKER_ADDED_DIR (&marker_added_dir)
+
+#define MARK_FINISHED(editor) ((editor)->finished = TRUE)
+#define SHOULD_NOT_BE_FINISHED(editor)  SVN_ERR_ASSERT(!(editor)->finished)
+
+#define CLEAR_INCOMPLETE(editor, relpath) \
+  apr_hash_set((editor)->pending_incomplete_children, relpath,  \
+               APR_HASH_KEY_STRING, NULL);
+
+#define MARK_RELPATH(editor, relpath, value) \
+  apr_hash_set((editor)->completed_nodes, \
+               apr_pstrdup((editor)->result_pool, relpath), \
+               APR_HASH_KEY_STRING, value)
+
+#define MARK_COMPLETED(editor, relpath) \
+  MARK_RELPATH(editor, relpath, MARKER_DONE)
+#define SHOULD_NOT_BE_COMPLETED(editor, relpath) \
+  SVN_ERR_ASSERT(apr_hash_get((editor)->completed_nodes, relpath, \
+                              APR_HASH_KEY_STRING) == NULL)
+
+#define MARK_ALLOW_ADD(editor, relpath) \
+  MARK_RELPATH(editor, relpath, MARKER_ALLOW_ADD)
+#define SHOULD_ALLOW_ADD(editor, relpath) \
+  SVN_ERR_ASSERT(allow_either(editor, relpath, MARKER_ALLOW_ADD, NULL))
+
+#define MARK_ALLOW_ALTER(editor, relpath) \
+  MARK_RELPATH(editor, relpath, MARKER_ALLOW_ALTER)
+#define SHOULD_ALLOW_ALTER(editor, relpath) \
+  SVN_ERR_ASSERT(allow_either(editor, relpath, MARKER_ALLOW_ALTER, NULL))
+
+#define MARK_ADDED_DIR(editor, relpath) \
+  MARK_RELPATH(editor, relpath, MARKER_ADDED_DIR)
+#define CHECK_UNKNOWN_CHILD(editor, relpath) \
+  SVN_ERR_ASSERT(check_unknown_child(editor, relpath))
+
+static svn_boolean_t
+allow_either(const svn_editor_t *editor,
+             const char *relpath,
+             const void *marker1,
+             const void *marker2)
+{
+  void *value = apr_hash_get(editor->completed_nodes, relpath,
+                             APR_HASH_KEY_STRING);
+  return value == marker1 || value == marker2;
+}
+
+static svn_boolean_t
+check_unknown_child(const svn_editor_t *editor,
+                    const char *relpath)
+{
+  const char *parent;
+
+  /* If we already know about the new child, then exit early.  */
+  if (apr_hash_get(editor->pending_incomplete_children, relpath,
+                   APR_HASH_KEY_STRING) != NULL)
+    return TRUE;
+
+  parent = svn_relpath_dirname(relpath, editor->scratch_pool);
+
+  /* Was this parent created via svn_editor_add_directory() ?  */
+  if (apr_hash_get(editor->completed_nodes, parent, APR_HASH_KEY_STRING)
+      == MARKER_ADDED_DIR)
+    {
+      /* Whoops. This child should have been listed in that add call,
+         and placed into ->pending_incomplete_children.  */
+      return FALSE;
+    }
+
+  /* The parent was not added in this drive.  */
+  return TRUE;
+}
+
+#else
+
+/* Be wary with the definition of these macros so that we don't
+   end up with "statement with no effect" warnings. Obviously, this
+   depends upon particular usage, which is easy to verify.  */
+
+#define MARK_FINISHED(editor)  /* empty */
+#define SHOULD_NOT_BE_FINISHED(editor)  /* empty */
+
+#define CLEAR_INCOMPLETE(editor, relpath)  /* empty */
+
+#define MARK_COMPLETED(editor, relpath)  /* empty */
+#define SHOULD_NOT_BE_COMPLETED(editor, relpath)  /* empty */
+
+#define MARK_ALLOW_ADD(editor, relpath)  /* empty */
+#define SHOULD_ALLOW_ADD(editor, relpath)  /* empty */
+
+#define MARK_ALLOW_ALTER(editor, relpath)  /* empty */
+#define SHOULD_ALLOW_ALTER(editor, relpath)  /* empty */
+
+#define MARK_ADDED_DIR(editor, relpath)  /* empty */
+#define CHECK_UNKNOWN_CHILD(editor, relpath)  /* empty */
+
+#endif /* ENABLE_ORDERING_CHECK */
+
 
 svn_error_t *
 svn_editor_create(svn_editor_t **editor,
@@ -79,10 +195,10 @@ svn_editor_create(svn_editor_t **editor,
   (*editor)->cancel_func = cancel_func;
   (*editor)->cancel_baton = cancel_baton;
   (*editor)->scratch_pool = svn_pool_create(result_pool);
+
 #ifdef ENABLE_ORDERING_CHECK
   (*editor)->pending_incomplete_children = apr_hash_make(result_pool);
   (*editor)->completed_nodes = apr_hash_make(result_pool);
-  (*editor)->needs_text_or_target = apr_hash_make(result_pool);
   (*editor)->finished = FALSE;
   (*editor)->result_pool = result_pool;
 #endif
@@ -132,31 +248,31 @@ svn_editor_setcb_add_absent(svn_editor_t
 
 
 svn_error_t *
-svn_editor_setcb_set_props(svn_editor_t *editor,
-                           svn_editor_cb_set_props_t callback,
-                           apr_pool_t *scratch_pool)
+svn_editor_setcb_alter_directory(svn_editor_t *editor,
+                                 svn_editor_cb_alter_directory_t callback,
+                                 apr_pool_t *scratch_pool)
 {
-  editor->funcs.cb_set_props = callback;
+  editor->funcs.cb_alter_directory = callback;
   return SVN_NO_ERROR;
 }
 
 
 svn_error_t *
-svn_editor_setcb_set_text(svn_editor_t *editor,
-                          svn_editor_cb_set_text_t callback,
-                          apr_pool_t *scratch_pool)
+svn_editor_setcb_alter_file(svn_editor_t *editor,
+                            svn_editor_cb_alter_file_t callback,
+                            apr_pool_t *scratch_pool)
 {
-  editor->funcs.cb_set_text = callback;
+  editor->funcs.cb_alter_file = callback;
   return SVN_NO_ERROR;
 }
 
 
 svn_error_t *
-svn_editor_setcb_set_target(svn_editor_t *editor,
-                            svn_editor_cb_set_target_t callback,
-                            apr_pool_t *scratch_pool)
+svn_editor_setcb_alter_symlink(svn_editor_t *editor,
+                               svn_editor_cb_alter_symlink_t callback,
+                               apr_pool_t *scratch_pool)
 {
-  editor->funcs.cb_set_target = callback;
+  editor->funcs.cb_alter_symlink = callback;
   return SVN_NO_ERROR;
 }
 
@@ -232,9 +348,9 @@ svn_editor_setcb_many(svn_editor_t *edit
   COPY_CALLBACK(cb_add_file);
   COPY_CALLBACK(cb_add_symlink);
   COPY_CALLBACK(cb_add_absent);
-  COPY_CALLBACK(cb_set_props);
-  COPY_CALLBACK(cb_set_text);
-  COPY_CALLBACK(cb_set_target);
+  COPY_CALLBACK(cb_alter_directory);
+  COPY_CALLBACK(cb_alter_file);
+  COPY_CALLBACK(cb_alter_symlink);
   COPY_CALLBACK(cb_delete);
   COPY_CALLBACK(cb_copy);
   COPY_CALLBACK(cb_move);
@@ -257,11 +373,11 @@ svn_editor_add_directory(svn_editor_t *e
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SVN_ERR_ASSERT(children != NULL);
+  SVN_ERR_ASSERT(props != NULL);
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_ALLOW_ADD(editor, relpath);
+  CHECK_UNKNOWN_CHILD(editor, relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -270,12 +386,11 @@ svn_editor_add_directory(svn_editor_t *e
     err = editor->funcs.cb_add_directory(editor->baton, relpath, children,
                                          props, replaces_rev,
                                          editor->scratch_pool);
+
+  MARK_ADDED_DIR(editor, relpath);
+  CLEAR_INCOMPLETE(editor, relpath);
+
 #ifdef ENABLE_ORDERING_CHECK
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-  apr_hash_set(editor->pending_incomplete_children, relpath,
-               APR_HASH_KEY_STRING, NULL);
   {
     int i;
     for (i = 0; i < children->nelts; i++)
@@ -285,10 +400,11 @@ svn_editor_add_directory(svn_editor_t *e
                                              editor->result_pool);
 
         apr_hash_set(editor->pending_incomplete_children, child,
-                     APR_HASH_KEY_STRING, (void *)0xdeadbeef);
+                     APR_HASH_KEY_STRING, "");
       }
   }
 #endif
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -304,11 +420,13 @@ svn_editor_add_file(svn_editor_t *editor
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SVN_ERR_ASSERT(checksum != NULL
+                    && checksum->kind == SVN_EDITOR_CHECKSUM_KIND);
+  SVN_ERR_ASSERT(contents != NULL);
+  SVN_ERR_ASSERT(props != NULL);
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_ALLOW_ADD(editor, relpath);
+  CHECK_UNKNOWN_CHILD(editor, relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -317,13 +435,10 @@ svn_editor_add_file(svn_editor_t *editor
     err = editor->funcs.cb_add_file(editor->baton, relpath,
                                     checksum, contents, props,
                                     replaces_rev, editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-  apr_hash_set(editor->pending_incomplete_children, relpath,
-               APR_HASH_KEY_STRING, NULL);
-#endif
+
+  MARK_COMPLETED(editor, relpath);
+  CLEAR_INCOMPLETE(editor, relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -338,11 +453,10 @@ svn_editor_add_symlink(svn_editor_t *edi
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SVN_ERR_ASSERT(props != NULL);
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_ALLOW_ADD(editor, relpath);
+  CHECK_UNKNOWN_CHILD(editor, relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -350,13 +464,10 @@ svn_editor_add_symlink(svn_editor_t *edi
   if (editor->funcs.cb_add_symlink)
     err = editor->funcs.cb_add_symlink(editor->baton, relpath, target, props,
                                        replaces_rev, editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-  apr_hash_set(editor->pending_incomplete_children, relpath,
-               APR_HASH_KEY_STRING, NULL);
-#endif
+
+  MARK_COMPLETED(editor, relpath);
+  CLEAR_INCOMPLETE(editor, relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -370,11 +481,9 @@ svn_editor_add_absent(svn_editor_t *edit
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_ALLOW_ADD(editor, relpath);
+  CHECK_UNKNOWN_CHILD(editor, relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -382,120 +491,100 @@ svn_editor_add_absent(svn_editor_t *edit
   if (editor->funcs.cb_add_absent)
     err = editor->funcs.cb_add_absent(editor->baton, relpath, kind,
                                       replaces_rev, editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-  apr_hash_set(editor->pending_incomplete_children, relpath,
-               APR_HASH_KEY_STRING, NULL);
-#endif
+
+  MARK_COMPLETED(editor, relpath);
+  CLEAR_INCOMPLETE(editor, relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
 
 
 svn_error_t *
-svn_editor_set_props(svn_editor_t *editor,
-                     const char *relpath,
-                     svn_revnum_t revision,
-                     apr_hash_t *props,
-                     svn_boolean_t complete)
+svn_editor_alter_directory(svn_editor_t *editor,
+                           const char *relpath,
+                           svn_revnum_t revision,
+                           apr_hash_t *props)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SVN_ERR_ASSERT(props != NULL);
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_ALLOW_ALTER(editor, relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  if (editor->funcs.cb_set_props)
-    err = editor->funcs.cb_set_props(editor->baton, relpath, revision, props,
-                                     complete, editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  /* ### Some of the ordering here depends upon the kind of RELPATH, but
-   * ### we have no way of determining what that is. */
-  if (complete)
-    {
-      apr_hash_set(editor->completed_nodes,
-                   apr_pstrdup(editor->result_pool, relpath),
-                   APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-    }
-  else
-    {
-      apr_hash_set(editor->needs_text_or_target,
-                   apr_pstrdup(editor->result_pool, relpath),
-                   APR_HASH_KEY_STRING, (void *) 0xba5eba11);
-    }
-#endif
+  if (editor->funcs.cb_alter_directory)
+    err = editor->funcs.cb_alter_directory(editor->baton,
+                                           relpath, revision, props,
+                                           editor->scratch_pool);
+
+  MARK_COMPLETED(editor, relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
 
 
 svn_error_t *
-svn_editor_set_text(svn_editor_t *editor,
-                    const char *relpath,
-                    svn_revnum_t revision,
-                    const svn_checksum_t *checksum,
-                    svn_stream_t *contents)
+svn_editor_alter_file(svn_editor_t *editor,
+                      const char *relpath,
+                      svn_revnum_t revision,
+                      apr_hash_t *props,
+                      const svn_checksum_t *checksum,
+                      svn_stream_t *contents)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SVN_ERR_ASSERT((checksum != NULL && contents != NULL)
+                 || (checksum == NULL && contents == NULL));
+  SVN_ERR_ASSERT(props != NULL || checksum != NULL);
+  if (checksum)
+    SVN_ERR_ASSERT(checksum->kind == SVN_EDITOR_CHECKSUM_KIND);
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_ALLOW_ALTER(editor, relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  if (editor->funcs.cb_set_text)
-    err = editor->funcs.cb_set_text(editor->baton, relpath, revision,
-                                    checksum, contents, editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  apr_hash_set(editor->needs_text_or_target, relpath, APR_HASH_KEY_STRING,
-               NULL);
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-#endif
+  if (editor->funcs.cb_alter_file)
+    err = editor->funcs.cb_alter_file(editor->baton,
+                                      relpath, revision, props,
+                                      checksum, contents,
+                                      editor->scratch_pool);
+
+  MARK_COMPLETED(editor, relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
 
 
 svn_error_t *
-svn_editor_set_target(svn_editor_t *editor,
-                      const char *relpath,
-                      svn_revnum_t revision,
-                      const char *target)
+svn_editor_alter_symlink(svn_editor_t *editor,
+                         const char *relpath,
+                         svn_revnum_t revision,
+                         apr_hash_t *props,
+                         const char *target)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SVN_ERR_ASSERT(props != NULL || target != NULL);
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_ALLOW_ALTER(editor, relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  if (editor->funcs.cb_set_target)
-    err = editor->funcs.cb_set_target(editor->baton, relpath, revision,
-                                      target, editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  apr_hash_set(editor->needs_text_or_target, relpath, APR_HASH_KEY_STRING,
-               NULL);
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-#endif
+  if (editor->funcs.cb_alter_symlink)
+    err = editor->funcs.cb_alter_symlink(editor->baton,
+                                         relpath, revision, props,
+                                         target,
+                                         editor->scratch_pool);
+
+  MARK_COMPLETED(editor, relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -508,11 +597,8 @@ svn_editor_delete(svn_editor_t *editor,
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_NOT_BE_COMPLETED(editor, relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -520,11 +606,9 @@ svn_editor_delete(svn_editor_t *editor,
   if (editor->funcs.cb_delete)
     err = editor->funcs.cb_delete(editor->baton, relpath, revision,
                                   editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-#endif
+
+  MARK_COMPLETED(editor, relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -539,11 +623,8 @@ svn_editor_copy(svn_editor_t *editor,
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, dst_relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_ALLOW_ADD(editor, dst_relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -552,6 +633,10 @@ svn_editor_copy(svn_editor_t *editor,
     err = editor->funcs.cb_copy(editor->baton, src_relpath, src_revision,
                                 dst_relpath, replaces_rev,
                                 editor->scratch_pool);
+
+  MARK_ALLOW_ALTER(editor, dst_relpath);
+  CLEAR_INCOMPLETE(editor, dst_relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -566,13 +651,9 @@ svn_editor_move(svn_editor_t *editor,
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, src_relpath,
-                               APR_HASH_KEY_STRING));
-  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, dst_relpath,
-                               APR_HASH_KEY_STRING));
-#endif
+  SHOULD_NOT_BE_FINISHED(editor);
+  SHOULD_NOT_BE_COMPLETED(editor, src_relpath);
+  SHOULD_ALLOW_ADD(editor, dst_relpath);
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -581,22 +662,11 @@ svn_editor_move(svn_editor_t *editor,
     err = editor->funcs.cb_move(editor->baton, src_relpath, src_revision,
                                 dst_relpath, replaces_rev,
                                 editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  /* ### after moving a node away, a new one can be created. how does
-     ### affect the "replaces_rev" concept elsewhere?  */
-#if 0
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, src_relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-#endif
 
-  /* ### hmm. post-move, it should be possible to change props/contents.  */
-#if 0
-  apr_hash_set(editor->completed_nodes,
-               apr_pstrdup(editor->result_pool, dst_relpath),
-               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
-#endif
-#endif
+  MARK_ALLOW_ADD(editor, src_relpath);
+  MARK_ALLOW_ALTER(editor, dst_relpath);
+  CLEAR_INCOMPLETE(editor, dst_relpath);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -609,9 +679,16 @@ svn_editor_rotate(svn_editor_t *editor,
 {
   svn_error_t *err = SVN_NO_ERROR;
 
+  SHOULD_NOT_BE_FINISHED(editor);
 #ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-  /* ### something more  */
+  {
+    int i;
+    for (i = 0; i < relpaths->nelts; i++)
+      {
+        const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
+        SHOULD_NOT_BE_COMPLETED(editor, relpath);
+      }
+  }
 #endif
 
   if (editor->cancel_func)
@@ -620,9 +697,18 @@ svn_editor_rotate(svn_editor_t *editor,
   if (editor->funcs.cb_rotate)
     err = editor->funcs.cb_rotate(editor->baton, relpaths, revisions,
                                   editor->scratch_pool);
+
 #ifdef ENABLE_ORDERING_CHECK
-  /* ### something more  */
+  {
+    int i;
+    for (i = 0; i < relpaths->nelts; i++)
+      {
+        const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
+        MARK_ALLOW_ALTER(editor, relpath);
+      }
+  }
 #endif
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -633,18 +719,16 @@ svn_editor_complete(svn_editor_t *editor
 {
   svn_error_t *err = SVN_NO_ERROR;
 
+  SHOULD_NOT_BE_FINISHED(editor);
 #ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
   SVN_ERR_ASSERT(apr_hash_count(editor->pending_incomplete_children) == 0);
-  SVN_ERR_ASSERT(apr_hash_count(editor->needs_text_or_target) == 0);
 #endif
 
   if (editor->funcs.cb_complete)
     err = editor->funcs.cb_complete(editor->baton, editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  if (!err)
-    editor->finished = TRUE;
-#endif
+
+  MARK_FINISHED(editor);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -655,15 +739,13 @@ svn_editor_abort(svn_editor_t *editor)
 {
   svn_error_t *err = SVN_NO_ERROR;
 
-#ifdef ENABLE_ORDERING_CHECK
-  SVN_ERR_ASSERT(!editor->finished);
-#endif
+  SHOULD_NOT_BE_FINISHED(editor);
 
   if (editor->funcs.cb_abort)
     err = editor->funcs.cb_abort(editor->baton, editor->scratch_pool);
-#ifdef ENABLE_ORDERING_CHECK
-  editor->finished = TRUE;
-#endif
+
+  MARK_FINISHED(editor);
+
   svn_pool_clear(editor->scratch_pool);
   return err;
 }

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/svndiff.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/svndiff.c Tue Mar  6 17:50:23 2012
@@ -645,7 +645,7 @@ decode_window(svn_txdelta_window_t *wind
       svn_stringbuf_t *ndout = svn_stringbuf_create_empty(pool);
 
       /* these may in fact simply return references to insend */
-      
+
       SVN_ERR(zlib_decode(insend, newlen, ndout,
                           SVN_DELTA_WINDOW_SIZE));
       SVN_ERR(zlib_decode(data, insend - data, instout,

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/text_delta.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/text_delta.c Tue Mar  6 17:50:23 2012
@@ -291,7 +291,7 @@ svn_txdelta__remove_copy(svn_txdelta__op
       /*  we can't modify svn_txdelta_target ops -> stop there */
       if (op->action_code == svn_txdelta_target)
         break;
-      
+
       /*  handle the case that we cannot remove the op entirely */
       if (op->length + len > max_len)
         {
@@ -303,18 +303,18 @@ svn_txdelta__remove_copy(svn_txdelta__op
                op->length -= max_len - len;
                len = max_len;
             }
-          
+
           break;
         }
-        
+
       /* drop the op entirely */
       if (op->action_code == svn_txdelta_new)
         build_baton->new_data->len -= op->length;
-      
+
       len += op->length;
       --build_baton->num_ops;
     }
-    
+
   return len;
 }
 

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/xdelta.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/xdelta.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/xdelta.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/xdelta.c Tue Mar  6 17:50:23 2012
@@ -257,14 +257,18 @@ reverse_match_length(const char *a, cons
       break;
 
   pos -= sizeof(apr_size_t);
-    
+
 #endif
 
+  /* If we find a mismatch at -pos, pos-1 characters matched.
+   */
   while (++pos <= max_len)
-    if (a[-pos] != b[-pos])
-      break;
-    
-  return pos-1;
+    if (a[0-pos] != b[0-pos])
+      return pos - 1;
+
+  /* No mismatch found -> at least MAX_LEN machting chars.
+   */
+  return max_len;
 }
 
 
@@ -390,7 +394,7 @@ compute_delta(svn_txdelta__ops_baton_t *
   apr_size_t lo = 0, pending_insert_start = 0;
 
   /* Optimization: directly compare window starts. If more than 4
-   * bytes match, we can immediately create a matching windows. 
+   * bytes match, we can immediately create a matching windows.
    * Shorter sequences result in a net data increase. */
   lo = match_length(a, b, asize > bsize ? bsize : asize);
   if ((lo > 4) || (lo == bsize))
@@ -442,7 +446,7 @@ compute_delta(svn_txdelta__ops_baton_t *
             svn_txdelta__insert_op(build_baton, svn_txdelta_new,
                                    0, lo - pending_insert_start,
                                    b + pending_insert_start, pool);
-          else 
+          else
             {
               /* the match borders on the previous op. Maybe, we found a
                * match that is better than / overlapping the previous one. */

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs/fs-loader.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs/fs-loader.c Tue Mar  6 17:50:23 2012
@@ -155,7 +155,7 @@ get_library_vtable_direct(fs_library_vta
 
     /* Invoke the FS module's initfunc function with the common
        pool protected by a lock. */
-    SVN_MUTEX__WITH_LOCK(common_pool_lock, 
+    SVN_MUTEX__WITH_LOCK(common_pool_lock,
                          initfunc(my_version, vtable, common_pool));
   }
   fs_version = (*vtable)->get_version();
@@ -357,7 +357,7 @@ svn_fs_create(svn_fs_t **fs_p, const cha
 
   /* Perform the actual creation. */
   *fs_p = fs_new(fs_config, pool);
-  
+
   SVN_MUTEX__WITH_LOCK(common_pool_lock,
                        vtable->create(*fs_p, path, pool, common_pool));
   return SVN_NO_ERROR;
@@ -394,7 +394,9 @@ svn_error_t *
 svn_fs_verify(const char *path,
               svn_cancel_func_t cancel_func,
               void *cancel_baton,
-              apr_pool_t *pool) 
+              svn_revnum_t start,
+              svn_revnum_t end,
+              apr_pool_t *pool)
 {
   fs_library_vtable_t *vtable;
   svn_fs_t *fs;
@@ -404,7 +406,7 @@ svn_fs_verify(const char *path,
 
   SVN_MUTEX__WITH_LOCK(common_pool_lock,
                        vtable->verify_fs(fs, path, cancel_func, cancel_baton,
-                                         pool, common_pool));
+                                         start, end, pool, common_pool));
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs/fs-loader.h?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs/fs-loader.h Tue Mar  6 17:50:23 2012
@@ -90,6 +90,8 @@ typedef struct fs_library_vtable_t
   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,
                             apr_pool_t *pool,
                             apr_pool_t *common_pool);
   svn_error_t *(*delete_fs)(const char *path, apr_pool_t *pool);

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/bdb/env.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/bdb/env.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/bdb/env.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/bdb/env.c Tue Mar  6 17:50:23 2012
@@ -378,7 +378,7 @@ bdb_init_cb(void *baton, apr_pool_t *poo
 {
   bdb_cache_pool = svn_pool_create(pool);
   bdb_cache = apr_hash_make(bdb_cache_pool);
-  
+
   SVN_ERR(svn_mutex__init(&bdb_cache_lock, TRUE, bdb_cache_pool));
   apr_pool_cleanup_register(bdb_cache_pool, NULL, clear_cache,
                             apr_pool_cleanup_null);
@@ -493,7 +493,7 @@ static svn_error_t *
 svn_fs_bdb__close_internal(bdb_env_t *bdb)
 {
   svn_error_t *err = SVN_NO_ERROR;
-  
+
   if (--bdb->refcount != 0)
     {
       /* If the environment is panicked and automatic recovery is not
@@ -543,7 +543,7 @@ svn_fs_bdb__close(bdb_env_baton_t *bdb_b
 
   /* This may run during final pool cleanup when the lock is NULL. */
   SVN_MUTEX__WITH_LOCK(bdb_cache_lock, svn_fs_bdb__close_internal(bdb));
-  
+
   return SVN_NO_ERROR;
 }
 
@@ -587,7 +587,7 @@ cleanup_env_baton(void *data)
 
 
 static svn_error_t *
-svn_fs_bdb__open_internal(bdb_env_baton_t **bdb_batonp, 
+svn_fs_bdb__open_internal(bdb_env_baton_t **bdb_batonp,
                           const char *path,
                           u_int32_t flags, int mode,
                           apr_pool_t *pool)
@@ -643,7 +643,7 @@ svn_fs_bdb__open_internal(bdb_env_baton_
           svn_error_clear(bdb_close(bdb));
           return svn_error_trace(err);
         }
-        
+
       apr_hash_set(bdb_cache, &bdb->key, sizeof bdb->key, bdb);
       bdb->flags = flags;
       bdb->refcount = 1;
@@ -669,11 +669,11 @@ svn_fs_bdb__open(bdb_env_baton_t **bdb_b
                  u_int32_t flags, int mode,
                  apr_pool_t *pool)
 {
-  SVN_MUTEX__WITH_LOCK(bdb_cache_lock, 
-                       svn_fs_bdb__open_internal(bdb_batonp, 
-                                                 path, 
-                                                 flags, 
-                                                 mode, 
+  SVN_MUTEX__WITH_LOCK(bdb_cache_lock,
+                       svn_fs_bdb__open_internal(bdb_batonp,
+                                                 path,
+                                                 flags,
+                                                 mode,
                                                  pool));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/fs.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/fs.c Tue Mar  6 17:50:23 2012
@@ -333,9 +333,10 @@ bdb_write_config(svn_fs_t *fs)
     "#\n"
     "# Make sure you read the documentation at:\n"
     "#\n"
-    "#   http://www.oracle.com/technology/documentation/berkeley-db/db/ref/lock/max.html\n"
+    "#   http://docs.oracle.com/cd/E17076_02/html/programmer_reference/lock_max.html\n"
     "#\n"
     "# before tweaking these values.\n"
+    "#\n"
     "set_lk_max_locks   2000\n"
     "set_lk_max_lockers 2000\n"
     "set_lk_max_objects 2000\n"
@@ -344,9 +345,9 @@ bdb_write_config(svn_fs_t *fs)
     "#\n"
     "# Make sure you read the documentation at:\n"
     "#\n"
-    "#   http://www.oracle.com/technology/documentation/berkeley-db/db/api_c/env_set_lg_bsize.html\n"
-    "#   http://www.oracle.com/technology/documentation/berkeley-db/db/api_c/env_set_lg_max.html\n"
-    "#   http://www.oracle.com/technology/documentation/berkeley-db/db/ref/log/limits.html\n"
+    "#   http://docs.oracle.com/cd/E17076_02/html/api_reference/C/envset_lg_bsize.html\n"
+    "#   http://docs.oracle.com/cd/E17076_02/html/api_reference/C/envset_lg_max.html\n"
+    "#   http://docs.oracle.com/cd/E17076_02/html/programmer_reference/log_limits.html\n"
     "#\n"
     "# Increase the size of the in-memory log buffer from the default\n"
     "# of 32 Kbytes to 256 Kbytes.  Decrease the log file size from\n"
@@ -354,24 +355,28 @@ bdb_write_config(svn_fs_t *fs)
     "# space required for hot backups.  The size of the log file must be\n"
     "# at least four times the size of the in-memory log buffer.\n"
     "#\n"
-    "# Note: Decreasing the in-memory buffer size below 256 Kbytes\n"
-    "# will hurt commit performance. For details, see this post from\n"
-    "# Daniel Berlin <da...@dberlin.org>:\n"
+    "# Note: Decreasing the in-memory buffer size below 256 Kbytes will hurt\n"
+    "# hurt commit performance. For details, see:\n"
+    "#\n"
+    "#   http://svn.haxx.se/dev/archive-2002-02/0141.shtml\n"
     "#\n"
-    "# http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgId=161960\n"
     "set_lg_bsize     262144\n"
     "set_lg_max      1048576\n"
     "#\n"
     "# If you see \"log region out of memory\" errors, bump lg_regionmax.\n"
-    "# See http://www.oracle.com/technology/documentation/berkeley-db/db/ref/log/config.html\n"
-    "# and http://svn.haxx.se/users/archive-2004-10/1001.shtml for more.\n"
+    "# For more information, see:\n"
+    "#\n"
+    "#   http://docs.oracle.com/cd/E17076_02/html/programmer_reference/log_config.html\n"
+    "#   http://svn.haxx.se/users/archive-2004-10/1000.shtml\n"
+    "#\n"
     "set_lg_regionmax 131072\n"
     "#\n"
     /* ### Configure this with "svnadmin create --bdb-cache-size" */
     "# The default cache size in BDB is only 256k. As explained in\n"
-    "# http://svn.haxx.se/dev/archive-2004-12/0369.shtml, this is too\n"
+    "# http://svn.haxx.se/dev/archive-2004-12/0368.shtml, this is too\n"
     "# small for most applications. Bump this number if \"db_stat -m\"\n"
     "# shows too many cache misses.\n"
+    "#\n"
     "set_cachesize    0 1048576 1\n";
 
   /* Run-time configurable options.
@@ -397,11 +402,12 @@ bdb_write_config(svn_fs_t *fs)
       "# Disable fsync of log files on transaction commit. Read the\n"
       "# documentation about DB_TXN_NOSYNC at:\n"
       "#\n"
-      "#   http://www.oracle.com/technology/documentation/berkeley-db/db/ref/log/config.html\n"
+      "#   http://docs.oracle.com/cd/E17076_02/html/programmer_reference/log_config.html\n"
       "#\n"
-      "# [requires Berkeley DB 4.0]\n",
+      "# [requires Berkeley DB 4.0]\n"
+      "#\n",
       /* inactive */
-      "# set_flags DB_TXN_NOSYNC\n",
+      "#set_flags DB_TXN_NOSYNC\n",
       /* active */
       "set_flags DB_TXN_NOSYNC\n" },
     /* Controlled by "svnadmin create --bdb-log-keep" */
@@ -411,11 +417,12 @@ bdb_write_config(svn_fs_t *fs)
       "# Enable automatic removal of unused transaction log files.\n"
       "# Read the documentation about DB_LOG_AUTOREMOVE at:\n"
       "#\n"
-      "#   http://www.oracle.com/technology/documentation/berkeley-db/db/ref/log/config.html\n"
+      "#   http://docs.oracle.com/cd/E17076_02/html/programmer_reference/log_config.html\n"
       "#\n"
-      "# [requires Berkeley DB 4.2]\n",
+      "# [requires Berkeley DB 4.2]\n"
+      "#\n",
       /* inactive */
-      "# set_flags DB_LOG_AUTOREMOVE\n",
+      "#set_flags DB_LOG_AUTOREMOVE\n",
       /* active */
       "set_flags DB_LOG_AUTOREMOVE\n" },
   };
@@ -876,6 +883,8 @@ 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,
             apr_pool_t *pool,
             apr_pool_t *common_pool)
 {

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/notes/structure
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/notes/structure?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/notes/structure (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_base/notes/structure Tue Mar  6 17:50:23 2012
@@ -104,8 +104,8 @@ structure summary" section of this docum
 NODE-REVISION: how we represent a node revision
 
 We represent a given revision of a file or directory node using a list
-skel (see skel.h for an explanation of skels).  A node revision skel
-has the form:
+skel (see include/private/svn_skel.h for an explanation of skels).
+A node revision skel has the form:
 
     (HEADER PROP-KEY KIND-SPECIFIC ...)
 

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/caching.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/caching.c Tue Mar  6 17:50:23 2012
@@ -339,6 +339,27 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
 
   SVN_ERR(init_callbacks(ffd->fulltext_cache, fs, no_handler, pool));
 
+  /* initialize revprop cache, if full-text caching has been enabled */
+  if (cache_fulltexts)
+    {
+      SVN_ERR(create_cache(&(ffd->revprop_cache),
+                           NULL,
+                           membuffer,
+                           0, 0, /* Do not use inprocess cache */
+                           svn_fs_fs__serialize_properties,
+                           svn_fs_fs__deserialize_properties,
+                           APR_HASH_KEY_STRING,
+                           apr_pstrcat(pool, prefix, "REVPROP",
+                                       (char *)NULL),
+                           fs->pool));
+    }
+  else
+    {
+      ffd->revprop_cache = NULL;
+    }
+
+  SVN_ERR(init_callbacks(ffd->revprop_cache, fs, no_handler, pool));
+
   /* initialize txdelta window cache, if that has been enabled */
   if (cache_txdeltas)
     {
@@ -360,6 +381,27 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
 
   SVN_ERR(init_callbacks(ffd->txdelta_window_cache, fs, no_handler, pool));
 
+  /* initialize txdelta window cache, if that has been enabled */
+  if (cache_txdeltas)
+    {
+      SVN_ERR(create_cache(&(ffd->combined_window_cache),
+                           NULL,
+                           membuffer,
+                           0, 0, /* Do not use inprocess cache */
+                           /* Values are svn_stringbuf_t */
+                           NULL, NULL,
+                           APR_HASH_KEY_STRING,
+                           apr_pstrcat(pool, prefix, "COMBINED_WINDOW",
+                                       (char *)NULL),
+                           fs->pool));
+    }
+  else
+    {
+      ffd->combined_window_cache = NULL;
+    }
+
+  SVN_ERR(init_callbacks(ffd->combined_window_cache, fs, no_handler, pool));
+
   /* initialize node revision cache, if caching has been enabled */
   SVN_ERR(create_cache(&(ffd->node_revision_cache),
                        NULL,

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/fs.c?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/fs.c Tue Mar  6 17:50:23 2012
@@ -92,7 +92,7 @@ fs_serialized_init(svn_fs_t *fs, apr_poo
                               SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
 
       /* ... not to mention locking the txn-current file. */
-      SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock, 
+      SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock,
                               SVN_FS_FS__USE_LOCK_MUTEX, common_pool));
 
       SVN_ERR(svn_mutex__init(&ffsd->txn_list_lock,
@@ -243,6 +243,8 @@ 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,
           apr_pool_t *pool,
           apr_pool_t *common_pool)
 {
@@ -251,7 +253,7 @@ 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, pool);
+  return svn_fs_fs__verify(fs, cancel_func, cancel_baton, start, end, pool);
 }
 
 static svn_error_t *

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/fs.h?rev=1297604&r1=1297603&r2=1297604&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_fs_fs/fs.h Tue Mar  6 17:50:23 2012
@@ -60,6 +60,8 @@ extern "C" {
 #define PATH_LOCKS_DIR        "locks"            /* Directory of locks */
 #define PATH_MIN_UNPACKED_REV "min-unpacked-rev" /* Oldest revision which
                                                     has not been packed. */
+#define PATH_REVPROP_GEN      "revprop-gen"      /* File containing the
+                                                    revprop change counter */
 /* If you change this, look at tests/svn_test_fs.c(maybe_install_fsfs_conf) */
 #define PATH_CONFIG           "fsfs.conf"        /* Configuration */
 
@@ -198,7 +200,8 @@ typedef struct fs_fs_shared_data_t
   apr_pool_t *common_pool;
 } fs_fs_shared_data_t;
 
-/* Private (non-shared) FSFS-specific data for each svn_fs_t object. */
+/* Private (non-shared) FSFS-specific data for each svn_fs_t object.
+   Any caches in here may be NULL. */
 typedef struct fs_fs_data_t
 {
   /* The format number of this FS. */
@@ -224,17 +227,28 @@ typedef struct fs_fs_data_t
      (svn_fs_id_t *).  (Not threadsafe.) */
   svn_cache__t *rev_root_id_cache;
 
-  /* DAG node cache for immutable nodes */
+  /* DAG node cache for immutable nodes.  Maps (revision, fspath)
+     to (dag_node_t *). */
   svn_cache__t *rev_node_cache;
 
   /* A cache of the contents of immutable directories; maps from
-     unparsed FS ID to ###x. */
+     unparsed FS ID to a apr_hash_t * mapping (const char *) dirent
+     names to (svn_fs_dirent_t *). */
   svn_cache__t *dir_cache;
 
   /* Fulltext cache; currently only used with memcached.  Maps from
-     rep key to svn_string_t. */
+     rep key (revision/offset) to svn_string_t. */
   svn_cache__t *fulltext_cache;
 
+  /* Revprop "generation" that is valid for this svn_fs_t.
+     It is the revprop change counter read once from "revprop-gen".
+     Will be read upon first access.  0 means that the value has not
+     been read from disk, yet. */
+  apr_int64_t revprop_generation;
+  
+  /* Revision property cache.  Maps from (rev,generation) to apr_hash_t. */
+  svn_cache__t *revprop_cache;
+
   /* Pack manifest cache; a cache mapping (svn_revnum_t) shard number to
      a manifest; and a manifest is a mapping from (svn_revnum_t) revision
      number offset within a shard to (apr_off_t) byte-offset in the
@@ -244,6 +258,10 @@ typedef struct fs_fs_data_t
   /* Cache for txdelta_window_t objects; the key is (revFilePath, offset) */
   svn_cache__t *txdelta_window_cache;
 
+  /* Cache for combined windows as svn_stringbuf_t objects;
+     the key is (revFilePath, offset) */
+  svn_cache__t *combined_window_cache;
+
   /* Cache for node_revision_t objects; the key is (revision, id offset) */
   svn_cache__t *node_revision_cache;