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 2017/08/24 08:42:42 UTC

svn commit: r1806008 [2/4] - in /subversion/branches/shelve-checkpoint3: ./ build/ build/ac-macros/ build/generator/ notes/ notes/api-errata/1.10/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_delta/ subver...

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_client/import.c Thu Aug 24 08:42:40 2017
@@ -73,32 +73,59 @@ typedef struct import_ctx_t
   apr_hash_t *autoprops;
 } import_ctx_t;
 
+typedef struct open_txdelta_stream_baton_t
+{
+  svn_boolean_t need_reset;
+  svn_stream_t *stream;
+} open_txdelta_stream_baton_t;
+
+/* Implements svn_txdelta_stream_open_func_t */
+static svn_error_t *
+open_txdelta_stream(svn_txdelta_stream_t **txdelta_stream_p,
+                    void *baton,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  open_txdelta_stream_baton_t *b = baton;
+
+  if (b->need_reset)
+    {
+      /* Under rare circumstances, we can be restarted and would need to
+       * supply the delta stream again.  In this case, reset the base
+       * stream. */
+      SVN_ERR(svn_stream_reset(b->stream));
+    }
+
+  /* Get the delta stream (delta against the empty string). */
+  svn_txdelta2(txdelta_stream_p, svn_stream_empty(result_pool),
+               b->stream, FALSE, result_pool);
+  b->need_reset = TRUE;
+  return SVN_NO_ERROR;
+}
 
 /* Apply LOCAL_ABSPATH's contents (as a delta against the empty string) to
    FILE_BATON in EDITOR.  Use POOL for any temporary allocation.
    PROPERTIES is the set of node properties set on this file.
 
-   Fill DIGEST with the md5 checksum of the sent file; DIGEST must be
-   at least APR_MD5_DIGESTSIZE bytes long. */
+   Return the resulting checksum in *RESULT_MD5_CHECKSUM_P. */
 
 /* ### how does this compare against svn_wc_transmit_text_deltas2() ??? */
 
 static svn_error_t *
