You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/11/17 01:09:55 UTC

svn commit: r1035869 [2/19] - in /subversion/branches/performance: ./ build/ build/generator/ build/generator/templates/ build/win32/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/ja...

Modified: subversion/branches/performance/subversion/bindings/swig/ruby/svn/fs.rb
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/bindings/swig/ruby/svn/fs.rb?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/bindings/swig/ruby/svn/fs.rb (original)
+++ subversion/branches/performance/subversion/bindings/swig/ruby/svn/fs.rb Wed Nov 17 00:09:50 2010
@@ -602,8 +602,13 @@ module Svn
           @tempfile1 = Tempfile.new("svn_fs")
           @tempfile2 = Tempfile.new("svn_fs")
 
-          dump_contents(@tempfile1, @root1, @path1)
-          dump_contents(@tempfile2, @root2, @path2)
+          begin
+            dump_contents(@tempfile1, @root1, @path1)
+            dump_contents(@tempfile2, @root2, @path2)
+          ensure
+            @tempfile1.close
+            @tempfile2.close
+          end
 
           [@tempfile1, @tempfile2]
         end
@@ -623,15 +628,10 @@ module Svn
       end
 
       private
-      def dump_contents(tempfile, root, path)
+      def dump_contents(open_tempfile, root, path)
         if root and path
-          begin
-            tempfile.open
-            root.file_contents(path) do |stream|
-              tempfile.print(stream.read)
-            end
-          ensure
-            tempfile.close
+          root.file_contents(path) do |stream|
+            open_tempfile.print(stream.read)
           end
         end
       end

