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 2012/09/25 16:06:34 UTC

svn commit: r1389867 - in /subversion/branches/10Gb: subversion/libsvn_ra_svn/editorp.c subversion/libsvn_ra_svn/marshal.c subversion/libsvn_ra_svn/ra_svn.h tools/client-side/svn-bench/null-export-cmd.c

Author: stefan2
Date: Tue Sep 25 14:06:34 2012
New Revision: 1389867

URL: http://svn.apache.org/viewvc?rev=1389867&view=rev
Log:
On the 10Gb branch: minimize client-side processing overhead for
null-export in quiet mode.  For ra_svn, skip through the command
stream without further processing as to not become the bottleneck
when running against a fast server.  The other RA modules don't
have that problem, yet.

* subversion/libsvn_ra_svn/ra_svn.h
  (svn_ra_svn__read_command_only): declare new private API
* subversion/libsvn_ra_svn/marshal.c
  (readbuf_skip,
   read_command_only): new skip-command processing utilities
  (svn_ra_svn__read_command_only): implement new private API

* subversion/libsvn_ra_svn/editorp.c
  (svn_ra_svn_drive_editor2): allow for EDITOR to be NULL;
   skip command processing if there is no editor

* tools/client-side/svn-bench/null-export-cmd.c
  (bench_null_export): add QUIET parameter; don't use an
   editor for ra_svn in that mode
  (svn_cl__null_export): update

Modified:
    subversion/branches/10Gb/subversion/libsvn_ra_svn/editorp.c
    subversion/branches/10Gb/subversion/libsvn_ra_svn/marshal.c
    subversion/branches/10Gb/subversion/libsvn_ra_svn/ra_svn.h
    subversion/branches/10Gb/tools/client-side/svn-bench/null-export-cmd.c

