subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pbu...@apache.org
Subject svn commit: r1395146 [5/7] - in /subversion/branches/auto-props-sdc: ./ build/ build/ac-macros/ subversion/bindings/swig/ subversion/bindings/swig/include/ subversion/bindings/swig/perl/libsvn_swig_perl/ subversion/bindings/swig/perl/native/ subversion...
Date Sat, 06 Oct 2012 18:31:33 GMT
Modified: subversion/branches/auto-props-sdc/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_ra_svn/marshal.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_ra_svn/marshal.c Sat Oct  6 18:31: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_size_t len)
+{
+  do
+  {
+    apr_size_t buflen = conn->read_end - conn->read_ptr;
+    apr_size_t copylen = (buflen < len) ? buflen : len;
+    conn->read_ptr += copylen;
+    len -= copylen;
+    if (len == 0)
+      break;
+
+    buflen = sizeof(conn->read_buf);
+    SVN_ERR(svn_ra_svn__stream_read(conn->stream, conn->read_buf, &buflen));
+    if (buflen == 0)
+      return svn_error_create(SVN_ERR_RA_SVN_CONNECTION_CLOSED, NULL, NULL);
+
+    conn->read_end = conn->read_buf + buflen;
+    conn->read_ptr = conn->read_buf;
+  }
+  while (len > 0);
+
+  return SVN_NO_ERROR;
+}
+
 /* Read data from the socket into the read buffer, which must be empty. */
 static svn_error_t *readbuf_fill(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
 {
@@ -562,13 +620,557 @@ 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;
+}
+
+
+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 }
+    };
+
+
+
+
 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 +1179,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 +1219,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 +1379,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 +1616,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 +1828,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 +1859,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/auto-props-sdc/subversion/libsvn_ra_svn/ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_ra_svn/ra_svn.h?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_ra_svn/ra_svn.h (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_ra_svn/ra_svn.h Sat Oct  6 18:31: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/auto-props-sdc/subversion/libsvn_repos/authz.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_repos/authz.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_repos/authz.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_repos/authz.c Sat Oct  6 18:31: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/auto-props-sdc/subversion/libsvn_repos/delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_repos/delta.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_repos/delta.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_repos/delta.c Sat Oct  6 18:31: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/auto-props-sdc/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_repos/deprecated.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_repos/deprecated.c Sat Oct  6 18:31:28 2012
@@ -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/auto-props-sdc/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_repos/fs-wrap.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_repos/fs-wrap.c Sat Oct  6 18:31:28 2012
@@ -50,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;
 
@@ -57,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))

