You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ko...@apache.org on 2015/09/16 15:14:17 UTC

svn commit: r1703397 - /subversion/branches/ra_serf-stream-commit/subversion/libsvn_ra_serf/commit.c

Author: kotkov
Date: Wed Sep 16 13:14:16 2015
New Revision: 1703397

URL: http://svn.apache.org/r1703397
Log:
On the ra_serf-stream-commit branch: Teach the ra_serf commit editor to
stream the file delta instead of writing it to a temporary file.  Don't
change the behavior of existing editor drives, such as svn_client_import5()
or svn_client_commit6(), yet.

* subversion/libsvn_ra_serf/commit.c
  (file_context_t): Extend with a boolean that indicates if the svndiff has
   been sent during apply_textdelta_stream().
  (apply_textdelta): Update the TODO comment about the temporary files being
   used to store svndiff.
  (open_txdelta_baton_t): New baton type.
  (create_body_from_txdelta_stream): New svn_ra_serf__request_body_delegate_t
   that creates the request body by opening a svn_txdelta_stream_t, turning
   it into svn_stream_t and giving away a bucket wrapping around that stream.
   Use it in ...
  (apply_textdelta_stream): ...this new function that performs a PUT, and
   streams the request body.
  (close_file): Don't do a PUT if we did it in apply_textdelta_stream().
  (svn_ra_serf__get_commit_editor): Install the new apply_textdelta_stream()
   callback.

Modified:
    subversion/branches/ra_serf-stream-commit/subversion/libsvn_ra_serf/commit.c

Modified: subversion/branches/ra_serf-stream-commit/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra_serf-stream-commit/subversion/libsvn_ra_serf/commit.c?rev=1703397&r1=1703396&r2=1703397&view=diff
==============================================================================
--- subversion/branches/ra_serf-stream-commit/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/ra_serf-stream-commit/subversion/libsvn_ra_serf/commit.c Wed Sep 16 13:14:16 2015
@@ -176,6 +176,9 @@ typedef struct file_context_t {
   /* Temporary file containing the svndiff. */
   apr_file_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;
 
@@ -1903,12 +1906,9 @@ apply_textdelta(void *file_baton,
   file_context_t *ctx = file_baton;
 
   /* Store the stream in a temporary file; 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
-   * 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.
+   * close this file.  Note that this commit editor can stream the request
+   * body instead of writing to a temporary file, but only when the editor
+   * drive uses apply_textdelta_stream().
    */
 
   ctx->stream = svn_stream_lazyopen_create(delayed_commit_stream_open,
@@ -1923,6 +1923,88 @@ apply_textdelta(void *file_baton,
   return SVN_NO_ERROR;
 }
 
+typedef struct open_txdelta_baton_t
+{
+  svn_txdelta_stream_open_func_t open_func;
+  void *open_baton;
+} open_txdelta_baton_t;
+
+/* 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;
+
+  SVN_ERR(b->open_func(&txdelta_stream, b->open_baton, pool));
+
+  stream = svn_txdelta_to_svndiff_stream(txdelta_stream, 0,
+                                         SVN_DELTA_COMPRESSION_LEVEL_DEFAULT,
+                                         pool);
+  *body_bkt = svn_ra_serf__create_stream_bucket(stream, alloc);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+apply_textdelta_stream(const svn_delta_editor_t *editor,
+                       void *file_baton,
+                       const char *base_checksum,
+                       const char *result_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;
+  svn_ra_serf__handler_t *handler;
+  int expected_result;
+
+  /* Remember that we've already send 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;
+  ctx->result_checksum = result_checksum;
+
+  handler = svn_ra_serf__create_handler(ctx->commit_ctx->session,
+                                        scratch_pool);
+
+  handler->method = "PUT";
+  handler->path = ctx->url;
+
+  handler->response_handler = svn_ra_serf__expect_empty_body;
+  handler->response_baton = handler;
+
+  open_txdelta_baton.open_func = open_func;
+  open_txdelta_baton.open_baton = open_baton;
+
+  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;
+
+  SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
+
+  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,
@@ -1958,8 +2040,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;
@@ -2191,6 +2273,7 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   editor->add_file = add_file;
   editor->open_file = open_file;
   editor->apply_textdelta = apply_textdelta;
+  editor->apply_textdelta_stream = apply_textdelta_stream;
   editor->change_file_prop = change_file_prop;
   editor->close_file = close_file;
   editor->close_edit = close_edit;