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 2015/08/06 15:08:33 UTC

svn commit: r1694490 - in /subversion/trunk: ./ subversion/include/private/svn_ra_svn_private.h subversion/libsvn_ra_svn/client.c subversion/libsvn_ra_svn/editorp.c subversion/libsvn_ra_svn/marshal.c

Author: stefan2
Date: Thu Aug  6 13:08:33 2015
New Revision: 1694490

URL: http://svn.apache.org/r1694490
Log:
Merge the ra-svn-tuning development branch to trunk and remove the
BRANCH-README file.  There were no conflicts.

Changes brought by this branch:
- More efficient protocol command dispatch.
- Efficient string handling (svn_string_t instead of const char *).
- Throughput improvements by providing optimized code paths
- Widen the internal 32 bit item ID to 64 bit to eliminate any chance of
  overflow in the future.

Modified:
    subversion/trunk/   (props changed)
    subversion/trunk/subversion/include/private/svn_ra_svn_private.h
    subversion/trunk/subversion/libsvn_ra_svn/client.c
    subversion/trunk/subversion/libsvn_ra_svn/editorp.c
    subversion/trunk/subversion/libsvn_ra_svn/marshal.c

Propchange: subversion/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Aug  6 13:08:33 2015
@@ -64,6 +64,7 @@
 /subversion/branches/performance:979193,980118,981087,981090,981189,981194,981287,981684,981827,982043,982355,983398,983406,983430,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601,985603,985606,985669,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,1029335-1029336,1029339-1029340,1029342,10
 29344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
 /subversion/branches/pin-externals:1643757-1659392
 /subversion/branches/py-tests-as-modules:956579-1033052
+/subversion/branches/ra-svn-tuning:1658201-1694489
 /subversion/branches/ra_serf-digest-authn:875693-876404
 /subversion/branches/reintegrate-improvements:873853-874164
 /subversion/branches/remote-only-status:1581845-1586090

Modified: subversion/trunk/subversion/include/private/svn_ra_svn_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_ra_svn_private.h?rev=1694490&r1=1694489&r2=1694490&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_ra_svn_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_ra_svn_private.h Thu Aug  6 13:08:33 2015
@@ -347,7 +347,7 @@ svn_error_t *
 svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
                                 apr_pool_t *pool,
                                 svn_revnum_t rev,