Modified: subversion/branches/auto-props-sdc/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_repos/reporter.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_repos/reporter.c Sat Oct  6 18:31: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,27 @@ 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 = { buf, 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 +553,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 +581,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 +711,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 +1549,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 +1563,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 +1585,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 +1599,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;

Modified: subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache-membuffer.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache-membuffer.c Sat Oct  6 18:31:28 2012
@@ -33,11 +33,12 @@
 #include "svn_string.h"
 #include "private/svn_dep_compat.h"
 #include "private/svn_mutex.h"
+#include "private/svn_pseudo_md5.h"
 
 /*
  * This svn_cache__t implementation actually consists of two parts:
  * a shared (per-process) singleton membuffer cache instance and shallow
- * svn_cache__t frontend instances that each use different key spaces.
+ * svn_cache__t front-end instances that each use different key spaces.
  * For data management, they all forward to the singleton membuffer cache.
  *
  * A membuffer cache consists of two parts:
@@ -65,7 +66,7 @@
  *
  * Insertion can occur at only one, sliding position. It is marked by its
  * offset in the data buffer plus the index of the first used entry at or
- * behind that position. If this gap is too small to accomodate the new
+ * behind that position. If this gap is too small to accommodate the new
  * item, the insertion window is extended as described below. The new entry
  * will always be inserted at the bottom end of the window and since the
  * next used entry is known, properly sorted insertion is possible.
@@ -79,7 +80,7 @@
  * get evicted, it is moved to the begin of that window and the window is
  * moved.
  *
- * Moreover, the entry's hits get halfed to make that entry more likely to
+ * Moreover, the entry's hits get halved to make that entry more likely to
  * be removed the next time the sliding insertion / removal window comes by.
  * As a result, frequently used entries are likely not to be dropped until
  * they get not used for a while. Also, even a cache thrashing situation
@@ -100,22 +101,34 @@
  * on their hash key.
  */
 
-/* A 8-way associative cache seems to be a good compromise between
+/* A 16-way associative cache seems to be a good compromise between
  * performance (worst-case lookups) and efficiency-loss due to collisions.
  *
  * This value may be changed to any positive integer.
  */
-#define GROUP_SIZE 8
+#define GROUP_SIZE 16
 
 /* For more efficient copy operations, let'a align all data items properly.
  * Must be a power of 2.
  */
 #define ITEM_ALIGNMENT 16
 
-/* Don't create cache segments smaller than this value unless the total
- * cache size itself is smaller.
+/* By default, don't create cache segments smaller than this value unless
+ * the total cache size itself is smaller.
  */
-#define MIN_SEGMENT_SIZE 0x2000000ull
+#define DEFAULT_MIN_SEGMENT_SIZE 0x2000000ull
+
+/* The minimum segment size we will allow for multi-segmented caches
+ */
+#define MIN_SEGMENT_SIZE 0x10000ull
+
+/* The maximum number of segments allowed. Larger numbers reduce the size
+ * of each segment, in turn reducing the max size of a cachable item.
+ * Also, each segment gets its own lock object. The actual number supported
+ * by the OS may therefore be lower and svn_cache__membuffer_cache_create
+ * may return an error.
+ */
+#define MAX_SEGMENT_COUNT 0x10000
 
 /* We don't mark the initialization status for every group but initialize
  * a number of groups at once. That will allow for a very small init flags
@@ -130,10 +143,6 @@
  */
 #define NO_INDEX APR_UINT32_MAX
 
-/* Invalid buffer offset reference value. Equivalent to APR_UINT32_T(-1)
- */
-#define NO_OFFSET APR_UINT64_MAX
-
 /* To save space in our group structure, we only use 32 bit size values
  * and, therefore, limit the size of each entry to just below 4GB.
  * Supporting larger items is not a good idea as the data transfer
@@ -298,8 +307,7 @@ typedef apr_uint64_t entry_key_t[2];
 /* A single dictionary entry. Since all entries will be allocated once
  * during cache creation, those entries might be either used or unused.
  * An entry is used if and only if it is contained in the doubly-linked
- * list of used entries. An entry is unused if and only if its OFFSET
- * member is NO_OFFSET.
+ * list of used entries.
  */
 typedef struct entry_t
 {
@@ -307,8 +315,7 @@ typedef struct entry_t
    */
   entry_key_t key;
 
-  /* If NO_OFFSET, the entry is not in used. Otherwise, it is the offset
-   * of the cached item's serialized data within the data buffer.
+  /* The offset of the cached item's serialized data within the data buffer.
    */
   apr_uint64_t offset;
 
@@ -346,7 +353,14 @@ typedef struct entry_t
 
 /* We group dictionary entries to make this GROUP-SIZE-way assicative.
  */
-typedef entry_t entry_group_t[GROUP_SIZE];
+typedef struct entry_group_t
+{
+  /* number of entries used [0 .. USED-1] */
+  apr_size_t used;
+
+  /* the actual entries */
+  entry_t entries[GROUP_SIZE];
+} entry_group_t;
 
 /* The cache header structure.
  */
@@ -446,6 +460,12 @@ struct svn_membuffer_t
    * thread-safe.
    */
   apr_thread_rwlock_t *lock;
+
+  /* If set, write access will wait until they get exclusive access.
+   * Otherwise, they will become no-ops if the segment is currently
+   * read-locked.
+   */
+  svn_boolean_t allow_blocking_writes;
 #endif
 };
 
@@ -473,18 +493,48 @@ read_lock_cache(svn_membuffer_t *cache)
   return SVN_NO_ERROR;
 }
 
-/* If locking is supported for CACHE, aquire a write lock for it.
+/* If locking is supported for CACHE, acquire a write lock for it.
  */
 static svn_error_t *