-send_file_contents(const char *local_abspath,
+send_file_contents(svn_checksum_t **result_md5_checksum_p,
+                   const char *local_abspath,
                    void *file_baton,
                    const svn_delta_editor_t *editor,
                    apr_hash_t *properties,
-                   unsigned char *digest,
                    apr_pool_t *pool)
 {
   svn_stream_t *contents;
-  svn_txdelta_window_handler_t handler;
-  void *handler_baton;
   const svn_string_t *eol_style_val = NULL, *keywords_val = NULL;
   svn_boolean_t special = FALSE;
   svn_subst_eol_style_t eol_style;
   const char *eol;
   apr_hash_t *keywords;
+  open_txdelta_stream_baton_t baton = { 0 };
 
   /* If there are properties, look for EOL-style and keywords ones. */
   if (properties)
@@ -111,10 +138,6 @@ send_file_contents(const char *local_abs
         special = TRUE;
     }
 
-  /* Get an editor func that wants to consume the delta stream. */
-  SVN_ERR(editor->apply_textdelta(file_baton, NULL, pool,
-                                  &handler, &handler_baton));
-
   if (eol_style_val)
     svn_subst_eol_style_from_value(&eol_style, &eol, eol_style_val->data);
   else
@@ -168,10 +191,17 @@ send_file_contents(const char *local_abs
         }
     }
 
-  /* Send the file's contents to the delta-window handler. */
-  return svn_error_trace(svn_txdelta_send_stream(contents, handler,
-                                                 handler_baton, digest,
-                                                 pool));
+  /* Arrange the stream to calculate the resulting MD5. */
+  contents = svn_stream_checksummed2(contents, result_md5_checksum_p, NULL,
+                                     svn_checksum_md5, TRUE, pool);
+  /* Send the contents. */
+  baton.need_reset = FALSE;
+  baton.stream = svn_stream_disown(contents, pool);
+  SVN_ERR(editor->apply_textdelta_stream(editor, file_baton, NULL,
+                                         open_txdelta_stream, &baton, pool));
+  SVN_ERR(svn_stream_close(contents));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -198,7 +228,7 @@ import_file(const svn_delta_editor_t *ed
 {
   void *file_baton;
   const char *mimetype = NULL;
-  unsigned char digest[APR_MD5_DIGESTSIZE];
+  svn_checksum_t *result_md5_checksum;
   const char *text_checksum;
   apr_hash_t* properties;
   apr_hash_index_t *hi;
@@ -262,13 +292,11 @@ import_file(const svn_delta_editor_t *ed
     }
 
   /* Now, transmit the file contents. */
-  SVN_ERR(send_file_contents(local_abspath, file_baton, editor,
-                             properties, digest, pool));
+  SVN_ERR(send_file_contents(&result_md5_checksum, local_abspath,
+                             file_baton, editor, properties, pool));
 
   /* Finally, close the file. */
-  text_checksum =
-    svn_checksum_to_cstring(svn_checksum__from_digest_md5(digest, pool), pool);
-
+  text_checksum = svn_checksum_to_cstring(result_md5_checksum, pool);
   return svn_error_trace(editor->close_file(file_baton, text_checksum, pool));
 }
 
@@ -577,26 +605,26 @@ import_dir(const svn_delta_editor_t *edi
 }
 
 
-/* Recursively import PATH to a repository using EDITOR and
- * EDIT_BATON.  PATH can be a file or directory.
+/* Recursively import LOCAL_ABSPATH to a repository using EDITOR and
+ * EDIT_BATON.  LOCAL_ABSPATH can be a file or directory.
  *
  * Sets *UPDATED_REPOSITORY to TRUE when the repository was modified by
  * a successfull commit, otherwise to FALSE.
  *
- * DEPTH is the depth at which to import PATH; it behaves as for
- * svn_client_import4().
+ * DEPTH is the depth at which to import LOCAL_ABSPATH; it behaves as for
+ * svn_client_import5().
  *
  * BASE_REV is the revision to use for the root of the commit. We
  * checked the preconditions against this revision.
  *
  * NEW_ENTRIES is an ordered array of path components that must be
  * created in the repository (where the ordering direction is
- * parent-to-child).  If PATH is a directory, NEW_ENTRIES may be empty
+ * parent-to-child).  If LOCAL_ABSPATH is a directory, NEW_ENTRIES may be empty
  * -- the result is an import which creates as many new entries in the
  * top repository target directory as there are importable entries in
- * the top of PATH; but if NEW_ENTRIES is not empty, its last item is
+ * the top of LOCAL_ABSPATH; but if NEW_ENTRIES is not empty, its last item is
  * the name of a new subdirectory in the repository to hold the
- * import.  If PATH is a file, NEW_ENTRIES may not be empty, and its
+ * import.  If LOCAL_ABSPATH is a file, NEW_ENTRIES may not be empty, and its
  * last item is the name used for the file in the repository.  If
  * NEW_ENTRIES contains more than one item, all but the last item are
  * the names of intermediate directories that are created before the
@@ -624,6 +652,8 @@ import_dir(const svn_delta_editor_t *edi
  * If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for
  * each imported path, passing actions svn_wc_notify_commit_added.
  *
+ * URL is used only in the 'commit_finalizing' notification.
+ *
  * Use POOL for any temporary allocation.
  *
  * Note: the repository directory receiving the import was specified

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_client/merge.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_client/merge.c Thu Aug 24 08:42:40 2017
@@ -2240,13 +2240,9 @@ merge_file_added(const char *relpath,
          Otherwise, we'll use a pure add. */
       if (merge_b->same_repos)
         {
-          const char *child =
-            svn_dirent_skip_ancestor(merge_b->target->abspath,
-                                     local_abspath);
-          SVN_ERR_ASSERT(child != NULL);
           copyfrom_url = svn_path_url_add_component2(
                                        merge_b->merge_source.loc2->url,
-                                       child, scratch_pool);
+                                       relpath, scratch_pool);
           copyfrom_rev = right_source->revision;
           SVN_ERR(check_repos_match(merge_b->target, local_abspath,
                                     copyfrom_url, scratch_pool));

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/cancel.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/cancel.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/cancel.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/cancel.c Thu Aug 24 08:42:40 2017
@@ -222,6 +222,26 @@ apply_textdelta(void *file_baton,
 }
 
 static svn_error_t *
+apply_textdelta_stream(const svn_delta_editor_t *editor,
+                       void *file_baton,
+                       const char *base_checksum,
+                       svn_txdelta_stream_open_func_t open_func,
+                       void *open_baton,
+                       apr_pool_t *scratch_pool)
+{
+  struct file_baton *fb = file_baton;
+  struct edit_baton *eb = fb->edit_baton;
+
+  SVN_ERR(eb->cancel_func(eb->cancel_baton));
+
+  return eb->wrapped_editor->apply_textdelta_stream(eb->wrapped_editor,
+                                                    fb->wrapped_file_baton,
+                                                    base_checksum,
+                                                    open_func, open_baton,
+                                                    scratch_pool);
+}
+
+static svn_error_t *
 close_file(void *file_baton,
            const char *text_checksum,
            apr_pool_t *pool)
@@ -354,6 +374,7 @@ svn_delta_get_cancellation_editor(svn_ca
       tree_editor->add_file = add_file;
       tree_editor->open_file = open_file;
       tree_editor->apply_textdelta = apply_textdelta;
+      tree_editor->apply_textdelta_stream = apply_textdelta_stream;
       tree_editor->change_file_prop = change_file_prop;
       tree_editor->close_file = close_file;
       tree_editor->absent_file = absent_file;

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/default_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/default_editor.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/default_editor.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/default_editor.c Thu Aug 24 08:42:40 2017
@@ -133,6 +133,33 @@ close_file(void *file_baton,
 }
 
 
+static svn_error_t *
+apply_textdelta_stream(const svn_delta_editor_t *editor,
+                       void *file_baton,
+                       const char *base_checksum,
+                       svn_txdelta_stream_open_func_t open_func,
+                       void *open_baton,
+                       apr_pool_t *scratch_pool)
+{
+  svn_txdelta_window_handler_t handler;
+  void *handler_baton;
+
+  SVN_ERR(editor->apply_textdelta(file_baton, base_checksum,
+                                  scratch_pool, &handler,
+                                  &handler_baton));
+  if (handler != svn_delta_noop_window_handler)
+    {
+      svn_txdelta_stream_t *txdelta_stream;
+
+      SVN_ERR(open_func(&txdelta_stream, open_baton, scratch_pool,
+                        scratch_pool));
+      SVN_ERR(svn_txdelta_send_txstream(txdelta_stream, handler,
+                                        handler_baton, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 static const svn_delta_editor_t default_editor =
 {
@@ -151,7 +178,8 @@ static const svn_delta_editor_t default_
   close_file,
   absent_xxx_func,
   single_baton_func,
-  single_baton_func
+  single_baton_func,
+  apply_textdelta_stream
 };
 
 svn_delta_editor_t *

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/svndiff.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/svndiff.c Thu Aug 24 08:42:40 2017
@@ -245,6 +245,8 @@ encode_window(svn_stringbuf_t **instruct
   return SVN_NO_ERROR;
 }
 
+/* Note: When changing things here, check the related comment in
+   the svn_txdelta_to_svndiff_stream() function.  */
 static svn_error_t *
 window_handler(svn_txdelta_window_t *window, void *baton)
 {
@@ -993,3 +995,104 @@ svn_txdelta__read_raw_window_len(apr_siz
   return SVN_NO_ERROR;
 }
 
+typedef struct svndiff_stream_baton_t
+{
+  apr_pool_t *scratch_pool;
+  svn_txdelta_stream_t *txstream;
+  svn_txdelta_window_handler_t handler;
+  void *handler_baton;
+  svn_stringbuf_t *window_buffer;
+  apr_size_t read_pos;
+  svn_boolean_t hit_eof;
+} svndiff_stream_baton_t;
+
+static svn_error_t *
+svndiff_stream_write_fn(void *baton, const char *data, apr_size_t *len)
+{
+  svndiff_stream_baton_t *b = baton;
+
+  /* The memory usage here is limited, as this buffer doesn't grow
+     beyond the (header size + max window size in svndiff format).
+     See the comment in svn_txdelta_to_svndiff_stream().  */
+  svn_stringbuf_appendbytes(b->window_buffer, data, *len);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+svndiff_stream_read_fn(void *baton, char *buffer, apr_size_t *len)
+{
+  svndiff_stream_baton_t *b = baton;
+  apr_size_t left = *len;
+  apr_size_t read = 0;
+
+  while (left && !b->hit_eof)
+    {
+      apr_size_t chunk_size;
+
+      if (b->read_pos == b->window_buffer->len)
+        {
+          svn_txdelta_window_t *window;
+
+          svn_pool_clear(b->scratch_pool);
+          svn_stringbuf_setempty(b->window_buffer);
+          SVN_ERR(svn_txdelta_next_window(&window, b->txstream,
+                                          b->scratch_pool));
+          SVN_ERR(b->handler(window, b->handler_baton));
+          b->read_pos = 0;
+
+          if (!window)
+            b->hit_eof = TRUE;
+        }
+
+      if (left > b->window_buffer->len - b->read_pos)
+        chunk_size = b->window_buffer->len - b->read_pos;
+      else
+        chunk_size = left;
+
+      memcpy(buffer, b->window_buffer->data + b->read_pos, chunk_size);
+      b->read_pos += chunk_size;
+      buffer += chunk_size;
+      read += chunk_size;
+      left -= chunk_size;
+    }
+
+  *len = read;
+  return SVN_NO_ERROR;
+}
+
+svn_stream_t *
+svn_txdelta_to_svndiff_stream(svn_txdelta_stream_t *txstream,
+                              int svndiff_version,
+                              int compression_level,
+                              apr_pool_t *pool)
+{
+  svndiff_stream_baton_t *baton;
+  svn_stream_t *push_stream;
+  svn_stream_t *pull_stream;
+
+  baton = apr_pcalloc(pool, sizeof(*baton));
+  baton->scratch_pool = svn_pool_create(pool);
+  baton->txstream = txstream;
+  baton->window_buffer = svn_stringbuf_create_empty(pool);
+  baton->hit_eof = FALSE;
+  baton->read_pos = 0;
+
+  push_stream = svn_stream_create(baton, pool);
+  svn_stream_set_write(push_stream, svndiff_stream_write_fn);
+
+  /* We rely on the implementation detail of the svn_txdelta_to_svndiff3()
+     function, namely, on how the window_handler() function behaves.
+     As long as it writes one svndiff window at a time to the target
+     stream, the memory usage of this function (in other words, how
+     much data can be accumulated in the internal 'window_buffer')
+     is limited.  */
+  svn_txdelta_to_svndiff3(&baton->handler, &baton->handler_baton,
+                          push_stream, svndiff_version,
+                          compression_level, pool);
+
+  pull_stream = svn_stream_create(baton, pool);
+  svn_stream_set_read2(pull_stream, NULL, svndiff_stream_read_fn);
+
+  return pull_stream;
+}

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/text_delta.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_delta/text_delta.c Thu Aug 24 08:42:40 2017
@@ -102,7 +102,7 @@ struct apply_baton {
   char *tbuf;                   /* Target buffer */
   apr_size_t tbuf_size;         /* Allocated target buffer space */
 
-  apr_md5_ctx_t md5_context;    /* Leads to result_digest below. */
+  svn_checksum_ctx_t *md5_context; /* Leads to result_digest below. */
   unsigned char *result_digest; /* MD5 digest of resultant fulltext;
                                    must point to at least APR_MD5_DIGESTSIZE
                                    bytes of storage. */
@@ -720,15 +720,23 @@ apply_window(svn_txdelta_window_t *windo
 {
   struct apply_baton *ab = (struct apply_baton *) baton;
   apr_size_t len;
-  svn_error_t *err;
 
   if (window == NULL)
     {
+      svn_error_t *err = SVN_NO_ERROR;
+
       /* We're done; just clean up.  */
       if (ab->result_digest)
-        apr_md5_final(ab->result_digest, &(ab->md5_context));
+        {
+          svn_checksum_t *md5_checksum;
+
+          err = svn_checksum_final(&md5_checksum, ab->md5_context, ab->pool);
+          if (!err)
+            memcpy(ab->result_digest, md5_checksum->digest,
+                   svn_checksum_size(md5_checksum));
+        }
 
-      err = svn_stream_close(ab->target);
+      err = svn_error_compose_create(err, svn_stream_close(ab->target));
       svn_pool_destroy(ab->pool);
 
       return err;
@@ -772,12 +780,10 @@ apply_window(svn_txdelta_window_t *windo
   if (ab->sbuf_len < window->sview_len)
     {
       len = window->sview_len - ab->sbuf_len;
-      err = svn_stream_read_full(ab->source, ab->sbuf + ab->sbuf_len, &len);
-      if (err == SVN_NO_ERROR && len != window->sview_len - ab->sbuf_len)
-        err = svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
-                               "Delta source ended unexpectedly");
-      if (err != SVN_NO_ERROR)
-        return err;
+      SVN_ERR(svn_stream_read_full(ab->source, ab->sbuf + ab->sbuf_len, &len));
+      if (len != window->sview_len - ab->sbuf_len)
+        return svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
+                                "Delta source ended unexpectedly");
       ab->sbuf_len = window->sview_len;
     }
 
@@ -791,7 +797,7 @@ apply_window(svn_txdelta_window_t *windo
 
   /* Just update the context here. */
   if (ab->result_digest)
-    apr_md5_update(&(ab->md5_context), ab->tbuf, len);
+    SVN_ERR(svn_checksum_update(ab->md5_context, ab->tbuf, len));
 
   return svn_stream_write(ab->target, ab->tbuf, &len);
 }
@@ -822,7 +828,7 @@ svn_txdelta_apply(svn_stream_t *source,
   ab->result_digest = result_digest;
 
   if (result_digest)
-    apr_md5_init(&(ab->md5_context));
+    ab->md5_context = svn_checksum_ctx_create(svn_checksum_md5, subpool);
 
   if (error_info)
     ab->error_info = apr_pstrdup(subpool, error_info);

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_base/fs.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_base/fs.c Thu Aug 24 08:42:40 2017
@@ -957,6 +957,7 @@ base_upgrade(svn_fs_t *fs,
       err = SVN_NO_ERROR;
     }
   SVN_ERR(err);
+  SVN_ERR(check_format(old_format_number));
 
   /* Bump the format file's stored version number. */
   SVN_ERR(svn_io_write_version_file(version_file_path,

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/fs.h?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/fs.h Thu Aug 24 08:42:40 2017
@@ -118,6 +118,7 @@ extern "C" {
 #define CONFIG_SECTION_DEBUG             "debug"
 #define CONFIG_OPTION_PACK_AFTER_COMMIT  "pack-after-commit"
 #define CONFIG_OPTION_VERIFY_BEFORE_COMMIT "verify-before-commit"
+#define CONFIG_OPTION_COMPRESSION        "compression"
 
 /* The format number of this filesystem.
    This is independent of the repository format number, and
@@ -162,6 +163,9 @@ extern "C" {
  * issues with very old servers, restrict those options to the 1.6+ format*/
 #define SVN_FS_FS__MIN_DELTIFICATION_FORMAT 4
 
+/* The minimum format number that supports a configuration file (fsfs.conf) */
+#define SVN_FS_FS__MIN_CONFIG_FILE 4
+
 /* The 1.7-dev format, never released, that packed revprops into SQLite
    revprops.db . */
 #define SVN_FS_FS__PACKED_REVPROP_SQLITE_DEV_FORMAT 5
@@ -184,9 +188,6 @@ extern "C" {
 /* The minimum format number that supports svndiff version 2. */
 #define SVN_FS_FS__MIN_SVNDIFF2_FORMAT 8
 
-/* The minimum format number that supports a configuration file (fsfs.conf) */
-#define SVN_FS_FS__MIN_CONFIG_FILE 4
-
 /* On most operating systems apr implements file locks per process, not
    per file.  On Windows apr implements the locking as per file handle
    locks, so we don't have to add our own mutex for just in-process
@@ -298,6 +299,13 @@ typedef struct window_cache_key_t
   apr_uint64_t item_index;
 } window_cache_key_t;
 
+typedef enum compression_type_t
+{
+  compression_type_none,
+  compression_type_zlib,
+  compression_type_lz4
+} compression_type_t;
+
 /* 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
@@ -473,7 +481,10 @@ typedef struct fs_fs_data_t
    * deltification history after which skip deltas will be used. */
   apr_int64_t max_linear_deltification;
 
-  /* Compression level to use with txdelta storage format in new revs. */
+  /* Compression type to use with txdelta storage format in new revs. */
+  compression_type_t delta_compression_type;
+
+  /* Compression level (currently, only used with compression_type_zlib). */
   int delta_compression_level;
 
   /* Pack after every commit. */

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/fs_fs.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/fs_fs.c Thu Aug 24 08:42:40 2017
@@ -683,6 +683,60 @@ verify_block_size(apr_int64_t block_size
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+parse_compression_option(compression_type_t *compression_type_p,
+                         int *compression_level_p,
+                         const char *value)
+{
+  compression_type_t type;
+  int level;
+  svn_boolean_t is_valid = TRUE;
+
+  /* compression = none | lz4 | zlib | zlib-1 ... zlib-9 */
+  if (strcmp(value, "none") == 0)
+    {
+      type = compression_type_none;
+      level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
+    }
+  else if (strcmp(value, "lz4") == 0)
+    {
+      type = compression_type_lz4;
+      level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
+    }
+  else if (strncmp(value, "zlib", 4) == 0)
+    {
+      const char *p = value + 4;
+
+      type = compression_type_zlib;
+      if (*p == 0)
+        {
+          level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
+        }
+      else if (*p == '-')
+        {
+          p++;
+          SVN_ERR(svn_cstring_atoi(&level, p));
+          if (level < 1 || level > 9)
+            is_valid = FALSE;
+        }
+      else
+        is_valid = FALSE;
+    }
+  else
+    {
+      is_valid = FALSE;
+    }
+
+  if (!is_valid)
+    return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+                           _("Invalid 'compression' value '%s' in the config"),
+                             value);
+
+  *compression_type_p = type;
+  *compression_level_p = level;
+  return SVN_NO_ERROR;
+}
+
 /* Read the configuration information of the file system at FS_PATH
  * and set the respective values in FFD.  Use pools as usual.
  */
@@ -709,8 +763,6 @@ read_config(fs_fs_data_t *ffd,
   /* Initialize deltification settings in ffd. */
   if (ffd->format >= SVN_FS_FS__MIN_DELTIFICATION_FORMAT)
     {
-      apr_int64_t compression_level;
-
       SVN_ERR(svn_config_get_bool(config, &ffd->deltify_directories,
                                   CONFIG_SECTION_DELTIFICATION,
                                   CONFIG_OPTION_ENABLE_DIR_DELTIFICATION,
@@ -727,14 +779,6 @@ read_config(fs_fs_data_t *ffd,
                                    CONFIG_SECTION_DELTIFICATION,
                                    CONFIG_OPTION_MAX_LINEAR_DELTIFICATION,
                                    SVN_FS_FS_MAX_LINEAR_DELTIFICATION));
-
-      SVN_ERR(svn_config_get_int64(config, &compression_level,
-                                   CONFIG_SECTION_DELTIFICATION,
-                                   CONFIG_OPTION_COMPRESSION_LEVEL,
-                                   SVN_DELTA_COMPRESSION_LEVEL_DEFAULT));
-      ffd->delta_compression_level
-        = (int)MIN(MAX(SVN_DELTA_COMPRESSION_LEVEL_NONE, compression_level),
-                   SVN_DELTA_COMPRESSION_LEVEL_MAX);
     }
   else
     {
@@ -742,7 +786,6 @@ read_config(fs_fs_data_t *ffd,
       ffd->deltify_properties = FALSE;
       ffd->max_deltification_walk = SVN_FS_FS_MAX_DELTIFICATION_WALK;
       ffd->max_linear_deltification = SVN_FS_FS_MAX_LINEAR_DELTIFICATION;
-      ffd->delta_compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
     }
 
   /* Initialize revprop packing settings in ffd. */
@@ -816,6 +859,72 @@ read_config(fs_fs_data_t *ffd,
     {
       ffd->pack_after_commit = FALSE;
     }
+
+  /* Initialize compression settings in ffd. */
+  if (ffd->format >= SVN_FS_FS__MIN_DELTIFICATION_FORMAT)
+    {
+      const char *compression_val;
+      const char *compression_level_val;
+
+      svn_config_get(config, &compression_val,
+                     CONFIG_SECTION_DELTIFICATION,
+                     CONFIG_OPTION_COMPRESSION, NULL);
+      svn_config_get(config, &compression_level_val,
+                     CONFIG_SECTION_DELTIFICATION,
+                     CONFIG_OPTION_COMPRESSION_LEVEL, NULL);
+      if (compression_val && compression_level_val)
+        {
+          return svn_error_create(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+                                  _("The 'compression' and 'compression-level' "
+                                    "config options are mutually exclusive"));
+        }
+      else if (compression_val)
+        {
+          SVN_ERR(parse_compression_option(&ffd->delta_compression_type,
+                                           &ffd->delta_compression_level,
+                                           compression_val));
+          if (ffd->delta_compression_type == compression_type_lz4 &&
+              ffd->format < SVN_FS_FS__MIN_SVNDIFF2_FORMAT)
+            {
+              return svn_error_create(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+                                      _("Compression type 'lz4' requires "
+                                        "filesystem format 8 or higher"));
+            }
+        }
+      else if (compression_level_val)
+        {
+          /* Handle the deprecated 'compression-level' option. */
+          ffd->delta_compression_type = compression_type_zlib;
+          SVN_ERR(svn_cstring_atoi(&ffd->delta_compression_level,
+                                   compression_level_val));
+          ffd->delta_compression_level =
+            MIN(MAX(SVN_DELTA_COMPRESSION_LEVEL_NONE,
+                    ffd->delta_compression_level),
+                SVN_DELTA_COMPRESSION_LEVEL_MAX);
+        }
+      else
+        {
+          /* Nothing specified explicitly, use the default settings:
+           * LZ4 compression for formats supporting it and zlib otherwise. */
+          if (ffd->format >= SVN_FS_FS__MIN_SVNDIFF2_FORMAT)
+            ffd->delta_compression_type = compression_type_lz4;
+          else
+            ffd->delta_compression_type = compression_type_zlib;
+
+          ffd->delta_compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
+        }
+    }
+  else if (ffd->format >= SVN_FS_FS__MIN_SVNDIFF1_FORMAT)
+    {
+      ffd->delta_compression_type = compression_type_zlib;
+      ffd->delta_compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
+    }
+  else
+    {
+      ffd->delta_compression_type = compression_type_none;
+      ffd->delta_compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
+    }
+
 #ifdef SVN_DEBUG
   SVN_ERR(svn_config_get_bool(config, &ffd->verify_before_commit,
                               CONFIG_SECTION_DEBUG,
@@ -947,23 +1056,29 @@ write_config(svn_fs_t *fs,
 "# " CONFIG_OPTION_MAX_LINEAR_DELTIFICATION " = 16"                          NL
 "###"                                                                        NL
 "### After deltification, we compress the data to minimize on-disk size."    NL
-"### This settings control the compression level for this process."          NL
-"### Revisions with highly compressible data in them may shrink in size"     NL
-"### if the setting is increased but may take much longer to commit."        NL
-"### The time taken to uncompress that data again is widely independent"     NL
-"### of the compression level.  Compression will be ineffective if the"      NL
-"### incoming content is already highly compressed.  In that case,"          NL
-"### disabling the compression entirely or using the special value 1"        NL
-"### (see below) will speed up commits as well as reading the data."         NL
-"### Repositories with many small compressible files (source code) but"      NL
-"### also a high percentage of large incompressible ones (artwork) may"      NL
-"### benefit from compression levels lowered."                               NL
-"### Valid values are 0 to 9 with 9 providing the highest compression"       NL
-"### ratio and 0 disabling it altogether.  Using 1 as the level enables"     NL
-"### LZ4 compression that provides a decent compression ratio, but"          NL
-"### performs better with large or incompressible files."                    NL
-"### The default value is 5."                                                NL
-"# " CONFIG_OPTION_COMPRESSION_LEVEL " = 5"                                  NL
+"### This setting controls the compression algorithm, which will be used in" NL
+"### future revisions.  It can be used to either disable compression or to"  NL
+"### select between available algorithms (zlib, lz4).  zlib is a general-"   NL
+"### purpose compression algorithm.  lz4 is a fast compression algorithm"    NL
+"### which should be preferred for repositories with large and, possibly,"   NL
+"### incompressible files.  Note that the compression ratio of lz4 is"       NL
+"### usually lower than the one provided by zlib, but using it can"          NL
+"### significantly speed up commits as well as reading the data."            NL
+"### lz4 compression algorithm is supported, starting from format 8"         NL
+"### repositories, available in Subversion 1.10 and higher."                 NL
+"### The syntax of this option is:"                                          NL
+"###   " CONFIG_OPTION_COMPRESSION " = none | lz4 | zlib | zlib-1 ... zlib-9" NL
+"### Versions prior to Subversion 1.10 will ignore this option."             NL
+"### The default value is 'lz4' if supported by the repository format and"   NL
+"### 'zlib' otherwise.  'zlib' is currently equivalent to 'zlib-5'."         NL
+"# " CONFIG_OPTION_COMPRESSION " = lz4"                                      NL
+"###"                                                                        NL
+"### DEPRECATED: The new '" CONFIG_OPTION_COMPRESSION "' option deprecates previously used" NL
+"### '" CONFIG_OPTION_COMPRESSION_LEVEL "' option, which was used to configure zlib compression." NL
+"### For compatibility with previous versions of Subversion, this option can"NL
+"### still be used (and it will result in zlib compression with the"         NL
+"### corresponding compression level)."                                      NL
+"###   " CONFIG_OPTION_COMPRESSION_LEVEL " = 0 ... 9 (default is 5)"         NL
 ""                                                                           NL
 "[" CONFIG_SECTION_PACKED_REVPROPS "]"                                       NL
 "### This parameter controls the size (in kBytes) of packed revprop files."  NL

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/transaction.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_fs_fs/transaction.c Thu Aug 24 08:42:40 2017
@@ -2168,27 +2168,24 @@ txdelta_to_svndiff(svn_txdelta_window_ha
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   int svndiff_version;
-  int svndiff_compression_level;
 
-  if (ffd->delta_compression_level == 1 &&
-      ffd->format >= SVN_FS_FS__MIN_SVNDIFF2_FORMAT)
+  if (ffd->delta_compression_type == compression_type_lz4)
     {
+      SVN_ERR_ASSERT_NO_RETURN(ffd->format >= SVN_FS_FS__MIN_SVNDIFF2_FORMAT);
       svndiff_version = 2;
-      svndiff_compression_level = 0;
     }
-  else if (ffd->format >= SVN_FS_FS__MIN_SVNDIFF1_FORMAT)
+  else if (ffd->delta_compression_type == compression_type_zlib)
     {
+      SVN_ERR_ASSERT_NO_RETURN(ffd->format >= SVN_FS_FS__MIN_SVNDIFF1_FORMAT);
       svndiff_version = 1;
-      svndiff_compression_level = ffd->delta_compression_level;
     }
   else
     {
       svndiff_version = 0;
-      svndiff_compression_level = 0;
     }
 
   svn_txdelta_to_svndiff3(handler, handler_baton, output, svndiff_version,
-                          svndiff_compression_level, pool);
+                          ffd->delta_compression_level, pool);
 }
 
 /* Get a rep_write_baton and store it in *WB_P for the representation

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/blame.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/blame.c Thu Aug 24 08:42:40 2017
@@ -81,7 +81,7 @@ typedef struct blame_context_t {
 
   svn_stream_t *stream;
 
-  svn_boolean_t using_compression;
+  svn_ra_serf__session_t *session;
 
 } blame_context_t;
 
@@ -329,8 +329,7 @@ setup_headers(serf_bucket_t *headers,
 {
   blame_context_t *blame_ctx = baton;
 
-  svn_ra_serf__setup_svndiff_accept_encoding(headers,
-                                             blame_ctx->using_compression);
+  svn_ra_serf__setup_svndiff_accept_encoding(headers, blame_ctx->session);
 
   return SVN_NO_ERROR;
 }
@@ -360,7 +359,7 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   blame_ctx->start = start;
   blame_ctx->end = end;
   blame_ctx->include_merged_revisions = include_merged_revisions;
-  blame_ctx->using_compression = session->using_compression;
+  blame_ctx->session = session;
 
   /* Since Subversion 1.8 we allow retrieving blames backwards. So we can't
      just unconditionally use end_rev as the peg revision as before */

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/commit.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/commit.c Thu Aug 24 08:42:40 2017
@@ -176,12 +176,18 @@ typedef struct file_context_t {
   /* Buffer holding the svndiff (can spill to disk). */
   svn_ra_serf__request_body_t *svndiff;
 
+  /* Did we send the svndiff in apply_textdelta_stream()? */
+  svn_boolean_t svndiff_sent;
+
   /* Our base checksum as reported by the WC. */
   const char *base_checksum;
 
   /* Our resulting checksum as reported by the WC. */
   const char *result_checksum;
 
+  /* Our resulting checksum as reported by the server. */
+  svn_checksum_t *remote_result_checksum;
+
   /* Changed properties (const char * -> svn_prop_t *) */
   apr_hash_t *prop_changes;
 
@@ -1859,61 +1865,50 @@ open_file(const char *path,
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-apply_textdelta(void *file_baton,
-                const char *base_checksum,
-                apr_pool_t *pool,
-                svn_txdelta_window_handler_t *handler,
-                void **handler_baton)
+static void
+negotiate_put_encoding(int *svndiff_version_p,
+                       int *svndiff_compression_level_p,
+                       svn_ra_serf__session_t *session)
 {
-  file_context_t *ctx = file_baton;
   int svndiff_version;
   int compression_level;
 
-  /* Construct a holder for the request body; we'll give it to serf when we
-   * close this file.
-   *
-   * TODO: There should be a way we can stream the request body instead of
-   * possibly writing to a temporary file (ugh). A special svn stream serf
-   * bucket that returns EAGAIN until we receive the done call?  But, when
-   * would we run through the serf context?  Grr.
-   *
-   * BH: If you wait to a specific event... why not use that event to
-   *     trigger the operation?
-   *     Having a request (body) bucket return EAGAIN until done stalls
-   *     the entire HTTP pipeline after writing the first part of the
-   *     request. It is not like we can interrupt some part of a request
-   *     and continue later. Or somebody else must use tempfiles and
-   *     always assume that clients work this bad... as it only knows
-   *     for sure after the request is completely available.
-   */
-
-  ctx->svndiff =
-    svn_ra_serf__request_body_create(SVN_RA_SERF__REQUEST_BODY_IN_MEM_SIZE,
-                                     ctx->pool);
-  ctx->stream = svn_ra_serf__request_body_get_stream(ctx->svndiff);
-
-  if (ctx->commit_ctx->session->supports_svndiff1 &&
-      ctx->commit_ctx->session->using_compression)
+  if (session->using_compression == svn_tristate_unknown)
     {
-      /* Prefer svndiff1 when using http compression, as svndiff2 is not a
+      /* With http-compression=auto, prefer svndiff2 to svndiff1 with a
+       * low latency connection (assuming the underlying network has high
+       * bandwidth), as it is faster and in this case, we don't care about
+       * worse compression ratio.
+       *
+       * Note: For future compatibility, we also handle a theoretically
+       * possible case where the server has advertised only svndiff2 support.
+       */
+      if (session->supports_svndiff2 &&
+          svn_ra_serf__is_low_latency_connection(session))
+        svndiff_version = 2;
+      else if (session->supports_svndiff1)
+        svndiff_version = 1;
+      else if (session->supports_svndiff2)
+        svndiff_version = 2;
+      else
+        svndiff_version = 0;
+    }
+  else if (session->using_compression == svn_tristate_true)
+    {
+      /* Otherwise, prefer svndiff1, as svndiff2 is not a reasonable
        * substitute for svndiff1 with default compression level.  (It gives
        * better speed and compression ratio comparable to svndiff1 with
        * compression level 1, but not 5).
        *
-       * It might make sense to tweak the current format negotiation scheme
-       * so that the server would say which versions of svndiff it accepts,
-       * _including_ the preferred order.  This would allow us to dynamically
-       * pick svndiff2 if that's what the server thinks is appropriate.
+       * Note: For future compatibility, we also handle a theoretically
+       * possible case where the server has advertised only svndiff2 support.
        */
-      svndiff_version = 1;
-      compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
-    }
-  else if (ctx->commit_ctx->session->supports_svndiff2 &&
-           ctx->commit_ctx->session->using_compression)
-    {
-      svndiff_version = 2;
-      compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
+      if (session->supports_svndiff1)
+        svndiff_version = 1;
+      else if (session->supports_svndiff2)
+        svndiff_version = 2;
+      else
+        svndiff_version = 0;
     }
   else
     {
@@ -1928,9 +1923,46 @@ apply_textdelta(void *file_baton,
        * client configuration option, if they want to.
        */
       svndiff_version = 0;
-      compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
     }
 
+  if (svndiff_version == 0)
+    compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
+  else
+    compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
+
+  *svndiff_version_p = svndiff_version;
+  *svndiff_compression_level_p = compression_level;
+}
+
+static svn_error_t *
+apply_textdelta(void *file_baton,
+                const char *base_checksum,
+                apr_pool_t *pool,
+                svn_txdelta_window_handler_t *handler,
+                void **handler_baton)
+{
+  file_context_t *ctx = file_baton;
+  int svndiff_version;
+  int compression_level;
+
+  /* Construct a holder for the request body; we'll give it to serf when we
+   * close this file.
+   *
+   * Please note that if this callback is used, large request bodies will
+   * be spilled into temporary files (that requires disk space and prevents
+   * simultaneous processing by the server and the client).  A better approach
+   * that streams the request body is implemented in apply_textdelta_stream().
+   * It will be used with most recent servers having the "send result checksum
+   * in response to a PUT" capability, and only if the editor driver uses the
+   * new callback.
+   */
+  ctx->svndiff =
+    svn_ra_serf__request_body_create(SVN_RA_SERF__REQUEST_BODY_IN_MEM_SIZE,
+                                     ctx->pool);
+  ctx->stream = svn_ra_serf__request_body_get_stream(ctx->svndiff);
+
+  negotiate_put_encoding(&svndiff_version, &compression_level,
+                         ctx->commit_ctx->session);
   /* Disown the stream; we'll close it explicitly in close_file(). */
   svn_txdelta_to_svndiff3(handler, handler_baton,
                           svn_stream_disown(ctx->stream, pool),
@@ -1942,6 +1974,146 @@ apply_textdelta(void *file_baton,
   return SVN_NO_ERROR;
 }
 
+typedef struct open_txdelta_baton_t
+{
+  svn_ra_serf__session_t *session;
+  svn_txdelta_stream_open_func_t open_func;
+  void *open_baton;
+  svn_error_t *err;
+} open_txdelta_baton_t;
+
+static void
+txdelta_stream_errfunc(void *baton, svn_error_t *err)
+{
+  open_txdelta_baton_t *b = baton;
+
+  /* Remember extended error info from the stream bucket.  Note that
+   * theoretically this errfunc could be called multiple times -- say,
+   * if the request gets restarted after an error.  Compose the errors
+   * so we don't leak one of them if this happens. */
+  b->err = svn_error_compose_create(b->err, svn_error_dup(err));
+}
+
+/* Implements svn_ra_serf__request_body_delegate_t */
+static svn_error_t *
+create_body_from_txdelta_stream(serf_bucket_t **body_bkt,
+                                void *baton,
+                                serf_bucket_alloc_t *alloc,
+                                apr_pool_t *pool /* request pool */,
+                                apr_pool_t *scratch_pool)
+{
+  open_txdelta_baton_t *b = baton;
+  svn_txdelta_stream_t *txdelta_stream;
+  svn_stream_t *stream;
+  int svndiff_version;
+  int compression_level;
+
+  SVN_ERR(b->open_func(&txdelta_stream, b->open_baton, pool, scratch_pool));
+
+  negotiate_put_encoding(&svndiff_version, &compression_level, b->session);
+  stream = svn_txdelta_to_svndiff_stream(txdelta_stream, svndiff_version,
+                                         compression_level, pool);
+  *body_bkt = svn_ra_serf__create_stream_bucket(stream, alloc,
+                                                txdelta_stream_errfunc, b);
+
+  return SVN_NO_ERROR;
+}
+
+/* Handler baton for PUT request. */
+typedef struct put_response_ctx_t
+{
+  svn_ra_serf__handler_t *handler;
+  file_context_t *file_ctx;
+} put_response_ctx_t;
+
+/* Implements svn_ra_serf__response_handler_t */
+static svn_error_t *
+put_response_handler(serf_request_t *request,
+                     serf_bucket_t *response,
+                     void *baton,
+                     apr_pool_t *scratch_pool)
+{
+  put_response_ctx_t *prc = baton;
+  serf_bucket_t *hdrs;
+  const char *val;
+
+  hdrs = serf_bucket_response_get_headers(response);
+  val = serf_bucket_headers_get(hdrs, SVN_DAV_RESULT_FULLTEXT_MD5_HEADER);
+  SVN_ERR(svn_checksum_parse_hex(&prc->file_ctx->remote_result_checksum,
+                                 svn_checksum_md5, val, prc->file_ctx->pool));
+
+  return svn_error_trace(
+           svn_ra_serf__expect_empty_body(request, response,
+                                          prc->handler, scratch_pool));
+}
+
+static svn_error_t *
+apply_textdelta_stream(const svn_delta_editor_t *editor,
+                       void *file_baton,
+                       const char *base_checksum,
+                       svn_txdelta_stream_open_func_t open_func,
+                       void *open_baton,
+                       apr_pool_t *scratch_pool)
+{
+  file_context_t *ctx = file_baton;
+  open_txdelta_baton_t open_txdelta_baton = {0};
+  svn_ra_serf__handler_t *handler;
+  put_response_ctx_t *prc;
+  int expected_result;
+  svn_error_t *err;
+
+  /* Remember that we have sent the svndiff.  A case when we need to
+   * perform a zero-byte file PUT (during add_file, close_file editor
+   * sequences) is handled in close_file().
+   */
+  ctx->svndiff_sent = TRUE;
+  ctx->base_checksum = base_checksum;
+
+  handler = svn_ra_serf__create_handler(ctx->commit_ctx->session,
+                                        scratch_pool);
+  handler->method = "PUT";
+  handler->path = ctx->url;
+
+  prc = apr_pcalloc(scratch_pool, sizeof(*prc));
+  prc->handler = handler;
+  prc->file_ctx = ctx;
+
+  handler->response_handler = put_response_handler;
+  handler->response_baton = prc;
+
+  open_txdelta_baton.session = ctx->commit_ctx->session;
+  open_txdelta_baton.open_func = open_func;
+  open_txdelta_baton.open_baton = open_baton;
+  open_txdelta_baton.err = SVN_NO_ERROR;
+
+  handler->body_delegate = create_body_from_txdelta_stream;
+  handler->body_delegate_baton = &open_txdelta_baton;
+  handler->body_type = SVN_SVNDIFF_MIME_TYPE;
+
+  handler->header_delegate = setup_put_headers;
+  handler->header_delegate_baton = ctx;
+
+  err = svn_ra_serf__context_run_one(handler, scratch_pool);
+  /* Do we have an error from the stream bucket?  If yes, use it. */
+  if (open_txdelta_baton.err)
+    {
+      svn_error_clear(err);
+      return svn_error_trace(open_txdelta_baton.err);
+    }
+  else if (err)
+    return svn_error_trace(err);
+
+  if (ctx->added && !ctx->copy_path)
+    expected_result = 201; /* Created */
+  else
+    expected_result = 204; /* Updated */
+
+  if (handler->sline.code != expected_result)
+    return svn_error_trace(svn_ra_serf__unexpected_status(handler));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 change_file_prop(void *file_baton,
                  const char *name,
@@ -1977,8 +2149,8 @@ close_file(void *file_baton,
   if ((!ctx->svndiff) && ctx->added && (!ctx->copy_path))
     put_empty_file = TRUE;
 
-  /* If we had a stream of changes, push them to the server... */
-  if (ctx->svndiff || put_empty_file)
+  /* If we have a stream of changes, push them to the server... */
+  if ((ctx->svndiff || put_empty_file) && !ctx->svndiff_sent)
     {
       svn_ra_serf__handler_t *handler;
       int expected_result;
@@ -2043,6 +2215,22 @@ close_file(void *file_baton,
                                  proppatch, scratch_pool));
     }
 
+  if (ctx->result_checksum && ctx->remote_result_checksum)
+    {
+      svn_checksum_t *result_checksum;
+
+      SVN_ERR(svn_checksum_parse_hex(&result_checksum, svn_checksum_md5,
+                                     ctx->result_checksum, scratch_pool));
+
+      if (!svn_checksum_match(result_checksum, ctx->remote_result_checksum))
+        return svn_checksum_mismatch_err(result_checksum,
+                                         ctx->remote_result_checksum,
+                                         scratch_pool,
+                                         _("Checksum mismatch for '%s'"),
+                                         svn_dirent_local_style(ctx->relpath,
+                                                                scratch_pool));
+    }
+
   ctx->commit_ctx->open_batons--;
 
   return SVN_NO_ERROR;
@@ -2218,6 +2406,12 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   editor->close_file = close_file;
   editor->close_edit = close_edit;
   editor->abort_edit = abort_edit;
+  /* Only install the callback that allows streaming PUT request bodies
+   * if the server has the necessary capability.  Otherwise, this will
+   * fallback to the default implementation using the temporary files.
+   * See default_editor.c:apply_textdelta_stream(). */
+  if (session->supports_put_result_checksum)
+    editor->apply_textdelta_stream = apply_textdelta_stream;
 
   *ret_editor = editor;
   *edit_baton = ctx;

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/get_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/get_file.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/get_file.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/get_file.c Thu Aug 24 08:42:40 2017
@@ -60,7 +60,7 @@ typedef struct stream_ctx_t {
   /* Have we read our response headers yet? */
   svn_boolean_t read_headers;
 
-  svn_boolean_t using_compression;
+  svn_ra_serf__session_t *session;
 
   /* This flag is set when our response is aborted before we reach the
    * end and we decide to requeue this request.
@@ -88,7 +88,7 @@ headers_fetch(serf_bucket_t *headers,
 {
   stream_ctx_t *fetch_ctx = baton;
 
-  if (fetch_ctx->using_compression)
+  if (fetch_ctx->session->using_compression != svn_tristate_false)
     {
       serf_bucket_headers_setn(headers, "Accept-Encoding", "gzip");
     }
@@ -396,7 +396,7 @@ svn_ra_serf__get_file(svn_ra_session_t *
           /* Create the fetch context. */
           stream_ctx = apr_pcalloc(scratch_pool, sizeof(*stream_ctx));
           stream_ctx->result_stream = stream;
-          stream_ctx->using_compression = session->using_compression;
+          stream_ctx->session = session;
 
           handler = svn_ra_serf__create_handler(session, scratch_pool);
 

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/options.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/options.c Thu Aug 24 08:42:40 2017
@@ -237,6 +237,10 @@ capabilities_headers_iterator_callback(v
           /* Same for svndiff2. */
           session->supports_svndiff2 = TRUE;
         }
+      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_PUT_RESULT_CHECKSUM, vals))
+        {
+          session->supports_put_result_checksum = TRUE;
+        }
     }
 
   /* SVN-specific headers -- if present, server supports HTTP protocol v2 */
@@ -361,6 +365,7 @@ options_response_handler(serf_request_t
     {
       svn_ra_serf__session_t *session = opt_ctx->session;
       serf_bucket_t *hdrs = serf_bucket_response_get_headers(response);
+      serf_connection_t *conn;
 
       /* Start out assuming all capabilities are unsupported. */
       svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,
@@ -390,6 +395,10 @@ options_response_handler(serf_request_t
         svn_hash_sets(session->capabilities, SVN_RA_CAPABILITY_MERGEINFO,
                       capability_no);
 
+      /* Remember our latency. */
+      conn = serf_request_get_conn(request);
+      session->conn_latency = serf_connection_get_latency(conn);
+
       opt_ctx->headers_processed = TRUE;
     }
 

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/ra_serf.h?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/ra_serf.h Thu Aug 24 08:42:40 2017
@@ -113,8 +113,12 @@ struct svn_ra_serf__session_t {
   /* Are we using ssl */
   svn_boolean_t using_ssl;
 
-  /* Should we use compression for network transmissions? */
-  svn_boolean_t using_compression;
+  /* Tristate flag that indicates if we should use compression for
+     network transmissions.  If svn_tristate_true or svn_tristate_false,
+     the compression should be enabled and disabled, respectively.
+     If svn_tristate_unknown, determine this automatically based
+     on network parameters. */
+  svn_tristate_t using_compression;
 
   /* The user agent string */
   const char *useragent;
@@ -264,6 +268,12 @@ struct svn_ra_serf__session_t {
 
   /* Indicates whether the server can understand svndiff version 2. */
   svn_boolean_t supports_svndiff2;
+
+  /* Indicates whether the server sends the result checksum in the response
+   * to a successful PUT request. */
+  svn_boolean_t supports_put_result_checksum;
+
+  apr_interval_time_t conn_latency;
 };
 
 #define SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(sess) ((sess)->me_resource != NULL)
@@ -1572,10 +1582,13 @@ svn_ra_serf__uri_parse(apr_uri_t *uri,
                        apr_pool_t *result_pool);
 
 /* Setup the "Accept-Encoding" header value for requests that expect
-   svndiff-encoded deltas, depending on the USING_COMPRESSION value. */
+   svndiff-encoded deltas, depending on the SESSION state. */
 void
 svn_ra_serf__setup_svndiff_accept_encoding(serf_bucket_t *headers,
-                                           svn_boolean_t using_compression);
+                                           svn_ra_serf__session_t *session);
+
+svn_boolean_t
+svn_ra_serf__is_low_latency_connection(svn_ra_serf__session_t *session);
 
 /* Default limit for in-memory size of a request body. */
 #define SVN_RA_SERF__REQUEST_BODY_IN_MEM_SIZE 256 * 1024
@@ -1609,6 +1622,19 @@ svn_error_t *
 svn_ra_serf__request_body_cleanup(svn_ra_serf__request_body_t *body,
                                   apr_pool_t *scratch_pool);
 
+/* Callback used in svn_ra_serf__create_stream_bucket().  ERR will be
+   will be cleared and becomes invalid after the callback returns,
+   use svn_error_dup() to preserve it. */
+typedef void
+(*svn_ra_serf__stream_bucket_errfunc_t)(void *baton, svn_error_t *err);
+
+/* Create a bucket that wraps a generic readable STREAM.  This function
+   takes ownership of the passed-in stream, and will close it. */
+serf_bucket_t *
+svn_ra_serf__create_stream_bucket(svn_stream_t *stream,
+                                  serf_bucket_alloc_t *allocator,
+                                  svn_ra_serf__stream_bucket_errfunc_t errfunc,
+                                  void *errfunc_baton);
 
 #if defined(SVN_DEBUG)
 /* Wrapper macros to collect file and line information */

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/replay.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/replay.c Thu Aug 24 08:42:40 2017
@@ -166,7 +166,7 @@ typedef struct revision_report_t {
   svn_ra_serf__handler_t *propfind_handler;
   svn_ra_serf__handler_t *report_handler; /* For done handler */
 
-  svn_boolean_t using_compression;
+  svn_ra_serf__session_t *session;
 
 } revision_report_t;
 
@@ -641,8 +641,7 @@ setup_headers(serf_bucket_t *headers,
 {
   struct revision_report_t *ctx = baton;
 
-  svn_ra_serf__setup_svndiff_accept_encoding(headers,
-                                             ctx->using_compression);
+  svn_ra_serf__setup_svndiff_accept_encoding(headers, ctx->session);
 
   return SVN_NO_ERROR;
 }
@@ -741,7 +740,7 @@ svn_ra_serf__replay_range(svn_ra_session
           rev_ctx->revision = rev;
           rev_ctx->low_water_mark = low_water_mark;
           rev_ctx->send_deltas = send_deltas;
-          rev_ctx->using_compression = session->using_compression;
+          rev_ctx->session = session;
 
           /* Request all properties of a certain revision. */
           rev_ctx->rev_props = apr_hash_make(rev_ctx->pool);

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/serf.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/serf.c Thu Aug 24 08:42:40 2017
@@ -180,9 +180,10 @@ load_config(svn_ra_serf__session_t *sess
       config_client = NULL;
     }
 
-  SVN_ERR(svn_config_get_bool(config, &session->using_compression,
-                              SVN_CONFIG_SECTION_GLOBAL,
-                              SVN_CONFIG_OPTION_HTTP_COMPRESSION, TRUE));
+  SVN_ERR(svn_config_get_tristate(config, &session->using_compression,
+                                  SVN_CONFIG_SECTION_GLOBAL,
+                                  SVN_CONFIG_OPTION_HTTP_COMPRESSION,
+                                  "auto", svn_tristate_unknown));
   svn_config_get(config, &timeout_str, SVN_CONFIG_SECTION_GLOBAL,
                  SVN_CONFIG_OPTION_HTTP_TIMEOUT, NULL);
 
@@ -266,10 +267,10 @@ load_config(svn_ra_serf__session_t *sess
 
   if (server_group)
     {
-      SVN_ERR(svn_config_get_bool(config, &session->using_compression,
-                                  server_group,
-                                  SVN_CONFIG_OPTION_HTTP_COMPRESSION,
-                                  session->using_compression));
+      SVN_ERR(svn_config_get_tristate(config, &session->using_compression,
+                                      server_group,
+                                      SVN_CONFIG_OPTION_HTTP_COMPRESSION,
+                                      "auto", session->using_compression));
       svn_config_get(config, &timeout_str, server_group,
                      SVN_CONFIG_OPTION_HTTP_TIMEOUT, timeout_str);
 
@@ -593,6 +594,10 @@ svn_ra_serf__open(svn_ra_session_t *sess
                  && apr_pool_is_ancestor(serf_sess->pool, scratch_pool));
 #endif
 
+  /* The actual latency will be determined as a part of the initial
+     OPTIONS request. */
+  serf_sess->conn_latency = -1;
+
   err = svn_ra_serf__exchange_capabilities(serf_sess, corrected_url,
                                            result_pool, scratch_pool);
 
@@ -752,6 +757,9 @@ ra_serf_dup_session(svn_ra_session_t *ne
   /* svn_boolean_t supports_inline_props */
   /* supports_rev_rsrc_replay */
   /* supports_svndiff1 */
+  /* supports_svndiff2 */
+  /* supports_put_result_checksum */
+  /* conn_latency */
 
   new_sess->context = serf_context_create(result_pool);
 

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/update.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/update.c Thu Aug 24 08:42:40 2017
@@ -365,7 +365,7 @@ typedef struct fetch_ctx_t {
   /* The handler representing this particular fetch.  */
   svn_ra_serf__handler_t *handler;
 
-  svn_boolean_t using_compression;
+  svn_ra_serf__session_t *session;
 
   /* Stores the information for the file we want to fetch. */
   file_baton_t *file;
@@ -797,10 +797,9 @@ headers_fetch(serf_bucket_t *headers,
     {
       serf_bucket_headers_setn(headers, SVN_DAV_DELTA_BASE_HEADER,
                                fetch_ctx->delta_base);
-      svn_ra_serf__setup_svndiff_accept_encoding(headers,
-                                                 fetch_ctx->using_compression);
+      svn_ra_serf__setup_svndiff_accept_encoding(headers, fetch_ctx->session);
     }
-  else if (fetch_ctx->using_compression)
+  else if (fetch_ctx->session->using_compression != svn_tristate_false)
     {
       serf_bucket_headers_setn(headers, "Accept-Encoding", "gzip");
     }
@@ -1278,7 +1277,7 @@ fetch_for_file(file_baton_t *file,
 
           fetch_ctx = apr_pcalloc(file->pool, sizeof(*fetch_ctx));
           fetch_ctx->file = file;
-          fetch_ctx->using_compression = ctx->sess->using_compression;
+          fetch_ctx->session = ctx->sess;
 
           /* Can we somehow get away with just obtaining a DIFF? */
           if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(ctx->sess))
@@ -2169,8 +2168,7 @@ setup_update_report_headers(serf_bucket_
 {
   report_context_t *report = baton;
 
-  svn_ra_serf__setup_svndiff_accept_encoding(headers,
-                                             report->sess->using_compression);
+  svn_ra_serf__setup_svndiff_accept_encoding(headers, report->sess);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/util.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_serf/util.c Thu Aug 24 08:42:40 2017
@@ -1571,7 +1571,7 @@ setup_request(serf_request_t *request,
     {
       accept_encoding = NULL;
     }
-  else if (handler->session->using_compression)
+  else if (handler->session->using_compression != svn_tristate_false)
     {
       /* Accept gzip compression if enabled. */
       accept_encoding = "gzip";
@@ -2026,20 +2026,42 @@ svn_ra_serf__uri_parse(apr_uri_t *uri,
 
 void
 svn_ra_serf__setup_svndiff_accept_encoding(serf_bucket_t *headers,
-                                           svn_boolean_t using_compression)
+                                           svn_ra_serf__session_t *session)
 {
-  if (using_compression)
+  if (session->using_compression == svn_tristate_false)
     {
-      /* We are equally interested in svndiff2 and svndiff1, let the
-         server choose the wire format. */
+      /* Don't advertise support for compressed svndiff formats if
+         compression is disabled. */
+      serf_bucket_headers_setn(
+        headers, "Accept-Encoding", "svndiff");
+    }
+  else if (session->using_compression == svn_tristate_unknown &&
+           svn_ra_serf__is_low_latency_connection(session))
+    {
+      /* With http-compression=auto, advertise that we prefer svndiff2
+         to svndiff1 with a low latency connection (assuming the underlying
+         network has high bandwidth), as it is faster and in this case, we
+         don't care about worse compression ratio. */
       serf_bucket_headers_setn(
         headers, "Accept-Encoding",
-        "gzip,svndiff2;q=0.9,svndiff1;q=0.9,svndiff;q=0.8");
+        "gzip,svndiff2;q=0.9,svndiff1;q=0.8,svndiff;q=0.7");
     }
   else
     {
-      /* Do not advertise svndiff1 support if we're not interested in
-         compression. */
-      serf_bucket_headers_setn(headers, "Accept-Encoding", "svndiff");
+      /* Otherwise, advertise that we prefer svndiff1 over svndiff2.
+         svndiff2 is not a reasonable substitute for svndiff1 with default
+         compression level, because, while it is faster, it also gives worse
+         compression ratio.  While we can use svndiff2 in some cases (see
+         above), we can't do this generally. */
+      serf_bucket_headers_setn(
+        headers, "Accept-Encoding",
+        "gzip,svndiff1;q=0.9,svndiff2;q=0.8,svndiff;q=0.7");
     }
 }
+
+svn_boolean_t
+svn_ra_serf__is_low_latency_connection(svn_ra_serf__session_t *session)
+{
+  return session->conn_latency >= 0 &&
+         session->conn_latency < apr_time_from_msec(5);
+}

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/client.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/client.c Thu Aug 24 08:42:40 2017
@@ -46,6 +46,7 @@
 #include "svn_props.h"
 #include "svn_mergeinfo.h"
 #include "svn_version.h"
+#include "svn_ctype.h"
 
 #include "svn_private_config.h"
 
@@ -398,7 +399,7 @@ static svn_error_t *find_tunnel_agent(co
        * versions have it too. If the user is using some other ssh
        * implementation that doesn't accept it, they can override it
        * in the [tunnels] section of the config. */
-      val = "$SVN_SSH ssh -q";
+      val = "$SVN_SSH ssh -q --";
     }
 
   if (!val || !*val)
@@ -443,7 +444,7 @@ static svn_error_t *find_tunnel_agent(co
   for (n = 0; cmd_argv[n] != NULL; n++)
     argv[n] = cmd_argv[n];
 
-  argv[n++] = svn_path_uri_decode(hostinfo, pool);
+  argv[n++] = hostinfo;
   argv[n++] = "svnserve";
   argv[n++] = "-t";
   argv[n] = NULL;
@@ -746,10 +747,11 @@ static svn_error_t *open_session(svn_ra_
    * capability list, and the URL, and subsequently there is an auth
    * request. */
   /* Client-side capabilities list: */
-  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "n(wwwwww)cc(?c)",
+  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "n(wwwwwww)cc(?c)",
                                   (apr_uint64_t) 2,
                                   SVN_RA_SVN_CAP_EDIT_PIPELINE,
                                   SVN_RA_SVN_CAP_SVNDIFF1,
+                                  SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED,
                                   SVN_RA_SVN_CAP_ABSENT_ENTRIES,
                                   SVN_RA_SVN_CAP_DEPTH,
                                   SVN_RA_SVN_CAP_MERGEINFO,
@@ -810,6 +812,32 @@ ra_svn_get_schemes(apr_pool_t *pool)
 }
 
 
+/* A simple whitelist to ensure the following are valid:
+ *   user@server
+ *   [::1]:22
+ *   server-name
+ *   server_name
+ *   127.0.0.1
+ * with an extra restriction that a leading '-' is invalid.
+ */
+static svn_boolean_t
+is_valid_hostinfo(const char *hostinfo)
+{
+  const char *p = hostinfo;
+
+  if (p[0] == '-')
+    return FALSE;
+
+  while (*p)
+    {
+      if (!svn_ctype_isalnum(*p) && !strchr(":.-_[]@", *p))
+        return FALSE;
+
+      ++p;
+    }
+
+  return TRUE;
+}
 
 static svn_error_t *ra_svn_open(svn_ra_session_t *session,
                                 const char **corrected_url,
@@ -843,8 +871,18 @@ static svn_error_t *ra_svn_open(svn_ra_s
           || (callbacks->check_tunnel_func && callbacks->open_tunnel_func
               && !callbacks->check_tunnel_func(callbacks->tunnel_baton,
                                                tunnel))))
-    SVN_ERR(find_tunnel_agent(tunnel, uri.hostinfo, &tunnel_argv, config,
-                              result_pool));
+    {
+      const char *decoded_hostinfo;
+
+      decoded_hostinfo = svn_path_uri_decode(uri.hostinfo, result_pool);
+
+      if (!is_valid_hostinfo(decoded_hostinfo))
+        return svn_error_createf(SVN_ERR_BAD_URL, NULL, _("Invalid host '%s'"),
+                                 uri.hostinfo);
+
+      SVN_ERR(find_tunnel_agent(tunnel, decoded_hostinfo, &tunnel_argv,
+                                config, result_pool));
+    }
   else
     tunnel_argv = NULL;
 

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/editorp.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/editorp.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/editorp.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/editorp.c Thu Aug 24 08:42:40 2017
@@ -353,6 +353,8 @@ static svn_error_t *ra_svn_apply_textdel
 
   /* If the connection does not support SVNDIFF1 or if we don't want to use
    * compression, use the non-compressing "version 0" implementation */
+ /* ### TODO: Check SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED and decide between
+  * ###       svndiff1[at compression_level] and svndiff2 */
   if (   svn_ra_svn_compression_level(b->conn) > 0
       && svn_ra_svn_has_capability(b->conn, SVN_RA_SVN_CAP_SVNDIFF1))
     svn_txdelta_to_svndiff3(wh, wh_baton, diff_stream, 1,

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/protocol
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/protocol?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/protocol (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_ra_svn/protocol Thu Aug 24 08:42:40 2017
@@ -188,6 +188,10 @@ capability and C indicates a client capa
 [CS] svndiff1          If both the client and server support svndiff version
                        1, this will be used as the on-the-wire format for 
                        svndiff instead of svndiff version 0.
+[CS] accepts-svndiff2  This capability advertises support for accepting
+                       svndiff2 deltas.  The sender of a delta (= the editor
+                       driver) may send it in any svndiff version the receiver
+                       has announced it can accept.
 [CS] absent-entries    If the remote end announces support for this capability,
                        it will accept the absent-dir and absent-file editor
                        commands.

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_repos/repos.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_repos/repos.c Thu Aug 24 08:42:40 2017
@@ -882,7 +882,7 @@ create_conf(svn_repos_t *repos, apr_pool
 "[sasl]"                                                                     NL
 "### This option specifies whether you want to use the Cyrus SASL"           NL
 "### library for authentication. Default is false."                          NL
-"### This section will be ignored if svnserve is not built with Cyrus"       NL
+"### Enabling this option requires svnserve to have been built with Cyrus"   NL
 "### SASL support; to check, run 'svnserve --version' and look for a line"   NL
 "### reading 'Cyrus SASL authentication is available.'"                      NL
 "# use-sasl = true"                                                          NL

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/checksum.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/checksum.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/checksum.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/checksum.c Thu Aug 24 08:42:40 2017
@@ -570,6 +570,36 @@ svn_checksum_ctx_create(svn_checksum_kin
 }
 
 svn_error_t *
+svn_checksum_ctx_reset(svn_checksum_ctx_t *ctx)
+{
+  switch (ctx->kind)
+    {
+      case svn_checksum_md5:
+        memset(ctx->apr_ctx, 0, sizeof(apr_md5_ctx_t));
+        apr_md5_init(ctx->apr_ctx);
+        break;
+
+      case svn_checksum_sha1:
+        memset(ctx->apr_ctx, 0, sizeof(apr_sha1_ctx_t));
+        apr_sha1_init(ctx->apr_ctx);
+        break;
+
+      case svn_checksum_fnv1a_32:
+        svn_fnv1a_32__context_reset(ctx->apr_ctx);
+        break;
+
+      case svn_checksum_fnv1a_32x4:
+        svn_fnv1a_32x4__context_reset(ctx->apr_ctx);
+        break;
+
+      default:
+        SVN_ERR_MALFUNCTION();
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_checksum_update(svn_checksum_ctx_t *ctx,
                     const void *data,
                     apr_size_t len)

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/config_file.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/config_file.c Thu Aug 24 08:42:40 2017
@@ -1148,6 +1148,7 @@ svn_config_ensure(const char *config_dir
         "###   http-timeout               Timeout for HTTP requests in seconds"
                                                                              NL
         "###   http-compression           Whether to compress HTTP requests" NL
+        "###                              (yes/no/auto)."                    NL
         "###   http-max-connections       Maximum number of parallel server" NL
         "###                              connections to use for any given"  NL
         "###                              HTTP operation."                   NL
@@ -1307,7 +1308,7 @@ svn_config_ensure(const char *config_dir
         "# http-proxy-port = 7000"                                           NL
         "# http-proxy-username = defaultusername"                            NL
         "# http-proxy-password = defaultpassword"                            NL
-        "# http-compression = no"                                            NL
+        "# http-compression = auto"                                          NL
         "# No http-timeout, so just use the builtin default."                NL
         "# ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem"   NL
         "#"                                                                  NL
@@ -1447,12 +1448,12 @@ svn_config_ensure(const char *config_dir
         "### passed to the tunnel agent as <user>@<hostname>.)  If the"      NL
         "### built-in ssh scheme were not predefined, it could be defined"   NL
         "### as:"                                                            NL
-        "# ssh = $SVN_SSH ssh -q"                                            NL
+        "# ssh = $SVN_SSH ssh -q --"                                         NL
         "### If you wanted to define a new 'rsh' scheme, to be used with"    NL
         "### 'svn+rsh:' URLs, you could do so as follows:"                   NL
-        "# rsh = rsh"                                                        NL
+        "# rsh = rsh --"                                                     NL
         "### Or, if you wanted to specify a full path and arguments:"        NL
-        "# rsh = /path/to/rsh -l myusername"                                 NL
+        "# rsh = /path/to/rsh -l myusername --"                              NL
         "### On Windows, if you are specifying a full path to a command,"    NL
         "### use a forward slash (/) or a paired backslash (\\\\) as the"    NL
         "### path separator.  A single backslash will be treated as an"      NL

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/dirent_uri.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/dirent_uri.c Thu Aug 24 08:42:40 2017
@@ -1862,18 +1862,18 @@ svn_uri_is_canonical(const char *uri, ap
           ptr++;
         }
 
-      if (ptr == schema_data)
+      if (ptr == schema_data && (*ptr == '/' || *ptr == '\0'))
         return FALSE; /* Fail on "http://host:" */
 
-      if (*ptr && *ptr != '/')
-        return FALSE; /* Not a port number */
-
       if (port == 80 && strncmp(uri, "http:", 5) == 0)
         return FALSE;
       else if (port == 443 && strncmp(uri, "https:", 6) == 0)
         return FALSE;
       else if (port == 3690 && strncmp(uri, "svn:", 4) == 0)
         return FALSE;
+
+      while (*ptr && *ptr != '/')
+        ++ptr; /* Allow "http://host:stuff" */
     }
 
   schema_data = ptr;

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/fnv1a.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/fnv1a.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/fnv1a.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/fnv1a.c Thu Aug 24 08:42:40 2017
@@ -166,6 +166,12 @@ svn_fnv1a_32__context_create(apr_pool_t
 }
 
 void
+svn_fnv1a_32__context_reset(svn_fnv1a_32__context_t *context)
+{
+  context->hash = FNV1_BASE_32;
+}
+
+void
 svn_fnv1a_32__update(svn_fnv1a_32__context_t *context,
                      const void *data,
                      apr_size_t len)
@@ -203,6 +209,17 @@ svn_fnv1a_32x4__context_create(apr_pool_
 }
 
 void
+svn_fnv1a_32x4__context_reset(svn_fnv1a_32x4__context_t *context)
+{
+  context->hashes[0] = FNV1_BASE_32;
+  context->hashes[1] = FNV1_BASE_32;
+  context->hashes[2] = FNV1_BASE_32;
+  context->hashes[3] = FNV1_BASE_32;
+
+  context->buffered = 0;
+}
+
+void
 svn_fnv1a_32x4__update(svn_fnv1a_32x4__context_t *context,
                        const void *data,
                        apr_size_t len)

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/fnv1a.h
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/fnv1a.h?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/fnv1a.h (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/fnv1a.h Thu Aug 24 08:42:40 2017
@@ -41,6 +41,11 @@ typedef struct svn_fnv1a_32__context_t s
 svn_fnv1a_32__context_t *
 svn_fnv1a_32__context_create(apr_pool_t *pool);
 
+/* Reset the FNV-1a checksum CONTEXT to initial state.
+ */
+void
+svn_fnv1a_32__context_reset(svn_fnv1a_32__context_t *context);
+
 /* Feed LEN bytes from DATA into the FNV-1a checksum creation CONTEXT.
  */
 void
@@ -63,6 +68,11 @@ typedef struct svn_fnv1a_32x4__context_t
 svn_fnv1a_32x4__context_t *
 svn_fnv1a_32x4__context_create(apr_pool_t *pool);
 
+/* Reset the modified FNV-1a checksum CONTEXT to initial state.
+ */
+void
+svn_fnv1a_32x4__context_reset(svn_fnv1a_32x4__context_t *context);
+
 /* Feed LEN bytes from DATA into the modified FNV-1a checksum creation
  * CONTEXT.
  */

Modified: subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/lz4/lz4.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/lz4/lz4.c?rev=1806008&r1=1806007&r2=1806008&view=diff
==============================================================================
--- subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/lz4/lz4.c (original)
+++ subversion/branches/shelve-checkpoint3/subversion/libsvn_subr/lz4/lz4.c Thu Aug 24 08:42:40 2017
@@ -1,3 +1,5 @@
+#include "svn_private_config.h"
+#if SVN_INTERNAL_LZ4
 /*
    LZ4 - Fast LZ compression algorithm
    Copyright (C) 2011-2016, Yann Collet.
@@ -89,7 +91,7 @@
 /*-************************************
 *  Dependency
 **************************************/
-#include "lz4.h"
+#include "lz4internal.h"
 /* see also "memory routines" below */
 
 
@@ -1463,3 +1465,4 @@ int LZ4_decompress_fast_withPrefix64k(co
 }
 
 #endif   /* LZ4_COMMONDEFS_ONLY */
+#endif /* SVN_INTERNAL_LZ4 */