-                                const char *token);
+                                const svn_string_t *token);
 
 /** Send a "delete-entry" command over connection @a conn.  Delete the
  * @a path at optional revision @a rev below @a parent_token.
@@ -358,7 +358,7 @@ svn_ra_svn__write_cmd_delete_entry(svn_r
                                    apr_pool_t *pool,
                                    const char *path,
                                    svn_revnum_t rev,
-                                   const char *parent_token);
+                                   const svn_string_t *parent_token);
 
 /** Send a "add-dir" command over connection @a conn.  Add a new directory
  * node named @a path under the directory identified by @a parent_token.
@@ -370,8 +370,8 @@ svn_error_t *
 svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
                               apr_pool_t *pool,
                               const char *path,
-                              const char *parent_token,
-                              const char *token,
+                              const svn_string_t *parent_token,
+                              const svn_string_t *token,
                               const char *copy_path,
                               svn_revnum_t copy_rev);
 
@@ -384,8 +384,8 @@ svn_error_t *
 svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
                                apr_pool_t *pool,
                                const char *path,
-                               const char *parent_token,
-                               const char *token,
+                               const svn_string_t *parent_token,
+                               const svn_string_t *token,
                                svn_revnum_t rev);
 
 /** Send a "change-dir-prop" command over connection @a conn.  Set the
@@ -395,7 +395,7 @@ svn_ra_svn__write_cmd_open_dir(svn_ra_sv
 svn_error_t *
 svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
                                       apr_pool_t *pool,
-                                      const char *token,
+                                      const svn_string_t *token,
                                       const char *name,
                                       const svn_string_t *value);
 
@@ -406,7 +406,7 @@ svn_ra_svn__write_cmd_change_dir_prop(sv
 svn_error_t *
 svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn,
                                 apr_pool_t *pool,
-                                const char *token);
+                                const svn_string_t *token);
 
 /** Send a "absent-dir" command over connection @a conn.  Directory node
  * named @a path under the directory identified by @a parent_token is
@@ -416,7 +416,7 @@ svn_error_t *
 svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
                                  apr_pool_t *pool,
                                  const char *path,
-                                 const char *parent_token);
+                                 const svn_string_t *parent_token);
 
 /** Send a "add-file" command over connection @a conn.  Add a new file
  * node named @a path under the directory identified by @a parent_token.
@@ -428,8 +428,8 @@ svn_error_t *
 svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
                                apr_pool_t *pool,
                                const char *path,
-                               const char *parent_token,
-                               const char *token,
+                               const svn_string_t *parent_token,
+                               const svn_string_t *token,
                                const char *copy_path,
                                svn_revnum_t copy_rev);
 
@@ -442,8 +442,8 @@ svn_error_t *
 svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
                                 apr_pool_t *pool,
                                 const char *path,
-                                const char *parent_token,
-                                const char *token,
+                                const svn_string_t *parent_token,
+                                const svn_string_t *token,
                                 svn_revnum_t rev);
 
 /** Send a "change-file-prop" command over connection @a conn.  Set the
@@ -453,7 +453,7 @@ svn_ra_svn__write_cmd_open_file(svn_ra_s
 svn_error_t *
 svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
                                        apr_pool_t *pool,
-                                       const char *token,
+                                       const svn_string_t *token,
                                        const char *name,
                                        const svn_string_t *value);
 
@@ -465,7 +465,7 @@ svn_ra_svn__write_cmd_change_file_prop(s
 svn_error_t *
 svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
                                  apr_pool_t *pool,
-                                 const char *token,
+                                 const svn_string_t *token,
                                  const char *text_checksum);
 
 /** Send a "absent-file" command over connection @a conn.  File node
@@ -476,7 +476,7 @@ svn_error_t *
 svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
                                   apr_pool_t *pool,
                                   const char *path,
-                                  const char *parent_token);
+                                  const svn_string_t *parent_token);
 
 /** Send a "apply-textdelta" command over connection @a conn.  Starts a
  * series of text deltas to be applied to the file identified by @a token.
@@ -486,7 +486,7 @@ svn_ra_svn__write_cmd_absent_file(svn_ra
 svn_error_t *
 svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
                                       apr_pool_t *pool,
-                                      const char *token,
+                                      const svn_string_t *token,
                                       const char *base_checksum);
 
 /** Send a "textdelta-chunk" command over connection @a conn.  Apply
@@ -496,7 +496,7 @@ svn_ra_svn__write_cmd_apply_textdelta(sv
 svn_error_t *
 svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
                                       apr_pool_t *pool,
-                                      const char *token,
+                                      const svn_string_t *token,
                                       const svn_string_t *chunk);
 
 /** Send a "textdelta-end" command over connection @a conn.  Ends the
@@ -506,7 +506,7 @@ svn_ra_svn__write_cmd_textdelta_chunk(sv
 svn_error_t *
 svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn,
                                     apr_pool_t *pool,
-                                    const char *token);
+                                    const svn_string_t *token);
 
 /** Send a "close-edit" command over connection @a conn.  Ends the editor
  * drive (successfully).  Use @a pool for allocations.
@@ -790,7 +790,7 @@ svn_error_t *
 svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
                              apr_pool_t *pool,
                              const char *path,
-                             const char *token,
+                             const svn_string_t *token,
                              svn_boolean_t break_lock);
 
 /** Send a "get-lock" command over connection @a conn.

Modified: subversion/trunk/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_svn/client.c?rev=1694490&r1=1694489&r2=1694490&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/trunk/subversion/libsvn_ra_svn/client.c Thu Aug  6 13:08:33 2015
@@ -2291,7 +2291,7 @@ static svn_error_t *ra_svn_unlock_compat
       const void *key;
       const char *path;
       void *val;
-      const char *token;
+      const svn_string_t *token;
       svn_error_t *err, *callback_err = NULL;
 
       svn_pool_clear(iterpool);
@@ -2299,7 +2299,7 @@ static svn_error_t *ra_svn_unlock_compat
       apr_hash_this(hi, &key, NULL, &val);
       path = key;
       if (strcmp(val, "") != 0)
-        token = val;
+        token = svn_string_create(val, iterpool);
       else
         token = NULL;
 

Modified: subversion/trunk/subversion/libsvn_ra_svn/editorp.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_svn/editorp.c?rev=1694490&r1=1694489&r2=1694490&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_svn/editorp.c (original)
+++ subversion/trunk/subversion/libsvn_ra_svn/editorp.c Thu Aug  6 13:08:33 2015
@@ -39,8 +39,11 @@
 #include "svn_pools.h"
 #include "svn_private_config.h"
 
+#include "private/svn_atomic.h"
 #include "private/svn_fspath.h"
 #include "private/svn_editor.h"
+#include "private/svn_string_private.h"
+#include "private/svn_subr_private.h"
 
 #include "ra_svn.h"
 
@@ -57,7 +60,7 @@ typedef struct ra_svn_edit_baton_t {
   svn_ra_svn_conn_t *conn;
   svn_ra_svn_edit_callback callback;    /* Called on successful completion. */
   void *callback_baton;
-  int next_token;
+  apr_uint64_t next_token;
   svn_boolean_t got_status;
 } ra_svn_edit_baton_t;
 
@@ -66,13 +69,19 @@ typedef struct ra_svn_baton_t {
   svn_ra_svn_conn_t *conn;
   apr_pool_t *pool;
   ra_svn_edit_baton_t *eb;
-  const char *token;
+  svn_string_t *token;
 } ra_svn_baton_t;
 
