subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cmpil...@apache.org
Subject svn commit: r1403849 [10/19] - in /subversion/branches/master-passphrase: ./ build/ build/ac-macros/ build/hudson/ contrib/server-side/fsfsfixer/ notes/ notes/api-errata/1.8/ notes/directory-index/ notes/obliterate/ notes/tree-conflicts/ subversion/bin...
Date Tue, 30 Oct 2012 20:03:39 GMT
Modified: subversion/branches/master-passphrase/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra_svn/marshal.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra_svn/marshal.c Tue Oct 30 20:03:28 2012
@@ -54,15 +54,34 @@
 
 #define SUSPICIOUSLY_HUGE_STRING_SIZE_THRESHOLD (0x100000)
 
+/* When zero copy has been enabled, don't use blocking writes.  Instead,
+ * time out after this many microseconds. */
+
+#define ZERO_COPY_TIMEOUT 1000000
+
+/* Return the APR socket timeout to be used for the connection depending
+ * on whether there is a blockage handler or zero copy has been activated. */
+static apr_interval_time_t
+get_timeout(svn_ra_svn_conn_t *conn)
+{
+  return conn->block_handler ? 0
+                             : (conn->zero_copy_limit ? ZERO_COPY_TIMEOUT
+                                                      : -1);
+}
+
 /* --- CONNECTION INITIALIZATION --- */
 
-svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock,
+svn_ra_svn_conn_t *svn_ra_svn_create_conn3(apr_socket_t *sock,
                                            apr_file_t *in_file,
                                            apr_file_t *out_file,
                                            int compression_level,
+                                           apr_size_t zero_copy_limit,
+                                           apr_size_t error_check_interval,
                                            apr_pool_t *pool)
 {
-  svn_ra_svn_conn_t *conn = apr_palloc(pool, sizeof(*conn));
+  svn_ra_svn_conn_t *conn;
+  void *mem = apr_palloc(pool, sizeof(*conn) + SVN_RA_SVN__PAGE_SIZE);
+  conn = (void*)APR_ALIGN((apr_uintptr_t)mem, SVN_RA_SVN__PAGE_SIZE);
 
   assert((sock && !in_file && !out_file) || (!sock && in_file && out_file));
 #ifdef SVN_HAVE_SASL
@@ -73,10 +92,14 @@ svn_ra_svn_conn_t *svn_ra_svn_create_con
   conn->read_ptr = conn->read_buf;
   conn->read_end = conn->read_buf;
   conn->write_pos = 0;
+  conn->written_since_error_check = 0;
+  conn->error_check_interval = error_check_interval;
+  conn->may_check_for_error = error_check_interval == 0;
   conn->block_handler = NULL;
   conn->block_baton = NULL;
   conn->capabilities = apr_hash_make(pool);
   conn->compression_level = compression_level;
+  conn->zero_copy_limit = zero_copy_limit;
   conn->pool = pool;
 
   if (sock != NULL)
@@ -86,6 +109,7 @@ svn_ra_svn_conn_t *svn_ra_svn_create_con
       if (!(apr_socket_addr_get(&sa, APR_REMOTE, sock) == APR_SUCCESS
             && apr_sockaddr_ip_get(&conn->remote_ip, sa) == APR_SUCCESS))
         conn->remote_ip = NULL;
+      svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
     }
   else
     {
@@ -96,14 +120,25 @@ svn_ra_svn_conn_t *svn_ra_svn_create_con
   return conn;
 }
 