-write_lock_cache(svn_membuffer_t *cache)
+write_lock_cache(svn_membuffer_t *cache, svn_boolean_t *success)
 {
 #if APR_HAS_THREADS
   if (cache->lock)
-  {
-    apr_status_t status = apr_thread_rwlock_wrlock(cache->lock);
-    if (status)
-      return svn_error_wrap_apr(status, _("Can't write-lock cache mutex"));
-  }
+    {
+      apr_status_t status;
+      if (cache->allow_blocking_writes)
+        {
+          status = apr_thread_rwlock_wrlock(cache->lock);
+        }
+      else
+        {
+          status = apr_thread_rwlock_trywrlock(cache->lock);
+          if (SVN_LOCK_IS_BUSY(status))
+            {
+              *success = FALSE;
+              status = APR_SUCCESS;
+            }
+        }
+    
+      if (status)
+        return svn_error_wrap_apr(status,
+                                  _("Can't write-lock cache mutex"));
+    }
+#endif
+  return SVN_NO_ERROR;
+}
+
+/* If locking is supported for CACHE, acquire an unconditional write lock
+ * for it.
+ */
+static svn_error_t *
+force_write_lock_cache(svn_membuffer_t *cache)
+{
+#if APR_HAS_THREADS
+  apr_status_t status = apr_thread_rwlock_wrlock(cache->lock);
+  if (status)
+    return svn_error_wrap_apr(status,
+                              _("Can't write-lock cache mutex"));
 #endif
   return SVN_NO_ERROR;
 }