Modified: subversion/branches/performance/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/private/svn_wc_private.h?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/private/svn_wc_private.h (original)
+++ subversion/branches/performance/subversion/include/private/svn_wc_private.h Wed Nov 17 00:09:50 2010
@@ -612,14 +612,14 @@ svn_wc__node_get_info_bits(apr_time_t *t
 
 
 /**
- * Acquire a recursive write lock for @a local_abspath or if @a lock_anchor
+ * Acquire a recursive write lock for @a local_abspath.  If @a lock_anchor
  * is true, determine if @a local_abspath has an anchor that should be locked
- * instead. Store the obtained lock in @a wc_ctx.
+ * instead; otherwise, @a local_abspath must be a versioned directory.
+ * Store the obtained lock in @a wc_ctx.
  *
  * If @a lock_root_abspath is not NULL, store the root of the lock in
  * @a *lock_root_abspath. If @a lock_root_abspath is NULL, then @a
- * local_abspath must be a versioned directory and @a lock_anchor must be
- * FALSE.
+ * lock_anchor must be FALSE.
  *
  * Returns @c SVN_ERR_WC_LOCKED if an existing lock is encountered, in
  * which case any locks acquired will have been released.

Modified: subversion/branches/performance/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_client.h?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_client.h (original)
+++ subversion/branches/performance/subversion/include/svn_client.h Wed Nov 17 00:09:50 2010
@@ -1189,6 +1189,9 @@ svn_client_checkout(svn_revnum_t *result
  * If @a allow_unver_obstructions is FALSE then the update will abort
  * if there are any unversioned obstructing items.
  *
+ * If @a make_parents is TRUE, create any non-existent parent
+ * directories also by checking them out at depth=empty.
+ *
  * If @a ctx->notify_func2 is non-NULL, invoke @a ctx->notify_func2 with
  * @a ctx->notify_baton2 for each item handled by the update, and also for
  * files restored from text-base.  If @a ctx->cancel_func is non-NULL, invoke
@@ -1207,8 +1210,28 @@ svn_client_checkout(svn_revnum_t *result
  *  implementation, and allows for the possibility that different
  *  targets may come from different repositories.
  *
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_client_update4(apr_array_header_t **result_revs,
+                   const apr_array_header_t *paths,
+                   const svn_opt_revision_t *revision,
+                   svn_depth_t depth,
+                   svn_boolean_t depth_is_sticky,
+                   svn_boolean_t ignore_externals,
+                   svn_boolean_t allow_unver_obstructions,
+                   svn_boolean_t make_parents,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool);
+
+/**
+ * Similar to svn_client_update4() but with @a make_parents always set
+ * to FALSE.
+ *
+ * @deprecated Provided for backward compatibility with the 1.6 API.
  * @since New in 1.5.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_client_update3(apr_array_header_t **result_revs,
                    const apr_array_header_t *paths,
@@ -2177,7 +2200,7 @@ svn_client_status5(svn_revnum_t *result_
 
 /**
  * Same as svn_client_status5(), but using #svn_wc_status_func3_t
- * instead of #svn_wc_status_func4_t and depth_as_sticky set to TRUE.
+ * instead of #svn_client_status_func_t and depth_as_sticky set to TRUE.
  *
  * @since New in 1.6.
  * @deprecated Provided for backward compatibility with the 1.6 API.

Modified: subversion/branches/performance/subversion/include/svn_error_codes.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_error_codes.h?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_error_codes.h (original)
+++ subversion/branches/performance/subversion/include/svn_error_codes.h Wed Nov 17 00:09:50 2010
@@ -219,6 +219,11 @@ SVN_ERROR_START
              SVN_ERR_BAD_CATEGORY_START + 13,
              "Unknown string value of token")
 
+  /** @since New in 1.7. */
+  SVN_ERRDEF(SVN_ERR_BAD_CHANGELIST_NAME,
+             SVN_ERR_BAD_CATEGORY_START + 14,
+             "Invalid changelist name")
+
   /* xml errors */
 
   SVN_ERRDEF(SVN_ERR_XML_ATTRIB_NOT_FOUND,
@@ -1391,6 +1396,10 @@ SVN_ERROR_START
              SVN_ERR_CL_CATEGORY_START + 10,
              "No external merge tool available")
 
+  SVN_ERRDEF(SVN_ERR_CL_ERROR_PROCESSING_EXTERNALS,
+             SVN_ERR_CL_CATEGORY_START + 11,
+             "Failed processing one or more externals definitions")
+
   /* malfunctions such as assertion failures */
 
   SVN_ERRDEF(SVN_ERR_ASSERTION_FAIL,

Modified: subversion/branches/performance/subversion/include/svn_path.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_path.h?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_path.h (original)
+++ subversion/branches/performance/subversion/include/svn_path.h Wed Nov 17 00:09:50 2010
@@ -64,6 +64,10 @@ extern "C" {
 
 
 /** Convert @a path from the local style to the canonical internal style.
+ *
+ * New code should use either svn_dirent_internal_style() (for local paths) or
+ * svn_relpath_internal_style() (for relative paths).
+ *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -71,6 +75,10 @@ const char *
 svn_path_internal_style(const char *path, apr_pool_t *pool);
 
 /** Convert @a path from the canonical internal style to the local style.
+ *
+ * New code should use either svn_dirent_local_style() (for local paths) or
+ * svn_relpath_local_style() (for relative paths).
+ *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -101,6 +109,9 @@ svn_path_local_style(const char *path, a
  * @a component won't be detected. An absolute URI can only be used
  * for the base.
  *
+ * New code should use either svn_dirent_join() (for local paths) or
+ * svn_uri_join() (for urls) or svn_relpath_join() (for relative paths).
+ *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -118,7 +129,9 @@ svn_path_join(const char *base, const ch
  * This function does not support URLs.
  *
  * See svn_path_join() for further notes about joining paths.
- *
+ * 
+ * New code should use svn_dirent_join_many() instead.
+ * 
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -139,7 +152,7 @@ svn_path_join_many(apr_pool_t *pool, con
  * @note If an empty string is passed, then an empty string will be returned.
  *
  * New code should use either svn_dirent_basename() (for local paths) or
- * svn_uri_basename() (for urls and repository paths).
+ * svn_uri_basename() (for urls) or svn_relpath_basename (for relative paths).
  *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
@@ -154,7 +167,7 @@ svn_path_basename(const char *path, apr_
  * The returned dirname will be allocated in @a pool.
  *
  * New code should use either svn_dirent_dirname() (for local paths) or
- * svn_uri_dirname() (for urls and repository paths).
+ * svn_uri_dirname() (for urls) or svn_relpath_dirname() (for relative paths).
  *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
@@ -227,7 +240,7 @@ svn_path_remove_components(svn_stringbuf
  *             - <pre>""              ==>  ""   and ""</pre>
  *
  * New code should use either svn_dirent_split() (for local paths) or
- * svn_uri_split() (for urls and repository paths).
+ * svn_uri_split() (for urls) or svn_relpath_split() (for relative paths).
  *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
@@ -266,6 +279,10 @@ svn_dirent_is_root(const char *dirent, a
  * The returned path may be statically allocated, equal to @a path, or
  * allocated from @a pool.
  *
+ * New code should use either svn_dirent_canonicalize() (for local paths) or
+ * svn_uri_canonicalize() (for urls) or svn_relpath_canonicalize() (for 
+ * relative paths).
+ *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -275,6 +292,10 @@ svn_path_canonicalize(const char *path, 
 /** Return @c TRUE iff path is canonical. Use @a pool for temporary
  * allocations.
  *
+ * New code should use either svn_dirent_is_canonical() (for local paths) or
+ * svn_uri_is_canonical() (for urls) or svn_relpath_is_canonical() (for
+ * relative paths).
+ *
  * @since New in 1.5.
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
@@ -300,6 +321,10 @@ svn_path_compare_paths(const char *path1
  * different resources), and (b) share a common ancestor in their path
  * component, i.e. 'protocol://' is not a sufficient ancestor.
  *
+ * New code should use either svn_dirent_get_longest_ancestor() 
+ * (for local paths) or svn_uri_get_longest_ancestor() (for urls) 
+ * or svn_relpath_get_longest_ancestor() (for relative paths).
+ *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -314,6 +339,8 @@ svn_path_get_longest_ancestor(const char
  * @a relative may be a URL, in which case no attempt is made to convert it,
  * and a copy of the URL is returned.
  *
+ * New code should use svn_dirent_get_absolute() instead.
+ *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -365,6 +392,9 @@ svn_path_split_if_file(const char *path,
  * If there are no items in @a targets, set @a *pcommon and (if
  * applicable) @a *pcondensed_targets to @c NULL.
  *
+ * New code should use either svn_dirent_condense_targets() (for local paths)
+ * or svn_uri_condense_targets() (for urls).
+ *
  * @note There is no guarantee that @a *pcommon is within a working
  * copy.
  *
@@ -489,6 +519,10 @@ svn_path_is_dotpath_present(const char *
  *       in which case a pointer into @a path2 will be returned to
  *       identify the remainder path.
  *
+ * New code should use either svn_dirent_is_child() (for local paths) or
+ * svn_uri_is_child() (for urls) or svn_relpath_is_child() 
+ * (for relative paths).
+ *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -499,6 +533,11 @@ svn_path_is_child(const char *path1, con
  * and FALSE otherwise.
  *
  * @since New in 1.3.
+ *
+ * New code should use either svn_dirent_is_ancestor() (for local paths) or
+ * svn_uri_is_ancestor() (for urls) or svn_relpath_is_ancestor() (for relative 
+ * paths).
+ *
  * @deprecated Provided for backward compatibility with the 1.6 API.
  */
 SVN_DEPRECATED
@@ -584,7 +623,7 @@ svn_path_url_add_component2(const char *
                             const char *component,
                             apr_pool_t *pool);
 
-/** Like svn_path_url_add_component2, but allows path components that
+/** Like svn_path_url_add_component2(), but allows path components that
  * end with a trailing '/'
  *
  * @deprecated Provided for backward compatibility with the 1.5 API.

Modified: subversion/branches/performance/subversion/include/svn_types.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/include/svn_types.h?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/include/svn_types.h (original)
+++ subversion/branches/performance/subversion/include/svn_types.h Wed Nov 17 00:09:50 2010
@@ -183,13 +183,13 @@ svn_node_kind_from_word(const char *word
 
 /** Generic three-state property to represent an unknown value for values
  * that are just like booleans.  The values have been set deliberately to
- * make tristates mainly compatible with #svn_boolean_t.
+ * make tristates disjoint from #svn_boolean_t.
  *
  * @since New in 1.7. */
 typedef enum
 {
-  svn_tristate_false = FALSE,
-  svn_tristate_true = TRUE,
+  svn_tristate_false = 2,
+  svn_tristate_true,
   svn_tristate_unknown
 } svn_tristate_t;
 

Modified: subversion/branches/performance/subversion/libsvn_client/changelist.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/changelist.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/changelist.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/changelist.c Wed Nov 17 00:09:50 2010
@@ -107,6 +107,10 @@ svn_client_add_to_changelist(const apr_a
   apr_hash_t *changelist_hash = NULL;
   int i;
 
+  if (changelist[0] == '\0')
+    return svn_error_create(SVN_ERR_BAD_CHANGELIST_NAME, NULL,
+                            _("Target changelist name must not be empty"));
+
   for (i = 0; i < paths->nelts; i++)
     {
       const char *path = APR_ARRAY_IDX(paths, i, const char *);

Modified: subversion/branches/performance/subversion/libsvn_client/checkout.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/checkout.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/checkout.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/checkout.c Wed Nov 17 00:09:50 2010
@@ -218,7 +218,7 @@ svn_client__checkout_internal(svn_revnum
                                     revision, depth, TRUE,
                                     ignore_externals,
                                     allow_unver_obstructions,
-                                    use_sleep, innercheckout,
+                                    use_sleep, innercheckout, FALSE,
                                     ctx, pool);
 
   if (err)

Modified: subversion/branches/performance/subversion/libsvn_client/cleanup.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/cleanup.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/cleanup.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/cleanup.c Wed Nov 17 00:09:50 2010
@@ -163,11 +163,9 @@ svn_client_upgrade(const char *path,
       externals_p = apr_array_make(iterpool, 1,
                                    sizeof(svn_wc_external_item2_t*));
 
-      SVN_ERR(svn_wc_parse_externals_description3(&externals_p,
-                                            svn_dirent_dirname(path,
-                                                               iterpool),
-                                                  external_desc->data, TRUE,
-                                                  iterpool));
+      SVN_ERR(svn_wc_parse_externals_description3(
+                  &externals_p, svn_dirent_dirname(path, iterpool),
+                  external_desc->data, TRUE, iterpool));
       for (i = 0; i < externals_p->nelts; i++)
         {
           svn_wc_external_item2_t *item;

Modified: subversion/branches/performance/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/client.h?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/client.h (original)
+++ subversion/branches/performance/subversion/libsvn_client/client.h Wed Nov 17 00:09:50 2010
@@ -39,34 +39,16 @@
 extern "C" {
 #endif /* __cplusplus */
 
-struct svn_cl__externals_store
-{
-  apr_pool_t *pool;
-  apr_hash_t *externals_old;
-  apr_hash_t *externals_new;
-  apr_hash_t *depths;
-};
-
-/* svn_wc_external_update_t handler, storing the received data in a
- * svn_cl__externals_store instance, which must be passed as baton.
- * When one of the hashes is NULL, these values are not stored */
-svn_error_t *
-svn_cl__store_externals(void *baton,
-                        const char *local_abspath,
-                        const svn_string_t *old_value,
-                        const svn_string_t *new_value,
-                        svn_depth_t depth,
-                        apr_pool_t *scratch_pool);
-
-
 
-/* Set *URL, allocated in RESULT_POOL, and *PEG_REVNUM (the latter is
-   ignored if NULL) to the repository URL of ABSPATH_OR_URL.  If
+/* Set *URL and *PEG_REVNUM (the latter is ignored if NULL) to the
+   repository URL of ABSPATH_OR_URL as found in revision PEG_REVISION.
+   If PEG_REVISION->kind is svn_opt_revision_unspecified, use the head
+   revision for a URL or the working revision for a local path.  If
    ABSPATH_OR_URL is an absolute WC path and PEG_REVISION->kind is
    svn_opt_revision_working, use the corresponding entry's copyfrom info.
    RA_SESSION may be NULL regardless of whether ABSPATH_OR_URL is a URL.
-   Use CTX for cancellation (ignored if NULL), and SCRATCH_POOL for all
-   temporary allocations. */
+   Use CTX for authentication and for a working copy context.  Allocate
+   *URL in RESULT_POOL. Use SCRATCH_POOL for temporary allocations. */
 svn_error_t *
 svn_client__derive_location(const char **url,
                             svn_revnum_t *peg_revnum,
@@ -91,7 +73,8 @@ svn_client__derive_location(const char *
 
    If PEG_REV_NUM is svn_opt_revision_unspecified, svn_opt_revision_number,
    svn_opt_revision_base, or svn_opt_revision_working then set *REVNUM
-   to the base revision. */
+   to the base revision.
+   ### What's up with this last paragraph? Sounds all wrong. */
 svn_error_t *
 svn_client__entry_location(const char **url,
                            svn_revnum_t *revnum,
@@ -491,6 +474,12 @@ svn_client__make_local_parents(const cha
    these obstructions cause the update to fail.
 
    If INNERUPDATE is true, no anchor check is performed on the update target.
+
+   If MAKE_PARENTS is true, allow the update to calculate and checkout
+   (with depth=empty) any parent directories of the requested update
+   target which are missing from the working copy.
+
+   NOTE:  You may not specify both INNERUPDATE and MAKE_PARENTS as true.
 */
 svn_error_t *
 svn_client__update_internal(svn_revnum_t *result_rev,
@@ -502,6 +491,7 @@ svn_client__update_internal(svn_revnum_t
                             svn_boolean_t allow_unver_obstructions,
                             svn_boolean_t *timestamp_sleep,
                             svn_boolean_t innerupdate,
+                            svn_boolean_t make_parents,
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool);
 
@@ -912,7 +902,6 @@ svn_client__do_commit(const char *base_u
 /*** Externals (Modules) ***/
 
 /* Handle changes to the svn:externals property described by EXTERNALS_OLD,
-
    EXTERNALS_NEW, and AMBIENT_DEPTHS.  The tree's top level directory
    is at TO_ABSPATH and corresponds to FROM_URL URL in the repository,
    which has a root URL of REPOS_ROOT_URL.  A write lock should be
@@ -1004,6 +993,44 @@ svn_client__do_external_status(svn_clien
                                void *status_baton,
                                apr_pool_t *pool);
 
+/* Set *EXTERNALS_P to a hash mapping const char * local absolute
+   paths to const svn_string_t * svn:externals property values, those
+   found by crawling LOCAL_ABSPATH to DEPTH. */
+svn_error_t *
+svn_client__crawl_for_externals(apr_hash_t **externals_p,
+                                const char *local_abspath,
+                                svn_depth_t depth,
+                                svn_client_ctx_t *ctx,
+                                apr_pool_t *scratch_pool,
+                                apr_pool_t *result_pool);
+
+/* Baton type for svn_wc__external_info_gatherer(). */
+typedef struct svn_client__external_func_baton_t
+{
+  apr_hash_t *externals_old;  /* Hash of old externals property values,
+                                 or NULL if the caller doesn't care. */
+  apr_hash_t *externals_new;  /* Hash of new externals property values,
+                                 or NULL if the caller doesn't care. */
+  apr_hash_t *ambient_depths; /* Hash of ambient depth values, or NULL
+                                 if the caller doesn't care. */
+  apr_pool_t *result_pool;    /* Pool to use for all stored values. */
+
+} svn_client__external_func_baton_t;
+
+
+/* This function gets invoked whenever external changes are encountered.
+   This implements the `svn_wc_external_update_t' interface, and can
+   be used with an svn_client__external_func_baton_t BATON to gather
+   information about changes to externals definitions. */
+svn_error_t *
+svn_client__external_info_gatherer(void *baton,
+                                   const char *local_abspath,
+                                   const svn_string_t *old_val,
+                                   const svn_string_t *new_val,
+                                   svn_depth_t depth,
+                                   apr_pool_t *scratch_pool);
+
+
 
 
 /* Retrieve log messages using the first provided (non-NULL) callback
@@ -1081,30 +1108,6 @@ svn_cl__rev_default_to_peg(const svn_opt
                            const svn_opt_revision_t *peg_revision);
 
 
-/* Some external traversal helpers.
- */
-/* This function gets invoked whenever external changes are encountered.
-   This implements svn_wc_external_update_t */
-svn_error_t *
-svn_client__external_info_gatherer(void *baton,
-                                   const char *local_abspath,
-                                   const svn_string_t *old_val,
-                                   const svn_string_t *new_val,
-                                   svn_depth_t depth,
-                                   apr_pool_t *scratch_pool);
-
-/* Baton type for svn_wc__external_info_gatherer().  All fields must be
-   populated before use. */
-typedef struct svn_client__external_func_baton_t
-{
-  apr_hash_t *externals_old;
-  apr_hash_t *externals_new;
-  apr_hash_t *ambient_depths;
-
-  apr_pool_t *result_pool;
-} svn_client__external_func_baton_t;
-
-
 
 
 #ifdef __cplusplus

Modified: subversion/branches/performance/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/deprecated.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/deprecated.c Wed Nov 17 00:09:50 2010
@@ -1796,6 +1796,22 @@ svn_client_status(svn_revnum_t *result_r
 
 /*** From update.c ***/
 svn_error_t *
+svn_client_update3(apr_array_header_t **result_revs,
+                   const apr_array_header_t *paths,
+                   const svn_opt_revision_t *revision,
+                   svn_depth_t depth,
+                   svn_boolean_t depth_is_sticky,
+                   svn_boolean_t ignore_externals,
+                   svn_boolean_t allow_unver_obstructions,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool)
+{
+  return svn_client_update4(result_revs, paths, revision,
+                            depth, depth_is_sticky, ignore_externals,
+                            allow_unver_obstructions, FALSE, ctx, pool);
+}
+
+svn_error_t *
 svn_client_update2(apr_array_header_t **result_revs,
                    const apr_array_header_t *paths,
                    const svn_opt_revision_t *revision,

Modified: subversion/branches/performance/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/externals.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/externals.c Wed Nov 17 00:09:50 2010
@@ -204,7 +204,7 @@ switch_dir_external(const char *path,
               SVN_ERR(svn_client__update_internal(NULL, local_abspath,
                                                   revision, svn_depth_unknown,
                                                   FALSE, FALSE, FALSE,
-                                                  timestamp_sleep, TRUE,
+                                                  timestamp_sleep, TRUE, FALSE,
                                                   ctx, subpool));
               svn_pool_destroy(subpool);
               return SVN_NO_ERROR;
@@ -1392,70 +1392,86 @@ svn_client__do_external_status(svn_clien
   return SVN_NO_ERROR;
 }
 
-/* Implements svn_wc_externals_update_t */
+
+/* Implements the `svn_wc_externals_update_t' interface. */
 svn_error_t *
-svn_cl__store_externals(void *baton,
-                        const char *local_abspath,
-                        const svn_string_t *old_value,
-                        const svn_string_t *new_value,
-                        svn_depth_t depth,
-                        apr_pool_t *scratch_pool)
+svn_client__external_info_gatherer(void *baton,
+                                   const char *local_abspath,
+                                   const svn_string_t *old_value,
+                                   const svn_string_t *new_value,
+                                   svn_depth_t depth,
+                                   apr_pool_t *scratch_pool)
 {
-  struct svn_cl__externals_store *eb = baton;
-  apr_pool_t *dup_pool = eb->pool;
+  svn_client__external_func_baton_t *efb = baton;
+
+  local_abspath = apr_pstrdup(efb->result_pool, local_abspath);
 
-  local_abspath = apr_pstrdup(dup_pool, local_abspath);
+  if (efb->externals_old != NULL && old_value != NULL)
+    apr_hash_set(efb->externals_old, local_abspath, APR_HASH_KEY_STRING,
+                 apr_pstrndup(efb->result_pool,
+                              old_value->data, old_value->len));
+
+  if (efb->externals_new != NULL && new_value != NULL)
+    apr_hash_set(efb->externals_new, local_abspath, APR_HASH_KEY_STRING,
+                 apr_pstrndup(efb->result_pool,
+                              new_value->data, new_value->len));
 
-  if (eb->externals_old != NULL && old_value != NULL)
-    apr_hash_set(eb->externals_new,
-                 local_abspath, APR_HASH_KEY_STRING,
-                 apr_pstrndup(dup_pool, old_value->data, old_value->len));
-
-  if (eb->externals_new != NULL && new_value != NULL)
-    apr_hash_set(eb->externals_new,
-                 local_abspath, APR_HASH_KEY_STRING,
-                 apr_pstrndup(dup_pool, new_value->data, new_value->len));
-
-  if (eb->depths != NULL)
-    apr_hash_set(eb->depths,
-                 local_abspath, APR_HASH_KEY_STRING,
+  if (efb->ambient_depths != NULL)
+    apr_hash_set(efb->ambient_depths, local_abspath, APR_HASH_KEY_STRING,
                  svn_depth_to_word(depth));
 
   return SVN_NO_ERROR;
 }
 
 
-
-svn_error_t *
-svn_client__external_info_gatherer(void *baton,
-                                   const char *local_abspath,
-                                   const svn_string_t *old_val,
-                                   const svn_string_t *new_val,
-                                   svn_depth_t depth,
-                                   apr_pool_t *scratch_pool)
+/* Callback of type svn_wc_external_update_t.  Just squirrels away an
+   svn:externals property value into BATON (which is an apr_hash_t *
+   keyed on local absolute path).  */
+static svn_error_t *
+externals_update_func(void *baton,
+                      const char *local_abspath,
+                      const svn_string_t *old_val,
+                      const svn_string_t *new_val,
+                      svn_depth_t depth,
+                      apr_pool_t *scratch_pool)
 {
-  svn_client__external_func_baton_t *efb = baton;
-  const char *dup_val = NULL;
-  const char *dup_path = apr_pstrdup(efb->result_pool, local_abspath);
+  apr_hash_t *externals_hash = baton;
+  apr_pool_t *hash_pool = apr_hash_pool_get(externals_hash);
 
-  if (old_val)
-    {
-      dup_val = apr_pstrmemdup(efb->result_pool, old_val->data, old_val->len);
+  apr_hash_set(externals_hash, apr_pstrdup(hash_pool, local_abspath),
+               APR_HASH_KEY_STRING, svn_string_dup(new_val, hash_pool));
+  return SVN_NO_ERROR;
+}
 
-      apr_hash_set(efb->externals_old, dup_path, APR_HASH_KEY_STRING, dup_val);
-    }
 
-  if (new_val)
-    {
-      /* In most cases the value is identical */
-      if (old_val != new_val)
-        dup_val = apr_pstrmemdup(efb->result_pool, new_val->data, new_val->len);
+/* Callback of type svn_wc_status_func4_t.  Does nothing. */
+static svn_error_t *
+status_noop_func(void *baton,
+                 const char *local_abspath,
+                 const svn_wc_status3_t *status,
+                 apr_pool_t *scratch_pool)
+{
+  return SVN_NO_ERROR;
+}
 
-      apr_hash_set(efb->externals_new, dup_path, APR_HASH_KEY_STRING, dup_val);
-    }
 
-  apr_hash_set(efb->ambient_depths, dup_path, APR_HASH_KEY_STRING,
-               svn_depth_to_word(depth));
+svn_error_t *
+svn_client__crawl_for_externals(apr_hash_t **externals_p,
+                                const char *local_abspath,
+                                svn_depth_t depth,
+                                svn_client_ctx_t *ctx,
+                                apr_pool_t *scratch_pool,
+                                apr_pool_t *result_pool)
+{
+  apr_hash_t *externals_hash = apr_hash_make(result_pool);
+
+  /* Do a status run just to harvest externals definitions. */
+  SVN_ERR(svn_wc_walk_status(ctx->wc_ctx, local_abspath, depth,
+                             FALSE, FALSE, NULL, status_noop_func, NULL,
+                             externals_update_func, externals_hash,
+                             ctx->cancel_func, ctx->cancel_baton,
+                             scratch_pool));
 
+  *externals_p = externals_hash;
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/performance/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/patch.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/patch.c Wed Nov 17 00:09:50 2010
@@ -203,6 +203,9 @@ typedef struct patch_target_t {
   /* True if the patch changed any of the properties of the target. */
   svn_boolean_t has_prop_changes;
 
+  /* True if the patch contained a svn:special property. */
+  svn_boolean_t is_special;
+
   /* All the information that is specific to the content of the target. */
   target_content_info_t *content_info;
 
@@ -235,7 +238,7 @@ strip_path(const char **result, const ch
   apr_array_header_t *stripped;
 
   components = svn_path_decompose(path, scratch_pool);
-  if (strip_count >= components->nelts)
+  if (strip_count > components->nelts)
     return svn_error_createf(SVN_ERR_CLIENT_PATCH_BAD_STRIP_COUNT, NULL,
                              _("Cannot strip %u components from '%s'"),
                              strip_count,
@@ -1609,44 +1612,6 @@ send_patch_notification(const patch_targ
   return SVN_NO_ERROR;
 }
 
-/* Close the streams of the TARGET so that their content is flushed
- * to disk. This will also close underlying streams and files. Use POOL for
- * temporary allocations. */
-static svn_error_t *
-close_target_streams(const patch_target_t *target,
-                     apr_pool_t *pool)
-{
-  apr_hash_index_t *hi;
-  target_content_info_t *prop_content_info;
-
-  /* First the streams belonging to properties .. */
-  for (hi = apr_hash_first(pool, target->prop_targets);
-       hi;
-       hi = apr_hash_next(hi))
-    {
-      prop_patch_target_t *prop_target;
-      prop_target = svn__apr_hash_index_val(hi);
-      prop_content_info = prop_target->content_info;
-
-      /* ### If the prop did not exist pre-patching we'll not have a
-       * ### stream to read from. Find a better way to store info on
-       * ### the existence of the target prop. */
-      if (prop_content_info->stream)
-        SVN_ERR(svn_stream_close(prop_content_info->stream));
-
-      SVN_ERR(svn_stream_close(prop_content_info->patched));
-    }
-
-  /* .. and then streams associated with the file.
-   * ### We're not closing the reject stream -- it still needed and
-   * ### will be closed later in write_out_rejected_hunks(). */
-  if (target->kind_on_disk == svn_node_file)
-    SVN_ERR(svn_stream_close(target->content_info->stream));
-  SVN_ERR(svn_stream_close(target->content_info->patched));
-
-  return SVN_NO_ERROR;
-}
-
 /* Apply a PATCH to a working copy at ABS_WC_PATH and put the result
  * into temporary files, to be installed in the working copy later.
  * Return information about the patch target in *PATCH_TARGET, allocated
@@ -1675,6 +1640,7 @@ apply_one_patch(patch_target_t **patch_t
   int i;
   static const int MAX_FUZZ = 2;
   apr_hash_index_t *hash_index;
+  target_content_info_t *prop_content_info;
 
   SVN_ERR(init_patch_target(&target, patch, abs_wc_path, wc_ctx, strip_count,
                             remove_tempfiles, result_pool, scratch_pool));
@@ -1773,6 +1739,9 @@ apply_one_patch(patch_target_t **patch_t
       prop_name = svn__apr_hash_index_key(hash_index);
       prop_patch = svn__apr_hash_index_val(hash_index);
 
+      if (! strcmp(prop_name, SVN_PROP_SPECIAL))
+        target->is_special = TRUE;
+
       /* We'll store matched hunks in prop_content_info. */
       prop_target = apr_hash_get(target->prop_targets, prop_name, 
                                  APR_HASH_KEY_STRING);
@@ -1855,7 +1824,31 @@ apply_one_patch(patch_target_t **patch_t
 
   svn_pool_destroy(iterpool);
 
-  SVN_ERR(close_target_streams(target, scratch_pool));
+  /* Now close some streams that we don't need any longer to get
+   * file buffers flushed to disk. First, close the props streams... */
+  for (hash_index = apr_hash_first(scratch_pool, target->prop_targets);
+       hash_index;
+       hash_index = apr_hash_next(hash_index))
+    {
+      prop_patch_target_t *prop_target;
+      prop_target = svn__apr_hash_index_val(hash_index);
+      prop_content_info = prop_target->content_info;
+
+      /* ### If the prop did not exist pre-patching we'll not have a
+       * ### stream to read from. Find a better way to store info on
+       * ### the existence of the target prop. */
+      if (prop_content_info->stream)
+        SVN_ERR(svn_stream_close(prop_content_info->stream));
+
+      SVN_ERR(svn_stream_close(prop_content_info->patched));
+    }
+
+  /* .. and then streams associated with the file.
+   * But we're not closing the reject stream -- it still needed and
+   * will be closed later in write_out_rejected_hunks(). */
+  if (target->kind_on_disk == svn_node_file)
+    SVN_ERR(svn_stream_close(target->content_info->stream));
+  SVN_ERR(svn_stream_close(target->content_info->patched));
 
   if (! target->skipped)
     {
@@ -2118,9 +2111,33 @@ install_patched_target(patch_target_t *t
 
       if (! dry_run && ! target->skipped)
         {
-          /* Copy the patched file on top of the target file. */
-          SVN_ERR(svn_io_copy_file(target->patched_path,
-                                   target->local_abspath, FALSE, pool));
+          if (target->is_special)
+            {
+              svn_stream_t *stream;
+              svn_stream_t *patched_stream;
+              apr_file_t *file;
+
+              SVN_ERR(svn_io_file_open(&file, target->patched_path,
+                                       APR_READ | APR_BINARY, APR_OS_DEFAULT,
+                                       pool));
+
+              patched_stream = svn_stream_from_aprfile2(file, FALSE /* disown */,
+                                                pool);
+              SVN_ERR(svn_subst_create_specialfile(&stream, 
+                                                   target->local_abspath,
+                                                   pool, pool));
+              SVN_ERR(svn_stream_copy3(patched_stream, stream, 
+                                       NULL, /* cancel_func */ 
+                                       NULL, /* cancel_baton */
+                                       pool));
+            }
+          else
+            {
+              /* Copy the patched file on top of the target file. */
+              SVN_ERR(svn_io_copy_file(target->patched_path,
+                                       target->local_abspath, FALSE, pool));
+            }
+
           if (target->added || target->replaced)
             {
               /* The target file didn't exist previously,
@@ -2736,6 +2753,12 @@ svn_client_patch(const char *patch_abspa
     return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
                             _("strip count must be positive"));
 
+  if (svn_path_is_url(local_abspath))
+    return svn_error_return(svn_error_createf(SVN_ERR_ILLEGAL_TARGET,
+                                              NULL,
+                                              _("'%s' is not a local path"),
+                                              local_abspath));
+
   baton.patch_abspath = patch_abspath;
   baton.abs_wc_path = local_abspath;
   baton.dry_run = dry_run;

Modified: subversion/branches/performance/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/relocate.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/relocate.c Wed Nov 17 00:09:50 2010
@@ -126,37 +126,6 @@ validator_func(void *baton,
 }
 
 
-/* Callback of type svn_wc_external_update_t.  Just squirrels away an
-   svn:externals property value into BATON (which is an apr_hash_t *
-   keyed on local absolute path).  */
-static svn_error_t *
-externals_update_func(void *baton,
-                      const char *local_abspath,
-                      const svn_string_t *old_val,
-                      const svn_string_t *new_val,
-                      svn_depth_t depth,
-                      apr_pool_t *scratch_pool)
-{
-  apr_hash_t *externals_hash = baton;
-  apr_pool_t *hash_pool = apr_hash_pool_get(externals_hash);
-
-  apr_hash_set(externals_hash, apr_pstrdup(hash_pool, local_abspath),
-               APR_HASH_KEY_STRING, svn_string_dup(new_val, hash_pool));
-  return SVN_NO_ERROR;
-}
-
-
-/* Callback of type svn_wc_status_func4_t.  Does nothing. */
-static svn_error_t *
-status_noop_func(void *baton,
-                 const char *local_abspath,
-                 const svn_wc_status3_t *status,
-                 apr_pool_t *scratch_pool)
-{
-  return SVN_NO_ERROR;
-}
-
-
 /* Examing the array of svn_wc_external_item2_t's EXT_DESC (parsed
    from the svn:externals property set on LOCAL_ABSPATH) and determine
    if the external working copies described by such should be
@@ -270,16 +239,10 @@ svn_client_relocate2(const char *wcroot_
   SVN_ERR(svn_client_root_url_from_path(&new_repos_root_url, local_abspath,
                                         ctx, pool));
 
-  externals_hash = apr_hash_make(pool);
-
-  /* Do a status run just to harvest externals definitions. */
-  SVN_ERR(svn_wc_walk_status(ctx->wc_ctx, local_abspath,
-                             svn_depth_infinity, FALSE, FALSE, NULL,
-                             status_noop_func, NULL,
-                             externals_update_func, externals_hash,
-                             ctx->cancel_func, ctx->cancel_baton, pool));
 
-  /* No externals?  No problem.  We're done here. */
+  /* Relocate externals, too (if any). */
+  SVN_ERR(svn_client__crawl_for_externals(&externals_hash, local_abspath,
+                                          svn_depth_infinity, ctx, pool, pool));
   if (! apr_hash_count(externals_hash))
     return SVN_NO_ERROR;
 

Modified: subversion/branches/performance/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/status.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/status.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/status.c Wed Nov 17 00:09:50 2010
@@ -267,7 +267,7 @@ svn_client_status5(svn_revnum_t *result_
   apr_array_header_t *ignores;
   svn_error_t *err;
   apr_hash_t *changelist_hash = NULL;
-  struct svn_cl__externals_store externals_store = { NULL };
+  struct svn_client__external_func_baton_t externals_store = { NULL };
 
   if (svn_path_is_url(path))
     return svn_error_return(svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
@@ -357,7 +357,7 @@ svn_client_status5(svn_revnum_t *result_
 
   if (!ignore_externals)
     {
-      externals_store.pool = pool;
+      externals_store.result_pool = pool;
       externals_store.externals_new = apr_hash_make(pool);
     }
 
@@ -393,10 +393,10 @@ svn_client_status5(svn_revnum_t *result_
                                     dir_abspath, target_basename,
                                     depth, get_all,
                                     no_ignore, ignores, tweak_status, &sb,
-                                    ignore_externals ? NULL
-                                                     : svn_cl__store_externals,
-                                    ignore_externals ? NULL
-                                                     : &externals_store,
+                                    ignore_externals
+                                        ? NULL
+                                        : svn_client__external_info_gatherer,
+                                    ignore_externals ? NULL : &externals_store,
                                     ctx->cancel_func, ctx->cancel_baton,
                                     pool, pool));
 
@@ -517,10 +517,10 @@ svn_client_status5(svn_revnum_t *result_
       err = svn_wc_walk_status(ctx->wc_ctx, target_abspath,
                                depth, get_all, no_ignore, ignores,
                                tweak_status, &sb,
-                               ignore_externals ? NULL
-                                                : svn_cl__store_externals,
-                               ignore_externals ? NULL
-                                                : &externals_store,
+                               ignore_externals
+                                   ? NULL
+                                   : svn_client__external_info_gatherer,
+                               ignore_externals ? NULL : &externals_store,
                                ctx->cancel_func, ctx->cancel_baton,
                                pool);
 

Modified: subversion/branches/performance/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_client/update.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_client/update.c (original)
+++ subversion/branches/performance/subversion/libsvn_client/update.c Wed Nov 17 00:09:50 2010
@@ -44,7 +44,18 @@
 
 /*** Code. ***/
 
-
+/* This is a helper for svn_client__update_internal(), which see for
+   an explanation of most of these parameters.  Some stuff that's
+   unique is as follows:
+
+   ANCHOR_ABSPATH is the local absolute path of the update anchor.
+   This is typically either the same as LOCAL_ABSPATH, or the
+   immediate parent of LOCAL_ABSPATH.
+
+   If NOTIFY_SUMMARY is set (and there's a notification hander in
+   CTX), transmit the final update summary upon successful
+   completion of the update.
+*/
 static svn_error_t *
 update_internal(svn_revnum_t *result_rev,
                 const char *local_abspath,
@@ -56,6 +67,7 @@ update_internal(svn_revnum_t *result_rev
                 svn_boolean_t allow_unver_obstructions,
                 svn_boolean_t *timestamp_sleep,
                 svn_boolean_t innerupdate,
+                svn_boolean_t notify_summary,
                 svn_client_ctx_t *ctx,
                 apr_pool_t *pool)
 {
@@ -235,8 +247,8 @@ update_internal(svn_revnum_t *result_rev
   if (sleep_here)
     svn_io_sleep_for_timestamps(local_abspath, pool);
 
-  /* Let everyone know we're finished here. */
-  if (ctx->notify_func2)
+  /* Let everyone know we're finished here (unless we're asked not to). */
+  if (ctx->notify_func2 && notify_summary)
     {
       svn_wc_notify_t *notify
         = svn_wc_create_notify(local_abspath, svn_wc_notify_update_completed,
@@ -266,44 +278,99 @@ svn_client__update_internal(svn_revnum_t
                             svn_boolean_t allow_unver_obstructions,
                             svn_boolean_t *timestamp_sleep,
                             svn_boolean_t innerupdate,
+                            svn_boolean_t make_parents,
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool)
 {
-  const char *anchor_abspath;
+  const char *anchor_abspath, *lockroot_abspath;
   svn_error_t *err;
+  svn_opt_revision_t peg_revision = *((svn_opt_revision_t *)revision);
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+  SVN_ERR_ASSERT(! (innerupdate && make_parents));
+
+  if (make_parents)
+    {
+      int i;
+      const char *parent_abspath = local_abspath;
+      apr_array_header_t *missing_parents = 
+        apr_array_make(pool, 4, sizeof(const char *));
+
+      while (1)
+        {
+          /* Try to lock.  If we can't lock because our target (or its
+             parent) isn't a working copy, we'll try to walk up the
+             tree to find a working copy, remembering this path's
+             parent as one we need to flesh out.  */
+          err = svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
+                                           parent_abspath, !innerupdate,
+                                           pool, pool);
+          if (!err)
+            break;
+          if ((err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
+              || svn_dirent_is_root(parent_abspath, strlen(parent_abspath)))
+            return err;
+          svn_error_clear(err);
+
+          /* Remember the parent of our update target as a missing
+             parent. */
+          parent_abspath = svn_dirent_dirname(parent_abspath, pool);
+          APR_ARRAY_PUSH(missing_parents, const char *) = parent_abspath;
+        }
+
+      /* Run 'svn up --depth=empty' (effectively) on the missing
+         parents, if any. */
+      anchor_abspath = lockroot_abspath;
+      for (i = missing_parents->nelts - 1; i >= 0; i--)
+        {
+          const char *missing_parent =
+            APR_ARRAY_IDX(missing_parents, i, const char *);
+          err = update_internal(result_rev, missing_parent, anchor_abspath,
+                                &peg_revision, svn_depth_empty, FALSE,
+                                ignore_externals, allow_unver_obstructions,
+                                timestamp_sleep, innerupdate, FALSE,
+                                ctx, pool);
+          if (err)
+            goto cleanup;
+          anchor_abspath = missing_parent;
 
-  if (!innerupdate)
-    SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath,
-                                       ctx->wc_ctx, local_abspath, TRUE,
-                                       pool, pool));
+          /* If we successfully updated a missing parent, let's re-use
+             the returned revision number for future updates for the
+             sake of consistency. */
+          peg_revision.kind = svn_opt_revision_number;
+          peg_revision.value.number = *result_rev;
+        }
+    }
   else
-    SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath,
-                                       ctx->wc_ctx, local_abspath, FALSE,
-                                       pool, pool));
+    {
+      SVN_ERR(svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
+                                         local_abspath, !innerupdate,
+                                         pool, pool));
+      anchor_abspath = lockroot_abspath;
+    }
 
   err = update_internal(result_rev, local_abspath, anchor_abspath,
-                         revision, depth, depth_is_sticky,
-                         ignore_externals, allow_unver_obstructions,
-                         timestamp_sleep, innerupdate, ctx, pool);
-
+                        &peg_revision, depth, depth_is_sticky,
+                        ignore_externals, allow_unver_obstructions,
+                        timestamp_sleep, innerupdate, TRUE, ctx, pool);
+ cleanup:
   err = svn_error_compose_create(
             err,
-            svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool));
+            svn_wc__release_write_lock(ctx->wc_ctx, lockroot_abspath, pool));
 
   return svn_error_return(err);
 }
 
 
 svn_error_t *
-svn_client_update3(apr_array_header_t **result_revs,
+svn_client_update4(apr_array_header_t **result_revs,
                    const apr_array_header_t *paths,
                    const svn_opt_revision_t *revision,
                    svn_depth_t depth,
                    svn_boolean_t depth_is_sticky,
                    svn_boolean_t ignore_externals,
                    svn_boolean_t allow_unver_obstructions,
+                   svn_boolean_t make_parents,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *pool)
 {
@@ -340,7 +407,8 @@ svn_client_update3(apr_array_header_t **
                                             revision, depth, depth_is_sticky,
                                             ignore_externals,
                                             allow_unver_obstructions,
-                                            &sleep, FALSE, ctx, subpool);
+                                            &sleep, FALSE, make_parents,
+                                            ctx, subpool);
 
           if (err && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
             {

Modified: subversion/branches/performance/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_diff/diff_file.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/performance/subversion/libsvn_diff/diff_file.c Wed Nov 17 00:09:50 2010
@@ -563,12 +563,42 @@ svn_diff_file_options_create(apr_pool_t 
   return apr_pcalloc(pool, sizeof(svn_diff_file_options_t));
 }
 
+/* A baton for use with opt_parsing_error_func(). */
+struct opt_parsing_error_baton_t
+{
+  svn_error_t *err;
+  apr_pool_t *pool;
+};
+
+/* Store an error message from apr_getopt_long().  Set BATON->err to a new
+ * error with a message generated from FMT and the remaining arguments.
+ * Implements apr_getopt_err_fn_t. */
+static void
+opt_parsing_error_func(void *baton,
+                       const char *fmt, ...)
+{
+  struct opt_parsing_error_baton_t *b = baton;
+  const char *message;
+  va_list ap;
+
+  va_start(ap, fmt);
+  message = apr_pvsprintf(b->pool, fmt, ap);
+  va_end(ap);
+
+  /* Skip leading ": " (if present, which it always is in known cases). */
+  if (strncmp(message, ": ", 2) == 0)
+    message += 2;
+
+  b->err = svn_error_create(SVN_ERR_INVALID_DIFF_OPTION, NULL, message);
+}
+
 svn_error_t *
 svn_diff_file_options_parse(svn_diff_file_options_t *options,
                             const apr_array_header_t *args,
                             apr_pool_t *pool)
 {
   apr_getopt_t *os;
+  struct opt_parsing_error_baton_t opt_parsing_error_baton = { NULL, pool };
   /* Make room for each option (starting at index 1) plus trailing NULL. */
   const char **argv = apr_palloc(pool, sizeof(char*) * (args->nelts + 2));
 
@@ -577,8 +607,12 @@ svn_diff_file_options_parse(svn_diff_fil
   argv[args->nelts + 1] = NULL;
 
   apr_getopt_init(&os, pool, args->nelts + 1, argv);
-  /* No printing of error messages, please! */
-  os->errfn = NULL;
+
+  /* Capture any error message from apr_getopt_long().  This will typically
+   * say which option is wrong, which we would not otherwise know. */
+  os->errfn = opt_parsing_error_func;
+  os->errarg = &opt_parsing_error_baton;
+
   while (1)
     {
       const char *opt_arg;
@@ -588,7 +622,13 @@ svn_diff_file_options_parse(svn_diff_fil
       if (APR_STATUS_IS_EOF(err))
         break;
       if (err)
-        return svn_error_wrap_apr(err, _("Error parsing diff options"));
+        /* Wrap apr_getopt_long()'s error message.  Its doc string implies
+         * it always will produce one, but never mind if it doesn't.  Avoid
+         * using the message associated with the return code ERR, because
+         * it refers to the "command line" which may be misleading here. */
+        return svn_error_create(SVN_ERR_INVALID_DIFF_OPTION,
+                                opt_parsing_error_baton.err,
+                                _("Error in options to internal diff"));
 
       switch (opt_id)
         {

Modified: subversion/branches/performance/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_fs_fs/dag.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/performance/subversion/libsvn_fs_fs/dag.c Wed Nov 17 00:09:50 2010
@@ -29,7 +29,6 @@
 #include "svn_pools.h"
 
 #include "dag.h"
-#include "err.h"
 #include "fs.h"
 #include "key-gen.h"
 #include "fs_fs.h"

Modified: subversion/branches/performance/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_fs_fs/fs.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/performance/subversion/libsvn_fs_fs/fs.c Wed Nov 17 00:09:50 2010
@@ -34,7 +34,6 @@
 #include "svn_version.h"
 #include "svn_pools.h"
 #include "fs.h"
-#include "err.h"
 #include "fs_fs.h"
 #include "tree.h"
 #include "lock.h"

Modified: subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.c Wed Nov 17 00:09:50 2010
@@ -51,7 +51,6 @@
 #include "svn_ctype.h"
 
 #include "fs.h"
-#include "err.h"
 #include "tree.h"
 #include "lock.h"
 #include "key-gen.h"
@@ -2225,6 +2224,16 @@ read_rep_offsets(representation_t **rep_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+err_dangling_id(svn_fs_t *fs, const svn_fs_id_t *id)
+{
+  svn_string_t *id_str = svn_fs_fs__id_unparse(id, fs->pool);
+  return svn_error_createf
+    (SVN_ERR_FS_ID_NOT_FOUND, 0,
+     _("Reference to non-existent node '%s' in filesystem '%s'"),
+     id_str->data, fs->path);
+}
+
 /* Combine the revision and offset of the ID to a string that will
  * be used as a cache key. Allocations will be made from POOL.
  */
@@ -2332,7 +2341,7 @@ get_node_revision_body(node_revision_t *
       if (APR_STATUS_IS_ENOENT(err->apr_err))
         {
           svn_error_clear(err);
-          return svn_fs_fs__err_dangling_id(fs, id);
+          return svn_error_return(err_dangling_id(fs, id));
         }
 
       return svn_error_return(err);
@@ -7300,15 +7309,41 @@ recover_body(void *baton, apr_pool_t *po
   SVN_ERR(svn_io_check_path(path_revprops(fs, max_rev, pool),
                             &youngest_revprops_kind, pool));
   if (youngest_revprops_kind == svn_node_none)
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Revision %ld has a revs file but no "
-                               "revprops file"),
-                             max_rev);
+    {
+      svn_boolean_t uhohs = TRUE;
+
+      /* No file?  Hrm... maybe that's because this repository is
+         packed and the youngest revision is in the revprops.db
+         file?  We can at least see if that's a possibility.
+
+         ### TODO: Could we check for revprops in the revprops.db?
+         ###       What if rNNN legitimately has no revprops? */
+      if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
+        {
+          svn_revnum_t min_unpacked_revprop;
+          const char *min_unpacked_revprop_path =
+            svn_dirent_join(fs->path, PATH_MIN_UNPACKED_REVPROP, pool);
+
+          SVN_ERR(read_min_unpacked_rev(&min_unpacked_revprop,
+                                        min_unpacked_revprop_path, pool));
+          if (min_unpacked_revprop == (max_rev + 1))
+            uhohs = FALSE;
+        }
+      if (uhohs)
+        {
+          return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                                   _("Revision %ld has a revs file but no "
+                                     "revprops file"),
+                                   max_rev);
+        }
+    }
   else if (youngest_revprops_kind != svn_node_file)
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Revision %ld has a non-file where its "
-                               "revprops file should be"),
-                             max_rev);
+    {
+      return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                               _("Revision %ld has a non-file where its "
+                                 "revprops file should be"),
+                               max_rev);
+    }
 
   /* Now store the discovered youngest revision, and the next IDs if
      relevant, in a new 'current' file. */
@@ -7385,7 +7420,7 @@ svn_fs_fs__set_uuid(svn_fs_t *fs,
    permissions as FS->path.*/
 svn_error_t *
 svn_fs_fs__ensure_dir_exists(const char *path,
-                             svn_fs_t *fs,
+                             const char *fs_path,
                              apr_pool_t *pool)
 {
   svn_error_t *err = svn_io_dir_make(path, APR_OS_DEFAULT, pool);
@@ -7398,7 +7433,7 @@ svn_fs_fs__ensure_dir_exists(const char 
 
   /* We successfully created a new directory.  Dup the permissions
      from FS->path. */
-  return svn_io_copy_perms(path, fs->path, pool);
+  return svn_io_copy_perms(path, fs_path, pool);
 }
 
 /* Set *NODE_ORIGINS to a hash mapping 'const char *' node IDs to
@@ -7470,7 +7505,7 @@ set_node_origins_for_file(svn_fs_t *fs,
   SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_join(fs->path,
                                                        PATH_NODE_ORIGINS_DIR,
                                                        pool),
-                                       fs, pool));
+                                       fs->path, pool));
 
   /* Read the previously existing origins (if any), and merge our
      update with it. */

Modified: subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.h?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/performance/subversion/libsvn_fs_fs/fs_fs.h Wed Nov 17 00:09:50 2010
@@ -490,9 +490,9 @@ svn_error_t *svn_fs_fs__txn_prop(svn_str
                                  const char *propname, apr_pool_t *pool);
 
 /* If directory PATH does not exist, create it and give it the same
-   permissions as FS->path.*/
+   permissions as FS_PATH.*/
 svn_error_t *svn_fs_fs__ensure_dir_exists(const char *path,
-                                          svn_fs_t *fs,
+                                          const char *fs_path,
                                           apr_pool_t *pool);
 
 /* Update the node origin index for FS, recording the mapping from

Modified: subversion/branches/performance/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_fs_fs/lock.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/performance/subversion/libsvn_fs_fs/lock.c Wed Nov 17 00:09:50 2010
@@ -36,7 +36,6 @@
 
 #include "lock.h"
 #include "tree.h"
-#include "err.h"
 #include "fs_fs.h"
 #include "../libsvn_fs/fs-loader.h"
 
@@ -108,17 +107,28 @@ hash_fetch(apr_hash_t *hash,
 }
 
 
+/* SVN_ERR_FS_CORRUPT: the lockfile for PATH in FS is corrupt.  */
+static svn_error_t *
+err_corrupt_lockfile(const char *fs_path, const char *path)
+{
+  return
+    svn_error_createf(
+     SVN_ERR_FS_CORRUPT, 0,
+     _("Corrupt lockfile for path '%s' in filesystem '%s'"),
+     path, fs_path);
+}
+
 
 /*** Digest file handling functions. ***/
 
 /* Return the path of the lock/entries file for which DIGEST is the
    hashed repository relative path. */
 static const char *
-digest_path_from_digest(svn_fs_t *fs,
+digest_path_from_digest(const char *fs_path,
                         const char *digest,
                         apr_pool_t *pool)
 {
-  return svn_dirent_join_many(pool, fs->path, PATH_LOCKS_DIR,
+  return svn_dirent_join_many(pool, fs_path, PATH_LOCKS_DIR,
                               apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN),
                               digest, NULL);
 }
@@ -128,12 +138,12 @@ digest_path_from_digest(svn_fs_t *fs,
    PATH, where PATH is the path to the lock file or lock entries file
    in FS. */
 static const char *
-digest_path_from_path(svn_fs_t *fs,
+digest_path_from_path(const char *fs_path,
                       const char *path,
                       apr_pool_t *pool)
 {
   const char *digest = make_digest(path, pool);
-  return svn_dirent_join_many(pool, fs->path, PATH_LOCKS_DIR,
+  return svn_dirent_join_many(pool, fs_path, PATH_LOCKS_DIR,
                               apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN),
                               digest, NULL);
 }
@@ -142,12 +152,15 @@ digest_path_from_path(svn_fs_t *fs,
 /* Write to DIGEST_PATH a representation of CHILDREN (which may be
    empty, if the versioned path in FS represented by DIGEST_PATH has
    no children) and LOCK (which may be NULL if that versioned path is
-   lock itself locked).  Use POOL for all allocations. */
+   lock itself locked).  Set the permissions of DIGEST_PATH to those of
+   PERMS_REFERENCE.  Use POOL for all allocations.
+ */
 static svn_error_t *
 write_digest_file(apr_hash_t *children,
                   svn_lock_t *lock,
-                  svn_fs_t *fs,
+                  const char *fs_path,
                   const char *digest_path,
+                  const char *perms_reference,
                   apr_pool_t *pool)
 {
   svn_error_t *err = SVN_NO_ERROR;
@@ -155,12 +168,11 @@ write_digest_file(apr_hash_t *children,
   apr_hash_index_t *hi;
   apr_hash_t *hash = apr_hash_make(pool);
   const char *tmp_path;
-  const char *rev_0_path;
 
-  SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_join(fs->path, PATH_LOCKS_DIR,
-                                                       pool), fs, pool));
+  SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_join(fs_path, PATH_LOCKS_DIR,
+                                                       pool), fs_path, pool));
   SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_dirname(digest_path, pool),
-                                       fs, pool));
+                                       fs_path, pool));
 
   if (lock)
     {
@@ -212,8 +224,8 @@ write_digest_file(apr_hash_t *children,
 
   SVN_ERR(svn_stream_close(stream));
   SVN_ERR(svn_io_file_rename(tmp_path, digest_path, pool));
-  SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, fs, 0, pool));
-  return svn_io_copy_perms(rev_0_path, digest_path, pool);
+  SVN_ERR(svn_io_copy_perms(perms_reference, digest_path, pool));
+  return SVN_NO_ERROR;
 }
 
 
@@ -224,7 +236,7 @@ write_digest_file(apr_hash_t *children,
 static svn_error_t *
 read_digest_file(apr_hash_t **children_p,
                  svn_lock_t **lock_p,
-                 svn_fs_t *fs,
+                 const char *fs_path,
                  const char *digest_path,
                  apr_pool_t *pool)
 {
@@ -275,17 +287,17 @@ read_digest_file(apr_hash_t **children_p
       lock->path = path;
 
       if (! ((lock->token = hash_fetch(hash, TOKEN_KEY, pool))))
-        return svn_fs_fs__err_corrupt_lockfile(fs, path);
+        return svn_error_return(err_corrupt_lockfile(fs_path, path));
 
       if (! ((lock->owner = hash_fetch(hash, OWNER_KEY, pool))))
-        return svn_fs_fs__err_corrupt_lockfile(fs, path);
+        return svn_error_return(err_corrupt_lockfile(fs_path, path));
 
       if (! ((val = hash_fetch(hash, IS_DAV_COMMENT_KEY, pool))))
-        return svn_fs_fs__err_corrupt_lockfile(fs, path);
+        return svn_error_return(err_corrupt_lockfile(fs_path, path));
       lock->is_dav_comment = (val[0] == '1');
 
       if (! ((val = hash_fetch(hash, CREATION_DATE_KEY, pool))))
-        return svn_fs_fs__err_corrupt_lockfile(fs, path);
+        return svn_error_return(err_corrupt_lockfile(fs_path, path));
       SVN_ERR(svn_time_from_cstring(&(lock->creation_date), val, pool));
 
       if ((val = hash_fetch(hash, EXPIRATION_DATE_KEY, pool)))
@@ -318,10 +330,16 @@ read_digest_file(apr_hash_t **children_p
      schema-supporting paths) ***/
 
 
-/* Write LOCK in FS to the actual OS filesystem. */
+/* Write LOCK in FS to the actual OS filesystem.
+
+   Use PERMS_REFERENCE for the permissions of any digest files.
+   
+   Note: this takes an FS_PATH because it's called from the hotcopy logic.
+ */
 static svn_error_t *
-set_lock(svn_fs_t *fs,
+set_lock(const char *fs_path,
          svn_lock_t *lock,
+         const char *perms_reference,
          apr_pool_t *pool)
 {
   svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool);
@@ -344,10 +362,10 @@ set_lock(svn_fs_t *fs,
 
       /* Calculate the DIGEST_PATH for the currently FS path, and then
          get its DIGEST_FILE basename. */
-      digest_path = digest_path_from_path(fs, this_path->data, subpool);
+      digest_path = digest_path_from_path(fs_path, this_path->data, subpool);
       digest_file = svn_dirent_basename(digest_path, subpool);
 
-      SVN_ERR(read_digest_file(&this_children, &this_lock, fs,
+      SVN_ERR(read_digest_file(&this_children, &this_lock, fs_path,
                                digest_path, subpool));
 
       /* We're either writing a new lock (first time through only) or
@@ -367,8 +385,8 @@ set_lock(svn_fs_t *fs,
           apr_hash_set(this_children, lock_digest_path,
                        APR_HASH_KEY_STRING, (void *)1);
         }
-      SVN_ERR(write_digest_file(this_children, this_lock, fs,
-                                digest_path, subpool));
+      SVN_ERR(write_digest_file(this_children, this_lock, fs_path,
+                                digest_path, perms_reference, subpool));
 
       /* Prep for next iteration, or bail if we're done. */
       if (svn_dirent_is_root(this_path->data, this_path->len))
@@ -406,10 +424,10 @@ delete_lock(svn_fs_t *fs,
 
       /* Calculate the DIGEST_PATH for the currently FS path, and then
          get its DIGEST_FILE basename. */
-      digest_path = digest_path_from_path(fs, this_path->data, subpool);
+      digest_path = digest_path_from_path(fs->path, this_path->data, subpool);
       digest_file = svn_dirent_basename(digest_path, subpool);
 
-      SVN_ERR(read_digest_file(&this_children, &this_lock, fs,
+      SVN_ERR(read_digest_file(&this_children, &this_lock, fs->path,
                                digest_path, subpool));
 
       /* Delete the lock (first time through only). */
@@ -431,8 +449,10 @@ delete_lock(svn_fs_t *fs,
         }
       else
         {
-          SVN_ERR(write_digest_file(this_children, this_lock, fs,
-                                    digest_path, subpool));
+          const char *rev_0_path;
+          SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, fs, 0, pool));
+          SVN_ERR(write_digest_file(this_children, this_lock, fs->path,
+                                    digest_path, rev_0_path, subpool));
         }
 
       /* Prep for next iteration, or bail if we're done. */
@@ -458,9 +478,9 @@ get_lock(svn_lock_t **lock_p,
          apr_pool_t *pool)
 {
   svn_lock_t *lock;
-  const char *digest_path = digest_path_from_path(fs, path, pool);
+  const char *digest_path = digest_path_from_path(fs->path, path, pool);
 
-  SVN_ERR(read_digest_file(NULL, &lock, fs, digest_path, pool));
+  SVN_ERR(read_digest_file(NULL, &lock, fs->path, digest_path, pool));
   if (! lock)
     return SVN_FS__ERR_NO_SUCH_LOCK(fs, path, pool);
 
@@ -513,43 +533,82 @@ get_lock_helper(svn_fs_t *fs,
 }
 
 
-/* A recursive function that calls GET_LOCKS_FUNC/GET_LOCKS_BATON for
-   all locks in and under PATH in FS.
-   HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
-   has the FS write lock. */
+/* Baton for locks_walker(). */
+struct walk_locks_baton {
+  svn_fs_get_locks_callback_t get_locks_func;
+  void *get_locks_baton;
+  svn_fs_t *fs;
+};
+
+/* Implements walk_digests_callback_t. */
 static svn_error_t *
-walk_digest_files(svn_fs_t *fs,
-                  const char *digest_path,
-                  svn_fs_get_locks_callback_t get_locks_func,
-                  void *get_locks_baton,
-                  svn_boolean_t have_write_lock,
-                  apr_pool_t *pool)
+locks_walker(void *baton,
+             const char *fs_path,
+             const char *digest_path,
+             apr_hash_t *children,
+             svn_lock_t *lock,
+             svn_boolean_t have_write_lock,
+             apr_pool_t *pool)
 {
-  apr_hash_t *children;
-  svn_lock_t *lock;
-  apr_hash_index_t *hi;
-  apr_pool_t *subpool;
+  struct walk_locks_baton *wlb = baton;
 
-  /* First, send up any locks in the current digest file. */
-  SVN_ERR(read_digest_file(&children, &lock, fs, digest_path, pool));
   if (lock)
     {
       /* Don't report an expired lock. */
       if (lock->expiration_date == 0
           || (apr_time_now() <= lock->expiration_date))
         {
-          if (get_locks_func)
-            SVN_ERR(get_locks_func(get_locks_baton, lock, pool));
+          if (wlb->get_locks_func)
+            SVN_ERR(wlb->get_locks_func(wlb->get_locks_baton, lock, pool));
         }
       else
         {
           /* Only remove the lock if we have the write lock.
              Read operations shouldn't change the filesystem. */
           if (have_write_lock)
-            SVN_ERR(delete_lock(fs, lock, pool));
+            SVN_ERR(delete_lock(wlb->fs, lock, pool));
         }
     }
 
+  return SVN_NO_ERROR;
+}
+
+/* Callback type for walk_digest_files().
+ * 
+ * CHILDREN and LOCK come from a read_digest_file(digest_path) call.
+ */
+typedef svn_error_t *(*walk_digests_callback_t)(void *baton,
+                                                const char *fs_path,
+                                                const char *digest_path,
+                                                apr_hash_t *children,
+                                                svn_lock_t *lock,
+                                                svn_boolean_t have_write_lock,
+                                                apr_pool_t *pool);
+
+/* A recursive function that calls WALK_DIGESTS_FUNC/WALK_DIGESTS_BATON for
+   all lock digest files in and under PATH in FS.
+   HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
+   has the FS write lock. */
+static svn_error_t *
+walk_digest_files(const char *fs_path,
+                  const char *digest_path,
+                  walk_digests_callback_t walk_digests_func,
+                  void *walk_digests_baton,
+                  svn_boolean_t have_write_lock,
+                  apr_pool_t *pool) 
+{
+  apr_hash_index_t *hi;
+  apr_hash_t *children;
+  apr_pool_t *subpool;
+  svn_lock_t *lock;
+
+  /* First, send up any locks in the current digest file. */
+  SVN_ERR(read_digest_file(&children, &lock, fs_path, digest_path, pool));
+
+  SVN_ERR(walk_digests_func(walk_digests_baton, fs_path, digest_path,
+                            children, lock,
+                            have_write_lock, pool));
+
   /* Now, recurse on this thing's child entries (if any; bail otherwise). */
   if (! apr_hash_count(children))
     return SVN_NO_ERROR;
@@ -559,13 +618,31 @@ walk_digest_files(svn_fs_t *fs,
       const char *digest = svn__apr_hash_index_key(hi);
       svn_pool_clear(subpool);
       SVN_ERR(walk_digest_files
-              (fs, digest_path_from_digest(fs, digest, subpool),
-               get_locks_func, get_locks_baton, have_write_lock, subpool));
+              (fs_path, digest_path_from_digest(fs_path, digest, subpool),
+               walk_digests_func, walk_digests_baton, have_write_lock, subpool));
     }
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
 
+/* A recursive function that calls GET_LOCKS_FUNC/GET_LOCKS_BATON for
+   all locks in and under PATH in FS.
+   HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
+   has the FS write lock. */
+static svn_error_t *
+walk_locks(svn_fs_t *fs,
+           const char *digest_path,
+           svn_fs_get_locks_callback_t get_locks_func,
+           void *get_locks_baton,
+           svn_boolean_t have_write_lock,
+           apr_pool_t *pool)
+{
+  struct walk_locks_baton wlb = { get_locks_func, get_locks_baton, fs };
+  SVN_ERR(walk_digest_files(fs->path, digest_path, locks_walker, &wlb,
+                            have_write_lock, pool));
+  return SVN_NO_ERROR;
+}
+
 
 /* Utility function:  verify that a lock can be used.  Interesting
    errors returned from this function:
@@ -625,9 +702,9 @@ svn_fs_fs__allow_locked_operation(const 
   if (recurse)
     {
       /* Discover all locks at or below the path. */
-      const char *digest_path = digest_path_from_path(fs, path, pool);
-      SVN_ERR(walk_digest_files(fs, digest_path, get_locks_callback,
-                                fs, have_write_lock, pool));
+      const char *digest_path = digest_path_from_path(fs->path, path, pool);
+      SVN_ERR(walk_locks(fs, digest_path, get_locks_callback,
+                         fs, have_write_lock, pool));
     }
   else
     {
@@ -667,6 +744,7 @@ lock_body(void *baton, apr_pool_t *pool)
   svn_lock_t *lock;
   svn_fs_root_t *root;
   svn_revnum_t youngest;
+  const char *rev_0_path;
 
   /* Until we implement directory locks someday, we only allow locks
      on files or non-existent paths. */
@@ -766,7 +844,8 @@ lock_body(void *baton, apr_pool_t *pool)
   lock->is_dav_comment = lb->is_dav_comment;
   lock->creation_date = apr_time_now();
   lock->expiration_date = lb->expiration_date;
-  SVN_ERR(set_lock(lb->fs, lock, pool));
+  SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, lb->fs, 0, pool));
+  SVN_ERR(set_lock(lb->fs->path, lock, rev_0_path, pool));
   *lb->lock_p = lock;
 
   return SVN_NO_ERROR;
@@ -973,7 +1052,8 @@ svn_fs_fs__get_locks(svn_fs_t *fs,
   glfb.get_locks_baton = get_locks_baton;
 
   /* Get the top digest path in our tree of interest, and then walk it. */
-  digest_path = digest_path_from_path(fs, path, pool);
-  return walk_digest_files(fs, digest_path, get_locks_filter_func, &glfb,
-                           FALSE, pool);
+  digest_path = digest_path_from_path(fs->path, path, pool);
+  SVN_ERR(walk_locks(fs, digest_path, get_locks_filter_func, &glfb,
+                     FALSE, pool));
+  return SVN_NO_ERROR;
 }

Modified: subversion/branches/performance/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_fs_fs/tree.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/performance/subversion/libsvn_fs_fs/tree.c Wed Nov 17 00:09:50 2010
@@ -51,7 +51,6 @@
 #include "svn_props.h"
 
 #include "fs.h"
-#include "err.h"
 #include "key-gen.h"
 #include "dag.h"
 #include "lock.h"

Modified: subversion/branches/performance/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_repos/load-fs-vtable.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/performance/subversion/libsvn_repos/load-fs-vtable.c Wed Nov 17 00:09:50 2010
@@ -626,7 +626,10 @@ set_node_property(void *baton,
 
   if (strcmp(name, SVN_PROP_MERGEINFO) == 0)
     {
-      svn_string_t *renumbered_mergeinfo, *prop_val = (svn_string_t *)value;
+      svn_string_t *renumbered_mergeinfo;
+      /* ### Need to cast away const. We cannot change the declaration of
+       * ### this function since it is part of svn_repos_parse_fns2_t. */
+      svn_string_t *prop_val = (svn_string_t *)value;
 
       /* Tolerate mergeinfo with "\r\n" line endings because some
          dumpstream sources might contain as much.  If so normalize