+svn_ra_svn_conn_t *svn_ra_svn_create_conn2(apr_socket_t *sock,
+                                           apr_file_t *in_file,
+                                           apr_file_t *out_file,
+                                           int compression_level,
+                                           apr_pool_t *pool)
+{
+  return svn_ra_svn_create_conn3(sock, in_file, out_file,
+                                 compression_level, 0, 0, pool);
+}
+
 /* backward-compatible implementation using the default compression level */
 svn_ra_svn_conn_t *svn_ra_svn_create_conn(apr_socket_t *sock,
                                           apr_file_t *in_file,
                                           apr_file_t *out_file,
                                           apr_pool_t *pool)
 {
-  return svn_ra_svn_create_conn2(sock, in_file, out_file,
-                                 SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
+  return svn_ra_svn_create_conn3(sock, in_file, out_file,
+                                 SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, 0, 0,
+                                 pool);
 }
 
 svn_error_t *svn_ra_svn_set_capabilities(svn_ra_svn_conn_t *conn,
@@ -146,6 +181,12 @@ svn_ra_svn_compression_level(svn_ra_svn_
   return conn->compression_level;
 }
 
+apr_size_t
+svn_ra_svn_zero_copy_limit(svn_ra_svn_conn_t *conn)
+{
+  return conn->zero_copy_limit;
+}
+
 const char *svn_ra_svn_conn_remote_host(svn_ra_svn_conn_t *conn)
 {
   return conn->remote_ip;
@@ -156,11 +197,9 @@ svn_ra_svn__set_block_handler(svn_ra_svn
                               ra_svn_block_handler_t handler,
                               void *baton)
 {
-  apr_interval_time_t interval = (handler) ? 0 : -1;
-
   conn->block_handler = handler;
   conn->block_baton = baton;
-  svn_ra_svn__stream_timeout(conn->stream, interval);
+  svn_ra_svn__stream_timeout(conn->stream, get_timeout(conn));
 }
 
 svn_boolean_t svn_ra_svn__input_waiting(svn_ra_svn_conn_t *conn,
@@ -171,20 +210,6 @@ svn_boolean_t svn_ra_svn__input_waiting(
 
 /* --- WRITE BUFFER MANAGEMENT --- */
 
-/* Write bytes into the write buffer until either the write buffer is
- * full or we reach END. */
-static const char *writebuf_push(svn_ra_svn_conn_t *conn, const char *data,
-                                 const char *end)
-{
-  apr_ssize_t buflen, copylen;
-
-  buflen = sizeof(conn->write_buf) - conn->write_pos;
-  copylen = (buflen < end - data) ? buflen : end - data;
-  memcpy(conn->write_buf + conn->write_pos, data, copylen);
-  conn->write_pos += copylen;
-  return data + copylen;
-}
-
 /* Write data to socket or output file as appropriate. */
 static svn_error_t *writebuf_output(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                     const char *data, apr_size_t len)
@@ -223,6 +248,10 @@ static svn_error_t *writebuf_output(svn_
         }
     }
 
+  conn->written_since_error_check += len;
+  conn->may_check_for_error
+    = conn->written_since_error_check >= conn->error_check_interval;
+
   if (subpool)
     svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
@@ -242,19 +271,23 @@ static svn_error_t *writebuf_flush(svn_r
 static svn_error_t *writebuf_write(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                    const char *data, apr_size_t len)
 {
-  const char *end = data + len;
-
-  if (conn->write_pos > 0 && conn->write_pos + len > sizeof(conn->write_buf))
+  /* data >= 8k is sent immediately */
+  if (len >= sizeof(conn->write_buf) / 2)
     {
-      /* Fill and then empty the write buffer. */
-      data = writebuf_push(conn, data, end);
-      SVN_ERR(writebuf_flush(conn, pool));
+      if (conn->write_pos > 0)
+        SVN_ERR(writebuf_flush(conn, pool));
+      
+      return writebuf_output(conn, pool, data, len);
     }
 
-  if (end - data > (apr_ssize_t)sizeof(conn->write_buf))
-    SVN_ERR(writebuf_output(conn, pool, data, end - data));
-  else
-    writebuf_push(conn, data, end);
+  /* ensure room for the data to add */
+  if (conn->write_pos + len > sizeof(conn->write_buf))
+    SVN_ERR(writebuf_flush(conn, pool));
+
+  /* buffer the new data block as well */
+  memcpy(conn->write_buf + conn->write_pos, data, len);
+  conn->write_pos += len;
+
   return SVN_NO_ERROR;
 }
 
@@ -331,6 +364,31 @@ 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_uint64_t len)
+{
+  do
+  {
+    apr_size_t buflen = conn->read_end - conn->read_ptr;
+    apr_size_t copylen = (buflen < len) ? buflen : (apr_size_t)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)
 {
@@ -562,13 +620,569 @@ svn_error_t *svn_ra_svn_flush(svn_ra_svn
 
 /* --- WRITING TUPLES --- */
 
+static svn_error_t *
+vwrite_tuple_cstring(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  const char *cstr = va_arg(*ap, const char *);
+  SVN_ERR_ASSERT(cstr);
+  return svn_ra_svn_write_cstring(conn, pool, cstr);
+}
+
+static svn_error_t *
+vwrite_tuple_cstring_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  const char *cstr = va_arg(*ap, const char *);
+  return cstr ? svn_ra_svn_write_cstring(conn, pool, cstr) : SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_tuple_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  const svn_string_t *str = va_arg(*ap, const svn_string_t *);
+  SVN_ERR_ASSERT(str);
+  return svn_ra_svn_write_string(conn, pool, str);
+}
+
+static svn_error_t *
+vwrite_tuple_string_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  const svn_string_t *str = va_arg(*ap, const svn_string_t *);
+  return str ? svn_ra_svn_write_string(conn, pool, str) : SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_tuple_start_list(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  return svn_ra_svn_start_list(conn, pool);
+}
+
+static svn_error_t *
+vwrite_tuple_end_list(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  return svn_ra_svn_end_list(conn, pool);
+}
+
+static svn_error_t *
+vwrite_tuple_word(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  const char *cstr = va_arg(*ap, const char *);
+  SVN_ERR_ASSERT(cstr);
+  return svn_ra_svn_write_word(conn, pool, cstr);
+}
+
+static svn_error_t *
+vwrite_tuple_word_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  const char *cstr = va_arg(*ap, const char *);
+  return cstr ? svn_ra_svn_write_word(conn, pool, cstr) : SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_tuple_revision(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  svn_revnum_t rev = va_arg(*ap, svn_revnum_t);
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
+  return svn_ra_svn_write_number(conn, pool, rev);
+}
+
+static svn_error_t *
+vwrite_tuple_revision_opt(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  svn_revnum_t rev = va_arg(*ap, svn_revnum_t);
+  return SVN_IS_VALID_REVNUM(rev)
+       ? svn_ra_svn_write_number(conn, pool, rev)
+       : SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_tuple_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  return svn_ra_svn_write_number(conn, pool, va_arg(*ap, apr_uint64_t));
+}
+
+static svn_error_t *
+vwrite_tuple_boolean(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  const char *cstr = va_arg(*ap, svn_boolean_t) ? "true" : "false";
+  return svn_ra_svn_write_word(conn, pool, cstr);
+}
+
+static svn_error_t *
+vwrite_cmd_open_root(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_delete_entry(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_add_dir(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_open_dir(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_change_dir_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_string_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_absent_dir(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_add_file(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_open_file(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_change_file_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_string_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_close_file(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_absent_file(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_textdelta_chunk(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_string(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_apply_textdelta(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_no_op(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_set_path(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_word(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_link_path(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_word(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_change_rev_prop2(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_string_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_string_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_change_rev_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_string_opt(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_rev_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_get_file(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_update(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_word(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_switch(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_word(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_status(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_word(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_diff(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_word(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_check_path(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_stat(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_get_file_revs(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_lock(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_unlock(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_cstring_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_get_locks(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_word(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_replay(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_replay_range(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_get_deleted_rev(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+vwrite_cmd_get_iprops(svn_ra_svn_conn_t *conn, apr_pool_t *pool, va_list *ap)
+{
+  SVN_ERR(vwrite_tuple_cstring(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_revision_opt(conn, pool, ap));
+  SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
+
+  return SVN_NO_ERROR;
+}
+ 
+typedef svn_error_t *
+(*vwrite_tuple_func)(svn_ra_svn_conn_t *, apr_pool_t *, va_list *);
+
+typedef struct cmd_template_t
+{
+  const char *start_sequence;
+  apr_size_t start_sequence_length;
+  vwrite_tuple_func write_ops;
+} cmd_template_t;
+
+static const cmd_template_t cmd_templates[svn_ra_svn_cmd__last]
+    = { {"( target-rev ( "      , 15, vwrite_tuple_revision },
+        {"( open-root ( "       , 14, vwrite_cmd_open_root },
+        {"( delete-entry ( "    , 17, vwrite_cmd_delete_entry },
+        {"( add-dir ( "         , 12, vwrite_cmd_add_dir },
+        {"( open-dir ( "        , 13, vwrite_cmd_open_dir },
+        {"( change-dir-prop ( " , 20, vwrite_cmd_change_dir_prop },
+        {"( close-dir ( "       , 14, vwrite_tuple_cstring },
+        {"( absent-dir ( "      , 15, vwrite_cmd_absent_dir },
+        {"( add-file ( "        , 13, vwrite_cmd_add_file },
+        {"( open-file ( "       , 14, vwrite_cmd_open_file },
+        {"( change-file-prop ( ", 21, vwrite_cmd_change_file_prop },
+        {"( close-file ( "      , 15, vwrite_cmd_close_file },
+        {"( absent-file ( "     , 16, vwrite_cmd_absent_file },
+        {"( textdelta-chunk ( " , 20, vwrite_cmd_textdelta_chunk },
+        {"( textdelta-end ( "   , 18, vwrite_tuple_cstring },
+        {"( apply-textdelta ( " , 20, vwrite_cmd_apply_textdelta },
+        {"( close-edit ( "      , 15, vwrite_cmd_no_op },
+        {"( abort-edit ( "      , 15, vwrite_cmd_no_op },
+
+        {"( set-path ( "        , 13, vwrite_cmd_set_path },
+        {"( delete-path ( "     , 16, vwrite_tuple_cstring },
+        {"( link-path ( "       , 14, vwrite_cmd_link_path },
+        {"( finish-report ( "   , 18, vwrite_cmd_no_op },
+        {"( abort-report ( "    , 17, vwrite_cmd_no_op },
+
+        {"( reparent ( "        , 13, vwrite_tuple_cstring },
+        {"( get-latest-rev ( "  , 19, vwrite_cmd_no_op },
+        {"( get-dated-rev ( "   , 18, vwrite_tuple_cstring },
+        {"( change-rev-prop2 ( ", 21, vwrite_cmd_change_rev_prop2 },
+        {"( change-rev-prop ( " , 20, vwrite_cmd_change_rev_prop },
+        {"( rev-proplist ( "    , 17, vwrite_tuple_revision },
+        {"( rev-prop ( "        , 13, vwrite_cmd_rev_prop },
+        {"( get-file ( "        , 13, vwrite_cmd_get_file },
+        {"( update ( "          , 11, vwrite_cmd_update },
+        {"( switch ( "          , 11, vwrite_cmd_switch },
+        {"( status ( "          , 11, vwrite_cmd_status },
+        {"( diff ( "            ,  9, vwrite_cmd_diff },
+        {"( check-path ( "      , 15, vwrite_cmd_check_path },
+        {"( stat ( "            ,  9, vwrite_cmd_stat },
+        {"( get-file-revs ( "   , 18, vwrite_cmd_get_file_revs },
+        {"( lock ( "            ,  9, vwrite_cmd_lock },
+        {"( unlock ( "          , 11, vwrite_cmd_unlock },
+        {"( get-lock ( "        , 13, vwrite_tuple_cstring },
+        {"( get-locks ( "       , 14, vwrite_cmd_get_locks },
+        {"( replay ( "          , 11, vwrite_cmd_replay },
+        {"( replay-range ( "    , 17, vwrite_cmd_replay_range },
+        {"( get-deleted-rev ( " , 20, vwrite_cmd_get_deleted_rev },
+        {"( get-iprops ( "      , 15, vwrite_cmd_get_iprops },
+        {"( finish-replay ( "   , 18, vwrite_cmd_no_op }
+    };
+
+
+
+
 static svn_error_t *vwrite_tuple(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                 const char *fmt, va_list ap)
+                                 const char *fmt, va_list *ap)
 {
   svn_boolean_t opt = FALSE;
-  svn_revnum_t rev;
-  const char *cstr;
-  const svn_string_t *str;
 
   if (*fmt == '!')
     fmt++;
@@ -577,53 +1191,30 @@ static svn_error_t *vwrite_tuple(svn_ra_
   for (; *fmt; fmt++)
     {
       if (*fmt == 'c')
-        {
-          cstr = va_arg(ap, const char *);
-          if (cstr)
-            SVN_ERR(svn_ra_svn_write_cstring(conn, pool, cstr));
-          else
-            SVN_ERR_ASSERT(opt);
-        }
+        SVN_ERR(opt ? vwrite_tuple_cstring_opt(conn, pool, ap)
+                    : vwrite_tuple_cstring(conn, pool, ap));
       else if (*fmt == 's')
-        {
-          str = va_arg(ap, const svn_string_t *);
-          if (str)
-            SVN_ERR(svn_ra_svn_write_string(conn, pool, str));
-          else
-            SVN_ERR_ASSERT(opt);
-        }
+        SVN_ERR(opt ? vwrite_tuple_string_opt(conn, pool, ap)
+                    : vwrite_tuple_string(conn, pool, ap));
       else if (*fmt == '(' && !opt)
-        SVN_ERR(svn_ra_svn_start_list(conn, pool));
+        SVN_ERR(vwrite_tuple_start_list(conn, pool, ap));
       else if (*fmt == ')')
         {
-          SVN_ERR(svn_ra_svn_end_list(conn, pool));
+          SVN_ERR(vwrite_tuple_end_list(conn, pool, ap));
           opt = FALSE;
         }
       else if (*fmt == '?')
         opt = TRUE;
       else if (*fmt == 'w')
-        {
-          cstr = va_arg(ap, const char *);
-          if (cstr)
-            SVN_ERR(svn_ra_svn_write_word(conn, pool, cstr));
-          else
-            SVN_ERR_ASSERT(opt);
-        }
+        SVN_ERR(opt ? vwrite_tuple_word_opt(conn, pool, ap)
+                    : vwrite_tuple_word(conn, pool, ap));
       else if (*fmt == 'r')
-        {
-          rev = va_arg(ap, svn_revnum_t);
-          if (SVN_IS_VALID_REVNUM(rev))
-            SVN_ERR(svn_ra_svn_write_number(conn, pool, rev));
-          else
-            SVN_ERR_ASSERT(opt);
-        }
+        SVN_ERR(opt ? vwrite_tuple_revision_opt(conn, pool, ap)
+                    : vwrite_tuple_revision(conn, pool, ap));
       else if (*fmt == 'n' && !opt)
-        SVN_ERR(svn_ra_svn_write_number(conn, pool, va_arg(ap, apr_uint64_t)));
+        SVN_ERR(vwrite_tuple_number(conn, pool, ap));
       else if (*fmt == 'b' && !opt)
-        {
-          cstr = va_arg(ap, svn_boolean_t) ? "true" : "false";
-          SVN_ERR(svn_ra_svn_write_word(conn, pool, cstr));
-        }
+        SVN_ERR(vwrite_tuple_boolean(conn, pool, ap));
       else if (*fmt == '!' && !*(fmt + 1))
         return SVN_NO_ERROR;
       else
@@ -640,7 +1231,7 @@ svn_error_t *svn_ra_svn_write_tuple(svn_
   va_list ap;
 
   va_start(ap, fmt);
-  err = vwrite_tuple(conn, pool, fmt, ap);
+  err = vwrite_tuple(conn, pool, fmt, &ap);
   va_end(ap);
   return err;
 }
@@ -800,6 +1391,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)
 {
@@ -948,6 +1628,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)
@@ -1148,11 +1840,28 @@ svn_error_t *svn_ra_svn_write_cmd(svn_ra
   SVN_ERR(svn_ra_svn_start_list(conn, pool));
   SVN_ERR(svn_ra_svn_write_word(conn, pool, cmdname));
   va_start(ap, fmt);
-  err = vwrite_tuple(conn, pool, fmt, ap);
+  err = vwrite_tuple(conn, pool, fmt, &ap);
   va_end(ap);
   return err ? svn_error_trace(err) : svn_ra_svn_end_list(conn, pool);
 }
 
+svn_error_t *svn_ra_svn_write_templated_cmd(svn_ra_svn_conn_t *conn,
+                                            apr_pool_t *pool,
+                                            svn_ra_svn_cmd_t cmd, ...)
+{
+  va_list ap;
+  svn_error_t *err;
+
+  SVN_ERR(writebuf_write_short_string(conn, pool,
+                                      cmd_templates[cmd].start_sequence,
+                                      cmd_templates[cmd].start_sequence_length));
+  va_start(ap, cmd);
+  err = cmd_templates[cmd].write_ops(conn, pool, &ap);
+  va_end(ap);
+
+  return err ? err : writebuf_write_short_string(conn, pool, ") ) ", 4);
+}
+
 svn_error_t *svn_ra_svn_write_cmd_response(svn_ra_svn_conn_t *conn,
                                            apr_pool_t *pool,
                                            const char *fmt, ...)
@@ -1162,7 +1871,7 @@ svn_error_t *svn_ra_svn_write_cmd_respon
 
   SVN_ERR(writebuf_write_short_string(conn, pool, "( success ", 10));
   va_start(ap, fmt);
-  err = vwrite_tuple(conn, pool, fmt, ap);
+  err = vwrite_tuple(conn, pool, fmt, &ap);
   va_end(ap);
   return err ? svn_error_trace(err) : svn_ra_svn_end_list(conn, pool);
 }

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra_svn/protocol
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra_svn/protocol?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra_svn/protocol (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra_svn/protocol Tue Oct 30 20:03:28 2012
@@ -202,6 +202,10 @@ capability and C indicates a client capa
 [S]  atomic-revprops   If the server presents this capability, it
                        supports the change-rev-prop2 command.
                        See section 3.1.1.
+[S]  inherited-props   If the server presents this capability, it supports the
+                       retrieval of inherited properties via the get-dir and
+                       get-file commands and also supports the get-iprops
+                       command (see section 3.1.1).
 
 3. Commands
 -----------
@@ -222,6 +226,7 @@ responds.
 Here are some miscellaneous prototypes used by the command sets:
 
   proplist:  ( ( name:string value:string ) ... )
+  iproplist: ( ( name:string proplist ) ... )
   propdelta: ( ( name:string [ value:string ] ) ... )
   node-kind: none|file|dir|unknown
   bool:      true|false
@@ -293,8 +298,10 @@ second place for auth-request point as n
                    ? ( post-commit-err:string ) )
 
   get-file
-    params:   ( path:string [ rev:number ] want-props:bool want-contents:bool )
-    response: ( [ checksum:string ] rev:number props:proplist )
+    params:   ( path:string [ rev:number ] want-props:bool want-contents:bool
+                [ want-iprops:bool ] )
+    response: ( [ checksum:string ] rev:number props:proplist
+                [ inherited-props:iproplist ] )
     If want-contents is specified, then after sending response, server
      sends file contents as a series of strings, terminated by the empty
      string, followed by a second empty command response to indicate
@@ -302,8 +309,9 @@ second place for auth-request point as n
 
   get-dir
     params:   ( path:string [ rev:number ] want-props:bool want-contents:bool
-                ? ( field:dirent-field ... ) )
-    response: ( rev:number props:proplist ( entry:dirent ... ) )]
+                ? ( field:dirent-field ... ) [ want-iprops:bool ] )
+    response: ( rev:number props:proplist ( entry:dirent ... )
+                [ inherited-props:iproplist ] )]
     dirent:   ( name:string kind:node-kind size:number has-props:bool
                 created-rev:number [ created-date:string ]
                 [ last-author:string ] )
@@ -464,6 +472,11 @@ second place for auth-request point as n
     params:   ( path:string peg-rev:number end-rev:number )
     response: ( deleted-rev:number )
 
+  get-iprops
+    params:   ( path:string [ rev:number ] )
+    response: ( inherited-props:iproplist )
+    New in svn 1.8.  If rev is not specified, the youngest revision is used.
+
 3.1.2. Editor Command Set
 
 An edit operation produces only one response, at close-edit or

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra_svn/ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra_svn/ra_svn.h?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra_svn/ra_svn.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra_svn/ra_svn.h Tue Oct 30 20:03:28 2012
@@ -56,9 +56,13 @@ typedef svn_error_t *(*ra_svn_block_hand
                                                apr_pool_t *pool,
                                                void *baton);
 
+/* The default "user agent". */
+#define SVN_RA_SVN__DEFAULT_USERAGENT  "SVN/" SVN_VER_NUMBER
+
 /* The size of our per-connection read and write buffers. */
-#define SVN_RA_SVN__READBUF_SIZE (4*4096)
-#define SVN_RA_SVN__WRITEBUF_SIZE (4*4096)
+#define SVN_RA_SVN__PAGE_SIZE 4096
+#define SVN_RA_SVN__READBUF_SIZE (4 * SVN_RA_SVN__PAGE_SIZE)
+#define SVN_RA_SVN__WRITEBUF_SIZE (4 * SVN_RA_SVN__PAGE_SIZE)
 
 /* Create forward reference */
 typedef struct svn_ra_svn__session_baton_t svn_ra_svn__session_baton_t;
@@ -66,6 +70,14 @@ typedef struct svn_ra_svn__session_baton
 /* This structure is opaque to the server.  The client pokes at the
  * first few fields during setup and cleanup. */
 struct svn_ra_svn_conn_st {
+
+  /* I/O buffers */
+  char write_buf[SVN_RA_SVN__WRITEBUF_SIZE];
+  char read_buf[SVN_RA_SVN__READBUF_SIZE];
+  char *read_ptr;
+  char *read_end;
+  apr_size_t write_pos;
+
   svn_ra_svn__stream_t *stream;
   svn_ra_svn__session_baton_t *session;
 #ifdef SVN_HAVE_SASL
@@ -75,19 +87,32 @@ struct svn_ra_svn_conn_st {
   apr_socket_t *sock;
   svn_boolean_t encrypted;
 #endif
-  char read_buf[SVN_RA_SVN__READBUF_SIZE];
-  char *read_ptr;
-  char *read_end;
-  char write_buf[SVN_RA_SVN__WRITEBUF_SIZE];
-  apr_size_t write_pos;
+
+  /* abortion check control */
+  apr_size_t written_since_error_check;
+  apr_size_t error_check_interval;
+  svn_boolean_t may_check_for_error;
+
+  /* repository info */
   const char *uuid;
   const char *repos_root;
+
+  /* TX block notification target */
   ra_svn_block_handler_t block_handler;
   void *block_baton;
+
+  /* server settings */
   apr_hash_t *capabilities;
   int compression_level;
+  apr_size_t zero_copy_limit;
+
+  /* who's on the other side of the connection? */
   char *remote_ip;
+
+  /* EV2 support*/
   svn_delta_shim_callbacks_t *shim_callbacks;
+
+  /* our pool */
   apr_pool_t *pool;
 };
 
@@ -104,6 +129,7 @@ struct svn_ra_svn__session_baton_t {
   void *callbacks_baton;
   apr_off_t bytes_read, bytes_written; /* apr_off_t's because that's what
                                           the callback interface uses */
+  const char *useragent;
 };
 
 /* Set a callback for blocked writes on conn.  This handler may
@@ -167,6 +193,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/master-passphrase/subversion/libsvn_repos/authz.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_repos/authz.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_repos/authz.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_repos/authz.c Tue Oct 30 20:03:28 2012
@@ -714,14 +714,15 @@ static svn_boolean_t authz_validate_sect
 {
   struct authz_validate_baton *b = baton;
 
-  /* If the section is the groups definition, use the group checking
-     callback. Otherwise, use the rule checking callback. */
-  if (strncmp(name, "groups", 6) == 0)
+  /* Use the group checking callback for the "groups" section... */
+  if (strcmp(name, "groups") == 0)
     svn_config_enumerate2(b->config, name, authz_validate_group,
                           baton, pool);
-  else if (strncmp(name, "aliases", 7) == 0)
+  /* ...and the alias checking callback for "aliases"... */
+  else if (strcmp(name, "aliases") == 0)
     svn_config_enumerate2(b->config, name, authz_validate_alias,
                           baton, pool);
+  /* ...but for everything else use the rule checking callback. */
   else
     {
       /* Validate the section's name. Skip the optional REPOS_NAME. */

Modified: subversion/branches/master-passphrase/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_repos/commit.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_repos/commit.c Tue Oct 30 20:03:28 2012
@@ -921,8 +921,8 @@ svn_repos_get_commit_editor5(const svn_d
                              const char *repos_url,
                              const char *base_path,
                              apr_hash_t *revprop_table,
-                             svn_commit_callback2_t callback,
-                             void *callback_baton,
+                             svn_commit_callback2_t commit_callback,
+                             void *commit_baton,
                              svn_repos_authz_callback_t authz_callback,
                              void *authz_baton,
                              apr_pool_t *pool)
@@ -967,8 +967,8 @@ svn_repos_get_commit_editor5(const svn_d
   /* Set up the edit baton. */
   eb->pool = subpool;
   eb->revprop_table = svn_prop_hash_dup(revprop_table, subpool);
-  eb->commit_callback = callback;
-  eb->commit_callback_baton = callback_baton;
+  eb->commit_callback = commit_callback;
+  eb->commit_callback_baton = commit_baton;
   eb->authz_callback = authz_callback;
   eb->authz_baton = authz_baton;
   eb->base_path = svn_fspath__canonicalize(base_path, subpool);

Modified: subversion/branches/master-passphrase/subversion/libsvn_repos/delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_repos/delta.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_repos/delta.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_repos/delta.c Tue Oct 30 20:03:28 2012
@@ -629,12 +629,23 @@ svn_repos__compare_files(svn_boolean_t *
   if (!*changed_p)
     return SVN_NO_ERROR;
 
-  /* From this point on, assume things haven't changed. */
+  /* If the SHA1 checksums match for these things, we'll claim they
+     have the same contents.  (We don't give quite as much weight to
+     MD5 checksums.)  */
+  SVN_ERR(svn_fs_file_checksum(&checksum1, svn_checksum_sha1,
+                               root1, path1, FALSE, pool));
+  SVN_ERR(svn_fs_file_checksum(&checksum2, svn_checksum_sha1,
+                               root2, path2, FALSE, pool));
+  if (checksum1 && checksum2)
+    {
+      *changed_p = !svn_checksum_match(checksum1, checksum2);
+      return SVN_NO_ERROR;
+    }
+
+  /* From this point on, our default answer is "Nothing's changed". */
   *changed_p = FALSE;
 
-  /* So, things have changed.  But we need to know if the two sets of
-     file contents are actually different.  If they have differing
-     sizes, then we know they differ. */
+  /* Different filesizes means the contents are different. */
   SVN_ERR(svn_fs_file_length(&size1, root1, path1, pool));
   SVN_ERR(svn_fs_file_length(&size2, root2, path2, pool));
   if (size1 != size2)
@@ -643,8 +654,7 @@ svn_repos__compare_files(svn_boolean_t *
       return SVN_NO_ERROR;
     }
 
-  /* Same sizes, huh?  Well, if their checksums differ, we know they
-     differ. */
+  /* Different MD5 checksums means the contents are different. */
   SVN_ERR(svn_fs_file_checksum(&checksum1, svn_checksum_md5, root1, path1,
                                FALSE, pool));
   SVN_ERR(svn_fs_file_checksum(&checksum2, svn_checksum_md5, root2, path2,
@@ -655,13 +665,11 @@ svn_repos__compare_files(svn_boolean_t *
       return SVN_NO_ERROR;
     }
 
-  /* Same sizes, same checksums.  Chances are reallllly good that they
-     don't differ, but to be absolute sure, we need to compare bytes. */
+  /* And finally, different contents means the ... uh ... contents are
+     different. */
   SVN_ERR(svn_fs_file_contents(&stream1, root1, path1, pool));
   SVN_ERR(svn_fs_file_contents(&stream2, root2, path2, pool));
-
   SVN_ERR(svn_stream_contents_same2(&same, stream1, stream2, pool));
-
   *changed_p = !same;
 
   return SVN_NO_ERROR;

Modified: subversion/branches/master-passphrase/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_repos/deprecated.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_repos/deprecated.c Tue Oct 30 20:03:28 2012
@@ -48,8 +48,8 @@ svn_repos_get_commit_editor4(const svn_d
                              const char *base_path,
                              const char *user,
                              const char *log_msg,
-                             svn_commit_callback2_t callback,
-                             void *callback_baton,
+                             svn_commit_callback2_t commit_callback,
+                             void *commit_baton,
                              svn_repos_authz_callback_t authz_callback,
                              void *authz_baton,
                              apr_pool_t *pool)
@@ -65,7 +65,7 @@ svn_repos_get_commit_editor4(const svn_d
                  svn_string_create(log_msg, pool));
   return svn_repos_get_commit_editor5(editor, edit_baton, repos, txn,
                                       repos_url, base_path, revprop_table,
-                                      callback, callback_baton,
+                                      commit_callback, commit_baton,
                                       authz_callback, authz_baton, pool);
 }
 
@@ -254,6 +254,41 @@ svn_repos_begin_report(void **report_bat
 }
 
 svn_error_t *
+svn_repos_begin_report2(void **report_baton,
+                        svn_revnum_t revnum,
+                        svn_repos_t *repos,
+                        const char *fs_base,
+                        const char *target,
+                        const char *tgt_path,
+                        svn_boolean_t text_deltas,
+                        svn_depth_t depth,
+                        svn_boolean_t ignore_ancestry,
+                        svn_boolean_t send_copyfrom_args,
+                        const svn_delta_editor_t *editor,
+                        void *edit_baton,
+                        svn_repos_authz_func_t authz_read_func,
+                        void *authz_read_baton,
+                        apr_pool_t *pool)
+{
+  return svn_repos_begin_report3(report_baton,
+                                 revnum,
+                                 repos,
+                                 fs_base,
+                                 target,
+                                 tgt_path,
+                                 text_deltas,
+                                 depth,
+                                 ignore_ancestry,
+                                 send_copyfrom_args,
+                                 editor,
+                                 edit_baton,
+                                 authz_read_func,
+                                 authz_read_baton,
+                                 0,     /* disable zero-copy code path */
+                                 pool);
+}
+
+svn_error_t *
 svn_repos_set_path2(void *baton, const char *path, svn_revnum_t rev,
                     svn_boolean_t start_empty, const char *lock_token,
                     apr_pool_t *pool)

Modified: subversion/branches/master-passphrase/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_repos/fs-wrap.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_repos/fs-wrap.c Tue Oct 30 20:03:28 2012
@@ -31,10 +31,12 @@
 #include "svn_props.h"
 #include "svn_repos.h"
 #include "svn_time.h"
+#include "svn_sorts.h"
 #include "repos.h"
 #include "svn_private_config.h"
 #include "private/svn_repos_private.h"
 #include "private/svn_utf_private.h"
+#include "private/svn_fspath.h"
 
 
 /*** Commit wrappers ***/
@@ -48,6 +50,9 @@ svn_repos_fs_commit_txn(const char **con
 {
   svn_error_t *err, *err2;
   const char *txn_name;
+  apr_hash_t *props;
+  apr_pool_t *iterpool;
+  apr_hash_index_t *hi;
 
   *new_rev = SVN_INVALID_REVNUM;
 
@@ -55,6 +60,24 @@ svn_repos_fs_commit_txn(const char **con
   SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
   SVN_ERR(svn_repos__hooks_pre_commit(repos, txn_name, pool));
 
+  /* Remove any ephemeral transaction properties. */
+  SVN_ERR(svn_fs_txn_proplist(&props, txn, pool));
+  iterpool = svn_pool_create(pool);
+  for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
+    {
+      const void *key;
+      apr_hash_this(hi, &key, NULL, NULL);
+
+      svn_pool_clear(iterpool);
+
+      if (strncmp(key, SVN_PROP_TXN_PREFIX,
+                  (sizeof(SVN_PROP_TXN_PREFIX) - 1)) == 0)
+        {
+          SVN_ERR(svn_fs_change_txn_prop(txn, key, NULL, iterpool));
+        }
+    }
+  svn_pool_destroy(iterpool);
+  
   /* Commit. */
   err = svn_fs_commit_txn(conflict_p, new_rev, txn, pool);
   if (! SVN_IS_VALID_REVNUM(*new_rev))
@@ -370,9 +393,9 @@ svn_repos_fs_revision_prop(svn_string_t 
     {
       /* Only svn:author and svn:date are fetchable. */
       if ((strncmp(propname, SVN_PROP_REVISION_AUTHOR,
-                   strlen(SVN_PROP_REVISION_AUTHOR)) != 0)
+                   sizeof(SVN_PROP_REVISION_AUTHOR)-1) != 0)
           && (strncmp(propname, SVN_PROP_REVISION_DATE,
-                      strlen(SVN_PROP_REVISION_DATE)) != 0))
+                      sizeof(SVN_PROP_REVISION_DATE)-1) != 0))
         *value_p = NULL;
 
       else
@@ -716,7 +739,54 @@ svn_repos_fs_pack2(svn_repos_t *repos,
                      cancel_func, cancel_baton, pool);
 }
 
+svn_error_t *
+svn_repos_fs_get_inherited_props(apr_array_header_t **inherited_props_p,
+                                 svn_fs_root_t *root,
+                                 const char *path,
+                                 svn_repos_authz_func_t authz_read_func,
+                                 void *authz_read_baton,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_array_header_t *inherited_props;
+  const char *parent_path = path;
+
+  inherited_props = apr_array_make(result_pool, 1,
+                                   sizeof(svn_prop_inherited_item_t *));
+  while (!(parent_path[0] == '/' && parent_path[1] == '\0'))
+    {
+      svn_boolean_t allowed = TRUE;
+      apr_hash_t *parent_properties;
+
+      svn_pool_clear(iterpool);
+      parent_path = svn_fspath__dirname(parent_path, iterpool);
+
+      if (authz_read_func)
+        SVN_ERR(authz_read_func(&allowed, root, parent_path,
+                                authz_read_baton, iterpool));
+      if (allowed)
+        {
+          SVN_ERR(svn_fs_node_proplist(&parent_properties, root,
+                                       parent_path, result_pool));
+          if (parent_properties && apr_hash_count(parent_properties))
+            {
+              svn_prop_inherited_item_t *i_props =
+                apr_pcalloc(result_pool, sizeof(*i_props));
+              i_props->path_or_url =
+                apr_pstrdup(result_pool, parent_path + 1);
+              i_props->prop_hash = parent_properties;
+              /* Build the output array in depth-first order. */
+              svn_sort__array_insert(&i_props, inherited_props, 0);
+            }
+        }
+    }
 
+  svn_pool_destroy(iterpool);
+
+  *inherited_props_p = inherited_props;
+  return SVN_NO_ERROR;
+}
 
 /*
  * vim:ts=4:sw=2:expandtab:tw=80:fo=tcroq

Modified: subversion/branches/master-passphrase/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_repos/log.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_repos/log.c Tue Oct 30 20:03:28 2012
@@ -39,6 +39,7 @@
 #include "repos.h"
 #include "private/svn_fspath.h"
 #include "private/svn_mergeinfo_private.h"
+#include "private/svn_subr_private.h"
 
 
 
@@ -159,6 +160,10 @@ svn_repos_check_revision_access(svn_repo
  * The CHANGED hash set and its keys and values are allocated in POOL;
  * keys are const char * paths and values are svn_log_changed_path_t.
  *
+ * To prevent changes from being processed over and over again, the
+ * changed paths for ROOT may be passed in PREFETCHED_CHANGES.  If the
+ * latter is NULL, we will request the list inside this function.
+ *
  * If optional AUTHZ_READ_FUNC is non-NULL, then use it (with
  * AUTHZ_READ_BATON and FS) to check whether each changed-path (and
  * copyfrom_path) is readable:
@@ -177,18 +182,20 @@ static svn_error_t *
 detect_changed(apr_hash_t **changed,
                svn_fs_root_t *root,
                svn_fs_t *fs,
+               apr_hash_t *prefetched_changes,
                svn_repos_authz_func_t authz_read_func,
                void *authz_read_baton,
                apr_pool_t *pool)
 {
-  apr_hash_t *changes;
+  apr_hash_t *changes = prefetched_changes;
   apr_hash_index_t *hi;
   apr_pool_t *subpool;
   svn_boolean_t found_readable = FALSE;
   svn_boolean_t found_unreadable = FALSE;
 
-  *changed = apr_hash_make(pool);
-  SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
+  *changed = svn_hash__make(pool);
+  if (changes == NULL)
+    SVN_ERR(svn_fs_paths_changed2(&changes, root, pool));
 
   if (apr_hash_count(changes) == 0)
     /* No paths changed in this revision?  Uh, sure, I guess the
@@ -551,26 +558,28 @@ next_history_rev(const apr_array_header_
 
 /* Set *DELETED_MERGEINFO_CATALOG and *ADDED_MERGEINFO_CATALOG to
    catalogs describing how mergeinfo values on paths (which are the
-   keys of those catalogs) were changed in REV. */
+   keys of those catalogs) were changed in REV.  If *PREFETCHED_CAHNGES
+   already contains the changed paths for REV, use that.  Otherwise,
+   request that data and return it in *PREFETCHED_CHANGES. */
 /* ### TODO: This would make a *great*, useful public function,
    ### svn_repos_fs_mergeinfo_changed()!  -- cmpilato  */
 static svn_error_t *
 fs_mergeinfo_changed(svn_mergeinfo_catalog_t *deleted_mergeinfo_catalog,
                      svn_mergeinfo_catalog_t *added_mergeinfo_catalog,
+                     apr_hash_t **prefetched_changes,
                      svn_fs_t *fs,
                      svn_revnum_t rev,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 
 {
-  apr_hash_t *changes;
   svn_fs_root_t *root;
   apr_pool_t *iterpool;
   apr_hash_index_t *hi;
 
   /* Initialize return variables. */
-  *deleted_mergeinfo_catalog = apr_hash_make(result_pool);
-  *added_mergeinfo_catalog = apr_hash_make(result_pool);
+  *deleted_mergeinfo_catalog = svn_hash__make(result_pool);
+  *added_mergeinfo_catalog = svn_hash__make(result_pool);
 
   /* Revision 0 has no mergeinfo and no mergeinfo changes. */
   if (rev == 0)
@@ -579,17 +588,20 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
   /* We're going to use the changed-paths information for REV to
      narrow down our search. */
   SVN_ERR(svn_fs_revision_root(&root, fs, rev, scratch_pool));
-  SVN_ERR(svn_fs_paths_changed2(&changes, root, scratch_pool));
+  if (*prefetched_changes == NULL)
+    SVN_ERR(svn_fs_paths_changed2(prefetched_changes, root, scratch_pool));
 
   /* No changed paths?  We're done. */
-  if (apr_hash_count(changes) == 0)
+  if (apr_hash_count(*prefetched_changes) == 0)
     return SVN_NO_ERROR;
 
   /* Loop over changes, looking for anything that might carry an
      svn:mergeinfo change and is one of our paths of interest, or a
      child or [grand]parent directory thereof. */
   iterpool = svn_pool_create(scratch_pool);
-  for (hi = apr_hash_first(scratch_pool, changes); hi; hi = apr_hash_next(hi))
+  for (hi = apr_hash_first(scratch_pool, *prefetched_changes); 
+       hi;
+       hi = apr_hash_next(hi))
     {
       const void *key;
       void *val;
@@ -769,10 +781,14 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
 /* Determine what (if any) mergeinfo for PATHS was modified in
    revision REV, returning the differences for added mergeinfo in
    *ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO.
+   If *PREFETCHED_CAHNGES already contains the changed paths for
+   REV, use that.  Otherwise, request that data and return it in
+   *PREFETCHED_CHANGES.
    Use POOL for all allocations. */
 static svn_error_t *
 get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo,
                                svn_mergeinfo_t *deleted_mergeinfo,
+                               apr_hash_t **prefetched_changes,
                                svn_fs_t *fs,
                                const apr_array_header_t *paths,
                                svn_revnum_t rev,
@@ -787,8 +803,8 @@ get_combined_mergeinfo_changes(svn_merge
   svn_error_t *err;
 
   /* Initialize return value. */
-  *added_mergeinfo = apr_hash_make(result_pool);
-  *deleted_mergeinfo = apr_hash_make(result_pool);
+  *added_mergeinfo = svn_hash__make(result_pool);
+  *deleted_mergeinfo = svn_hash__make(result_pool);
 
   /* If we're asking about revision 0, there's no mergeinfo to be found. */
   if (rev == 0)
@@ -804,6 +820,7 @@ get_combined_mergeinfo_changes(svn_merge
   /* Fetch the mergeinfo changes for REV. */
   err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog,
                              &added_mergeinfo_catalog,
+                             prefetched_changes,
                              fs, rev, scratch_pool, scratch_pool);
   if (err)
     {
@@ -829,6 +846,7 @@ get_combined_mergeinfo_changes(svn_merge
     {
       const char *path = APR_ARRAY_IDX(paths, i, const char *);
       const char *prev_path;
+      apr_ssize_t klen;
       svn_revnum_t appeared_rev, prev_rev;
       svn_fs_root_t *prev_root;
       svn_mergeinfo_catalog_t catalog, inherited_catalog;
@@ -899,8 +917,9 @@ get_combined_mergeinfo_changes(svn_merge
                                     FALSE, /* adjust_inherited_mergeinfo */
                                     iterpool, iterpool));
 
-      prev_mergeinfo = apr_hash_get(catalog, prev_path, APR_HASH_KEY_STRING);
-      prev_inherited_mergeinfo = apr_hash_get(inherited_catalog, prev_path, APR_HASH_KEY_STRING);
+      klen = strlen(prev_path);
+      prev_mergeinfo = apr_hash_get(catalog, prev_path, klen);
+      prev_inherited_mergeinfo = apr_hash_get(inherited_catalog, prev_path, klen);
 
       /* Fetch the current mergeinfo (as of REV, and including
          inherited stuff) for this path. */
@@ -915,8 +934,9 @@ get_combined_mergeinfo_changes(svn_merge
                                     FALSE, /* adjust_inherited_mergeinfo */
                                     iterpool, iterpool));
 
-      mergeinfo = apr_hash_get(catalog, path, APR_HASH_KEY_STRING);
-      inherited_mergeinfo = apr_hash_get(inherited_catalog, path, APR_HASH_KEY_STRING);
+      klen = strlen(path);
+      mergeinfo = apr_hash_get(catalog, path, klen);
+      inherited_mergeinfo = apr_hash_get(inherited_catalog, path, klen);
 
       if (!prev_mergeinfo && !mergeinfo)
         continue;
@@ -935,6 +955,16 @@ get_combined_mergeinfo_changes(svn_merge
           if (inherits_same_mergeinfo)
             continue;
         }
+      else
+        {
+          svn_boolean_t same_mergeinfo;
+          SVN_ERR(svn_mergeinfo__equals(&same_mergeinfo,
+                                        prev_inherited_mergeinfo,
+                                        FALSE,
+                                        TRUE, iterpool));
+          if (same_mergeinfo)
+            continue;
+        }
 
       /* Compare, constrast, and combine the results. */
       SVN_ERR(svn_mergeinfo_diff2(&deleted, &added, prev_mergeinfo,
@@ -989,6 +1019,7 @@ static svn_error_t *
 fill_log_entry(svn_log_entry_t *log_entry,
                svn_revnum_t rev,
                svn_fs_t *fs,
+               apr_hash_t *prefetched_changes,
                svn_boolean_t discover_changed_paths,
                const apr_array_header_t *revprops,
                svn_repos_authz_func_t authz_read_func,
@@ -1008,7 +1039,7 @@ fill_log_entry(svn_log_entry_t *log_entr
 
       SVN_ERR(svn_fs_revision_root(&newroot, fs, rev, pool));
       patherr = detect_changed(&changed_paths,
-                               newroot, fs,
+                               newroot, fs, prefetched_changes,
                                authz_read_func, authz_read_baton,
                                pool);
 
@@ -1048,7 +1079,7 @@ fill_log_entry(svn_log_entry_t *log_entr
           if (censor_revprops)
             {
               /* ... but we can only return author/date. */
-              log_entry->revprops = apr_hash_make(pool);
+              log_entry->revprops = svn_hash__make(pool);
               apr_hash_set(log_entry->revprops, SVN_PROP_REVISION_AUTHOR,
                            APR_HASH_KEY_STRING,
                            apr_hash_get(r_props, SVN_PROP_REVISION_AUTHOR,
@@ -1077,7 +1108,7 @@ fill_log_entry(svn_log_entry_t *log_entr
                 /* ... but we can only return author/date. */
                 continue;
               if (log_entry->revprops == NULL)
-                log_entry->revprops = apr_hash_make(pool);
+                log_entry->revprops = svn_hash__make(pool);
               apr_hash_set(log_entry->revprops, name,
                            APR_HASH_KEY_STRING, value);
             }
@@ -1119,6 +1150,7 @@ fill_log_entry(svn_log_entry_t *log_entr
 static svn_error_t *
 send_log(svn_revnum_t rev,
          svn_fs_t *fs,
+         apr_hash_t *prefetched_changes,
          svn_mergeinfo_t log_target_history_as_mergeinfo,
          apr_hash_t *nested_merges,
          svn_boolean_t discover_changed_paths,
@@ -1137,7 +1169,7 @@ send_log(svn_revnum_t rev,
   svn_boolean_t found_rev_of_interest = TRUE;
 
   log_entry = svn_log_entry_create(pool);
-  SVN_ERR(fill_log_entry(log_entry, rev, fs,
+  SVN_ERR(fill_log_entry(log_entry, rev, fs, prefetched_changes,
                          discover_changed_paths || handling_merged_revision,
                          revprops, authz_read_func, authz_read_baton,
                          pool));
@@ -1800,7 +1832,7 @@ store_search(svn_mergeinfo_t processed,
      singe revisions where HIST_START is equal to HIST_END. */
   svn_revnum_t start = hist_start <= hist_end ? hist_start : hist_end;
   svn_revnum_t end = hist_start <= hist_end ? hist_end + 1 : hist_start + 1;
-  svn_mergeinfo_t mergeinfo = apr_hash_make(scratch_pool);
+  svn_mergeinfo_t mergeinfo = svn_hash__make(scratch_pool);
   apr_pool_t *processed_pool = apr_hash_pool_get(processed);
   int i;
 
@@ -1941,6 +1973,7 @@ do_logs(svn_fs_t *fs,
           svn_mergeinfo_t added_mergeinfo = NULL;
           svn_mergeinfo_t deleted_mergeinfo = NULL;
           svn_boolean_t has_children = FALSE;
+          apr_hash_t *changes = NULL;
 
           /* If we're including merged revisions, we need to calculate
              the mergeinfo deltas committed in this revision to our
@@ -1961,6 +1994,7 @@ do_logs(svn_fs_t *fs,
                 }
               SVN_ERR(get_combined_mergeinfo_changes(&added_mergeinfo,
                                                      &deleted_mergeinfo,
+                                                     &changes,
                                                      fs, cur_paths,
                                                      current, iterpool,
                                                      iterpool));
@@ -1973,7 +2007,7 @@ do_logs(svn_fs_t *fs,
              in anyway). */
           if (descending_order)
             {
-              SVN_ERR(send_log(current, fs,
+              SVN_ERR(send_log(current, fs, changes,
                                log_target_history_as_mergeinfo, nested_merges,
                                discover_changed_paths,
                                subtractive_merge, handling_merged_revisions,
@@ -1989,8 +2023,8 @@ do_logs(svn_fs_t *fs,
                          single hash to be shared across all of the merged
                          recursions so we can track and squelch duplicates. */
                       subpool = svn_pool_create(pool);
-                      nested_merges = apr_hash_make(subpool);
-                      processed = apr_hash_make(subpool);
+                      nested_merges = svn_hash__make(subpool);
+                      processed = svn_hash__make(subpool);
                     }
 
                   SVN_ERR(handle_merged_revisions(
@@ -2035,7 +2069,7 @@ do_logs(svn_fs_t *fs,
 
                   *cur_rev = current;
                   if (! rev_mergeinfo)
-                    rev_mergeinfo = apr_hash_make(pool);
+                    rev_mergeinfo = svn_hash__make(pool);
                   apr_hash_set(rev_mergeinfo, cur_rev, sizeof(*cur_rev),
                                add_and_del_mergeinfo);
                 }
@@ -2078,8 +2112,8 @@ do_logs(svn_fs_t *fs,
                               || apr_hash_count(deleted_mergeinfo) > 0);
             }
 
-          SVN_ERR(send_log(current, fs, log_target_history_as_mergeinfo,
-                           nested_merges,
+          SVN_ERR(send_log(current, fs, NULL,
+                           log_target_history_as_mergeinfo, nested_merges,
                            discover_changed_paths, subtractive_merge,
                            handling_merged_revisions, revprops, has_children,
                            receiver, receiver_baton, authz_read_func,
@@ -2089,7 +2123,7 @@ do_logs(svn_fs_t *fs,
               if (!nested_merges)
                 {
                   subpool = svn_pool_create(pool);
-                  nested_merges = apr_hash_make(subpool);
+                  nested_merges = svn_hash__make(subpool);
                 }
 
               SVN_ERR(handle_merged_revisions(current, fs,
@@ -2169,7 +2203,7 @@ get_paths_history_as_mergeinfo(svn_merge
       end_rev = tmp_rev;
     }
 
-  *paths_history_mergeinfo = apr_hash_make(result_pool);
+  *paths_history_mergeinfo = svn_hash__make(result_pool);
 
   for (i = 0; i < paths->nelts; i++)
     {
@@ -2302,7 +2336,8 @@ svn_repos_get_logs4(svn_repos_t *repos,
             rev = end - i;
           else
             rev = start + i;
-          SVN_ERR(send_log(rev, fs, NULL, NULL, discover_changed_paths, FALSE,
+          SVN_ERR(send_log(rev, fs, NULL, NULL, NULL,
+                           discover_changed_paths, FALSE,
                            FALSE, revprops, FALSE, receiver,
                            receiver_baton, authz_read_func,
                            authz_read_baton, iterpool));

Modified: subversion/branches/master-passphrase/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_repos/replay.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_repos/replay.c Tue Oct 30 20:03:28 2012
@@ -150,7 +150,6 @@ struct path_driver_cb_baton
   apr_pool_t *pool;
 };
 
-#ifndef USE_EV2_IMPL
 /* Recursively traverse EDIT_PATH (as it exists under SOURCE_ROOT) emitting
    the appropriate editor calls to add it and its children without any
    history.  This is meant to be used when either a subset of the tree
@@ -342,7 +341,6 @@ add_subdir(svn_fs_root_t *source_root,
 
   return SVN_NO_ERROR;
 }
-#endif
 
 /* Given PATH deleted under ROOT, return in READABLE whether the path was
    readable prior to the deletion.  Consult COPIES (a stack of 'struct
@@ -459,7 +457,6 @@ fill_copyfrom(svn_fs_root_t **copyfrom_r
   return SVN_NO_ERROR;
 }
 
-#ifndef USE_EV2_IMPL
 static svn_error_t *
 path_driver_cb_func(void **dir_baton,
                     void *parent_baton,
@@ -784,8 +781,7 @@ path_driver_cb_func(void **dir_baton,
   return SVN_NO_ERROR;
 }
 
-#else
-
+#ifdef USE_EV2_IMPL
 static svn_error_t *
 fetch_kind_func(svn_kind_t *kind,
                 void *baton,
@@ -795,8 +791,14 @@ fetch_kind_func(svn_kind_t *kind,
 {
   svn_fs_root_t *root = baton;
   svn_node_kind_t node_kind;
+  svn_fs_root_t *prev_root;
+  svn_fs_t *fs = svn_fs_root_fs(root);
 
-  SVN_ERR(svn_fs_check_path(&node_kind, root, path, scratch_pool));
+  if (!SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = svn_fs_revision_root_revision(root) - 1;
+
+  SVN_ERR(svn_fs_revision_root(&prev_root, fs, base_revision, scratch_pool));
+  SVN_ERR(svn_fs_check_path(&node_kind, prev_root, path, scratch_pool));
 
   *kind = svn__kind_from_node_kind(node_kind, FALSE);
   return SVN_NO_ERROR;
@@ -814,15 +816,14 @@ fetch_props_func(apr_hash_t **props,
   svn_fs_root_t *prev_root;
   svn_fs_t *fs = svn_fs_root_fs(root);
 
-  SVN_ERR(svn_fs_revision_root(&prev_root, fs,
-                               svn_fs_revision_root_revision(root) - 1,
-                               scratch_pool));
+  if (!SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = svn_fs_revision_root_revision(root) - 1;
 
+  SVN_ERR(svn_fs_revision_root(&prev_root, fs, base_revision, scratch_pool));
   SVN_ERR(svn_fs_node_proplist(props, prev_root, path, result_pool));
 
   return SVN_NO_ERROR;
 }
-
 #endif
 
 
@@ -947,9 +948,9 @@ svn_repos_replay2(svn_fs_root_t *root,
     }
 
   /* Call the path-based editor driver. */
-  return svn_delta_path_driver(editor, edit_baton,
-                               SVN_INVALID_REVNUM, paths,
-                               path_driver_cb_func, &cb_baton, pool);
+  return svn_delta_path_driver2(editor, edit_baton,
+                                paths, TRUE,
+                                path_driver_cb_func, &cb_baton, pool);
 #else
   svn_editor_t *editorv2;
   struct svn_delta__extra_baton *exb;
@@ -1009,7 +1010,6 @@ svn_repos_replay2(svn_fs_root_t *root,
  *                      Ev2 Implementation                       *
  *****************************************************************/
 
-#ifdef USE_EV2_IMPL
 /* Recursively traverse EDIT_PATH (as it exists under SOURCE_ROOT) emitting
    the appropriate editor calls to add it and its children without any
    history.  This is meant to be used when either a subset of the tree
@@ -1018,16 +1018,16 @@ svn_repos_replay2(svn_fs_root_t *root,
    unavailable because of authz and we need to use it as the source of
    a copy. */
 static svn_error_t *
-add_subdir(svn_fs_root_t *source_root,
-           svn_fs_root_t *target_root,
-           svn_editor_t *editor,
-           const char *repos_relpath,
-           const char *source_fspath,
-           svn_repos_authz_func_t authz_read_func,
-           void *authz_read_baton,
-           apr_hash_t *changed_paths,
-           apr_pool_t *result_pool,
-           apr_pool_t *scratch_pool)
+add_subdir_ev2(svn_fs_root_t *source_root,
+               svn_fs_root_t *target_root,
+               svn_editor_t *editor,
+               const char *repos_relpath,
+               const char *source_fspath,
+               svn_repos_authz_func_t authz_read_func,
+               void *authz_read_baton,
+               apr_hash_t *changed_paths,
+               apr_pool_t *result_pool,
+               apr_pool_t *scratch_pool)
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_hash_index_t *hi;
@@ -1131,11 +1131,11 @@ add_subdir(svn_fs_root_t *source_root,
             }
           else
             {
-              SVN_ERR(add_subdir(new_source_root, target_root,
-                                 editor, child_relpath,
-                                 new_source_fspath,
-                                 authz_read_func, authz_read_baton,
-                                 changed_paths, result_pool, iterpool));
+              SVN_ERR(add_subdir_ev2(new_source_root, target_root,
+                                     editor, child_relpath,
+                                     new_source_fspath,
+                                     authz_read_func, authz_read_baton,
+                                     changed_paths, result_pool, iterpool));
             }
         }
       else if (dent->kind == svn_node_file)
@@ -1164,7 +1164,6 @@ add_subdir(svn_fs_root_t *source_root,
 
   return SVN_NO_ERROR;
 }
-#endif
 
 static svn_error_t *
 replay_node(svn_fs_root_t *root,
@@ -1178,11 +1177,6 @@ replay_node(svn_fs_root_t *root,
             void *authz_read_baton,
             apr_pool_t *result_pool,
             apr_pool_t *scratch_pool)
-#ifndef USE_EV2_IMPL
-{
-  SVN__NOT_IMPLEMENTED();
-}
-#else
 {
   svn_fs_path_change2_t *change;
   svn_boolean_t do_add = FALSE;
@@ -1297,10 +1291,11 @@ replay_node(svn_fs_root_t *root,
              contents. */
           if (change->copyfrom_path && ! copyfrom_path)
             {
-              SVN_ERR(add_subdir(copyfrom_root, root, editor,
-                                 repos_relpath, change->copyfrom_path,
-                                 authz_read_func, authz_read_baton,
-                                 changed_paths, result_pool, scratch_pool));
+              SVN_ERR(add_subdir_ev2(copyfrom_root, root, editor,
+                                     repos_relpath, change->copyfrom_path,
+                                     authz_read_func, authz_read_baton,
+                                     changed_paths, result_pool,
+                                     scratch_pool));
             }
           else
             {
@@ -1437,15 +1432,18 @@ replay_node(svn_fs_root_t *root,
       if (change->node_kind == svn_node_file
           && (change->text_mod || change->prop_mod || downgraded_copy))
         {
-          svn_checksum_t *checksum;
-          svn_stream_t *contents;
+          svn_checksum_t *checksum = NULL;
+          svn_stream_t *contents = NULL;
 
-          SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
-                                       root, repos_relpath, TRUE,
-                                       scratch_pool));
+          if (change->text_mod)
+            {
+              SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
+                                           root, repos_relpath, TRUE,
+                                           scratch_pool));
 
-          SVN_ERR(svn_fs_file_contents(&contents, root, repos_relpath,
-                                       scratch_pool));
+              SVN_ERR(svn_fs_file_contents(&contents, root, repos_relpath,
+                                           scratch_pool));
+            }
 
           SVN_ERR(svn_editor_alter_file(editor, repos_relpath,
                                         SVN_INVALID_REVNUM, props, checksum,
@@ -1465,7 +1463,6 @@ replay_node(svn_fs_root_t *root,
 
   return SVN_NO_ERROR;
 }
-#endif
 
 svn_error_t *
 svn_repos__replay_ev2(svn_fs_root_t *root,

Modified: subversion/branches/master-passphrase/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_repos/reporter.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_repos/reporter.c Tue Oct 30 20:03:28 2012
@@ -36,6 +36,7 @@
 #include "private/svn_dep_compat.h"
 #include "private/svn_fspath.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_string_private.h"
 
 #define NUM_CACHED_SOURCE_ROOTS 4
 
@@ -102,13 +103,15 @@ typedef struct revision_info_t
    driven by the client as it describes its working copy revisions. */
 typedef struct report_baton_t
 {
-  /* Parameters remembered from svn_repos_begin_report2 */
+  /* Parameters remembered from svn_repos_begin_report3 */
   svn_repos_t *repos;
   const char *fs_base;         /* fspath corresponding to wc anchor */
   const char *s_operand;       /* anchor-relative wc target (may be empty) */
   svn_revnum_t t_rev;          /* Revnum which the edit will bring the wc to */
   const char *t_path;          /* FS path the edit will bring the wc to */
   svn_boolean_t text_deltas;   /* Whether to report text deltas */
+  apr_size_t zero_copy_limit;  /* Max item size that will be sent using
+                                  the zero-copy code path. */
 
   /* If the client requested a specific depth, record it here; if the
      client did not, then this is svn_depth_unknown, and the depth of
@@ -135,8 +138,10 @@ typedef struct report_baton_t
 
   /* Cache for revision properties. This is used to eliminate redundant
      revprop fetching. */
-  apr_hash_t* revision_infos;
+  apr_hash_t *revision_infos;
 
+  /* This will not change. So, fetch it once and reuse it. */
+  svn_string_t *repos_uuid;
   apr_pool_t *pool;
 } report_baton_t;
 
@@ -513,25 +518,29 @@ delta_proplists(report_baton_t *b, svn_r
                 void *object, apr_pool_t *pool)
 {
   svn_fs_root_t *s_root;
-  apr_hash_t *s_props, *t_props;
+  apr_hash_t *s_props = NULL, *t_props;
   apr_array_header_t *prop_diffs;
   int i;
   svn_revnum_t crev;
-  const char *uuid;
-  svn_string_t *cr_str;
-  revision_info_t* revision_info;
+  revision_info_t *revision_info;
   svn_boolean_t changed;
   const svn_prop_t *pc;
   svn_lock_t *lock;
+  apr_hash_index_t *hi;
 
   /* Fetch the created-rev and send entry props. */
   SVN_ERR(svn_fs_node_created_rev(&crev, b->t_root, t_path, pool));
   if (SVN_IS_VALID_REVNUM(crev))
     {
+      /* convert committed-rev to  string */
+      char buf[SVN_INT64_BUFFER_SIZE];
+      svn_string_t cr_str;
+      cr_str.data = buf;
+      cr_str.len = svn__i64toa(buf, crev);
+
       /* Transmit the committed-rev. */
-      cr_str = svn_string_createf(pool, "%ld", crev);
       SVN_ERR(change_fn(b, object,
-                        SVN_PROP_ENTRY_COMMITTED_REV, cr_str, pool));
+                        SVN_PROP_ENTRY_COMMITTED_REV, &cr_str, pool));
 
       SVN_ERR(get_revision_info(b, crev, &revision_info, pool));
 
@@ -546,9 +555,8 @@ delta_proplists(report_baton_t *b, svn_r
                           revision_info->author, pool));
 
       /* Transmit the UUID. */
-      SVN_ERR(svn_fs_get_uuid(b->repos->fs, &uuid, pool));
       SVN_ERR(change_fn(b, object, SVN_PROP_ENTRY_UUID,
-                        svn_string_create(uuid, pool), pool));
+                        b->repos_uuid, pool));
     }
 
   /* Update lock properties. */
@@ -575,23 +583,83 @@ delta_proplists(report_baton_t *b, svn_r
       /* If so, go ahead and get the source path's properties. */
       SVN_ERR(svn_fs_node_proplist(&s_props, s_root, s_path, pool));
     }
-  else
-    s_props = apr_hash_make(pool);
 
   /* Get the target path's properties */
   SVN_ERR(svn_fs_node_proplist(&t_props, b->t_root, t_path, pool));
 
-  /* Now transmit the differences. */
-  SVN_ERR(svn_prop_diffs(&prop_diffs, t_props, s_props, pool));
-  for (i = 0; i < prop_diffs->nelts; i++)
+  if (s_props && apr_hash_count(s_props))
+    {
+      /* Now transmit the differences. */
+      SVN_ERR(svn_prop_diffs(&prop_diffs, t_props, s_props, pool));
+      for (i = 0; i < prop_diffs->nelts; i++)
+        {
+          pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
+          SVN_ERR(change_fn(b, object, pc->name, pc->value, pool));
+        }
+    }
+  else if (apr_hash_count(t_props))
+    {
+      /* So source, i.e. all new.  Transmit all target props. */
+      for (hi = apr_hash_first(pool, t_props); hi; hi = apr_hash_next(hi))
+        {
+          const void *key;
+          void *val;
+
+          apr_hash_this(hi, &key, NULL, &val);
+          SVN_ERR(change_fn(b, object, key, val, pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Baton type to be passed into send_zero_copy_delta.
+ */
+typedef struct zero_copy_baton_t
+{
+  /* don't process data larger than this limit */
+  apr_size_t zero_copy_limit;
+
+  /* window handler and baton to send the data to */
+  svn_txdelta_window_handler_t dhandler;
+  void *dbaton;
+
+  /* return value: will be set to TRUE, if the data was processed. */
+  svn_boolean_t zero_copy_succeeded;
+} zero_copy_baton_t;
+
+/* Implement svn_fs_process_contents_func_t.  If LEN is smaller than the
+ * limit given in *BATON, send the CONTENTS as an delta windows to the
+ * handler given in BATON and set the ZERO_COPY_SUCCEEDED flag in that
+ * BATON.  Otherwise, reset it to FALSE.
+ * Use POOL for temporary allocations.
+ */
+static svn_error_t *
+send_zero_copy_delta(const unsigned char *contents,
+                     apr_size_t len,
+                     void *baton,
+                     apr_pool_t *pool)
+{
+  zero_copy_baton_t *zero_copy_baton = baton;
+
+  /* if the item is too large, the caller must revert to traditional
+     streaming code. */
+  if (len > zero_copy_baton->zero_copy_limit)
     {
-      pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
-      SVN_ERR(change_fn(b, object, pc->name, pc->value, pool));
+      zero_copy_baton->zero_copy_succeeded = FALSE;
+      return SVN_NO_ERROR;
     }
 
+  SVN_ERR(svn_txdelta_send_contents(contents, len,
+                                    zero_copy_baton->dhandler,
+                                    zero_copy_baton->dbaton, pool));
+
+  /* all fine now */
+  zero_copy_baton->zero_copy_succeeded = TRUE;
   return SVN_NO_ERROR;
 }
 
+
 /* Make the appropriate edits on FILE_BATON to change its contents and
    properties from those in S_REV/S_PATH to those in B->t_root/T_PATH,
    possibly using LOCK_TOKEN to determine if the client's lock on the file
@@ -645,6 +713,26 @@ delta_files(report_baton_t *b, void *fil
     {
       if (b->text_deltas)
         {
+          /* if we send deltas against empty streams, we may use our
+             zero-copy code. */
+          if (b->zero_copy_limit > 0 && s_path == NULL)
+            {
+              zero_copy_baton_t baton = { b->zero_copy_limit
+                                        , dhandler
+                                        , dbaton
+                                        , FALSE};
+              svn_boolean_t called = FALSE;
+              SVN_ERR(svn_fs_try_process_file_contents(&called,
+                                                       b->t_root, t_path,
+                                                       send_zero_copy_delta,
+                                                       &baton, pool));
+
+              /* data has been available and small enough,
+                 i.e. been processed? */
+              if (called && baton.zero_copy_succeeded)
+                return SVN_NO_ERROR;
+            }
+
           SVN_ERR(svn_fs_get_file_delta_stream(&dstream, s_root, s_path,
                                                b->t_root, t_path, pool));
           SVN_ERR(svn_txdelta_send_txstream(dstream, dhandler, dbaton, pool));
@@ -1463,7 +1551,7 @@ svn_repos_abort_report(void *baton, apr_
 
 
 svn_error_t *
-svn_repos_begin_report2(void **report_baton,
+svn_repos_begin_report3(void **report_baton,
                         svn_revnum_t revnum,
                         svn_repos_t *repos,
                         const char *fs_base,
@@ -1477,14 +1565,18 @@ svn_repos_begin_report2(void **report_ba
                         void *edit_baton,
                         svn_repos_authz_func_t authz_read_func,
                         void *authz_read_baton,
+                        apr_size_t zero_copy_limit,
                         apr_pool_t *pool)
 {
   report_baton_t *b;
+  const char *uuid;
 
   if (depth == svn_depth_exclude)
     return svn_error_create(SVN_ERR_REPOS_BAD_ARGS, NULL,
                             _("Request depth 'exclude' not supported"));
 
+  SVN_ERR(svn_fs_get_uuid(repos->fs, &uuid, pool));
+
   /* Build a reporter baton.  Copy strings in case the caller doesn't
      keep track of them. */
   b = apr_palloc(pool, sizeof(*b));
@@ -1495,6 +1587,7 @@ svn_repos_begin_report2(void **report_ba
   b->t_path = switch_path ? svn_fspath__canonicalize(switch_path, pool)
                           : svn_fspath__join(b->fs_base, s_operand, pool);
   b->text_deltas = text_deltas;
+  b->zero_copy_limit = zero_copy_limit;
   b->requested_depth = depth;
   b->ignore_ancestry = ignore_ancestry;
   b->send_copyfrom_args = send_copyfrom_args;
@@ -1508,6 +1601,7 @@ svn_repos_begin_report2(void **report_ba
   b->reader = svn_spillbuf__reader_create(1000 /* blocksize */,
                                           1000000 /* maxsize */,
                                           pool);
+  b->repos_uuid = svn_string_create(uuid, pool);
 
   /* Hand reporter back to client. */
   *report_baton = b;



Mime
View raw message