You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/15 10:52:18 UTC

svn commit: r1532250 [22/37] - in /subversion/branches/cache-server: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/emacs/ contrib/hook-scripts/ contrib/server-side/fsfsfixer/ contrib/se...

Modified: subversion/branches/cache-server/subversion/libsvn_subr/hash.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/hash.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/hash.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/hash.c Tue Oct 15 08:52:06 2013
@@ -31,6 +31,7 @@
 #include <apr_hash.h>
 #include <apr_file_io.h>
 
+#include "svn_private_config.h"
 #include "svn_types.h"
 #include "svn_string.h"
 #include "svn_error.h"
@@ -42,8 +43,6 @@
 #include "private/svn_dep_compat.h"
 #include "private/svn_subr_private.h"
 
-#include "svn_private_config.h"
-
 
 
 
@@ -576,20 +575,16 @@ svn_hash__get_bool(apr_hash_t *hash, con
 
 /*** Optimized hash function ***/
 
-/* Optimized version of apr_hashfunc_default in APR 1.4.5 and earlier.
- * It assumes that the CPU has 32-bit multiplications with high throughput
- * of at least 1 operation every 3 cycles. Latency is not an issue. Another
- * optimization is a mildly unrolled main loop and breaking the dependency
- * chain within the loop.
- *
- * Note that most CPUs including Intel Atom, VIA Nano, ARM feature the
- * assumed pipelined multiplication circuitry. They can do one MUL every
- * or every other cycle.
- *
- * The performance is ultimately limited by the fact that most CPUs can
- * do only one LOAD and only one BRANCH operation per cycle. The best we
- * can do is to process one character per cycle - provided the processor
- * is wide enough to do 1 LOAD, COMPARE, BRANCH, MUL and ADD per cycle.
+/* apr_hashfunc_t optimized for the key that we use in SVN: paths and 
+ * property names.  Its primary goal is speed for keys of known length.
+ * 
+ * Since strings tend to spawn large value spaces (usually differ in many
+ * bits with differences spanning a larger section of the key), we can be
+ * quite sloppy extracting a hash value.  The more keys there are in a
+ * hash container, the more bits of the value returned by this function
+ * will be used.  For a small number of string keys, choosing bits from any 
+ * any fix location close to the tail of those keys would usually be good
+ * enough to prevent high collision rates.
  */
 static unsigned int
 hashfunc_compatible(const char *char_key, apr_ssize_t *klen)
@@ -600,37 +595,29 @@ hashfunc_compatible(const char *char_key
     apr_ssize_t i;
 
     if (*klen == APR_HASH_KEY_STRING)
+      *klen = strlen(char_key);
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+    for (p = key, i = *klen; i >= 4; i-=4, p+=4)
       {
-        for (p = key; ; p+=4)
-          {
-            unsigned int new_hash = hash * 33 * 33 * 33 * 33;
-            if (!p[0]) break;
-            new_hash += p[0] * 33 * 33 * 33;
-            if (!p[1]) break;
-            new_hash += p[1] * 33 * 33;
-            if (!p[2]) break;
-            new_hash += p[2] * 33;
-            if (!p[3]) break;
-            hash = new_hash + p[3];
-          }
-        for (; *p; p++)
-            hash = hash * 33 + *p;
+        apr_uint32_t chunk = *(apr_uint32_t *)p;
 
-        *klen = p - key;
+        /* the ">> 17" part gives upper bits in the chunk a chance to make
+           some impact as well */
+        hash = hash * 33 * 33 * 33 * 33 + chunk + (chunk >> 17);
       }
-    else
+#else
+    for (p = key, i = *klen; i >= 4; i-=4, p+=4)
       {
-        for (p = key, i = *klen; i >= 4; i-=4, p+=4)
-          {
-            hash = hash * 33 * 33 * 33 * 33
-                 + p[0] * 33 * 33 * 33
-                 + p[1] * 33 * 33
-                 + p[2] * 33
-                 + p[3];
-          }
-        for (; i; i--, p++)
-            hash = hash * 33 + *p;
+        hash = hash * 33 * 33 * 33 * 33
+              + p[0] * 33 * 33 * 33
+              + p[1] * 33 * 33
+              + p[2] * 33
+              + p[3];
       }
+#endif
+    for (; i; i--, p++)
+        hash = hash * 33 + *p;
 
     return hash;
 }

Modified: subversion/branches/cache-server/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/io.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/io.c Tue Oct 15 08:52:06 2013
@@ -51,6 +51,11 @@
 #include <arch/win32/apr_arch_file_io.h>
 #endif
 
+#if APR_HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_types.h"
 #include "svn_dirent_uri.h"
@@ -61,7 +66,6 @@
 #include "svn_pools.h"
 #include "svn_utf.h"
 #include "svn_config.h"
-#include "svn_private_config.h"
 #include "svn_ctype.h"
 
 #include "private/svn_atomic.h"
@@ -139,6 +143,26 @@
 #endif
 #endif
 
+#ifdef WIN32
+/* One-time initialization of the late bound Windows API functions. */
+static volatile svn_atomic_t win_dynamic_imports_state = 0;
+
+/* Pointer to GetFinalPathNameByHandleW function from kernel32.dll. */
+typedef DWORD (WINAPI *GETFINALPATHNAMEBYHANDLE)(
+               HANDLE hFile,
+               apr_wchar_t *lpszFilePath,
+               DWORD cchFilePath,
+               DWORD dwFlags);
+
+static GETFINALPATHNAMEBYHANDLE get_final_path_name_by_handle_proc = NULL;
+
+/* Forward declaration. */
+static svn_error_t * io_win_read_link(svn_string_t **dest,
+                                      const char *path,
+                                      apr_pool_t *pool);
+
+#endif
+
 /* Forward declaration */
 static apr_status_t
 dir_is_empty(const char *dir, apr_pool_t *pool);
@@ -660,7 +684,7 @@ svn_io_read_link(svn_string_t **dest,
                  const char *path,
                  apr_pool_t *pool)
 {
-#ifdef HAVE_READLINK
+#if defined(HAVE_READLINK)
   svn_string_t dest_apr;
   const char *path_apr;
   char buf[1025];
@@ -681,6 +705,8 @@ svn_io_read_link(svn_string_t **dest,
 
   /* ### Cast needed, one of these interfaces is wrong */
   return svn_utf_string_to_utf8((const svn_string_t **)dest, &dest_apr, pool);
+#elif defined(WIN32)
+  return io_win_read_link(dest, path, pool);
 #else
   return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                           _("Symbolic links are not supported on this "
@@ -1140,9 +1166,11 @@ svn_io_make_dir_recursively(const char *
   return SVN_NO_ERROR;
 }
 
-svn_error_t *svn_io_file_create(const char *file,
-                                const char *contents,
-                                apr_pool_t *pool)
+svn_error_t *
+svn_io_file_create_binary(const char *file,
+                          const char *contents,
+                          apr_size_t length,
+                          apr_pool_t *pool)
 {
   apr_file_t *f;
   apr_size_t written;
@@ -1152,25 +1180,57 @@ svn_error_t *svn_io_file_create(const ch
                            (APR_WRITE | APR_CREATE | APR_EXCL),
                            APR_OS_DEFAULT,
                            pool));
-  if (contents && *contents)
-    err = svn_io_file_write_full(f, contents, strlen(contents),
-                                 &written, pool);
+  if (length)
+    err = svn_io_file_write_full(f, contents, length, &written, pool);
 
+  err = svn_error_compose_create(
+                    err,
+                    svn_io_file_close(f, pool));
 
-  return svn_error_trace(
-                        svn_error_compose_create(err,
-                                                 svn_io_file_close(f, pool)));
+  if (err)
+    {
+      /* Our caller doesn't know if we left a file or not if we return
+         an error. Better to cleanup after ourselves if we created the
+         file. */
+      return svn_error_trace(
+                svn_error_compose_create(
+                    err,
+                    svn_io_remove_file2(file, TRUE, pool)));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_io_file_create(const char *file,
+                   const char *contents,
+                   apr_pool_t *pool)
+{
+  return svn_error_trace(svn_io_file_create_binary(file, contents,
+                                                   contents
+                                                        ? strlen(contents)
+                                                        : 0,
+                                                   pool));
 }
 
-svn_error_t *svn_io_dir_file_copy(const char *src_path,
-                                  const char *dest_path,
-                                  const char *file,
-                                  apr_pool_t *pool)
+svn_error_t *
+svn_io_file_create_empty(const char *file,
+                         apr_pool_t *pool)
+{
+  return svn_error_trace(svn_io_file_create_binary(file, "", 0, pool));
+}
+
+svn_error_t *
+svn_io_dir_file_copy(const char *src_path,
+                     const char *dest_path,
+                     const char *file,
+                     apr_pool_t *pool)
 {
   const char *file_dest_path = svn_dirent_join(dest_path, file, pool);
   const char *file_src_path = svn_dirent_join(src_path, file, pool);
 
-  return svn_io_copy_file(file_src_path, file_dest_path, TRUE, pool);
+  return svn_error_trace(
+            svn_io_copy_file(file_src_path, file_dest_path, TRUE, pool));
 }
 
 
@@ -1697,6 +1757,46 @@ static apr_status_t io_utf8_to_unicode_p
             *t = L'\\';
     return APR_SUCCESS;
 }
+
+/* copy of the apr function unicode_to_utf8_path since apr doesn't export this
+ * one */
+static apr_status_t io_unicode_to_utf8_path(char* retstr, apr_size_t retlen,
+                                            const apr_wchar_t* srcstr)
+{
+    /* Skip the leading 4 characters if the path begins \\?\, or substitute
+     * // for the \\?\UNC\ path prefix, allocating the maximum string
+     * length based on the remaining string, plus the trailing null.
+     * then transform \\'s back into /'s since the \\?\ form never
+     * allows '/' path seperators, and APR always uses '/'s.
+     */
+    apr_size_t srcremains = wcslen(srcstr) + 1;
+    apr_status_t rv;
+    char *t = retstr;
+    if (srcstr[0] == L'\\' && srcstr[1] == L'\\' && 
+        srcstr[2] == L'?'  && srcstr[3] == L'\\') {
+        if (srcstr[4] == L'U' && srcstr[5] == L'N' && 
+            srcstr[6] == L'C' && srcstr[7] == L'\\') {
+            srcremains -= 8;
+            srcstr += 8;
+            retstr[0] = '\\';
+            retstr[1] = '\\';
+            retlen -= 2;
+            t += 2;
+        }
+        else {
+            srcremains -= 4;
+            srcstr += 4;
+        }
+    }
+        
+    if ((rv = apr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen))) {
+        return rv;
+    }
+    if (srcremains) {
+        return APR_ENAMETOOLONG;
+    }
+    return APR_SUCCESS;
+}
 #endif
 
 static apr_status_t io_win_file_attrs_set(const char *fname,
@@ -1756,6 +1856,83 @@ static apr_status_t io_win_file_attrs_se
     return APR_SUCCESS;
 }
 
+static svn_error_t *win_init_dynamic_imports(void *baton, apr_pool_t *pool)
+{
+    get_final_path_name_by_handle_proc = (GETFINALPATHNAMEBYHANDLE)
+      GetProcAddress(GetModuleHandleA("kernel32.dll"),
+                     "GetFinalPathNameByHandleW");
+
+    return SVN_NO_ERROR;
+}
+
+static svn_error_t * io_win_read_link(svn_string_t **dest,
+                                      const char *path,
+                                      apr_pool_t *pool)
+{
+#if APR_HAS_UNICODE_FS
+    SVN_ERR(svn_atomic__init_once(&win_dynamic_imports_state,
+                                  win_init_dynamic_imports, NULL, pool));
+
+    if (get_final_path_name_by_handle_proc)
+      {
+        DWORD rv;
+        apr_status_t status;
+        apr_file_t *file;
+        apr_os_file_t filehand;
+        apr_wchar_t wdest[APR_PATH_MAX];
+        char buf[APR_PATH_MAX];
+
+        /* reserve one char for terminating zero. */
+        DWORD wdest_len = sizeof(wdest)/sizeof(wdest[0]) - 1;
+
+        status = apr_file_open(&file, path, APR_OPENINFO, APR_OS_DEFAULT, pool);
+
+        if (status)
+          return svn_error_wrap_apr(status,
+                                    _("Can't read contents of link"));
+
+        apr_os_file_get(&filehand, file);
+
+        rv = get_final_path_name_by_handle_proc(
+               filehand, wdest, wdest_len,
+               FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+
+        /* Save error code. */
+        status = apr_get_os_error();
+
+        /* Close file/directory handle in any case. */
+        apr_file_close(file);
+
+        /* GetFinaPathNameByHandleW returns number of characters copied to
+         * output buffer. Returns zero on error. Returns required buffer size
+         * if supplied buffer is not enough. */
+        if (rv > wdest_len || rv == 0)
+          {
+            return svn_error_wrap_apr(status,
+                                      _("Can't read contents of link"));
+          }
+
+        /* GetFinaPathNameByHandleW doesn't add terminating NUL. */
+        wdest[rv] = 0;
+
+        status = io_unicode_to_utf8_path(buf, sizeof(buf), wdest);
+        if (status)
+          return svn_error_wrap_apr(status,
+                                    _("Can't read contents of link"));
+
+        *dest = svn_string_create(buf, pool);
+
+        return SVN_NO_ERROR;
+      }
+    else
+#endif
+      {
+        return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                                _("Symbolic links are not supported on this "
+                                "platform"));
+      }
+}
+
 #endif
 
 svn_error_t *
@@ -2091,11 +2268,12 @@ svn_error_t *svn_io_file_flush_to_disk(a
 {
   apr_os_file_t filehand;
 
+  /* ### In apr 1.4+ we could delegate most of this function to
+         apr_file_sync(). The only major difference is that this doesn't
+         contain the retry loop for EINTR on linux. */
+
   /* First make sure that any user-space buffered data is flushed. */
-  SVN_ERR(do_io_file_wrapper_cleanup(file, apr_file_flush(file),
-                                     N_("Can't flush file '%s'"),
-                                     N_("Can't flush stream"),
-                                     pool));
+  SVN_ERR(svn_io_file_flush(file, pool));
 
   apr_os_file_get(&filehand, file);
 
@@ -2112,7 +2290,11 @@ svn_error_t *svn_io_file_flush_to_disk(a
       int rv;
 
       do {
+#ifdef F_FULLFSYNC
+        rv = fcntl(filehand, F_FULLFSYNC, 0);
+#else
         rv = fsync(filehand);
+#endif
       } while (rv == -1 && APR_STATUS_IS_EINTR(apr_get_os_error()));
 
       /* If the file is in a memory filesystem, fsync() may return
@@ -2152,36 +2334,35 @@ stringbuf_from_aprfile(svn_stringbuf_t *
   svn_error_t *err;
   svn_stringbuf_t *res = NULL;
   apr_size_t res_initial_len = SVN__STREAM_CHUNK_SIZE;
-  char *buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
+  char *buf;
 
   /* If our caller wants us to check the size of the file for
      efficient memory handling, we'll try to do so. */
   if (check_size)
     {
-      apr_status_t status;
-
-      /* If our caller didn't tell us the file's name, we'll ask APR
-         if it knows the name.  No problem if we can't figure it out.  */
-      if (! filename)
-        {
-          const char *filename_apr;
-          if (! (status = apr_file_name_get(&filename_apr, file)))
-            filename = filename_apr;
-        }
+      apr_finfo_t finfo;
 
-      /* If we now know the filename, try to stat().  If we succeed,
-         we know how to allocate our stringbuf.  */
-      if (filename)
-        {
-          apr_finfo_t finfo;
-          if (! (status = apr_stat(&finfo, filename, APR_FINFO_MIN, pool)))
-            res_initial_len = (apr_size_t)finfo.size;
+      /* In some cases we get size 0 and no error for non files,
+          so we also check for the name. (= cached in apr_file_t) */
+      if (! apr_file_info_get(&finfo, APR_FINFO_SIZE | APR_FINFO_NAME, file)
+          && finfo.name != NULL)
+        {
+          /* we've got the file length. Now, read it in one go. */
+          svn_boolean_t eof;
+          res_initial_len = (apr_size_t)finfo.size;
+          res = svn_stringbuf_create_ensure(res_initial_len, pool);
+          SVN_ERR(svn_io_file_read_full2(file, res->data,
+                                         res_initial_len, &res->len,
+                                         &eof, pool));
+          res->data[res->len] = 0;
+          
+          *result = res;
+          return SVN_NO_ERROR;
         }
     }
 
-
   /* XXX: We should check the incoming data for being of type binary. */
-
+  buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
   res = svn_stringbuf_create_ensure(res_initial_len, pool);
 
   /* apr_file_read will not return data and eof in the same call. So this loop
@@ -2197,7 +2378,7 @@ stringbuf_from_aprfile(svn_stringbuf_t *
 
   /* Having read all the data we *expect* EOF */
   if (err && !APR_STATUS_IS_EOF(err->apr_err))
-    return err;
+    return svn_error_trace(err);
   svn_error_clear(err);
 
   *result = res;
@@ -2795,10 +2976,23 @@ svn_io_wait_for_cmd(apr_proc_t *cmd_proc
 
   if (exitwhy)
     *exitwhy = exitwhy_val;
+  else if (APR_PROC_CHECK_SIGNALED(exitwhy_val)
+           && APR_PROC_CHECK_CORE_DUMP(exitwhy_val))
+    return svn_error_createf
+      (SVN_ERR_EXTERNAL_PROGRAM, NULL,
+       _("Process '%s' failed (signal %d, core dumped)"),
+       cmd, exitcode_val);
+  else if (APR_PROC_CHECK_SIGNALED(exitwhy_val))
+    return svn_error_createf
+      (SVN_ERR_EXTERNAL_PROGRAM, NULL,
+       _("Process '%s' failed (signal %d)"),
+       cmd, exitcode_val);
   else if (! APR_PROC_CHECK_EXIT(exitwhy_val))
+    /* Don't really know what happened here. */
     return svn_error_createf
       (SVN_ERR_EXTERNAL_PROGRAM, NULL,
-       _("Process '%s' failed (exitwhy %d)"), cmd, exitwhy_val);
+       _("Process '%s' failed (exitwhy %d, exitcode %d)"),
+       cmd, exitwhy_val, exitcode_val);
 
   if (exitcode)
     *exitcode = exitcode_val;
@@ -3293,7 +3487,7 @@ do_io_file_wrapper_cleanup(apr_file_t *f
 
   /* ### Issue #3014: Return a specific error for broken pipes,
    * ### with a single element in the error chain. */
-  if (APR_STATUS_IS_EPIPE(status))
+  if (SVN__APR_STATUS_IS_EPIPE(status))
     return svn_error_create(SVN_ERR_IO_PIPE_WRITE_ERROR, NULL, NULL);
 
   if (name)
@@ -3396,6 +3590,101 @@ svn_io_file_seek(apr_file_t *file, apr_s
              pool);
 }
 
+svn_error_t *
+svn_io_file_aligned_seek(apr_file_t *file,
+                         apr_off_t block_size,
+                         apr_off_t *buffer_start,
+                         apr_off_t offset,
+                         apr_pool_t *pool)
+{
+  const apr_size_t apr_default_buffer_size = 4096;
+  apr_size_t file_buffer_size = apr_default_buffer_size;
+  apr_off_t desired_offset = 0;
+  apr_off_t current = 0;
+  apr_off_t aligned_offset = 0;
+  svn_boolean_t fill_buffer = FALSE;
+
+  /* paranoia check: huge blocks on 32 bit machines may cause overflows */
+  SVN_ERR_ASSERT(block_size == (apr_size_t)block_size);
+
+  /* default for invalid block sizes */
+  if (block_size == 0)
+    block_size = apr_default_buffer_size;
+
+  /* on old APRs, we are simply stuck with 4k blocks */
+#if APR_VERSION_AT_LEAST(1,3,0)
+  file_buffer_size = apr_file_buffer_size_get(file);
+
+  /* don't try to set a buffer size for non-buffered files! */
+  if (file_buffer_size == 0)
+    {
+      aligned_offset = offset;
+    }
+  else if (file_buffer_size != (apr_size_t)block_size)
+    {
+      /* FILE has the wrong buffer size. correct it */
+      char *buffer;
+      file_buffer_size = (apr_size_t)block_size;
+      buffer = apr_palloc(apr_file_pool_get(file), file_buffer_size);
+      apr_file_buffer_set(file, buffer, file_buffer_size);
+
+      /* seek to the start of the block and cause APR to read 1 block */
+      aligned_offset = offset - (offset % block_size);
+      fill_buffer = TRUE;
+    }
+#endif
+    {
+      aligned_offset = offset - (offset % file_buffer_size);
+
+      /* We have no way to determine the block start of an APR file.
+         Furthermore, we don't want to throw away the current buffer
+         contents.  Thus, we re-align the buffer only if the CURRENT
+         offset definitely lies outside the desired, aligned buffer.
+         This covers the typical case of linear reads getting very
+         close to OFFSET but reading the previous / following block.
+
+         Note that ALIGNED_OFFSET may still be within the current
+         buffer and no I/O will actually happen in the FILL_BUFFER
+         section below.
+       */
+      SVN_ERR(svn_io_file_seek(file, SEEK_CUR, &current, pool));
+      fill_buffer = aligned_offset + file_buffer_size <= current
+                 || current <= aligned_offset;
+    }
+
+  if (fill_buffer)
+    {
+      char dummy;
+      apr_status_t status;
+
+      /* seek to the start of the block and cause APR to read 1 block */
+      SVN_ERR(svn_io_file_seek(file, SEEK_SET, &aligned_offset, pool));
+      status = apr_file_getc(&dummy, file);
+
+      /* read may fail if we seek to or behind EOF.  That's ok then. */
+      if (status != APR_SUCCESS && !APR_STATUS_IS_EOF(status))
+        return do_io_file_wrapper_cleanup(file, status,
+                                          N_("Can't read file '%s'"),
+                                          N_("Can't read stream"),
+                                          pool);
+    }
+
+  /* finally, seek to the OFFSET the caller wants */
+  desired_offset = offset;
+  SVN_ERR(svn_io_file_seek(file, SEEK_SET, &offset, pool));
+  if (desired_offset != offset)
+    return do_io_file_wrapper_cleanup(file, APR_EOF,
+                                      N_("Can't seek in file '%s'"),
+                                      N_("Can't seek in stream"),
+                                      pool);
+
+  /* return the buffer start that we (probably) enforced */
+  if (buffer_start)
+    *buffer_start = aligned_offset;
+
+  return SVN_NO_ERROR;
+}
+
 
 svn_error_t *
 svn_io_file_write(apr_file_t *file, const void *buf,
@@ -3408,6 +3697,16 @@ svn_io_file_write(apr_file_t *file, cons
      pool));
 }
 
+svn_error_t *
+svn_io_file_flush(apr_file_t *file,
+                  apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(do_io_file_wrapper_cleanup(
+     file, apr_file_flush(file),
+     N_("Can't flush file '%s'"),
+     N_("Can't flush stream"),
+     scratch_pool));
+}
 
 svn_error_t *
 svn_io_file_write_full(apr_file_t *file, const void *buf,
@@ -3472,23 +3771,76 @@ svn_io_write_unique(const char **tmp_pat
 
   err = svn_io_file_write_full(new_file, buf, nbytes, NULL, pool);
 
-  /* ### BH: Windows doesn't have the race condition between the write and the
-     ###     rename that other operating systems might have. So allow windows
-     ###     to decide when it wants to perform the disk synchronization using
-     ###     the normal file locking and journaling filesystem rules.
-
-     ### Note that this function doesn't handle the rename, so we aren't even
-     ### sure that we really have to sync. */
-#ifndef WIN32
-  if (!err && nbytes > 0)
-    err = svn_io_file_flush_to_disk(new_file, pool);
-#endif
+  if (!err)
+    {
+      /* svn_io_file_flush_to_disk() can be very expensive, so use the
+         cheaper standard flush if the file is created as temporary file
+         anyway */
+      if (delete_when == svn_io_file_del_none)
+        err = svn_io_file_flush_to_disk(new_file, pool);
+      else
+        err = svn_io_file_flush(new_file, pool);
+    }
 
   return svn_error_trace(
                   svn_error_compose_create(err,
                                            svn_io_file_close(new_file, pool)));
 }
 
+svn_error_t *
+svn_io_write_atomic(const char *final_path,
+                    const void *buf,
+                    apr_size_t nbytes,
+                    const char *copy_perms_path,
+                    apr_pool_t *scratch_pool)
+{
+  apr_file_t *tmp_file;
+  const char *tmp_path;
+  svn_error_t *err;
+  const char *dirname = svn_dirent_dirname(final_path, scratch_pool);
+
+  SVN_ERR(svn_io_open_unique_file3(&tmp_file, &tmp_path, dirname,
+                                   svn_io_file_del_none,
+                                   scratch_pool, scratch_pool));
+
+  err = svn_io_file_write_full(tmp_file, buf, nbytes, NULL, scratch_pool);
+
+  if (!err)
+    err = svn_io_file_flush_to_disk(tmp_file, scratch_pool);
+
+  err = svn_error_compose_create(err,
+                                 svn_io_file_close(tmp_file, scratch_pool));
+
+  if (!err && copy_perms_path)
+    err = svn_io_copy_perms(copy_perms_path, tmp_path, scratch_pool);
+
+  if (err)
+    {
+      return svn_error_compose_create(err,
+                                      svn_io_remove_file2(tmp_path, FALSE,
+                                                          scratch_pool));
+    }
+
+  SVN_ERR(svn_io_file_rename(tmp_path, final_path, scratch_pool));
+
+#ifdef __linux__
+  {
+    /* Linux has the unusual feature that fsync() on a file is not
+       enough to ensure that a file's directory entries have been
+       flushed to disk; you have to fsync the directory as well.
+       On other operating systems, we'd only be asking for trouble
+       by trying to open and fsync a directory. */
+    apr_file_t *file;
+
+    SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
+                             scratch_pool));
+    SVN_ERR(svn_io_file_flush_to_disk(file, scratch_pool));
+    SVN_ERR(svn_io_file_close(file, scratch_pool));
+  }
+#endif
+
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_io_file_trunc(apr_file_t *file, apr_off_t offset, apr_pool_t *pool)
@@ -3529,6 +3881,9 @@ svn_io_read_length_line(apr_file_t *file
       apr_size_t bytes_read = 0;
       char *eol;
 
+      if (to_read == 0)
+        break;
+
       /* read data block (or just a part of it) */
       SVN_ERR(svn_io_file_read_full2(file, buf, to_read,
                                      &bytes_read, &eof, pool));

Modified: subversion/branches/cache-server/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/mergeinfo.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/mergeinfo.c Tue Oct 15 08:52:06 2013
@@ -23,6 +23,7 @@
 #include <assert.h>
 #include <ctype.h>
 
+#include "svn_private_config.h"
 #include "svn_path.h"
 #include "svn_types.h"
 #include "svn_ctype.h"
@@ -36,7 +37,6 @@
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_string_private.h"
 #include "private/svn_subr_private.h"
-#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "private/svn_dep_compat.h"
 
@@ -611,6 +611,23 @@ svn_rangelist__parse(svn_rangelist_t **r
   return SVN_NO_ERROR;
 }
 
+/* Return TRUE, if all ranges in RANGELIST are in ascending order and do
+ * not overlap.  If this returns FALSE, you probaly want to qsort() the
+ * ranges and then call svn_rangelist__combine_adjacent_ranges().
+ */
+static svn_boolean_t
+is_rangelist_normalized(svn_rangelist_t *rangelist)
+{
+  int i;
+  svn_merge_range_t **ranges = (svn_merge_range_t **)rangelist->elts;
+
+  for (i = 0; i < rangelist->nelts-1; ++i)
+    if (ranges[i]->end >= ranges[i+1]->start)
+      return FALSE;
+
+  return TRUE;
+}
+
 svn_error_t *
 svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist,
                                        apr_pool_t *scratch_pool)
@@ -692,9 +709,11 @@ parse_revision_line(const char **input, 
   if (*input != end)
     *input = *input + 1;
 
-  /* Sort the rangelist, combine adjacent ranges into single ranges,
-     and make sure there are no overlapping ranges. */
-  if (rangelist->nelts > 1)
+  /* Sort the rangelist, combine adjacent ranges into single ranges, and
+     make sure there are no overlapping ranges.  Luckily, most data in
+     svn:mergeinfo will already be in normalized form and we can skip this.
+   */
+  if (! is_rangelist_normalized(rangelist))
     {
       qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
             svn_sort_compare_ranges);
@@ -2223,16 +2242,19 @@ svn_rangelist_dup(const svn_rangelist_t 
 
   /* allocate target range buffer with a single operation */
   svn_merge_range_t *copy = apr_palloc(pool, sizeof(*copy) * rangelist->nelts);
+
+  /* for efficiency, directly address source and target reference buffers */
+  svn_merge_range_t **source = (svn_merge_range_t **)(rangelist->elts);
+  svn_merge_range_t **target = (svn_merge_range_t **)(new_rl->elts);
   int i;
 
-  /* fill it iteratively and link it into the range list */
+  /* copy ranges iteratively and link them into the target range list */
   for (i = 0; i < rangelist->nelts; i++)
     {
-      memcpy(copy + i,
-             APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *),
-             sizeof(*copy));
-      APR_ARRAY_PUSH(new_rl, svn_merge_range_t *) = copy + i;
+      copy[i] = *source[i];
+      target[i] = &copy[i];
     }
+  new_rl->nelts = rangelist->nelts;
 
   return new_rl;
 }

Modified: subversion/branches/cache-server/subversion/libsvn_subr/named_atomic.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/named_atomic.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/named_atomic.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/named_atomic.c Tue Oct 15 08:52:06 2013
@@ -251,6 +251,7 @@ struct svn_atomic_namespace__t
  */
 static svn_mutex__t *thread_mutex = NULL;
 
+#if APR_HAS_MMAP
 /* Initialization flag for the above used by svn_atomic__init_once.
  */
 static volatile svn_atomic_t mutex_initialized = FALSE;
@@ -266,6 +267,7 @@ init_thread_mutex(void *baton, apr_pool_
 
   return svn_mutex__init(&thread_mutex, USE_THREAD_MUTEX, global_pool);
 }
+#endif /* APR_HAS_MMAP */
 
 /* Utility that acquires our global mutex and converts error types.
  */
@@ -297,6 +299,7 @@ unlock(struct mutex_t *mutex, svn_error_
                                                     unlock_err));
 }
 
+#if APR_HAS_MMAP
 /* The last user to close a particular namespace should also remove the
  * lock file.  Failure to do so, however, does not affect further uses
  * of the same namespace.
@@ -318,6 +321,7 @@ delete_lock_file(void *arg)
 
   return status;
 }
+#endif /* APR_HAS_MMAP */
 
 /* Validate the ATOMIC parameter, i.e it's address.  Correct code will
  * never need this but if someone should accidentally to use a NULL or
@@ -351,7 +355,11 @@ return_atomic(svn_named_atomic__t **atom
 svn_boolean_t
 svn_named_atomic__is_supported(void)
 {
-#ifdef _WIN32
+#if !APR_HAS_MMAP
+  return FALSE;
+#elif !defined(_WIN32)
+  return TRUE;
+#else
   static svn_tristate_t result = svn_tristate_unknown;
 
   if (result == svn_tristate_unknown)
@@ -373,9 +381,7 @@ svn_named_atomic__is_supported(void)
     }
 
   return result == svn_tristate_true;
-#else
-  return TRUE;
-#endif
+#endif /* _WIN32 */
 }
 
 svn_boolean_t
@@ -389,6 +395,9 @@ svn_atomic_namespace__create(svn_atomic_
                              const char *name,
                              apr_pool_t *result_pool)
 {
+#if !APR_HAS_MMAP
+  return svn_error_create(APR_ENOTIMPL, NULL, NULL);
+#else
   apr_status_t apr_err;
   svn_error_t *err;
   apr_file_t *file;
@@ -489,6 +498,7 @@ svn_atomic_namespace__create(svn_atomic_
   /* Unlock to allow other processes may access the shared memory as well.
    */
   return unlock(&new_ns->mutex, err);
+#endif /* APR_HAS_MMAP */
 }
 
 svn_error_t *

Modified: subversion/branches/cache-server/subversion/libsvn_subr/nls.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/nls.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/nls.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/nls.c Tue Oct 15 08:52:06 2013
@@ -56,10 +56,9 @@ svn_nls_init(void)
       char* utf8_path;
       const char* internal_path;
       apr_pool_t* pool;
-      apr_status_t apr_err;
       apr_size_t inwords, outbytes, outlength;
 
-      apr_pool_create(&pool, 0);
+      pool = svn_pool_create(0);
       /* get exe name - our locale info will be in '../share/locale' */
       inwords = GetModuleFileNameW(0, ucs2_path,
                                    sizeof(ucs2_path) / sizeof(ucs2_path[0]));
@@ -99,10 +98,10 @@ svn_nls_init(void)
 
           if (outbytes == 0)
             {
-              err = svn_error_createf(apr_err, NULL,
-                                      _("Can't convert module path "
-                                        "to UTF-8 from UCS-2: '%s'"),
-                                      ucs2_path);
+              err = svn_error_wrap_apr(apr_get_os_error(),
+                                       _("Can't convert module path "
+                                         "to UTF-8 from UCS-2: '%s'"),
+                                       ucs2_path);
             }
           else
             {

Modified: subversion/branches/cache-server/subversion/libsvn_subr/opt.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/opt.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/opt.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/opt.c Tue Oct 15 08:52:06 2013
@@ -34,6 +34,7 @@
 #include <apr_lib.h>
 #include <apr_file_info.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_cmdline.h"
 #include "svn_version.h"
@@ -50,7 +51,6 @@
 #include "private/svn_opt_private.h"
 
 #include "opt.h"
-#include "svn_private_config.h"
 
 
 /*** Code. ***/

Modified: subversion/branches/cache-server/subversion/libsvn_subr/path.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/path.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/path.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/path.c Tue Oct 15 08:52:06 2013
@@ -1164,11 +1164,8 @@ svn_path_cstring_to_utf8(const char **pa
 }
 
 
-/* Return a copy of PATH, allocated from POOL, for which control
-   characters have been escaped using the form \NNN (where NNN is the
-   octal representation of the byte's ordinal value).  */
-static const char *
-illegal_path_escape(const char *path, apr_pool_t *pool)
+const char *
+svn_path_illegal_path_escape(const char *path, apr_pool_t *pool)
 {
   svn_stringbuf_t *retstr;
   apr_size_t i, copied = 0;
@@ -1194,7 +1191,7 @@ illegal_path_escape(const char *path, ap
                                   i - copied);
 
       /* Make sure buffer is big enough for '\' 'N' 'N' 'N' (and NUL) */
-      svn_stringbuf_ensure(retstr, retstr->len + 4);
+      svn_stringbuf_ensure(retstr, retstr->len + 5);
       /*### The backslash separator doesn't work too great with Windows,
          but it's what we'll use for consistency with invalid utf8
          formatting (until someone has a better idea) */
@@ -1228,11 +1225,11 @@ svn_path_check_valid(const char *path, a
     {
       if (svn_ctype_iscntrl(*c))
         {
-          return svn_error_createf
-            (SVN_ERR_FS_PATH_SYNTAX, NULL,
+          return svn_error_createf(SVN_ERR_FS_PATH_SYNTAX, NULL,
              _("Invalid control character '0x%02x' in path '%s'"),
              (unsigned char)*c,
-             illegal_path_escape(svn_dirent_local_style(path, pool), pool));
+             svn_path_illegal_path_escape(svn_dirent_local_style(path, pool),
+                                          pool));
         }
     }
 

Modified: subversion/branches/cache-server/subversion/libsvn_subr/pool.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/pool.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/pool.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/pool.c Tue Oct 15 08:52:06 2013
@@ -51,7 +51,7 @@ abort_on_pool_failure(int retcode)
 {
   /* Don't translate this string! It requires memory allocation to do so!
      And we don't have any of it... */
-  printf("Out of memory - terminating application.\n");
+  printf("libsvn: Out of memory - terminating application.\n");
   abort();
   return 0; /* not reached */
 }

Modified: subversion/branches/cache-server/subversion/libsvn_subr/prompt.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/prompt.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/prompt.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/prompt.c Tue Oct 15 08:52:06 2013
@@ -236,7 +236,6 @@ terminal_puts(const char *string, termin
               apr_pool_t *pool)
 {
   svn_error_t *err;
-  apr_status_t status;
   const char *converted;
 
   err = svn_cmdline_cstring_from_utf8(&converted, string, pool);
@@ -255,13 +254,10 @@ terminal_puts(const char *string, termin
     }
 #endif
 
-  status = apr_file_write_full(terminal->outfd, converted,
-                               strlen(converted), NULL);
-  if (!status)
-    status = apr_file_flush(terminal->outfd);
-  if (status)
-    return svn_error_wrap_apr(status, _("Can't write to terminal"));
-  return SVN_NO_ERROR;
+  SVN_ERR(svn_io_file_write_full(terminal->outfd, converted,
+                                 strlen(converted), NULL, pool));
+
+  return svn_error_trace(svn_io_file_flush(terminal->outfd, pool));
 }
 
 /* These codes can be returned from terminal_getc instead of a character. */

Modified: subversion/branches/cache-server/subversion/libsvn_subr/properties.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/properties.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/properties.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/properties.c Tue Oct 15 08:52:06 2013
@@ -27,6 +27,8 @@
 #include <apr_hash.h>
 #include <apr_tables.h>
 #include <string.h>       /* for strncmp() */
+
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_string.h"
 #include "svn_props.h"

Modified: subversion/branches/cache-server/subversion/libsvn_subr/simple_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/simple_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/simple_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/simple_providers.c Tue Oct 15 08:52:06 2013
@@ -28,6 +28,8 @@
 /*** Includes. ***/
 
 #include <apr_pools.h>
+
+#include "svn_private_config.h"
 #include "svn_auth.h"
 #include "svn_dirent_uri.h"
 #include "svn_hash.h"
@@ -39,8 +41,6 @@
 
 #include "private/svn_auth_private.h"
 
-#include "svn_private_config.h"
-
 #include "auth.h"
 
 /*-----------------------------------------------------------------------*/

Modified: subversion/branches/cache-server/subversion/libsvn_subr/sorts.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/sorts.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/sorts.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/sorts.c Tue Oct 15 08:52:06 2013
@@ -28,6 +28,8 @@
 #include <apr_tables.h>
 #include <stdlib.h>       /* for qsort()   */
 #include <assert.h>
+
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_path.h"
 #include "svn_sorts.h"
@@ -307,3 +309,148 @@ svn_sort__array_reverse(apr_array_header
         }
     }
 }
+
+/* Our priority queue data structure:
+ * Simply remember the constructor parameters.
+ */
+struct svn_priority_queue__t
+{
+  /* the queue elements, ordered as a heap according to COMPARE_FUNC */
+  apr_array_header_t *elements;
+
+  /* predicate used to order the heap */
+  int (*compare_func)(const void *, const void *);
+};
+
+/* Return TRUE, if heap element number LHS in QUEUE is smaller than element
+ * number RHS according to QUEUE->COMPARE_FUNC
+ */
+static int
+heap_is_less(svn_priority_queue__t *queue,
+             apr_size_t lhs,
+             apr_size_t rhs)
+{
+  char *lhs_value = queue->elements->elts + lhs * queue->elements->elt_size;
+  char *rhs_value = queue->elements->elts + rhs * queue->elements->elt_size;
+
+  assert(lhs < queue->elements->nelts);
+  assert(rhs < queue->elements->nelts);
+  return queue->compare_func((void *)lhs_value, (void *)rhs_value) < 0;
+}
+
+/* Exchange elements number LHS and RHS in QUEUE.
+ */
+static void
+heap_swap(svn_priority_queue__t *queue,
+          apr_size_t lhs,
+          apr_size_t rhs)
+{
+  int i;
+  char *lhs_value = queue->elements->elts + lhs * queue->elements->elt_size;
+  char *rhs_value = queue->elements->elts + rhs * queue->elements->elt_size;
+
+  for (i = 0; i < queue->elements->elt_size; ++i)
+    {
+      char temp = lhs_value[i];
+      lhs_value[i] = rhs_value[i];
+      rhs_value[i] = temp;
+    }
+}
+
+/* Move element number IDX to lower indexes until the heap criterion is
+ * fulfilled again.
+ */
+static void
+heap_bubble_down(svn_priority_queue__t *queue,
+                 int idx)
+{
+  while (idx > 0 && heap_is_less(queue, idx, (idx - 1) / 2))
+    {
+      heap_swap(queue, idx, (idx - 1) / 2);
+      idx = (idx - 1) / 2;
+    }
+}
+
+/* Move element number IDX to higher indexes until the heap criterion is
+ * fulfilled again.
+ */
+static void
+heap_bubble_up(svn_priority_queue__t *queue,
+               int idx)
+{
+  while (2 * idx + 2 < queue->elements->nelts)
+    {
+      int child = heap_is_less(queue, 2 * idx + 1, 2 * idx + 2)
+                ? 2 * idx + 1
+                : 2 * idx + 2;
+
+      if (heap_is_less(queue, idx, child))
+        return;
+
+      heap_swap(queue, idx, child);
+      idx = child;
+    }
+
+  if (   2 * idx + 1 < queue->elements->nelts
+      && heap_is_less(queue, 2 * idx + 1, idx))
+    heap_swap(queue, 2 * idx + 1, idx);
+}
+
+svn_priority_queue__t *
+svn_priority_queue__create(apr_array_header_t *elements,
+                           int (*compare_func)(const void *, const void *))
+{
+  int i;
+
+  svn_priority_queue__t *queue = apr_pcalloc(elements->pool, sizeof(*queue));
+  queue->elements = elements;
+  queue->compare_func = compare_func;
+
+  for (i = elements->nelts / 2; i >= 0; --i)
+    heap_bubble_up(queue, i);
+  
+  return queue;
+}
+
+apr_size_t
+svn_priority_queue__size(svn_priority_queue__t *queue)
+{
+  return queue->elements->nelts;
+}
+
+void *
+svn_priority_queue__peek(svn_priority_queue__t *queue)
+{
+  return queue->elements->nelts ? queue->elements->elts : NULL;
+}
+
+void
+svn_priority_queue__update(svn_priority_queue__t *queue)
+{
+  heap_bubble_up(queue, 0);
+}
+
+void
+svn_priority_queue__pop(svn_priority_queue__t *queue)
+{
+  if (queue->elements->nelts)
+    {
+      memcpy(queue->elements->elts,
+             queue->elements->elts + (queue->elements->nelts - 1)
+                                   * queue->elements->elt_size,
+             queue->elements->elt_size);
+      --queue->elements->nelts;
+      heap_bubble_up(queue, 0);
+    }
+}
+
+void
+svn_priority_queue__push(svn_priority_queue__t *queue,
+                         const void *element)
+{
+  /* we cannot duplicate elements due to potential array re-allocs */
+  assert(element && element != queue->elements->elts);
+
+  memcpy(apr_array_push(queue->elements), element, queue->elements->elt_size);
+  heap_bubble_down(queue, queue->elements->nelts - 1);
+}

Modified: subversion/branches/cache-server/subversion/libsvn_subr/spillbuf.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/spillbuf.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/spillbuf.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/spillbuf.c Tue Oct 15 08:52:06 2013
@@ -73,12 +73,26 @@ struct svn_spillbuf_t {
 
   /* How much content remains in SPILL.  */
   svn_filesize_t spill_size;
+
+  /* When false, do not delete the spill file when it is closed. */
+  svn_boolean_t delete_on_close;
+
+  /* When true, and the amount of data written to the spillbuf is
+     larger than MAXSIZE, all spillbuf contents will be written to the
+     spill file. */
+  svn_boolean_t spill_all_contents;
+
+  /* The directory in which the spill file is created. */
+  const char *dirpath;
+
+  /* The name of the temporary spill file. */
+  const char *filename;
 };
 
 
 struct svn_spillbuf_reader_t {
   /* Embed the spill-buffer within the reader.  */
-  struct svn_spillbuf_t buf;
+  struct svn_spillbuf_t *buf;
 
   /* When we read content from the underlying spillbuf, these fields store
      the ptr/len pair. The ptr will be incremented as we "read" out of this
@@ -99,28 +113,86 @@ struct svn_spillbuf_reader_t {
 };
 
 
+/* Extended spillbuf initialization. */
+static void
+init_spillbuf_extended(svn_spillbuf_t *buf,
+                       apr_size_t blocksize,
+                       apr_size_t maxsize,
+                       svn_boolean_t delete_on_close,
+                       svn_boolean_t spill_all_contents,
+                       const char *dirpath,
+                       apr_pool_t *result_pool)
+{
+  buf->pool = result_pool;
+  buf->blocksize = blocksize;
+  buf->maxsize = maxsize;
+  buf->delete_on_close = delete_on_close;
+  buf->spill_all_contents = spill_all_contents;
+  buf->dirpath = dirpath;
+}
+
+/* Common constructor for initializing spillbufs.
+   Used by svn_spillbuf__create, svn_spilbuff__reader_create. */
+static void
+init_spillbuf(svn_spillbuf_t *buf,
+              apr_size_t blocksize,
+              apr_size_t maxsize,
+              apr_pool_t *result_pool)
+{
+  init_spillbuf_extended(buf, blocksize, maxsize,
+                         TRUE, FALSE, NULL,
+                         result_pool);
+}
+
 svn_spillbuf_t *
 svn_spillbuf__create(apr_size_t blocksize,
                      apr_size_t maxsize,
                      apr_pool_t *result_pool)
 {
   svn_spillbuf_t *buf = apr_pcalloc(result_pool, sizeof(*buf));
+  init_spillbuf(buf, blocksize, maxsize, result_pool);
+  return buf;
+}
 
-  buf->pool = result_pool;
-  buf->blocksize = blocksize;
-  buf->maxsize = maxsize;
-  /* Note: changes here should also go into svn_spillbuf__reader_create() */
 
+svn_spillbuf_t *
+svn_spillbuf__create_extended(apr_size_t blocksize,
+                              apr_size_t maxsize,
+                              svn_boolean_t delete_on_close,
+                              svn_boolean_t spill_all_contents,
+                              const char *dirpath,
+                              apr_pool_t *result_pool)
+{
+  svn_spillbuf_t *buf = apr_pcalloc(result_pool, sizeof(*buf));
+  init_spillbuf_extended(buf, blocksize, maxsize,
+                         delete_on_close, spill_all_contents, dirpath,
+                         result_pool);
   return buf;
 }
 
-
 svn_filesize_t
 svn_spillbuf__get_size(const svn_spillbuf_t *buf)
 {
   return buf->memory_size + buf->spill_size;
 }
 
+svn_filesize_t
+svn_spillbuf__get_memory_size(const svn_spillbuf_t *buf)
+{
+  return buf->memory_size;
+}
+
+const char *
+svn_spillbuf__get_filename(const svn_spillbuf_t *buf)
+{
+  return buf->filename;
+}
+
+apr_file_t *
+svn_spillbuf__get_file(const svn_spillbuf_t *buf)
+{
+  return buf->spill;
+}
 
 /* Get a memblock from the spill-buffer. It will be the block that we
    passed out for reading, come from the free list, or allocated.  */
@@ -173,10 +245,32 @@ svn_spillbuf__write(svn_spillbuf_t *buf,
       && (buf->memory_size + len) > buf->maxsize)
     {
       SVN_ERR(svn_io_open_unique_file3(&buf->spill,
-                                       NULL /* temp_path */,
-                                       NULL /* dirpath */,
-                                       svn_io_file_del_on_close,
+                                       &buf->filename,
+                                       buf->dirpath,
+                                       (buf->delete_on_close
+                                        ? svn_io_file_del_on_close
+                                        : svn_io_file_del_none),
                                        buf->pool, scratch_pool));
+
+      /* Optionally write the memory contents into the file. */
+      if (buf->spill_all_contents)
+        {
+          mem = buf->head;
+          while (mem != NULL)
+            {
+              SVN_ERR(svn_io_file_write_full(buf->spill, mem->data, mem->size,
+                                             NULL, scratch_pool));
+              mem = mem->next;
+            }
+
+          /* Adjust the start offset for reading from the spill file.
+
+             ### FIXME: Instead, we should simply discard the memory
+             buffers; but currently some tests expect to read data in
+             the same chunk sizes as were written, so we'll leave this
+             change for later.*/
+          buf->spill_start = buf->memory_size;
+        }
     }
 
   /* Once a spill file has been constructed, then we need to put all
@@ -440,16 +534,10 @@ svn_spillbuf__reader_create(apr_size_t b
                             apr_pool_t *result_pool)
 {
   svn_spillbuf_reader_t *sbr = apr_pcalloc(result_pool, sizeof(*sbr));
-
-  /* See svn_spillbuf__create()  */
-  sbr->buf.pool = result_pool;
-  sbr->buf.blocksize = blocksize;
-  sbr->buf.maxsize = maxsize;
-
+  sbr->buf = svn_spillbuf__create(blocksize, maxsize, result_pool);
   return sbr;
 }
 
-
 svn_error_t *
 svn_spillbuf__reader_read(apr_size_t *amt,
                           svn_spillbuf_reader_t *reader,
@@ -488,7 +576,7 @@ svn_spillbuf__reader_read(apr_size_t *am
           if (reader->sb_len == 0)
             {
               SVN_ERR(svn_spillbuf__read(&reader->sb_ptr, &reader->sb_len,
-                                         &reader->buf,
+                                         reader->buf,
                                          scratch_pool));
 
               /* We've run out of content, so return with whatever has
@@ -547,7 +635,8 @@ svn_spillbuf__reader_write(svn_spillbuf_
   if (reader->sb_len > 0)
     {
       if (reader->save_ptr == NULL)
-        reader->save_ptr = apr_palloc(reader->buf.pool, reader->buf.blocksize);
+        reader->save_ptr = apr_palloc(reader->buf->pool,
+                                      reader->buf->blocksize);
 
       memcpy(reader->save_ptr, reader->sb_ptr, reader->sb_len);
       reader->save_len = reader->sb_len;
@@ -557,7 +646,7 @@ svn_spillbuf__reader_write(svn_spillbuf_
       reader->sb_len = 0;
     }
 
-  return svn_error_trace(svn_spillbuf__write(&reader->buf, data, len,
+  return svn_error_trace(svn_spillbuf__write(reader->buf, data, len,
                                              scratch_pool));
 }
 
@@ -596,14 +685,14 @@ write_handler_spillbuf(void *baton, cons
 
 
 svn_stream_t *
-svn_stream__from_spillbuf(apr_size_t blocksize,
-                          apr_size_t maxsize,
+svn_stream__from_spillbuf(svn_spillbuf_t *buf,
                           apr_pool_t *result_pool)
 {
   svn_stream_t *stream;
   struct spillbuf_baton *sb = apr_palloc(result_pool, sizeof(*sb));
 
-  sb->reader = svn_spillbuf__reader_create(blocksize, maxsize, result_pool);
+  sb->reader = apr_pcalloc(result_pool, sizeof(*sb->reader));
+  sb->reader->buf = buf;
   sb->scratch_pool = svn_pool_create(result_pool);
 
   stream = svn_stream_create(sb, result_pool);

Modified: subversion/branches/cache-server/subversion/libsvn_subr/sqlite.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/sqlite.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/sqlite.c Tue Oct 15 08:52:06 2013
@@ -38,6 +38,11 @@
 #include "private/svn_skel.h"
 #include "private/svn_token.h"
 
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+#include "private/svn_utf_private.h"
+#include "private/svn_string_private.h"
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
 #ifdef SQLITE3_DEBUG
 #include "private/svn_debug.h"
 #endif
@@ -60,6 +65,13 @@ extern int (*const svn_sqlite3__api_conf
 #error SQLite is too old -- version 3.7.12 is the minimum required version
 #endif
 
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+/* Limit the length of a GLOB or LIKE pattern. */
+#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
+# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
+#endif
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
 const char *
 svn_sqlite__compiled_version(void)
 {
@@ -104,6 +116,13 @@ struct svn_sqlite__db_t
   int nbr_statements;
   svn_sqlite__stmt_t **prepared_stmts;
   apr_pool_t *state_pool;
+
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+  /* Buffers for SQLite extensoins. */
+  svn_membuf_t sqlext_buf1;
+  svn_membuf_t sqlext_buf2;
+  svn_membuf_t sqlext_buf3;
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
 };
 
 struct svn_sqlite__stmt_t
@@ -140,9 +159,9 @@ struct svn_sqlite__value_t
   int sqlite_err__temp = (x);                                    \
   if (sqlite_err__temp != SQLITE_OK)                             \
     return svn_error_createf(SQLITE_ERROR_CODE(sqlite_err__temp), \
-                             NULL, "sqlite: %s (S%d)",             \
-                             sqlite3_errmsg((db)->db3),           \
-                             sqlite_err__temp);                   \
+                             NULL, "sqlite[S%d]: %s",             \
+                             sqlite_err__temp,                    \
+                             sqlite3_errmsg((db)->db3));          \
 } while (0)
 
 #define SQLITE_ERR_MSG(x, msg) do                                \
@@ -150,8 +169,8 @@ struct svn_sqlite__value_t
   int sqlite_err__temp = (x);                                    \
   if (sqlite_err__temp != SQLITE_OK)                             \
     return svn_error_createf(SQLITE_ERROR_CODE(sqlite_err__temp), \
-                             NULL, "sqlite: %s (S%d)", (msg),     \
-                             sqlite_err__temp);                  \
+                             NULL, "sqlite[S%d]: %s",            \
+                             sqlite_err__temp, msg);             \
 } while (0)
 
 
@@ -173,9 +192,9 @@ exec_sql2(svn_sqlite__db_t *db, const ch
   if (sqlite_err != SQLITE_OK && sqlite_err != ignored_err)
     {
       svn_error_t *err = svn_error_createf(SQLITE_ERROR_CODE(sqlite_err), NULL,
-                                           _("sqlite: %s (S%d),"
+                                           _("sqlite[S%d]: %s,"
                                              " executing statement '%s'"),
-                                           err_msg, sqlite_err, sql);
+                                           sqlite_err, err_msg, sql);
       sqlite3_free(err_msg);
       return err;
     }
@@ -292,8 +311,8 @@ svn_sqlite__step(svn_boolean_t *got_row,
       svn_error_t *err1, *err2;
 
       err1 = svn_error_createf(SQLITE_ERROR_CODE(sqlite_result), NULL,
-                               "sqlite: %s (S%d)",
-                               sqlite3_errmsg(stmt->db->db3), sqlite_result);
+                               "sqlite[S%d]: %s",
+                               sqlite_result, sqlite3_errmsg(stmt->db->db3));
       err2 = svn_sqlite__reset(stmt);
       return svn_error_compose_create(err1, err2);
     }
@@ -744,7 +763,7 @@ init_sqlite(void *baton, apr_pool_t *poo
     int err = sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
     if (err != SQLITE_OK && err != SQLITE_MISUSE)
       return svn_error_createf(SQLITE_ERROR_CODE(err), NULL,
-                               _("Could not configure SQLite (S%d)"), err);
+                               _("Could not configure SQLite [S%d]"), err);
   }
   SQLITE_ERR_MSG(sqlite3_initialize(), _("Could not initialize SQLite"));
 
@@ -873,6 +892,99 @@ close_apr(void *data)
   return APR_SUCCESS;
 }
 
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+/* Unicode normalizing collation for WC paths */
+static int
+collate_ucs_nfd(void *baton,
+                int len1, const void *key1,
+                int len2, const void *key2)
+{
+  svn_sqlite__db_t *db = baton;
+  int result;
+
+  if (svn_utf__normcmp(key1, len1, key2, len2,
+                       &db->sqlext_buf1, &db->sqlext_buf2, &result))
+    {
+      /* There is really nothing we can do here if an error occurs
+         during Unicode normalizetion, and attempting to recover could
+         result in the wc.db index being corrupted. Presumably this
+         can only happen if the index already contains invalid UTF-8
+         strings, which should never happen in any case ... */
+      SVN_ERR_MALFUNCTION_NO_RETURN();
+    }
+
+  return result;
+}
+
+static void
+glob_like_ucs_nfd_common(sqlite3_context *context,
+                         int argc, sqlite3_value **argv,
+                         svn_boolean_t sql_like)
+{
+  svn_sqlite__db_t *const db = sqlite3_user_data(context);
+
+  const char *const pattern = (void*)sqlite3_value_text(argv[0]);
+  const apr_size_t pattern_len = sqlite3_value_bytes(argv[0]);
+  const char *const string = (void*)sqlite3_value_text(argv[1]);
+  const apr_size_t string_len = sqlite3_value_bytes(argv[1]);
+
+  const char *escape = NULL;
+  apr_size_t escape_len = 0;
+
+  svn_boolean_t match;
+  svn_error_t *err;
+
+  if (pattern_len > SQLITE_MAX_LIKE_PATTERN_LENGTH)
+    {
+      sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
+      return;
+    }
+
+  if (argc == 3 && sql_like)
+    {
+      escape = (void*)sqlite3_value_text(argv[2]);
+      escape_len = sqlite3_value_bytes(argv[2]);
+    }
+
+  if (pattern && string)
+    {
+      err = svn_utf__glob(pattern, pattern_len, string, string_len,
+                          escape, escape_len, sql_like,
+                          &db->sqlext_buf1, &db->sqlext_buf2, &db->sqlext_buf3,
+                          &match);
+
+      if (err)
+        {
+          const char *errmsg;
+          svn_membuf__ensure(&db->sqlext_buf1, 512);
+          errmsg = svn_err_best_message(err,
+                                        db->sqlext_buf1.data,
+                                        db->sqlext_buf1.size - 1);
+          svn_error_clear(err);
+          sqlite3_result_error(context, errmsg, -1);
+          return;
+        }
+
+      sqlite3_result_int(context, match);
+    }
+}
+
+/* Unicode normalizing implementation of GLOB */
+static void
+glob_ucs_nfd(sqlite3_context *context,
+             int argc, sqlite3_value **argv)
+{
+  glob_like_ucs_nfd_common(context, argc, argv, FALSE);
+}
+
+/* Unicode normalizing implementation of LIKE */
+static void
+like_ucs_nfd(sqlite3_context *context,
+             int argc, sqlite3_value **argv)
+{
+  glob_like_ucs_nfd_common(context, argc, argv, TRUE);
+}
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
 
 svn_error_t *
 svn_sqlite__open(svn_sqlite__db_t **db, const char *path,
@@ -887,6 +999,28 @@ svn_sqlite__open(svn_sqlite__db_t **db, 
 
   SVN_ERR(internal_open(&(*db)->db3, path, mode, scratch_pool));
 
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+  /* Create extension buffers with space for 200 UCS-4 characters. */
+  svn_membuf__create(&(*db)->sqlext_buf1, 800, result_pool);
+  svn_membuf__create(&(*db)->sqlext_buf2, 800, result_pool);
+  svn_membuf__create(&(*db)->sqlext_buf3, 800, result_pool);
+
+  /* Register collation and LIKE and GLOB operator replacements. */
+  SQLITE_ERR(sqlite3_create_collation((*db)->db3,
+                                      "svn-ucs-nfd", SQLITE_UTF8,
+                                      *db, collate_ucs_nfd),
+             *db);
+  SQLITE_ERR(sqlite3_create_function((*db)->db3, "glob", 2, SQLITE_UTF8,
+                                     *db, glob_ucs_nfd, NULL, NULL),
+             *db);
+  SQLITE_ERR(sqlite3_create_function((*db)->db3, "like", 2, SQLITE_UTF8,
+                                     *db, like_ucs_nfd, NULL, NULL),
+             *db);
+  SQLITE_ERR(sqlite3_create_function((*db)->db3, "like", 3, SQLITE_UTF8,
+                                     *db, like_ucs_nfd, NULL, NULL),
+             *db);
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
 #ifdef SQLITE3_DEBUG
   sqlite3_trace((*db)->db3, sqlite_tracer, (*db)->db3);
 #endif

Modified: subversion/branches/cache-server/subversion/libsvn_subr/sqlite3wrapper.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/sqlite3wrapper.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/sqlite3wrapper.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/sqlite3wrapper.c Tue Oct 15 08:52:06 2013
@@ -39,6 +39,17 @@
 #      pragma GCC diagnostic ignored "-Wshorten-64-to-32"
 #    endif
 #  endif
+#  ifdef __APPLE__
+#    include <Availability.h>
+#    if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+       /* <libkern/OSAtomic.h> is included on OS X by sqlite3.c, and
+          on old systems (Leopard or older), it cannot be compiled
+          with -std=c89 because it uses inline. This is a work-around. */
+#      define inline __inline__
+#      include <libkern/OSAtomic.h>
+#      undef inline
+#    endif
+#  endif
 #  include <sqlite3.c>
 #  if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))
 #    pragma GCC diagnostic pop

Modified: subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_providers.c Tue Oct 15 08:52:06 2013
@@ -29,6 +29,8 @@
 /*** Includes. ***/
 
 #include <apr_pools.h>
+
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_auth.h"
 #include "svn_error.h"
@@ -79,13 +81,12 @@ ssl_client_cert_file_first_credentials(v
 }
 
 
-static const svn_auth_provider_t ssl_client_cert_file_provider =
-  {
-    SVN_AUTH_CRED_SSL_CLIENT_CERT,
-    ssl_client_cert_file_first_credentials,
-    NULL,
-    NULL
-  };
+static const svn_auth_provider_t ssl_client_cert_file_provider = {
+  SVN_AUTH_CRED_SSL_CLIENT_CERT,
+  ssl_client_cert_file_first_credentials,
+  NULL,
+  NULL
+};
 
 
 /*** Public API to SSL file providers. ***/

Modified: subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_pw_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_pw_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_pw_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/ssl_client_cert_pw_providers.c Tue Oct 15 08:52:06 2013
@@ -25,6 +25,7 @@
 
 #include <apr_pools.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_auth.h"
 #include "svn_error.h"
@@ -33,7 +34,6 @@
 
 #include "private/svn_auth_private.h"
 
-#include "svn_private_config.h"
 
 /*-----------------------------------------------------------------------*/
 /* File provider                                                         */

Modified: subversion/branches/cache-server/subversion/libsvn_subr/ssl_server_trust_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/ssl_server_trust_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/ssl_server_trust_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/ssl_server_trust_providers.c Tue Oct 15 08:52:06 2013
@@ -24,6 +24,7 @@
 
 #include <apr_pools.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_auth.h"
 #include "svn_error.h"
@@ -78,13 +79,7 @@ ssl_server_trust_file_first_credentials(
       failstr = svn_hash_gets(creds_hash, AUTHN_FAILURES_KEY);
 
       if (failstr)
-        {
-          char *endptr;
-          unsigned long tmp_ulong = strtoul(failstr->data, &endptr, 10);
-
-          if (*endptr == '\0')
-            last_failures = (apr_uint32_t) tmp_ulong;
-        }
+        SVN_ERR(svn_cstring_atoui(&last_failures, failstr->data));
 
       /* If the cert is trusted and there are no new failures, we
        * accept it by clearing all failures. */
@@ -149,9 +144,9 @@ ssl_server_trust_file_save_credentials(s
 
 static const svn_auth_provider_t ssl_server_trust_file_provider = {
   SVN_AUTH_CRED_SSL_SERVER_TRUST,
-  &ssl_server_trust_file_first_credentials,
+  ssl_server_trust_file_first_credentials,
   NULL,
-  &ssl_server_trust_file_save_credentials,
+  ssl_server_trust_file_save_credentials,
 };
 
 

Modified: subversion/branches/cache-server/subversion/libsvn_subr/stream.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/stream.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/stream.c Tue Oct 15 08:52:06 2013
@@ -56,6 +56,7 @@ struct svn_stream_t {
   svn_stream_mark_fn_t mark_fn;
   svn_stream_seek_fn_t seek_fn;
   svn_stream__is_buffered_fn_t is_buffered_fn;
+  apr_file_t *file; /* Maybe NULL */
 };
 
 
@@ -81,6 +82,7 @@ svn_stream_create(void *baton, apr_pool_
   stream->mark_fn = NULL;
   stream->seek_fn = NULL;
   stream->is_buffered_fn = NULL;
+  stream->file = NULL;
   return stream;
 }
 
@@ -913,6 +915,7 @@ svn_stream_from_aprfile2(apr_file_t *fil
   svn_stream_set_mark(stream, mark_handler_apr);
   svn_stream_set_seek(stream, seek_handler_apr);
   svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
+  stream->file = file;
 
   if (! disown)
     svn_stream_set_close(stream, close_handler_apr);
@@ -920,6 +923,12 @@ svn_stream_from_aprfile2(apr_file_t *fil
   return stream;
 }
 
+apr_file_t *
+svn_stream__aprfile(svn_stream_t *stream)
+{
+  return stream->file;
+}
+
 
 /* Compressed stream support */
 
@@ -1370,6 +1379,36 @@ svn_stream_checksummed(svn_stream_t *str
 
 
 /* Miscellaneous stream functions. */
+
+svn_error_t *
+svn_stringbuf_from_stream(svn_stringbuf_t **str,
+                          svn_stream_t *stream,
+                          apr_size_t len_hint,
+                          apr_pool_t *pool)
+{
+#define MIN_READ_SIZE 64
+
+  apr_size_t to_read = 0;
+  svn_stringbuf_t *text
+    = svn_stringbuf_create_ensure(len_hint ? len_hint : MIN_READ_SIZE, pool);
+
+  do
+    {
+      to_read = text->blocksize - 1 - text->len;
+      SVN_ERR(svn_stream_read(stream, text->data + text->len, &to_read));
+      text->len += to_read;
+
+      if (to_read && text->blocksize < text->len + MIN_READ_SIZE)
+        svn_stringbuf_ensure(text, text->blocksize * 2);
+    }
+  while (to_read);
+
+  text->data[text->len] = '\0';
+  *str = text;
+
+  return SVN_NO_ERROR;
+}
+
 struct stringbuf_stream_baton
 {
   svn_stringbuf_t *str;
@@ -1648,7 +1687,7 @@ svn_string_from_stream(svn_string_t **re
 }
 
 
-/* These are somewhat arbirary, if we ever get good empirical data as to
+/* These are somewhat arbitrary, if we ever get good empirical data as to
    actually valid values, feel free to update them. */
 #define BUFFER_BLOCK_SIZE 1024
 #define BUFFER_MAX_SIZE 100000
@@ -1656,7 +1695,9 @@ svn_string_from_stream(svn_string_t **re
 svn_stream_t *
 svn_stream_buffered(apr_pool_t *result_pool)
 {
-  return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE, BUFFER_MAX_SIZE,
+  return svn_stream__from_spillbuf(svn_spillbuf__create(BUFFER_BLOCK_SIZE,
+                                                        BUFFER_MAX_SIZE,
+                                                        result_pool),
                                    result_pool);
 }
 

Modified: subversion/branches/cache-server/subversion/libsvn_subr/string.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/string.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/string.c Tue Oct 15 08:52:06 2013
@@ -53,9 +53,9 @@ membuf_create(void **data, apr_size_t *s
   /* apr_palloc will allocate multiples of 8.
    * Thus, we would waste some of that memory if we stuck to the
    * smaller size. Note that this is safe even if apr_palloc would
-   * use some other aligment or none at all. */
+   * use some other alignment or none at all. */
   minimum_size = APR_ALIGN_DEFAULT(minimum_size);
-  *data = (!minimum_size ? NULL : apr_palloc(pool, minimum_size));
+  *data = apr_palloc(pool, minimum_size);
   *size = minimum_size;
 }
 
@@ -121,7 +121,10 @@ svn_membuf__resize(svn_membuf_t *membuf,
   const apr_size_t old_size = membuf->size;
 
   membuf_ensure(&membuf->data, &membuf->size, size, membuf->pool);
-  if (membuf->data && old_data && old_data != membuf->data)
+
+  /* If we re-allocated MEMBUF->DATA, it cannot be NULL.
+   * Statically initialized membuffers (OLD_DATA) may be NULL, though. */
+  if (old_data && old_data != membuf->data)
     memcpy(membuf->data, old_data, old_size);
 }
 
@@ -418,6 +421,17 @@ svn_stringbuf_create_from_string(const s
   return svn_stringbuf_ncreate(str->data, str->len, pool);
 }
 
+svn_stringbuf_t *
+svn_stringbuf_create_wrap(char *str, apr_pool_t *pool)
+{
+  svn_stringbuf_t *result = apr_palloc(pool, sizeof(*result));
+  result->pool = pool;
+  result->data = str;
+  result->len = strlen(str);
+  result->blocksize = result->len + 1;
+
+  return result;
+}
 
 svn_stringbuf_t *
 svn_stringbuf_createv(apr_pool_t *pool, const char *fmt, va_list ap)
@@ -595,6 +609,21 @@ svn_stringbuf_appendbytes(svn_stringbuf_
                                   to null-terminate. */
 }
 
+void
+svn_stringbuf_appendfill(svn_stringbuf_t *str,
+                         char byte,
+                         apr_size_t count)
+{
+  apr_size_t new_len = str->len + count;
+  svn_stringbuf_ensure(str, new_len);
+
+  memset(str->data + str->len, byte, count);
+
+  /* update buffer length and always NUL-terminate it */
+  str->len = new_len;
+  str->data[new_len] = '\0';
+}
+
 
 void
 svn_stringbuf_appendstr(svn_stringbuf_t *targetstr,
@@ -1027,6 +1056,36 @@ svn__strtoff(apr_off_t *offset, const ch
 #endif
 }
 
+unsigned long
+svn__strtoul(const char* buffer, const char** end)
+{
+  unsigned long result = 0;
+
+  /* this loop will execute in just 2 CPU cycles, confirmed by measurement:
+     7 macro-ops (max 4 / cycle => 2 cycles)
+       1 load (max 1 / cycle)
+       1 jumps (compare + conditional jump == 1 macro op; max 1 / cycle)
+       2 arithmetic ops (subtract, increment; max 3 / cycle)
+       2 scale-and-add AGU ops (max 3 / cycle)
+       1 compiler-generated move operation
+     dependency chain: temp = result * 4 + result; result = temp * 2 + c
+                       (2 ops with latency 1 => 2 cycles)
+   */
+  while (1)
+    {
+      unsigned long c = *buffer - '0';
+      if (c > 9)
+        break;
+
+      result = result * 10 + c;
+      ++buffer;
+    }
+
+  *end = buffer;
+  return result;
+}
+
+
 /* "Precalculated" itoa values for 2 places (including leading zeros).
  * For maximum performance, make sure all table entries are word-aligned.
  */
@@ -1166,6 +1225,86 @@ svn__i64toa_sep(apr_int64_t number, char
   return apr_pstrdup(pool, buffer);
 }
 
+apr_size_t
+svn__ui64tobase36(char *dest, apr_uint64_t value)
+{
+  char *dest_start = dest;
+  if (value < 10)
+    {
+      /* pretty frequent and trivial case. Make it fast. */
+      *(dest++) = (char)(value) + '0';
+    }
+  else
+    {
+      char buffer[SVN_INT64_BUFFER_SIZE];
+      char *p = buffer;
+
+      /* write result as little-endian to buffer */
+      while (value > 0)
+        {
+          char c = (char)(value % 36);
+          value /= 36;
+
+          *p = (c <= 9) ? (c + '0') : (c - 10 + 'a');
+          ++p;
+        }
+
+      /* copy as big-endian to DEST */
+      while (p > buffer)
+        *(dest++) = *(--p);
+    }
+
+  *dest = '\0';
+  return dest - dest_start;
+}
+
+apr_uint64_t
+svn__base36toui64(const char **next, const char *source)
+{
+  apr_uint64_t result = 0;
+  apr_uint64_t factor = 1;
+  int i  = 0;
+  char digits[SVN_INT64_BUFFER_SIZE];
+
+  /* convert digits to numerical values and count the number of places.
+   * Also, prevent buffer overflow. */
+  while (i < sizeof(digits))
+    {
+      char c = *source;
+      if (c < 'a')
+        {
+          /* includes detection of NUL terminator */
+          if (c < '0' || c > '9')
+            break;
+
+          c -= '0';
+        }
+      else
+        {
+          if (c < 'a' || c > 'z')
+            break;
+
+          c -= 'a' - 10;
+        }
+
+      digits[i++] = c;
+      source++;
+    }
+
+  /* fold digits into the result */
+  while (i > 0)
+    {
+      result += factor * (apr_uint64_t)digits[--i];
+      factor *= 36;
+    }
+
+  if (next)
+    *next = source;
+
+  return result;
+}
+
+
 unsigned int
 svn_cstring__similarity(const char *stra, const char *strb,
                         svn_membuf_t *buffer, apr_size_t *rlcs)
@@ -1271,3 +1410,67 @@ svn_string__similarity(const svn_string_
   else
     return 1000;
 }
+
+apr_size_t
+svn_cstring__match_length(const char *a,
+                          const char *b,
+                          apr_size_t max_len)
+{
+  apr_size_t pos = 0;
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+
+  /* Chunky processing is so much faster ...
+   *
+   * We can't make this work on architectures that require aligned access
+   * because A and B will probably have different alignment. So, skipping
+   * the first few chars until alignment is reached is not an option.
+   */
+  for (; pos + sizeof(apr_size_t) <= max_len; pos += sizeof(apr_size_t))
+    if (*(const apr_size_t*)(a + pos) != *(const apr_size_t*)(b + pos))
+      break;
+
+#endif
+
+  for (; pos < max_len; ++pos)
+    if (a[pos] != b[pos])
+      break;
+
+  return pos;
+}
+
+apr_size_t
+svn_cstring__reverse_match_length(const char *a,
+                                  const char *b,
+                                  apr_size_t max_len)
+{
+  apr_size_t pos = 0;
+
+#if SVN_UNALIGNED_ACCESS_IS_OK
+
+  /* Chunky processing is so much faster ...
+   *
+   * We can't make this work on architectures that require aligned access
+   * because A and B will probably have different alignment. So, skipping
+   * the first few chars until alignment is reached is not an option.
+   */
+  for (pos = sizeof(apr_size_t); pos <= max_len; pos += sizeof(apr_size_t))
+    if (*(const apr_size_t*)(a - pos) != *(const apr_size_t*)(b - pos))
+      break;
+
+  pos -= sizeof(apr_size_t);
+
+#endif
+
+  /* If we find a mismatch at -pos, pos-1 characters matched.
+   */
+  while (++pos <= max_len)
+    if (a[0-pos] != b[0-pos])
+      return pos - 1;
+
+  /* No mismatch found -> at least MAX_LEN matching chars.
+   */
+  return max_len;
+}
+
+

Modified: subversion/branches/cache-server/subversion/libsvn_subr/subst.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/subst.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/subst.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/subst.c Tue Oct 15 08:52:06 2013
@@ -33,6 +33,7 @@
 #include <apr_file_io.h>
 #include <apr_strings.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_cmdline.h"
 #include "svn_types.h"
@@ -47,9 +48,8 @@
 #include "svn_pools.h"
 #include "private/svn_io_private.h"
 
-#include "svn_private_config.h"
-
 #include "private/svn_string_private.h"
+#include "private/svn_eol_private.h"
 
 /**
  * The textual elements of a detranslated special file.  One of these
@@ -297,14 +297,23 @@ build_keywords(apr_hash_t **kw,
   for (i = 0; i < keyword_tokens->nelts; ++i)
     {
       const char *keyword = APR_ARRAY_IDX(keyword_tokens, i, const char *);
-      apr_array_header_t *custom_keyword_tokens = NULL;
+      const char *custom_fmt = NULL;
 
       if (expand_custom_keywords)
-        custom_keyword_tokens = svn_cstring_split(keyword, "=",
-                                                  TRUE /* chop */, pool);
-      if (expand_custom_keywords && custom_keyword_tokens->nelts == 2)
         {
-          const char *custom_fmt;
+          char *sep;
+
+          /* Check if there is a custom keyword definition, started by '='. */
+          sep = strchr(keyword, '=');
+          if (sep)
+            {
+              *sep = '\0'; /* Split keyword's name from custom format. */
+              custom_fmt = sep + 1;
+            }
+        }
+
+      if (custom_fmt)
+        {
           svn_string_t *custom_val;
 
           /* Custom keywords must be allowed to match the name of an
@@ -312,9 +321,6 @@ build_keywords(apr_hash_t **kw,
            * in case new fixed keywords are added to Subversion which
            * happen to match a custom keyword defined somewhere.
            * There is only one global namespace for keyword names. */
-
-          keyword = APR_ARRAY_IDX(custom_keyword_tokens, 0, const char*);
-          custom_fmt = APR_ARRAY_IDX(custom_keyword_tokens, 1, const char*);
           custom_val = keyword_printf(custom_fmt, rev, url, repos_root_url,
                                       date, author, pool);
           svn_hash_sets(*kw, keyword, custom_val);
@@ -1116,28 +1122,42 @@ translate_chunk(svn_stream_t *dst,
               /* skip current EOL */
               len += b->eol_str_len;
 
-              /* Check 4 bytes at once to allow for efficient pipelining
-                 and to reduce loop condition overhead. */
-              while ((p + len + 4) <= end)
+              if (b->keywords)
                 {
-                  if (interesting[(unsigned char)p[len]]
-                      || interesting[(unsigned char)p[len+1]]
-                      || interesting[(unsigned char)p[len+2]]
-                      || interesting[(unsigned char)p[len+3]])
-                    break;
-
-                  len += 4;
+                  /* Check 4 bytes at once to allow for efficient pipelining
+                    and to reduce loop condition overhead. */
+                  while ((p + len + 4) <= end)
+                    {
+                      if (interesting[(unsigned char)p[len]]
+                          || interesting[(unsigned char)p[len+1]]
+                          || interesting[(unsigned char)p[len+2]]
+                          || interesting[(unsigned char)p[len+3]])
+                        break;
+
+                      len += 4;
+                    }
+
+                  /* Found an interesting char or EOF in the next 4 bytes.
+                     Find its exact position. */
+                  while ((p + len) < end
+                         && !interesting[(unsigned char)p[len]])
+                    ++len;
+                }
+              else
+                {
+                  /* use our optimized sub-routine to find the next EOL */
+                  const char *start = p + len;
+                  const char *eol
+                    = svn_eol__find_eol_start((char *)start, end - start);
+                  
+                  /* EOL will be NULL if we did not find a line ending */
+                  len += (eol ? eol : end) - start;
                 }
-
-               /* Found an interesting char or EOF in the next 4 bytes.
-                  Find its exact position. */
-               while ((p + len) < end && !interesting[(unsigned char)p[len]])
-                 ++len;
             }
           while (b->nl_translation_skippable ==
                    svn_tristate_true &&       /* can potentially skip EOLs */
                  p + len + 2 < end &&         /* not too close to EOF */
-                 eol_unchanged (b, p + len)); /* EOL format already ok */
+                 eol_unchanged(b, p + len));  /* EOL format already ok */
 
           while ((p + len) < end && !interesting[(unsigned char)p[len]])
             len++;
@@ -1939,7 +1959,11 @@ svn_subst_translate_string2(svn_string_t
       return SVN_NO_ERROR;
     }
 
-  if (encoding)
+  if (encoding && !strcmp(encoding, "UTF-8")) 
+    {
+      val_utf8 = value->data;
+    }
+  else if (encoding)
     {
       SVN_ERR(svn_utf_cstring_to_utf8_ex2(&val_utf8, value->data,
                                           encoding, scratch_pool));

Modified: subversion/branches/cache-server/subversion/libsvn_subr/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/temp_serializer.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/temp_serializer.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/temp_serializer.c Tue Oct 15 08:52:06 2013
@@ -279,6 +279,26 @@ svn_temp_serializer__pop(svn_temp_serial
   context->recycler = old;
 }
 
+void
+svn_temp_serializer__add_leaf(svn_temp_serializer__context_t *context,
+                              const void * const * source_struct,
+                              apr_size_t struct_size)
+{
+  const void *source = *source_struct;
+
+  /* the serialized structure must be properly aligned */
+  if (source)
+    align_buffer_end(context);
+
+  /* Store the offset at which the struct data that will the appended.
+   * Write 0 for NULL pointers. */
+  store_current_end_pointer(context, source_struct);
+
+  /* finally, actually append the struct contents */
+  if (*source_struct)
+    svn_stringbuf_appendbytes(context->buffer, source, struct_size);
+}
+
 /* Serialize a string referenced from the current structure within the
  * serialization CONTEXT. S must be a reference to the char* pointer in
  * the original structure so that the correspondence in the serialized

Modified: subversion/branches/cache-server/subversion/libsvn_subr/types.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/types.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/types.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/types.c Tue Oct 15 08:52:06 2013
@@ -24,42 +24,54 @@
 #include <apr_pools.h>
 #include <apr_uuid.h>
 
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_string.h"
 #include "svn_props.h"
-#include "svn_private_config.h"
+
+#include "private/svn_dep_compat.h"
+#include "private/svn_string_private.h"
 
 svn_error_t *
 svn_revnum_parse(svn_revnum_t *rev,
                  const char *str,
                  const char **endptr)
 {
-  char *end;
+  const char *end;
 
-  svn_revnum_t result = strtol(str, &end, 10);
+  svn_revnum_t result = (svn_revnum_t)svn__strtoul(str, &end);
 
   if (endptr)
-    *endptr = end;
+    *endptr = str;
 
   if (str == end)
-    return svn_error_createf(SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
-                             _("Invalid revision number found parsing '%s'"),
-                             str);
-
-  if (result < 0)
+    return svn_error_createf
+              (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
+               *str == '-' ? _("Negative revision number found parsing '%s'")
+                           : _("Invalid revision number found parsing '%s'"),
+               str);
+
+  /* a revision number with more than 9 digits is suspicious.
+     Have a closer look at those. */
+  if (str + 10 <= end)
     {
-      /* The end pointer from strtol() is valid, but a negative revision
-         number is invalid, so move the end pointer back to the
-         beginning of the string. */
-      if (endptr)
-        *endptr = str;
-
-      return svn_error_createf(SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
-                               _("Negative revision number found parsing '%s'"),
-                               str);
+      /* we support 32 bit revision numbers only. check for overflows */
+      if (str + 10 < end)
+        return svn_error_createf
+                  (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
+                  _("Revision number longer than 10 digits '%s'"), str);
+        
+      /* we support 32 bit revision numbers only. check for overflows */
+      if (*str > '2' || (apr_uint32_t)result > APR_INT32_MAX)
+        return svn_error_createf
+                  (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
+                  _("Revision number too large '%s'"), str);
     }
+  
+  if (endptr)
+    *endptr = end;
 
   *rev = result;
 

Modified: subversion/branches/cache-server/subversion/libsvn_subr/username_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/cache-server/subversion/libsvn_subr/username_providers.c?rev=1532250&r1=1532249&r2=1532250&view=diff
==============================================================================
--- subversion/branches/cache-server/subversion/libsvn_subr/username_providers.c (original)
+++ subversion/branches/cache-server/subversion/libsvn_subr/username_providers.c Tue Oct 15 08:52:06 2013
@@ -28,6 +28,8 @@
 /*** Includes. ***/
 
 #include <apr_pools.h>
+
+#include "svn_private_config.h"
 #include "svn_hash.h"
 #include "svn_auth.h"
 #include "svn_error.h"