Modified: subversion/branches/10Gb/subversion/libsvn_ra_svn/editorp.c
URL: http://svn.apache.org/viewvc/subversion/branches/10Gb/subversion/libsvn_ra_svn/editorp.c?rev=1389867&r1=1389866&r2=1389867&view=diff
==============================================================================
--- subversion/branches/10Gb/subversion/libsvn_ra_svn/editorp.c (original)
+++ subversion/branches/10Gb/subversion/libsvn_ra_svn/editorp.c Tue Sep 25 14:06:34 2012
@@ -929,30 +929,47 @@ svn_error_t *svn_ra_svn_drive_editor2(sv
   while (!state.done)
     {
       svn_pool_clear(subpool);
-      SVN_ERR(svn_ra_svn_read_tuple(conn, subpool, "wl", &cmd, &params));
-      for (i = 0; ra_svn_edit_cmds[i].cmd; i++)
+      if (editor)
         {
-          if (strcmp(cmd, ra_svn_edit_cmds[i].cmd) == 0)
-            break;
-        }
-      if (ra_svn_edit_cmds[i].cmd)
-        err = (*ra_svn_edit_cmds[i].handler)(conn, subpool, params, &state);
-      else if (strcmp(cmd, "failure") == 0)
-        {
-          /* While not really an editor command this can occur when
-             reporter->finish_report() fails before the first editor command */
-          if (aborted)
-            *aborted = TRUE;
-          err = svn_ra_svn__handle_failure_status(params, pool);
-          return svn_error_compose_create(
-                            err,
-                            editor->abort_edit(edit_baton, subpool));
+          SVN_ERR(svn_ra_svn_read_tuple(conn, subpool, "wl", &cmd, &params));
+          for (i = 0; ra_svn_edit_cmds[i].cmd; i++)
+              if (strcmp(cmd, ra_svn_edit_cmds[i].cmd) == 0)
+                break;
+
+          if (ra_svn_edit_cmds[i].cmd)
+            err = (*ra_svn_edit_cmds[i].handler)(conn, subpool, params, &state);
+          else if (strcmp(cmd, "failure") == 0)
+            {
+              /* While not really an editor command this can occur when
+                reporter->finish_report() fails before the first editor
+                command */
+              if (aborted)
+                *aborted = TRUE;
+              err = svn_ra_svn__handle_failure_status(params, pool);
+              return svn_error_compose_create(
+                                err,
+                                editor->abort_edit(edit_baton, subpool));
+            }
+          else
+            {
+              err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
+                                      _("Unknown command '%s'"), cmd);
+              err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
+            }
         }
       else
         {
-          err = svn_error_createf(SVN_ERR_RA_SVN_UNKNOWN_CMD, NULL,
-                                  _("Unknown command '%s'"), cmd);
-          err = svn_error_create(SVN_ERR_RA_SVN_CMD_ERR, err, NULL);
+          const char* command = NULL;
+          SVN_ERR(svn_ra_svn__read_command_only(conn, subpool, &command));
+          if (strcmp(command, "close-edit") == 0)
+            {
+              state.done = TRUE;
+              if (aborted)
+                *aborted = FALSE;
+              err = svn_ra_svn_write_cmd_response(conn, pool, "");
+            }
+          else
+            err = NULL;
         }
 
       if (err && err->apr_err == SVN_ERR_RA_SVN_CMD_ERR)
@@ -962,7 +979,8 @@ svn_error_t *svn_ra_svn_drive_editor2(sv
           if (!state.done)
             {
               /* Abort the edit and use non-blocking I/O to write the error. */
-              svn_error_clear(editor->abort_edit(edit_baton, subpool));
+              if (editor)
+                svn_error_clear(editor->abort_edit(edit_baton, subpool));
               svn_ra_svn__set_block_handler(conn, blocked_write, &state);
             }
           write_err = svn_ra_svn_write_cmd_failure(

Modified: subversion/branches/10Gb/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/10Gb/subversion/libsvn_ra_svn/marshal.c?rev=1389867&r1=1389866&r2=1389867&view=diff
==============================================================================
--- subversion/branches/10Gb/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/10Gb/subversion/libsvn_ra_svn/marshal.c Tue Sep 25 14:06:34 2012
@@ -352,6 +352,33 @@ static svn_error_t *readbuf_input(svn_ra
   return SVN_NO_ERROR;
 }
 
+/* Treat the next LEN input bytes from CONN as "read" */
+static svn_error_t *readbuf_skip(svn_ra_svn_conn_t *conn, apr_size_t len)
+{
+  apr_ssize_t buflen, copylen;
+
+  do
+  {
+    buflen = conn->read_end - conn->read_ptr;
+    copylen = (buflen < len) ? buflen : len;
+    conn->read_ptr += copylen;
+    len -= copylen;
+    if (len == 0)
+      break;
+
+    buflen = sizeof(conn->read_buf);
+    SVN_ERR(svn_ra_svn__stream_read(conn->stream, conn->read_buf, &buflen));
+    if (buflen == 0)
+      return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
+
+    conn->read_end = conn->read_buf + buflen;
+    conn->read_ptr = conn->read_buf;
+  }
+  while (len > 0);
+
+  return SVN_NO_ERROR;
+}
+
 /* Read data from the socket into the read buffer, which must be empty. */
 static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
 {
@@ -1070,6 +1097,95 @@ static svn_error_t *read_item(svn_ra_svn
   return SVN_NO_ERROR;
 }
 
+/* Given the first non-whitespace character FIRST_CHAR, read the first
+ * command (word) encountered in CONN into *ITEM.  If ITEM is NULL, skip
+ * to the end of the current list.  Use POOL for allocations. */
+static svn_error_t *
+read_command_only(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                  const char **item, char first_char)
+{
+  char c = first_char;
+
+  /* Determine the item type and read it in.  Make sure that c is the
+  * first character at the end of the item so we can test to make
+  * sure it's whitespace. */
+  if (svn_ctype_isdigit(c))
+    {
+      /* It's a number or a string.  Read the number part, either way. */
+      apr_uint64_t val, prev_val=0;
+      val = c - '0';
+      while (1)
+        {
+          prev_val = val;
+          SVN_ERR(readbuf_getchar(conn, pool, &c));
+          if (!svn_ctype_isdigit(c))
+            break;
+          val = val * 10 + (c - '0');
+          if (prev_val >= (APR_UINT64_MAX / 10)) /* > maximum value? */
+            return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                    _("Number is larger than maximum"));
+        }
+      if (c == ':')
+        {
+          /* It's a string. */
+          SVN_ERR(readbuf_skip(conn, val));
+          SVN_ERR(readbuf_getchar(conn, pool, &c));
+        }
+    }
+  else if (svn_ctype_isalpha(c))
+    {
+      /* It's a word. */
+      if (item)
+        {
+          /* This is the word we want to read */
+          
+          char *buf = apr_palloc(pool, 32);
+          apr_size_t len = 1;
+          buf[0] = c;
+
+          while (1)
+            {
+              SVN_ERR(readbuf_getchar(conn, pool, &c));
+              if (!svn_ctype_isalnum(c) && c != '-')
+                break;
+              buf[len] = c;
+              if (++len == 32)
+                return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                        _("Word too long"));
+            }
+          buf[len] = 0;
+          *item = buf;
+        }
+      else
+        {
+          /* we don't need the actual word, just skip it */
+          do
+          {
+            SVN_ERR(readbuf_getchar(conn, pool, &c));
+          }
+          while (svn_ctype_isalnum(c) || c == '-');
+        }
+    }
+  else if (c == '(')
+    {
+      /* Read in the list items. */
+      while (1)
+        {
+          SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
+          if (c == ')')
+            break;
+
+          if (item && *item == NULL)
+            SVN_ERR(read_command_only(conn, pool, item, c));
+          else
+            SVN_ERR(read_command_only(conn, pool, NULL, c));
+        }
+      SVN_ERR(readbuf_getchar(conn, pool, &c));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *svn_ra_svn_read_item(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                   svn_ra_svn_item_t **item)
 {
@@ -1218,6 +1334,18 @@ svn_error_t *svn_ra_svn_read_tuple(svn_r
   return err;
 }
 
+svn_error_t *svn_ra_svn__read_command_only(svn_ra_svn_conn_t *conn,
+                                           apr_pool_t *pool,
+                                           const char **command)
+{
+  char c;
+  SVN_ERR(readbuf_getchar_skip_whitespace(conn, pool, &c));
+
+  *command = NULL;
+  return read_command_only(conn, pool, command, c);
+}
+
+
 svn_error_t *svn_ra_svn_parse_proplist(const apr_array_header_t *list,
                                        apr_pool_t *pool,
                                        apr_hash_t **props)

Modified: subversion/branches/10Gb/subversion/libsvn_ra_svn/ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/10Gb/subversion/libsvn_ra_svn/ra_svn.h?rev=1389867&r1=1389866&r2=1389867&view=diff
==============================================================================
--- subversion/branches/10Gb/subversion/libsvn_ra_svn/ra_svn.h (original)
+++ subversion/branches/10Gb/subversion/libsvn_ra_svn/ra_svn.h Tue Sep 25 14:06:34 2012
@@ -189,6 +189,13 @@ svn_error_t *svn_ra_svn__stream_write(sv
 svn_error_t *svn_ra_svn__stream_read(svn_ra_svn__stream_t *stream,
                                      char *data, apr_size_t *len);
 
+/* Read the command word from CONN, return it in *COMMAND and skip to the
+ * end of the command.  Allocate data in POOL.
+ */
+svn_error_t *svn_ra_svn__read_command_only(svn_ra_svn_conn_t *conn,
+                                           apr_pool_t *pool,
+                                           const char **command);
+
 /* Set the timeout for operations on STREAM to INTERVAL. */
 void svn_ra_svn__stream_timeout(svn_ra_svn__stream_t *stream,
                                 apr_interval_time_t interval);

Modified: subversion/branches/10Gb/tools/client-side/svn-bench/null-export-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/10Gb/tools/client-side/svn-bench/null-export-cmd.c?rev=1389867&r1=1389866&r2=1389867&view=diff
==============================================================================
--- subversion/branches/10Gb/tools/client-side/svn-bench/null-export-cmd.c (original)
+++ subversion/branches/10Gb/tools/client-side/svn-bench/null-export-cmd.c Tue Sep 25 14:06:34 2012
@@ -168,7 +168,7 @@ close_file(void *file_baton,
 
 /*** Public Interfaces ***/
 
-svn_error_t *
+static svn_error_t *
 bench_null_export(svn_revnum_t *result_rev,
                   const char *from_path_or_url,
                   svn_opt_revision_t *peg_revision,
@@ -176,6 +176,7 @@ bench_null_export(svn_revnum_t *result_r
                   svn_depth_t depth,
                   void *baton,
                   svn_client_ctx_t *ctx,
+                  svn_boolean_t quiet,
                   apr_pool_t *pool)
 {
   svn_revnum_t edit_revision = SVN_INVALID_REVNUM;
@@ -223,7 +224,7 @@ bench_null_export(svn_revnum_t *result_r
       else if (kind == svn_node_dir)
         {
           void *edit_baton = NULL;
-          const svn_delta_editor_t *export_editor;
+          const svn_delta_editor_t *export_editor = NULL;
           const svn_ra_reporter3_t *reporter;
           void *report_baton;
 
@@ -238,8 +239,8 @@ bench_null_export(svn_revnum_t *result_r
           editor->change_file_prop = change_file_prop;
           editor->change_dir_prop = change_dir_prop;
 
-          export_editor = editor;
-          if (ctx->cancel_func)
+          /* for ra_svn, we don't need an editior in quiet mode */
+          if (!quiet || strncmp(loc->repos_root_url, "svn:", 4))
             SVN_ERR(svn_delta_get_cancellation_editor(ctx->cancel_func,
                                                       ctx->cancel_baton,
                                                       editor,
@@ -339,7 +340,7 @@ svn_cl__null_export(apr_getopt_t *os,
                           &(opt_state->start_revision),
                           opt_state->depth,
                           &eb,
-                          ctx, pool);
+                          ctx, opt_state->quiet, pool);
 
   if (!opt_state->quiet)
     SVN_ERR(svn_cmdline_printf(pool,