@@ -510,7 +560,7 @@ unlock_cache(svn_membuffer_t *cache, svn
 }
 
 /* If supported, guard the execution of EXPR with a read lock to cache.
- * Macro has been modelled after SVN_MUTEX__WITH_LOCK.
+ * Macro has been modeled after SVN_MUTEX__WITH_LOCK.
  */
 #define WITH_READ_LOCK(cache, expr)         \
 do {                                        \
@@ -519,12 +569,29 @@ do {                                    
 } while (0)
 
 /* If supported, guard the execution of EXPR with a write lock to cache.
- * Macro has been modelled after SVN_MUTEX__WITH_LOCK.
- */
-#define WITH_WRITE_LOCK(cache, expr)        \
-do {                                        \
-  SVN_ERR(write_lock_cache(cache));         \
-  SVN_ERR(unlock_cache(cache, (expr)));     \
+ * Macro has been modeled after SVN_MUTEX__WITH_LOCK.
+ *
+ * The write lock process is complicated if we don't allow to wait for
+ * the lock: If we didn't get the lock, we may still need to remove an
+ * existing entry for the given key because that content is now stale.
+ * Once we discovered such an entry, we unconditionally do a blocking
+ * wait for the write lock.  In case no old content could be found, a
+ * failing lock attempt is simply a no-op and we exit the macro.
+ */
+#define WITH_WRITE_LOCK(cache, expr)                            \
+do {                                                            \
+  svn_boolean_t got_lock = TRUE;                                \
+  SVN_ERR(write_lock_cache(cache, &got_lock));                  \
+  if (!got_lock)                                                \
+    {                                                           \
+      svn_boolean_t exists;                                     \
+      SVN_ERR(entry_exists(cache, group_index, key, &exists));  \
+      if (exists)                                               \
+        SVN_ERR(force_write_lock_cache(cache));                 \
+      else                                                      \
+        break;                                                  \
+    }                                                           \
+  SVN_ERR(unlock_cache(cache, (expr)));                         \
 } while (0)
 
 /* Resolve a dictionary entry reference, i.e. return the entry
@@ -533,7 +600,7 @@ do {                                    
 static APR_INLINE entry_t *
 get_entry(svn_membuffer_t *cache, apr_uint32_t idx)
 {
-  return &cache->directory[idx / GROUP_SIZE][idx % GROUP_SIZE];
+  return &cache->directory[idx / GROUP_SIZE].entries[idx % GROUP_SIZE];
 }
 
 /* Get the entry references for the given ENTRY.
@@ -541,7 +608,11 @@ get_entry(svn_membuffer_t *cache, apr_ui
 static APR_INLINE apr_uint32_t
 get_index(svn_membuffer_t *cache, entry_t *entry)
 {
-  return (apr_uint32_t)(entry - (entry_t *)cache->directory);
+  apr_uint32_t group_index
+    = ((char *)entry - (char *)cache->directory) / sizeof(entry_group_t);
+
+  return group_index * GROUP_SIZE
+       + (apr_uint32_t)(entry - cache->directory[group_index].entries);
 }
 
 /* Remove the used ENTRY from the CACHE, i.e. make it "unused".
@@ -550,11 +621,16 @@ get_index(svn_membuffer_t *cache, entry_
 static void
 drop_entry(svn_membuffer_t *cache, entry_t *entry)
 {
+  /* the group that ENTRY belongs to plus a number of useful index values
+   */
   apr_uint32_t idx = get_index(cache, entry);
+  apr_uint32_t group_index = idx / GROUP_SIZE;
+  entry_group_t *group = &cache->directory[group_index];
+  apr_uint32_t last_in_group = group_index * GROUP_SIZE + group->used - 1;
 
   /* Only valid to be called for used entries.
    */
-  assert(entry->offset != NO_OFFSET);
+  assert(idx <= last_in_group);
 
   /* update global cache usage counters
    */
@@ -597,9 +673,35 @@ drop_entry(svn_membuffer_t *cache, entry
   else
     get_entry(cache, entry->next)->previous = entry->previous;
 
-  /* Mark the entry as unused.
+  /* Move last entry into hole (if the removed one is not the last used).
+   * We need to do this since all used entries are at the beginning of
+   * the group's entries array.
    */
-  entry->offset = NO_OFFSET;
+  if (idx < last_in_group)
+    {
+      /* copy the last used entry to the removed entry's index
+       */
+      *entry = group->entries[group->used-1];
+
+      /* update foreign links to new index
+       */
+      if (last_in_group == cache->next)
+        cache->next = idx;
+
+      if (entry->previous == NO_INDEX)
+        cache->first = idx;
+      else
+        get_entry(cache, entry->previous)->next = idx;
+      
+      if (entry->next == NO_INDEX)
+        cache->last = idx;
+      else
+        get_entry(cache, entry->next)->previous = idx;
+    }
+
+  /* Update the number of used entries.
+   */
+  group->used--;
 }
 
 /* Insert ENTRY into the chain of used dictionary entries. The entry's
@@ -609,21 +711,28 @@ drop_entry(svn_membuffer_t *cache, entry
 static void
 insert_entry(svn_membuffer_t *cache, entry_t *entry)
 {
+  /* the group that ENTRY belongs to plus a number of useful index values
+   */
   apr_uint32_t idx = get_index(cache, entry);
+  apr_uint32_t group_index = idx / GROUP_SIZE;
+  entry_group_t *group = &cache->directory[group_index];
   entry_t *next = cache->next == NO_INDEX
                 ? NULL
                 : get_entry(cache, cache->next);
 
   /* The entry must start at the beginning of the insertion window.
+   * It must also be the first unused entry in the group.
    */
   assert(entry->offset == cache->current_data);
+  assert(idx == group_index * GROUP_SIZE + group->used);
   cache->current_data = ALIGN_VALUE(entry->offset + entry->size);
 
-  /* update global cache usage counters
+  /* update usage counters
    */
   cache->used_entries++;
   cache->data_used += entry->size;
   entry->hit_count = 0;
+  group->used++;
 
   /* update entry chain
    */
@@ -672,9 +781,11 @@ static apr_uint32_t
 get_group_index(svn_membuffer_t **cache,
                 entry_key_t key)
 {
-  /* select the cache segment to use */
-  *cache = &(*cache)[key[0] & ((*cache)->segment_count -1)];
-  return key[0] % (*cache)->group_count;
+  svn_membuffer_t *segment0 = *cache;
+  
+  /* select the cache segment to use. they have all the same group_count */
+  *cache = &segment0[key[0] & (segment0->segment_count -1)];
+  return key[1] % segment0->group_count;
 }
 
 /* Reduce the hit count of ENTRY and update the accumunated hit info
@@ -710,7 +821,7 @@ static void
 initialize_group(svn_membuffer_t *cache, apr_uint32_t group_index)
 {
   unsigned char bit_mask;
-  apr_uint32_t i, j;
+  apr_uint32_t i;
 
   /* range of groups to initialize due to GROUP_INIT_GRANULARITY */
   apr_uint32_t first_index =
@@ -720,8 +831,7 @@ initialize_group(svn_membuffer_t *cache,
     last_index = cache->group_count;
 
   for (i = first_index; i < last_index; ++i)
-    for (j = 0; j < GROUP_SIZE; j++)
-        cache->directory[i][j].offset = NO_OFFSET;
+    cache->directory[i].used = 0;
 
   /* set the "initialized" bit for these groups */
   bit_mask
@@ -748,13 +858,13 @@ find_entry(svn_membuffer_t *cache,
            const apr_uint64_t to_find[2],
            svn_boolean_t find_empty)
 {
-  entry_t *group;
+  entry_group_t *group;
   entry_t *entry = NULL;
   int i;
 
   /* get the group that *must* contain the entry
    */
-  group = &cache->directory[group_index][0];
+  group = &cache->directory[group_index];
 
   /* If the entry group has not been initialized, yet, there is no data.
    */
@@ -763,7 +873,7 @@ find_entry(svn_membuffer_t *cache,
       if (find_empty)
         {
           initialize_group(cache, group_index);
-          entry = group;
+          entry = &group->entries[0];
 
           /* initialize entry for the new key */
           entry->key[0] = to_find[0];
@@ -775,54 +885,51 @@ find_entry(svn_membuffer_t *cache,
 
   /* try to find the matching entry
    */
-  for (i = 0; i < GROUP_SIZE; ++i)
-    if (   group[i].offset != NO_OFFSET
-        && to_find[0] == group[i].key[0]
-        && to_find[1] == group[i].key[1])
+  for (i = 0; i < group->used; ++i)
+    if (   to_find[0] == group->entries[i].key[0]
+        && to_find[1] == group->entries[i].key[1])
       {
         /* found it
          */
-        entry = &group[i];
+        entry = &group->entries[i];
         if (find_empty)
           drop_entry(cache, entry);
-
-        return entry;
+        else
+          return entry;
       }
 
   /* None found. Are we looking for a free entry?
    */
   if (find_empty)
     {
-      /* look for an empty entry and return that ...
+      /* if there is no empty entry, delete the oldest entry
        */
-      for (i = 0; i < GROUP_SIZE; ++i)
-        if (group[i].offset == NO_OFFSET)
-          {
-            entry = &group[i];
-            break;
-          }
-
-      /* ... or, if none is empty, delete the oldest entry
-       */
-      if (entry == NULL)
+      if (group->used == GROUP_SIZE)
         {
-          entry = &group[0];
+          /* every entry gets the same chance of being removed.
+           * Otherwise, we free the first entry, fill it and
+           * remove it again on the next occasion without considering
+           * the other entries in this group.
+           */
+          entry = &group->entries[rand() % GROUP_SIZE];
           for (i = 1; i < GROUP_SIZE; ++i)
-            if (entry->hit_count > group[i].hit_count)
-              entry = &group[i];
+            if (entry->hit_count > group->entries[i].hit_count)
+              entry = &group->entries[i];
 
           /* for the entries that don't have been removed,
            * reduce their hitcounts to put them at a relative
            * disadvantage the next time.
            */
           for (i = 0; i < GROUP_SIZE; ++i)
-            if (entry != &group[i])
+            if (entry != &group->entries[i])
               let_entry_age(cache, entry);
 
           drop_entry(cache, entry);
         }
 
-      /* initialize entry for the new key */
+      /* initialize entry for the new key
+       */
+      entry = &group->entries[group->used];
       entry->key[0] = to_find[0];
       entry->key[1] = to_find[1];
     }
@@ -950,22 +1057,38 @@ ensure_data_insertable(svn_membuffer_t *
             }
           else
             {
-              /* Roll the dice and determine a threshold somewhere from 0 up
-               * to 2 times the average hit count.
-               */
-              average_hit_value = cache->hit_count / cache->used_entries;
-              threshold = (average_hit_value+1) * (rand() % 4096) / 2048;
+              svn_boolean_t keep;
 
-              /* Drop the entry from the end of the insertion window, if it
-               * has been hit less than the threshold. Otherwise, keep it and
-               * move the insertion window one entry further.
-               */
-              if (entry->hit_count >= threshold)
+              if (cache->hit_count > cache->used_entries)
+                {
+                  /* Roll the dice and determine a threshold somewhere from 0 up
+                   * to 2 times the average hit count.
+                   */
+                  average_hit_value = cache->hit_count / cache->used_entries;
+                  threshold = (average_hit_value+1) * (rand() % 4096) / 2048;
+
+                  keep = entry->hit_count >= threshold;
+                }
+              else
+                {
+                  /* general hit count is low. Keep everything that got hit
+                   * at all and assign some 50% survival chance to everything
+                   * else.
+                   */
+                  keep = (entry->hit_count > 0) || (rand() & 1);
+                }
+
+              /* keepers or destroyers? */
+              if (keep)
                 {
                   move_entry(cache, entry);
                 }
               else
                 {
+                 /* Drop the entry from the end of the insertion window, if it
+                  * has been hit less than the threshold. Otherwise, keep it and
+                  * move the insertion window one entry further.
+                  */
                   drop_size += entry->size;
                   drop_entry(cache, entry);
                 }
@@ -999,56 +1122,67 @@ static void* secure_aligned_alloc(apr_po
   return memory;
 }
 
-/* Create a new membuffer cache instance. If the TOTAL_SIZE of the
- * memory i too small to accomodate the DICTIONARY_SIZE, the latte
- * will be resized automatically. Also, a minumum size is assured
- * for the DICTIONARY_SIZE. THREAD_SAFE may be FALSE, if there will
- * be no concurrent acccess to the CACHE returned.
- *
- * All allocations, in particular the data buffer and dictionary will
- * be made from POOL.
- */
 svn_error_t *
 svn_cache__membuffer_cache_create(svn_membuffer_t **cache,
                                   apr_size_t total_size,
                                   apr_size_t directory_size,
+                                  apr_size_t segment_count,
                                   svn_boolean_t thread_safe,
+                                  svn_boolean_t allow_blocking_writes,
                                   apr_pool_t *pool)
 {
   svn_membuffer_t *c;
 
-  apr_uint32_t segment_count_shift = 0;
-  apr_uint32_t segment_count = 1;
-
   apr_uint32_t seg;
   apr_uint32_t group_count;
   apr_uint32_t group_init_size;
   apr_uint64_t data_size;
   apr_uint64_t max_entry_size;
 
-  /* Determine a reasonable number of cache segments. Segmentation is
-   * only useful for multi-threaded / multi-core servers as it reduces
-   * lock contention on these systems.
-   *
-   * But on these systems, we can assume that ample memory has been
-   * allocated to this cache. Smaller caches should not be segmented
-   * as this severely limites the maximum size of cachable items.
-   *
-   * Segments should not be smaller than 32MB and max. cachable item
-   * size should grow as fast as segmentation.
+  /* Limit the segment count
    */
-  while (((2 * MIN_SEGMENT_SIZE) << (2 * segment_count_shift)) < total_size)
-    ++segment_count_shift;
+  if (segment_count > MAX_SEGMENT_COUNT)
+    segment_count = MAX_SEGMENT_COUNT;
+  if (segment_count * MIN_SEGMENT_SIZE > total_size)
+    segment_count = total_size / MIN_SEGMENT_SIZE;
+    
+  /* The segment count must be a power of two. Round it down as necessary.
+   */
+  while ((segment_count & (segment_count-1)) != 0)
+    segment_count &= segment_count-1;
+
+  /* if the caller hasn't provided a reasonable segment count or the above
+   * limitations set it to 0, derive one from the absolute cache size
+   */
+  if (segment_count < 1)
+    {
+      /* Determine a reasonable number of cache segments. Segmentation is
+       * only useful for multi-threaded / multi-core servers as it reduces
+       * lock contention on these systems.
+       *
+       * But on these systems, we can assume that ample memory has been
+       * allocated to this cache. Smaller caches should not be segmented
+       * as this severely limits the maximum size of cachable items.
+       *
+       * Segments should not be smaller than 32MB and max. cachable item
+       * size should grow as fast as segmentation.
+       */
 
-  segment_count = 1 << segment_count_shift;
+      apr_uint32_t segment_count_shift = 0;
+      while (((2 * DEFAULT_MIN_SEGMENT_SIZE) << (2 * segment_count_shift))
+             < total_size)
+        ++segment_count_shift;
+
+      segment_count = 1 << segment_count_shift;
+    }
 
   /* allocate cache as an array of segments / cache objects */
   c = apr_palloc(pool, segment_count * sizeof(*c));
 
   /* Split total cache size into segments of equal size
    */
-  total_size >>= segment_count_shift;
-  directory_size >>= segment_count_shift;
+  total_size /= segment_count;
+  directory_size /= segment_count;
 
   /* prevent pathological conditions: ensure a certain minimum cache size
    */
@@ -1143,6 +1277,10 @@ svn_cache__membuffer_cache_create(svn_me
           if (status)
             return svn_error_wrap_apr(status, _("Can't create cache mutex"));
         }
+
+      /* Select the behavior of write operations.
+       */
+      c[seg].allow_blocking_writes = allow_blocking_writes;
 #endif
     }
 
@@ -1152,6 +1290,40 @@ svn_cache__membuffer_cache_create(svn_me
   return SVN_NO_ERROR;
 }
 
+/* Look for the cache entry in group GROUP_INDEX of CACHE, identified
+ * by the hash value TO_FIND and set *FOUND accordingly.
+ *
+ * Note: This function requires the caller to serialize access.
+ * Don't call it directly, call entry_exists instead.
+ */
+static svn_error_t *
+entry_exists_internal(svn_membuffer_t *cache,
+                      apr_uint32_t group_index,
+                      entry_key_t to_find,
+                      svn_boolean_t *found)
+{
+  *found = find_entry(cache, group_index, to_find, FALSE) != NULL;
+  return SVN_NO_ERROR;
+}
+
+/* Look for the cache entry in group GROUP_INDEX of CACHE, identified
+ * by the hash value TO_FIND and set *FOUND accordingly.
+ */
+static svn_error_t *
+entry_exists(svn_membuffer_t *cache,
+             apr_uint32_t group_index,
+             entry_key_t to_find,
+             svn_boolean_t *found)
+{
+  WITH_READ_LOCK(cache,
+                 entry_exists_internal(cache,
+                                       group_index,
+                                       to_find,
+                                       found));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* Try to insert the serialized item given in BUFFER with SIZE into
  * the group GROUP_INDEX of CACHE and uniquely identify it by hash
@@ -1174,15 +1346,38 @@ membuffer_cache_set_internal(svn_membuff
                              DEBUG_CACHE_MEMBUFFER_TAG_ARG
                              apr_pool_t *scratch_pool)
 {
+  /* first, look for a previous entry for the given key */
+  entry_t *entry = find_entry(cache, group_index, to_find, FALSE);
+
+  /* if there is an old version of that entry and the new data fits into
+   * the old spot, just re-use that space. */
+  if (buffer && entry && entry->size >= size)
+    {
+      cache->data_used += size - entry->size;
+      entry->size = size;
+
+#ifdef SVN_DEBUG_CACHE_MEMBUFFER
+
+      /* Remember original content, type and key (hashes)
+       */
+      SVN_ERR(store_content_part(tag, buffer, size, scratch_pool));
+      memcpy(&entry->tag, tag, sizeof(*tag));
+
+#endif
+
+      if (size)
+        memcpy(cache->data + entry->offset, buffer, size);
+
+      cache->total_writes++;
+      return SVN_NO_ERROR;
+    }
+
   /* if necessary, enlarge the insertion window.
    */
   if (   buffer != NULL
       && cache->max_entry_size >= size
       && ensure_data_insertable(cache, size))
     {
-      /* first, look for a previous entry for the given key */
-      entry_t *entry = find_entry(cache, group_index, to_find, FALSE);
-
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER
 
       /* Remember original content, type and key (hashes)
@@ -1192,26 +1387,17 @@ membuffer_cache_set_internal(svn_membuff
 
 #endif
 
-      /* if there is an old version of that entry and the new data fits into
-       * the old spot, just re-use that space. */
-      if (entry && entry->size >= size)
-        {
-          entry->size = size;
-        }
-      else
-        {
-          /* Remove old data for this key, if that exists.
-           * Get an unused entry for the key and and initialize it with
-           * the serialized item's (future) position within data buffer.
-           */
-          entry = find_entry(cache, group_index, to_find, TRUE);
-          entry->size = size;
-          entry->offset = cache->current_data;
+      /* Remove old data for this key, if that exists.
+       * Get an unused entry for the key and and initialize it with
+       * the serialized item's (future) position within data buffer.
+       */
+      entry = find_entry(cache, group_index, to_find, TRUE);
+      entry->size = size;
+      entry->offset = cache->current_data;
 
-          /* Link the entry properly.
-           */
-          insert_entry(cache, entry);
-        }
+      /* Link the entry properly.
+        */
+      insert_entry(cache, entry);
 
       /* Copy the serialized item data into the cache.
        */
@@ -1224,8 +1410,10 @@ membuffer_cache_set_internal(svn_membuff
     {
       /* if there is already an entry for this key, drop it.
        */
-      find_entry(cache, group_index, to_find, TRUE);
+      if (entry)
+        drop_entry(cache, entry);
     }
+
   return SVN_NO_ERROR;
 }
 
@@ -1523,7 +1711,7 @@ membuffer_cache_set_partial_internal(svn
 
 #endif
 
-      /* modify it, preferrably in-situ.
+      /* modify it, preferably in-situ.
        */
       err = func((void **)&data, &size, baton, scratch_pool);
 
@@ -1544,7 +1732,7 @@ membuffer_cache_set_partial_internal(svn
             {
               /* Remove the old entry and try to make space for the new one.
                */
-              drop_entry(cache, entry);
+              entry = find_entry(cache, group_index, to_find, TRUE);
               if (   (cache->max_entry_size >= size)
                   && ensure_data_insertable(cache, size))
                 {
@@ -1692,7 +1880,31 @@ combine_key(svn_membuffer_cache_t *cache
   if (key_len == APR_HASH_KEY_STRING)
     key_len = strlen((const char *) key);
 
-  apr_md5((unsigned char*)cache->combined_key, key, key_len);
+  if (key_len < 16)
+    {
+      apr_uint32_t data[4] = { 0 };
+      memcpy(data, key, key_len);
+
+      svn__pseudo_md5_15((apr_uint32_t *)cache->combined_key, data);
+    }
+  else if (key_len < 32)
+    {
+      apr_uint32_t data[8] = { 0 };
+      memcpy(data, key, key_len);
+
+      svn__pseudo_md5_31((apr_uint32_t *)cache->combined_key, data);
+    }
+  else if (key_len < 64)
+    {
+      apr_uint32_t data[16] = { 0 };
+      memcpy(data, key, key_len);
+
+      svn__pseudo_md5_63((apr_uint32_t *)cache->combined_key, data);
+    }
+  else
+    {
+      apr_md5((unsigned char*)cache->combined_key, key, key_len);
+    }
 
   cache->combined_key[0] ^= cache->prefix[0];
   cache->combined_key[1] ^= cache->prefix[1];

Modified: subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache-memcache.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache-memcache.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache-memcache.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache-memcache.c Sat Oct  6 18:31:28 2012
@@ -470,7 +470,8 @@ add_memcache_server(const char *name,
                                        0,  /* min connections */
                                        5,  /* soft max connections */
                                        10, /* hard max connections */
-                                       50, /* connection time to live (secs) */
+                                       /*  time to live (in microseconds) */
+                                       apr_time_from_sec(50),
                                        &server);
   if (apr_err != APR_SUCCESS)
     {

Modified: subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache_config.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache_config.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache_config.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_subr/cache_config.c Sat Oct  6 18:31:28 2012
@@ -119,7 +119,9 @@ svn_cache__get_global_membuffer_cache(vo
           &new_cache,
           (apr_size_t)cache_size,
           (apr_size_t)(cache_size / 10),
+          0,
           ! svn_cache_config_get()->single_threaded,
+          FALSE,
           pool);
 
       /* Some error occured. Most likely it's an OOM error but we don't

Modified: subversion/branches/auto-props-sdc/subversion/libsvn_subr/ssl_client_cert_pw_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/auto-props-sdc/subversion/libsvn_subr/ssl_client_cert_pw_providers.c?rev=1395146&r1=1395145&r2=1395146&view=diff
==============================================================================
--- subversion/branches/auto-props-sdc/subversion/libsvn_subr/ssl_client_cert_pw_providers.c (original)
+++ subversion/branches/auto-props-sdc/subversion/libsvn_subr/ssl_client_cert_pw_providers.c Sat Oct  6 18:31:28 2012
@@ -82,7 +82,7 @@ svn_auth__ssl_client_cert_pw_get(svn_boo
       return SVN_NO_ERROR;
     }
   *done = FALSE;
-  return FALSE;
+  return SVN_NO_ERROR;
 }
 
 /* This implements the svn_auth__password_set_t interface.



Mime
View raw message