+/* Forward declaration. */
+typedef struct ra_svn_token_entry_t ra_svn_token_entry_t;
+
 typedef struct ra_svn_driver_state_t {
   const svn_delta_editor_t *editor;
   void *edit_baton;
   apr_hash_t *tokens;
+
+  /* Entry for the last token seen.  May be NULL. */
+  ra_svn_token_entry_t *last_token;
   svn_boolean_t *aborted;
   svn_boolean_t done;
   apr_pool_t *pool;
@@ -90,26 +99,33 @@ typedef struct ra_svn_driver_state_t {
    field in this structure is vestigial for files, and we use it for a
    different purpose instead: at apply-textdelta time, we set it to a
    subpool of the file pool, which is destroyed in textdelta-end. */
-typedef struct ra_svn_token_entry_t {
+struct ra_svn_token_entry_t {
   svn_string_t *token;
   void *baton;
   svn_boolean_t is_file;
   svn_stream_t *dstream;  /* svndiff stream for apply_textdelta */
   apr_pool_t *pool;
-} ra_svn_token_entry_t;
+};
 
 /* --- CONSUMING AN EDITOR BY PASSING EDIT OPERATIONS OVER THE NET --- */
 
-static const char *make_token(char type, ra_svn_edit_baton_t *eb,
-                              apr_pool_t *pool)
-{
-  return apr_psprintf(pool, "%c%d", type, eb->next_token++);
+static svn_string_t *
+make_token(char type,
+           ra_svn_edit_baton_t *eb,
+           apr_pool_t *pool)
+{
+  apr_size_t len;
+  char buffer[1 + SVN_INT64_BUFFER_SIZE];
+  buffer[0] = type;
+  len = 1 + svn__ui64toa(&buffer[1], eb->next_token++);
+  
+  return svn_string_ncreate(buffer, len, pool);
 }
 
 static ra_svn_baton_t *ra_svn_make_baton(svn_ra_svn_conn_t *conn,
                                          apr_pool_t *pool,
                                          ra_svn_edit_baton_t *eb,
-                                         const char *token)
+                                         svn_string_t *token)
 {
   ra_svn_baton_t *b;
 
@@ -171,7 +187,7 @@ static svn_error_t *ra_svn_open_root(voi
                                      apr_pool_t *pool, void **root_baton)
 {
   ra_svn_edit_baton_t *eb = edit_baton;
-  const char *token = make_token('d', eb, pool);
+  svn_string_t *token = make_token('d', eb, pool);
 
   SVN_ERR(check_for_error(eb, pool));
   SVN_ERR(svn_ra_svn__write_cmd_open_root(eb->conn, pool, rev, token));
@@ -196,7 +212,7 @@ static svn_error_t *ra_svn_add_dir(const
                                    apr_pool_t *pool, void **child_baton)
 {
   ra_svn_baton_t *b = parent_baton;
-  const char *token = make_token('d', b->eb, pool);
+  svn_string_t *token = make_token('d', b->eb, pool);
 
   SVN_ERR_ASSERT((copy_path && SVN_IS_VALID_REVNUM(copy_rev))
                  || (!copy_path && !SVN_IS_VALID_REVNUM(copy_rev)));
@@ -212,7 +228,7 @@ static svn_error_t *ra_svn_open_dir(cons
                                     void **child_baton)
 {
   ra_svn_baton_t *b = parent_baton;
-  const char *token = make_token('d', b->eb, pool);
+  svn_string_t *token = make_token('d', b->eb, pool);
 
   SVN_ERR(check_for_error(b->eb, pool));
   SVN_ERR(svn_ra_svn__write_cmd_open_dir(b->conn, pool, path, b->token,
@@ -265,7 +281,7 @@ static svn_error_t *ra_svn_add_file(cons
                                     void **file_baton)
 {
   ra_svn_baton_t *b = parent_baton;
-  const char *token = make_token('c', b->eb, pool);
+  svn_string_t *token = make_token('c', b->eb, pool);
 
   SVN_ERR_ASSERT((copy_path && SVN_IS_VALID_REVNUM(copy_rev))
                  || (!copy_path && !SVN_IS_VALID_REVNUM(copy_rev)));
@@ -283,7 +299,7 @@ static svn_error_t *ra_svn_open_file(con
                                      void **file_baton)
 {
   ra_svn_baton_t *b = parent_baton;
-  const char *token = make_token('c', b->eb, pool);
+  svn_string_t *token = make_token('c', b->eb, pool);
 
   SVN_ERR(check_for_error(b->eb, b->pool));
   SVN_ERR(svn_ra_svn__write_cmd_open_file(b->conn, pool, path, b->token,
@@ -480,6 +496,7 @@ static ra_svn_token_entry_t *store_token
   entry->pool = pool;
 
   apr_hash_set(ds->tokens, entry->token->data, entry->token->len, entry);
+  ds->last_token = entry;
 
   return entry;
 }
@@ -489,7 +506,16 @@ static svn_error_t *lookup_token(ra_svn_
                                  svn_boolean_t is_file,
                                  ra_svn_token_entry_t **entry)
 {
-  *entry = apr_hash_get(ds->tokens, token->data, token->len);
+  if (ds->last_token && svn_string_compare(ds->last_token->token, token))
+    {
+      *entry = ds->last_token;
+    }
+  else
+    {
+      *entry = apr_hash_get(ds->tokens, token->data, token->len);
+      ds->last_token = *entry;
+    }
+
   if (!*entry || (*entry)->is_file != is_file)
     return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                             _("Invalid file or dir token during edit"));
@@ -883,11 +909,15 @@ static svn_error_t *ra_svn_handle_finish
   return SVN_NO_ERROR;
 }
 
+/* Common function signature for all editor command handlers. */
+typedef svn_error_t *(*cmd_handler_t)(svn_ra_svn_conn_t *conn,
+                                      apr_pool_t *pool,
+                                      const apr_array_header_t *params,
+                                      ra_svn_driver_state_t *ds);
+
 static const struct {
   const char *cmd;
-  svn_error_t *(*handler)(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                          const apr_array_header_t *params,
-                          ra_svn_driver_state_t *ds);
+  cmd_handler_t handler;
 } ra_svn_edit_cmds[] = {
   { "change-file-prop", ra_svn_handle_change_file_prop },
   { "open-file",        ra_svn_handle_open_file },
@@ -911,6 +941,92 @@ static const struct {
   { NULL }
 };
 
+/* All editor commands are kept in a collision-free hash table. */
+
+/* Hash table entry.
+   It is similar to ra_svn_edit_cmds but uses our SVN string type. */
+typedef struct cmd_t {
+  svn_string_t cmd;
+  cmd_handler_t handler;
+} cmd_t;
+
+/* The actual hash table.  It will be filled once before first usage.
+
+   If you add more commands, you may have to tweak the table size to
+   eliminate collisions.  Alternatively, you may modify the hash function.
+
+   Be sure to initialize all elements with 0 as the has conflict detection
+   will rely on it (see init_cmd_hash).
+ */
+#define CMD_HASH_SIZE 67
+static cmd_t cmd_hash[CMD_HASH_SIZE] = { { { NULL } } };
+
+/* Init flag that controls CMD_HASH's atomic initialization. */
+static volatile svn_atomic_t cmd_hash_initialized = FALSE;
+
+/* Super-fast hash function that works very well with the structure of our
+   command words.  It produces no conflicts for them.
+
+   Return the index within CMD_HASH that a command NAME of LEN chars would
+   be found.  LEN > 0.
+ */
+static apr_size_t
+cmd_hash_func(const char *name,
+              apr_size_t len)
+{
+  apr_size_t value =     (apr_byte_t)(name[0] - 'a') % 8
+                   + 1 * (apr_byte_t)(name[len - 1] - 'a') % 8
+                   + 10 * (len - 7);
+  return value % CMD_HASH_SIZE;
+}
+
+/* svn_atomic__init_once callback that fills the CMD_HASH table.  It will
+   error out on hash collisions.  BATON and POOL are not used. */
+static svn_error_t *
+init_cmd_hash(void *baton,
+              apr_pool_t *pool)
+{
+  int i;
+  for (i = 0; ra_svn_edit_cmds[i].cmd; i++)
+    {
+      apr_size_t len = strlen(ra_svn_edit_cmds[i].cmd);
+      apr_size_t value = cmd_hash_func(ra_svn_edit_cmds[i].cmd, len);
+      SVN_ERR_ASSERT(cmd_hash[value].cmd.data == NULL);
+
+      cmd_hash[value].cmd.data = ra_svn_edit_cmds[i].cmd;
+      cmd_hash[value].cmd.len = len;
+      cmd_hash[value].handler = ra_svn_edit_cmds[i].handler;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Return the command handler function for the command name CMD.
+   Return NULL if no such handler exists */
+static cmd_handler_t
+cmd_lookup(const char *cmd)
+{
+  apr_size_t value;
+  apr_size_t len = strlen(cmd);
+
+  /* Malicious data that our hash function may not like? */
+  if (len == 0)
+    return NULL;
+
+  /* Hash lookup. */
+  value = cmd_hash_func(cmd, len);
+
+  /* Hit? */
+  if (cmd_hash[value].cmd.len != len)
+    return NULL;
+
+  if (memcmp(cmd_hash[value].cmd.data, cmd, len))
+    return NULL;
+
+  /* Yes! */
+  return cmd_hash[value].handler;
+}
+
 static svn_error_t *blocked_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                   void *baton)
 {
@@ -939,13 +1055,16 @@ svn_error_t *svn_ra_svn_drive_editor2(sv
   ra_svn_driver_state_t state;
   apr_pool_t *subpool = svn_pool_create(pool);
   const char *cmd;
-  int i;
   svn_error_t *err, *write_err;
   apr_array_header_t *params;
 
+  SVN_ERR(svn_atomic__init_once(&cmd_hash_initialized, init_cmd_hash, NULL,
+                                pool));
+
   state.editor = editor;
   state.edit_baton = edit_baton;
-  state.tokens = apr_hash_make(pool);
+  state.tokens = svn_hash__make(pool);
+  state.last_token = NULL;
   state.aborted = aborted;
   state.done = FALSE;
   state.pool = pool;
@@ -958,13 +1077,12 @@ svn_error_t *svn_ra_svn_drive_editor2(sv
       svn_pool_clear(subpool);
       if (editor)
         {
+          cmd_handler_t handler;
           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;
+          handler = cmd_lookup(cmd);
 
-          if (ra_svn_edit_cmds[i].cmd)
-            err = (*ra_svn_edit_cmds[i].handler)(conn, subpool, params, &state);
+          if (handler)
+            err = (*handler)(conn, subpool, params, &state);
           else if (strcmp(cmd, "failure") == 0)
             {
               /* While not really an editor command this can occur when

Modified: subversion/trunk/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_svn/marshal.c?rev=1694490&r1=1694489&r2=1694490&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/trunk/subversion/libsvn_ra_svn/marshal.c Thu Aug  6 13:08:33 2015
@@ -60,9 +60,10 @@
 
 /* We don't use "words" longer than this in our protocol.  The longest word
  * we are currently using is only about 16 chars long but we leave room for
- * longer future capability and command names.
+ * longer future capability and command names.  See read_item() to understand
+ * why MAX_WORD_LENGTH - 1 should be a multiple of 8.
  */
-#define MAX_WORD_LENGTH 31
+#define MAX_WORD_LENGTH 25
 
 /* The generic parsers will use the following value to limit the recursion
  * depth to some reasonable value.  The current protocol implementation
@@ -512,22 +513,65 @@ svn_ra_svn__write_number(svn_ra_svn_conn
   return write_number(conn, pool, number, ' ');
 }
 
+/* Write string S of length LEN to TARGET and return the first position
+   after the written data.
+
+   NOTE: This function assumes that TARGET has enough room for S, the LEN
+         prefix and the required separators.  The available buffer size
+         should be SVN_INT64_BUFFER_SIZE + LEN + 1 to avoid any chance of
+         overflow.
+ */
+static char *
+write_ncstring_quick(char *target,
+                     const char *s,
+                     apr_size_t len)
+{
+  /* Write string length. */
+  if (len < 10)
+    {
+      *target = (char)(len + '0');
+      target++;
+    }
+  else
+    {
+      target += svn__ui64toa(target, len);
+    }
+
+  /* Separator & contents. */
+  target[0] = ':';
+  memcpy(target + 1, s, len);
+  target[len + 1] = ' ';
+
+  /* First location after the string. */
+  return target + len + 2;
+}
+
+
 static svn_error_t *
 svn_ra_svn__write_ncstring(svn_ra_svn_conn_t *conn,
                            apr_pool_t *pool,
                            const char *s,
                            apr_size_t len)
 {
-  if (len < 10)
-    {
-      SVN_ERR(writebuf_writechar(conn, pool, (char)(len + '0')));
-      SVN_ERR(writebuf_writechar(conn, pool, ':'));
+  apr_size_t needed = SVN_INT64_BUFFER_SIZE + len + 1;
+
+  /* In most cases, there is enough left room in the WRITE_BUF
+     the we can serialize directly into it. */
+  if (conn->write_pos + needed < sizeof(conn->write_buf))
+    {
+      /* Quick path. */
+      conn->write_pos = write_ncstring_quick(conn->write_buf
+                                               + conn->write_pos, s, len)
+                      - conn->write_buf;
     }
   else
-    SVN_ERR(write_number(conn, pool, len, ':'));
+    {
+      /* Slower fallback code. */
+      SVN_ERR(write_number(conn, pool, len, ':'));
 
-  SVN_ERR(writebuf_write(conn, pool, s, len));
-  SVN_ERR(writebuf_writechar(conn, pool, ' '));
+      SVN_ERR(writebuf_write(conn, pool, s, len));
+      SVN_ERR(writebuf_writechar(conn, pool, ' '));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -755,6 +799,52 @@ write_tuple_string_opt(svn_ra_svn_conn_t
   return str ? svn_ra_svn__write_string(conn, pool, str) : SVN_NO_ERROR;
 }
 
+/* Optimized sending code for the "(s?)" pattern. */
+static svn_error_t *
+write_tuple_string_opt_list(svn_ra_svn_conn_t *conn,
+                            apr_pool_t *pool,
+                            const svn_string_t *str)
+{
+  apr_size_t needed;
+
+  /* Special case. */
+  if (!str)
+    return writebuf_write(conn, pool, "( ) ", 4);
+
+  /* If there is at least this much the room left in the WRITE_BUF,
+     we can serialize directly into it. */
+  needed = 2                       /* open list */
+         + SVN_INT64_BUFFER_SIZE   /* string length + separator */
+         + str->len                /* string contents */
+         + 2;                      /* close list */
+
+  if (conn->write_pos + needed <= sizeof(conn->write_buf))
+    {
+      /* Quick path. */
+      /* Open list. */
+      char *p = conn->write_buf + conn->write_pos;
+      p[0] = '(';
+      p[1] = ' ';
+
+      /* Write string. */
+      p = write_ncstring_quick(p + 2, str->data, str->len);
+
+      /* Close list. */
+      p[0] = ')';
+      p[1] = ' ';
+      conn->write_pos = p + 2 - conn->write_buf;
+    }
+  else
+    {
+      /* Standard code path (fallback). */
+      SVN_ERR(svn_ra_svn__start_list(conn, pool));
+      SVN_ERR(svn_ra_svn__write_string(conn, pool, str));
+      SVN_ERR(svn_ra_svn__end_list(conn, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 write_tuple_start_list(svn_ra_svn_conn_t *conn,
                        apr_pool_t *pool)
@@ -809,14 +899,14 @@ static svn_error_t *
 write_cmd_add_node(svn_ra_svn_conn_t *conn,
                    apr_pool_t *pool,
                    const char *path,
-                   const char *parent_token,
-                   const char *token,
+                   const svn_string_t *parent_token,
+                   const svn_string_t *token,
                    const char *copy_path,
                    svn_revnum_t copy_rev)
 {
   SVN_ERR(write_tuple_cstring(conn, pool, path));
-  SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, parent_token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(write_tuple_start_list(conn, pool));
   SVN_ERR(write_tuple_cstring_opt(conn, pool, copy_path));
   SVN_ERR(write_tuple_revision_opt(conn, pool, copy_rev));
@@ -829,13 +919,13 @@ static svn_error_t *
 write_cmd_open_node(svn_ra_svn_conn_t *conn,
                     apr_pool_t *pool,
                     const char *path,
-                    const char *parent_token,
-                    const char *token,
+                    const svn_string_t *parent_token,
+                    const svn_string_t *token,
                     svn_revnum_t rev)
 {
   SVN_ERR(write_tuple_cstring(conn, pool, path));
-  SVN_ERR(write_tuple_cstring(conn, pool, parent_token));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, parent_token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(write_tuple_start_list(conn, pool));
   SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
   SVN_ERR(write_tuple_end_list(conn, pool));
@@ -846,15 +936,13 @@ write_cmd_open_node(svn_ra_svn_conn_t *c
 static svn_error_t *
 write_cmd_change_node_prop(svn_ra_svn_conn_t *conn,
                            apr_pool_t *pool,
-                           const char *token,
+                           const svn_string_t *token,
                            const char *name,
                            const svn_string_t *value)
 {
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(write_tuple_cstring(conn, pool, name));
-  SVN_ERR(write_tuple_start_list(conn, pool));
-  SVN_ERR(write_tuple_string_opt(conn, pool, value));
-  SVN_ERR(write_tuple_end_list(conn, pool));
+  SVN_ERR(write_tuple_string_opt_list(conn, pool, value));
 
   return SVN_NO_ERROR;
 }
@@ -863,10 +951,10 @@ static svn_error_t *
 write_cmd_absent_node(svn_ra_svn_conn_t *conn,
                       apr_pool_t *pool,
                       const char *path,
-                      const char *token)
+                      const svn_string_t *token)
 {
   SVN_ERR(write_tuple_cstring(conn, pool, path));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
 
   return SVN_NO_ERROR;
 }
@@ -1060,17 +1148,40 @@ static svn_error_t *read_item(svn_ra_svn
       char *p = buffer + 1;
 
       buffer[0] = c;
-      while (1)
+      if (conn->read_ptr + MAX_WORD_LENGTH <= conn->read_end)
         {
-          SVN_ERR(readbuf_getchar(conn, pool, p));
-          if (!svn_ctype_isalnum(*p) && *p != '-')
-            break;
+          /* Fast path: we can simply take a chunk from the read
+           * buffer and inspect it with no overflow checks etc.
+           *
+           * Copying these 24 bytes unconditionally is also faster
+           * than a variable-sized memcpy.  Note that P is at BUFFER[1].
+           */
+          memcpy(p, conn->read_ptr, MAX_WORD_LENGTH - 1);
+          *end = 0;
+
+          /* This will terminate at P == END because of *END == NUL. */
+          while (svn_ctype_isalnum(*p) || *p == '-')
+            ++p;
 
-          if (++p == end)
-            return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
-                                    _("Word is too long"));
+          /* Only now do we mark data as actually read. */
+          conn->read_ptr += p - buffer;
+        }
+      else
+        {
+          /* Slow path. Byte-by-byte copying and checking for
+           * input and output buffer boundaries. */
+          for (p = buffer + 1; p != end; ++p)
+            {
+              SVN_ERR(readbuf_getchar(conn, pool, p));
+              if (!svn_ctype_isalnum(*p) && *p != '-')
+                break;
+            }
         }
 
+      if (p == end)
+        return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
+                                _("Word is too long"));
+
       c = *p;
       *p = '\0';
 
@@ -1673,13 +1784,13 @@ svn_error_t *
 svn_ra_svn__write_cmd_open_root(svn_ra_svn_conn_t *conn,
                                 apr_pool_t *pool,
                                 svn_revnum_t rev,
-                                const char *token)
+                                const svn_string_t *token)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( open-root ( "));
   SVN_ERR(write_tuple_start_list(conn, pool));
   SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
   SVN_ERR(write_tuple_end_list(conn, pool));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
 
   return SVN_NO_ERROR;
@@ -1690,14 +1801,14 @@ svn_ra_svn__write_cmd_delete_entry(svn_r
                                    apr_pool_t *pool,
                                    const char *path,
                                    svn_revnum_t rev,
-                                   const char *token)
+                                   const svn_string_t *token)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( delete-entry ( "));
   SVN_ERR(write_tuple_cstring(conn, pool, path));
   SVN_ERR(write_tuple_start_list(conn, pool));
   SVN_ERR(write_tuple_revision_opt(conn, pool, rev));
   SVN_ERR(write_tuple_end_list(conn, pool));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
 
   return SVN_NO_ERROR;
@@ -1707,8 +1818,8 @@ svn_error_t *
 svn_ra_svn__write_cmd_add_dir(svn_ra_svn_conn_t *conn,
                               apr_pool_t *pool,
                               const char *path,
-                              const char *parent_token,
-                              const char *token,
+                              const svn_string_t *parent_token,
+                              const svn_string_t *token,
                               const char *copy_path,
                               svn_revnum_t copy_rev)
 {
@@ -1724,8 +1835,8 @@ svn_error_t *
 svn_ra_svn__write_cmd_open_dir(svn_ra_svn_conn_t *conn,
                                apr_pool_t *pool,
                                const char *path,
-                               const char *parent_token,
-                               const char *token,
+                               const svn_string_t *parent_token,
+                               const svn_string_t *token,
                                svn_revnum_t rev)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( open-dir ( "));
@@ -1738,7 +1849,7 @@ svn_ra_svn__write_cmd_open_dir(svn_ra_sv
 svn_error_t *
 svn_ra_svn__write_cmd_change_dir_prop(svn_ra_svn_conn_t *conn,
                                       apr_pool_t *pool,
-                                      const char *token,
+                                      const svn_string_t *token,
                                       const char *name,
                                       const svn_string_t *value)
 {
@@ -1752,10 +1863,10 @@ svn_ra_svn__write_cmd_change_dir_prop(sv
 svn_error_t *
 svn_ra_svn__write_cmd_close_dir(svn_ra_svn_conn_t *conn,
                                 apr_pool_t *pool,
-                                const char *token)
+                                const svn_string_t *token)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( close-dir ( "));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
 
   return SVN_NO_ERROR;
@@ -1765,7 +1876,7 @@ svn_error_t *
 svn_ra_svn__write_cmd_absent_dir(svn_ra_svn_conn_t *conn,
                                  apr_pool_t *pool,
                                  const char *path,
-                                 const char *parent_token)
+                                 const svn_string_t *parent_token)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( absent-dir ( "));
   SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
@@ -1778,8 +1889,8 @@ svn_error_t *
 svn_ra_svn__write_cmd_add_file(svn_ra_svn_conn_t *conn,
                                apr_pool_t *pool,
                                const char *path,
-                               const char *parent_token,
-                               const char *token,
+                               const svn_string_t *parent_token,
+                               const svn_string_t *token,
                                const char *copy_path,
                                svn_revnum_t copy_rev)
 {
@@ -1795,8 +1906,8 @@ svn_error_t *
 svn_ra_svn__write_cmd_open_file(svn_ra_svn_conn_t *conn,
                                 apr_pool_t *pool,
                                 const char *path,
-                                const char *parent_token,
-                                const char *token,
+                                const svn_string_t *parent_token,
+                                const svn_string_t *token,
                                 svn_revnum_t rev)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( open-file ( "));
@@ -1809,7 +1920,7 @@ svn_ra_svn__write_cmd_open_file(svn_ra_s
 svn_error_t *
 svn_ra_svn__write_cmd_change_file_prop(svn_ra_svn_conn_t *conn,
                                        apr_pool_t *pool,
-                                       const char *token,
+                                       const svn_string_t *token,
                                        const char *name,
                                        const svn_string_t *value)
 {
@@ -1823,11 +1934,11 @@ svn_ra_svn__write_cmd_change_file_prop(s
 svn_error_t *
 svn_ra_svn__write_cmd_close_file(svn_ra_svn_conn_t *conn,
                                  apr_pool_t *pool,
-                                 const char *token,
+                                 const svn_string_t *token,
                                  const char *text_checksum)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( close-file ( "));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(write_tuple_start_list(conn, pool));
   SVN_ERR(write_tuple_cstring_opt(conn, pool, text_checksum));
   SVN_ERR(write_tuple_end_list(conn, pool));
@@ -1840,7 +1951,7 @@ svn_error_t *
 svn_ra_svn__write_cmd_absent_file(svn_ra_svn_conn_t *conn,
                                   apr_pool_t *pool,
                                   const char *path,
-                                  const char *parent_token)
+                                  const svn_string_t *parent_token)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( absent-file ( "));
   SVN_ERR(write_cmd_absent_node(conn, pool, path, parent_token));
@@ -1852,11 +1963,11 @@ svn_ra_svn__write_cmd_absent_file(svn_ra
 svn_error_t *
 svn_ra_svn__write_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn,
                                       apr_pool_t *pool,
-                                      const char *token,
+                                      const svn_string_t *token,
                                       const svn_string_t *chunk)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-chunk ( "));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(write_tuple_string(conn, pool, chunk));
   SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
 
@@ -1866,10 +1977,10 @@ svn_ra_svn__write_cmd_textdelta_chunk(sv
 svn_error_t *
 svn_ra_svn__write_cmd_textdelta_end(svn_ra_svn_conn_t *conn,
                                     apr_pool_t *pool,
-                                    const char *token)
+                                    const svn_string_t *token)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( textdelta-end ( "));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
 
   return SVN_NO_ERROR;
@@ -1878,11 +1989,11 @@ svn_ra_svn__write_cmd_textdelta_end(svn_
 svn_error_t *
 svn_ra_svn__write_cmd_apply_textdelta(svn_ra_svn_conn_t *conn,
                                       apr_pool_t *pool,
-                                      const char *token,
+                                      const svn_string_t *token,
                                       const char *base_checksum)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( apply-textdelta ( "));
-  SVN_ERR(write_tuple_cstring(conn, pool, token));
+  SVN_ERR(write_tuple_string(conn, pool, token));
   SVN_ERR(write_tuple_start_list(conn, pool));
   SVN_ERR(write_tuple_cstring_opt(conn, pool, base_checksum));
   SVN_ERR(write_tuple_end_list(conn, pool));
@@ -2020,9 +2131,7 @@ svn_ra_svn__write_cmd_change_rev_prop2(s
   SVN_ERR(writebuf_write_literal(conn, pool, "( change-rev-prop2 ( "));
   SVN_ERR(write_tuple_revision(conn, pool, rev));
   SVN_ERR(write_tuple_cstring(conn, pool, name));
-  SVN_ERR(write_tuple_start_list(conn, pool));
-  SVN_ERR(write_tuple_string_opt(conn, pool, value));
-  SVN_ERR(write_tuple_end_list(conn, pool));
+  SVN_ERR(write_tuple_string_opt_list(conn, pool, value));
   SVN_ERR(write_tuple_start_list(conn, pool));
   SVN_ERR(write_tuple_boolean(conn, pool, dont_care));
   SVN_ERR(write_tuple_string_opt(conn, pool, old_value));
@@ -2274,14 +2383,12 @@ svn_error_t *
 svn_ra_svn__write_cmd_unlock(svn_ra_svn_conn_t *conn,
                              apr_pool_t *pool,
                              const char *path,
-                             const char *token,
+                             const svn_string_t *token,
                              svn_boolean_t break_lock)
 {
   SVN_ERR(writebuf_write_literal(conn, pool, "( unlock ( "));
   SVN_ERR(write_tuple_cstring(conn, pool, path));
-  SVN_ERR(write_tuple_start_list(conn, pool));
-  SVN_ERR(write_tuple_cstring_opt(conn, pool, token));
-  SVN_ERR(write_tuple_end_list(conn, pool));
+  SVN_ERR(write_tuple_string_opt_list(conn, pool, token));
   SVN_ERR(write_tuple_boolean(conn, pool, break_lock));
   SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
 
@@ -2431,6 +2538,49 @@ svn_error_t *svn_ra_svn__write_cmd_failu
   return writebuf_write_literal(conn, pool, ") ) ");
 }
 
+/* Initializer for static svn_string_t . */
+#define STATIC_SVN_STRING(x) { x, sizeof(x) - 1 }
+
+/* Return a pre-cooked serialized representation for the changed path
+   flags NODE_KIND, TEXT_MODIFIED and PROPS_MODIFIED.  If we don't
+   have a suitable pre-cooked string, return an empty string. */
+static const svn_string_t *
+changed_path_flags(svn_node_kind_t node_kind,
+                   svn_boolean_t text_modified,
+                   svn_boolean_t props_modified)
+{
+  const static svn_string_t file_flags[4]
+    = { STATIC_SVN_STRING(" ) ( 4:file false false ) ) "),
+        STATIC_SVN_STRING(" ) ( 4:file false true ) ) "),
+        STATIC_SVN_STRING(" ) ( 4:file true false ) ) "),
+        STATIC_SVN_STRING(" ) ( 4:file true true ) ) ") };
+
+  const static svn_string_t dir_flags[4]
+    = { STATIC_SVN_STRING(" ) ( 3:dir false false ) ) "),
+        STATIC_SVN_STRING(" ) ( 3:dir false true ) ) "),
+        STATIC_SVN_STRING(" ) ( 3:dir true false ) ) "),
+        STATIC_SVN_STRING(" ) ( 3:dir true true ) ) ") };
+
+  const static svn_string_t no_flags = STATIC_SVN_STRING("");
+
+  /* Select the array based on the NODE_KIND. */
+  const svn_string_t *flags;
+  if (node_kind == svn_node_file)
+    flags = file_flags;
+  else if (node_kind == svn_node_dir)
+    flags = dir_flags;
+  else
+    return &no_flags;
+
+  /* Select the correct array entry. */
+  if (text_modified)
+    flags += 2;
+  if (props_modified)
+    flags++;
+
+  return flags;
+}
+
 svn_error_t *
 svn_ra_svn__write_data_log_changed_path(svn_ra_svn_conn_t *conn,
                                         apr_pool_t *pool,
@@ -2442,21 +2592,77 @@ svn_ra_svn__write_data_log_changed_path(
                                         svn_boolean_t text_modified,
                                         svn_boolean_t props_modified)
 {
-  SVN_ERR(write_tuple_start_list(conn, pool));
+  apr_size_t path_len = strlen(path);
+  apr_size_t copyfrom_len = copyfrom_path ? strlen(copyfrom_path) : 0;
+  const svn_string_t *flags_str = changed_path_flags(node_kind,
+                                                     text_modified,
+                                                     props_modified);
+
+  /* How much buffer space do we need (worst case)? */
+  apr_size_t needed = 2                 /* list start */
+                    + path_len + SVN_INT64_BUFFER_SIZE
+                                        /* path */
+                    + 2                 /* action */
+                    + 2 + copyfrom_len + 2 * SVN_INT64_BUFFER_SIZE
+                                        /* list start + copy-from info */
+                    + flags_str->len;   /* flags and closing lists */
+
+  /* If the remaining buffer is big enough and we've got all parts,
+     directly copy into the buffer. */
+  if (   (conn->write_pos + needed <= sizeof(conn->write_buf))
+      && (flags_str->len > 0))
+    {
+      /* Quick path. */
+      /* Open list. */
+      char *p = conn->write_buf + conn->write_pos;
+      p[0] = '(';
+      p[1] = ' ';
+
+      /* Write path. */
+      p = write_ncstring_quick(p + 2, path, path_len);
+
+      /* Action */
+      p[0] = action;
+      p[1] = ' ';
+      p[2] = '(';
+
+      /* Copy-from info (if given) */
+      if (copyfrom_path)
+        {
+          p[3] = ' ';
+          p = write_ncstring_quick(p + 4, copyfrom_path, copyfrom_len);
+          p += svn__ui64toa(p, copyfrom_rev);
+        }
+      else
+        {
+          p += 3;
+        }
 
-  SVN_ERR(write_tuple_cstring(conn, pool, path));
-  SVN_ERR(writebuf_writechar(conn, pool, action));
-  SVN_ERR(writebuf_writechar(conn, pool, ' '));
-  SVN_ERR(write_tuple_start_list(conn, pool));
-  SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
-  SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
-  SVN_ERR(write_tuple_end_list(conn, pool));
-  SVN_ERR(write_tuple_start_list(conn, pool));
-  SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
-  SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
-  SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
+      /* Close with flags. */
+      memcpy(p, flags_str->data, flags_str->len);
+      conn->write_pos = p + flags_str->len - conn->write_buf;
+    }
+  else
+    {
+      /* Standard code path (fallback). */
+      SVN_ERR(write_tuple_start_list(conn, pool));
 
-  return writebuf_write_literal(conn, pool, ") ) ");
+      SVN_ERR(svn_ra_svn__write_ncstring(conn, pool, path, path_len));
+      SVN_ERR(writebuf_writechar(conn, pool, action));
+      SVN_ERR(writebuf_writechar(conn, pool, ' '));
+      SVN_ERR(write_tuple_start_list(conn, pool));
+      SVN_ERR(write_tuple_cstring_opt(conn, pool, copyfrom_path));
+      SVN_ERR(write_tuple_revision_opt(conn, pool, copyfrom_rev));
+      SVN_ERR(write_tuple_end_list(conn, pool));
+      SVN_ERR(write_tuple_start_list(conn, pool));
+      SVN_ERR(write_tuple_cstring(conn, pool, svn_node_kind_to_word(node_kind)));
+      SVN_ERR(write_tuple_boolean(conn, pool, text_modified));
+      SVN_ERR(write_tuple_boolean(conn, pool, props_modified));
+
+      SVN_ERR(writebuf_write_literal(conn, pool, ") ) "));
+    }
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -2471,15 +2677,9 @@ svn_ra_svn__write_data_log_entry(svn_ra_
                                  unsigned revprop_count)
 {
   SVN_ERR(write_tuple_revision(conn, pool, revision));
-  SVN_ERR(write_tuple_start_list(conn, pool));
-  SVN_ERR(write_tuple_string_opt(conn, pool, author));
-  SVN_ERR(write_tuple_end_list(conn, pool));
-  SVN_ERR(write_tuple_start_list(conn, pool));
-  SVN_ERR(write_tuple_string_opt(conn, pool, date));
-  SVN_ERR(write_tuple_end_list(conn, pool));
-  SVN_ERR(write_tuple_start_list(conn, pool));
-  SVN_ERR(write_tuple_string_opt(conn, pool, message));
-  SVN_ERR(write_tuple_end_list(conn, pool));
+  SVN_ERR(write_tuple_string_opt_list(conn, pool, author));
+  SVN_ERR(write_tuple_string_opt_list(conn, pool, date));
+  SVN_ERR(write_tuple_string_opt_list(conn, pool, message));
   SVN_ERR(write_tuple_boolean(conn, pool, has_children));
   SVN_ERR(write_tuple_boolean(conn, pool, invalid_revnum));
   SVN_ERR(svn_ra_svn__write_number(conn, pool, revprop_count));