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/07/22 13:22:20 UTC

svn commit: r1505660 [3/5] - in /subversion/branches/fsfs-improvements: ./ build/generator/ build/generator/swig/ build/generator/templates/ notes/http-and-webdav/ subversion/ subversion/bindings/swig/ subversion/bindings/swig/ruby/libsvn_swig_ruby/ su...

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h Mon Jul 22 11:22:18 2013
@@ -195,12 +195,14 @@ svn_fs_fs__set_proplist(svn_fs_t *fs,
 
 /* Commit the transaction TXN in filesystem FS and return its new
    revision number in *REV.  If the transaction is out of date, return
-   the error SVN_ERR_FS_TXN_OUT_OF_DATE.  Use POOL for temporary
-   allocations. */
+   the error SVN_ERR_FS_TXN_OUT_OF_DATE. Update commit time to ensure that
+   svn:date revprops remain ordered if SET_TIMESTAMP is non-zero. Use POOL for
+   temporary allocations. */
 svn_error_t *
 svn_fs_fs__commit(svn_revnum_t *new_rev_p,
                   svn_fs_t *fs,
                   svn_fs_txn_t *txn,
+                  svn_boolean_t set_timestamp,
                   apr_pool_t *pool);
 
 /* Set *NAMES_P to an array of names which are all the active

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.c Mon Jul 22 11:22:18 2013
@@ -1991,6 +1991,7 @@ svn_error_t *
 svn_fs_fs__commit_txn(const char **conflict_p,
                       svn_revnum_t *new_rev,
                       svn_fs_txn_t *txn,
+                      svn_boolean_t set_timestamp,
                       apr_pool_t *pool)
 {
   /* How do commits work in Subversion?
@@ -2087,7 +2088,7 @@ svn_fs_fs__commit_txn(const char **confl
       txn->base_rev = youngish_rev;
 
       /* Try to commit. */
-      err = svn_fs_fs__commit(new_rev, fs, txn, iterpool);
+      err = svn_fs_fs__commit(new_rev, fs, txn, set_timestamp, iterpool);
       if (err && (err->apr_err == SVN_ERR_FS_TXN_OUT_OF_DATE))
         {
           /* Did someone else finish committing a new revision while we

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.h?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/tree.h Mon Jul 22 11:22:18 2013
@@ -48,10 +48,12 @@ svn_error_t *svn_fs_fs__deltify(svn_fs_t
 /* Commit the transaction TXN as a new revision.  Return the new
    revision in *NEW_REV.  If the transaction conflicts with other
    changes return SVN_ERR_FS_CONFLICT and set *CONFLICT_P to a string
-   that details the cause of the conflict.  Perform temporary
-   allocations in POOL. */
+   that details the cause of the conflict.
+   Update commit time to ensure that svn:date revprops remain ordered if
+   SET_TIMESTAMP is non-zero. Perform temporary allocations in POOL. */
 svn_error_t *svn_fs_fs__commit_txn(const char **conflict_p,
                                    svn_revnum_t *new_rev, svn_fs_txn_t *txn,
+                                   svn_boolean_t set_timestamp,
                                    apr_pool_t *pool);
 
 /* Set ROOT_P to the root directory of transaction TXN.  Allocate the

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/ra_serf.h?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/ra_serf.h Mon Jul 22 11:22:18 2013
@@ -658,11 +658,6 @@ struct svn_ra_serf__xml_parser_t {
 
      See libsvn_ra_serf/util.c  */
   struct svn_ra_serf__pending_t *pending;
-
-  /* Response restart support */
-  const void *headers_baton; /* Last pointer to headers */
-  apr_off_t skip_size; /* Number of bytes to skip */
-  apr_off_t read_size; /* Number of bytes read from response */
 };
 
 

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/update.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/update.c Mon Jul 22 11:22:18 2013
@@ -82,7 +82,7 @@ typedef enum report_state_e {
     NEED_PROP_NAME,
     TXDELTA
 
-#ifdef USE_TRANSITION_PARSER
+#ifdef NOT_USED_YET
     ,
 
     CHECKED_IN,
@@ -390,6 +390,9 @@ struct report_context_t {
   /* The path to the REPORT request */
   const char *path;
 
+  /* Are we done parsing the REPORT response? */
+  svn_boolean_t done;
+
   /* Did we receive all data from the network? */
   svn_boolean_t report_received;
 
@@ -411,7 +414,7 @@ struct report_context_t {
 #define V_ SVN_DAV_PROP_NS_DAV
 static const svn_ra_serf__xml_transition_t update_ttable[] = {
   { INITIAL, S_, "update-report", UPDATE_REPORT,
-    FALSE, { NULL }, TRUE },
+    FALSE, { NULL }, FALSE },
 
   { UPDATE_REPORT, S_, "target-revision", TARGET_REVISION,
     FALSE, { "rev", NULL }, TRUE },
@@ -2565,6 +2568,7 @@ update_closed(svn_ra_serf__xml_estate_t 
   if (leaving_state == UPDATE_REPORT)
     {
       ctx->report_completed = TRUE;
+      ctx->done = TRUE;
     }
   else if (leaving_state == TARGET_REVISION)
     {
@@ -2816,10 +2820,9 @@ finish_report(void *report_baton,
   report_context_t *report = report_baton;
   svn_ra_serf__session_t *sess = report->sess;
   svn_ra_serf__handler_t *handler;
+  svn_ra_serf__xml_parser_t *parser_ctx;
 #ifdef USE_TRANSITION_PARSER
   svn_ra_serf__xml_context_t *xmlctx;
-#else
-  svn_ra_serf__xml_parser_t *parser_ctx;
 #endif
   const char *report_target;
   svn_stringbuf_t *buf = NULL;
@@ -2882,7 +2885,7 @@ finish_report(void *report_baton,
   parser_ctx->start = start_report;
   parser_ctx->end = end_report;
   parser_ctx->cdata = cdata_report;
-  parser_ctx->done = &handler->done;
+  parser_ctx->done = &report->done;
 
   handler->response_handler = svn_ra_serf__handle_xml_parser;
   handler->response_baton = parser_ctx;
@@ -2902,7 +2905,7 @@ finish_report(void *report_baton,
      network or because we've spooled the entire response into our "pending"
      content of the XML parser. The DONE flag will get set when all the
      XML content has been received *and* parsed.  */
-  while (!handler->done
+  while (!report->done
          || report->num_active_fetches
          || report->num_active_propfinds)
     {
@@ -3144,7 +3147,6 @@ finish_report(void *report_baton,
         }
       report->done_dir_propfinds = NULL;
 
-#ifndef USE_TRANSITION_PARSER
       /* If the parser is paused, and the number of active requests has
          dropped far enough, then resume parsing.  */
       if (parser_ctx->paused
@@ -3159,7 +3161,6 @@ finish_report(void *report_baton,
         SVN_ERR(svn_ra_serf__process_pending(parser_ctx,
                                              &report->report_received,
                                              iterpool_inner));
-#endif
 
       /* Debugging purposes only! */
       for (i = 0; i < sess->num_conns; i++)
@@ -3280,6 +3281,7 @@ make_update_reporter(svn_ra_session_t *r
 
   report->update_editor = update_editor;
   report->update_baton = update_baton;
+  report->done = FALSE;
 
   *reporter = &ra_serf_reporter;
   *report_baton = report;

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/util.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_ra_serf/util.c Mon Jul 22 11:22:18 2013
@@ -747,8 +747,6 @@ svn_ra_serf__context_run_wait(svn_boolea
          the connection timed out.  */
       if (APR_STATUS_IS_TIMEUP(status))
         {
-          svn_error_clear(err);
-          err = SVN_NO_ERROR;
           status = 0;
 
           if (sess->timeout)
@@ -759,8 +757,11 @@ svn_ra_serf__context_run_wait(svn_boolea
                 }
               else
                 {
-                  return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
-                                          _("Connection timed out"));
+                  return
+                      svn_error_compose_create(
+                            err,
+                            svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+                                             _("Connection timed out")));
                 }
             }
         }
@@ -808,6 +809,23 @@ svn_ra_serf__context_run_one(svn_ra_serf
   /* Wait until the response logic marks its DONE status.  */
   err = svn_ra_serf__context_run_wait(&handler->done, handler->session,
                                       scratch_pool);
+
+  /* A callback invocation has been canceled. In this simple case of
+     context_run_one, we can keep the ra-session operational by resetting
+     the connection.
+
+     If we don't do this, the next context run will notice that the connection
+     is still in the error state and will just return SVN_ERR_CEASE_INVOCATION
+     (=the last error for the connection) again  */
+  if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
+    {
+      apr_status_t status = serf_connection_reset(handler->conn->conn);
+
+      if (status)
+        err = svn_error_compose_create(err,
+                                       svn_ra_serf__wrap_err(status, NULL));
+    }
+
   if (handler->server_error)
     {
       err = svn_error_compose_create(err, handler->server_error->error);
@@ -1606,22 +1624,6 @@ svn_ra_serf__handle_xml_parser(serf_requ
       return svn_error_trace(err);
     }
 
-  if (ctx->headers_baton == NULL)
-    ctx->headers_baton = serf_bucket_response_get_headers(response);
-  else if (ctx->headers_baton != serf_bucket_response_get_headers(response))
-    {
-      /* We got a new response to an existing parser...
-         This tells us the connection has restarted and we should continue
-         where we stopped last time.
-       */
-
-      /* Is this a second attempt?? */
-      if (!ctx->skip_size)
-        ctx->skip_size = ctx->read_size;
-
-      ctx->read_size = 0; /* New request, nothing read */
-    }
-
   if (!ctx->xmlp)
     {
       ctx->xmlp = XML_ParserCreate(NULL);
@@ -1641,41 +1643,11 @@ svn_ra_serf__handle_xml_parser(serf_requ
       apr_size_t len;
 
       status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
-
       if (SERF_BUCKET_READ_ERROR(status))
         {
           return svn_ra_serf__wrap_err(status, NULL);
         }
 
-      ctx->read_size += len;
-
-      if (ctx->skip_size)
-        {
-          /* Handle restarted requests correctly: Skip what we already read */
-          apr_size_t skip;
-
-          if (ctx->skip_size >= ctx->read_size)
-            {
-            /* Eek.  What did the file shrink or something? */
-              if (APR_STATUS_IS_EOF(status))
-                {
-                  SVN_ERR_MALFUNCTION();
-                }
-
-              /* Skip on to the next iteration of this loop. */
-              if (APR_STATUS_IS_EAGAIN(status))
-                {
-                  return svn_ra_serf__wrap_err(status, NULL);
-                }
-              continue;
-            }
-
-          skip = (apr_size_t)(len - (ctx->read_size - ctx->skip_size));
-          data += skip;
-          len -= skip;
-          ctx->skip_size = 0;
-        }
-
       /* Note: once the callbacks invoked by inject_to_parser() sets the
          PAUSED flag, then it will not be cleared. write_to_pending() will
          only save the content. Logic outside of serf_context_run() will
@@ -1859,12 +1831,26 @@ handle_response(serf_request_t *request,
     {
       /* Uh-oh. Our connection died.  */
       if (handler->response_error)
-        SVN_ERR(handler->response_error(request, response, 0,
-                                        handler->response_error_baton));
-
-      /* Requeue another request for this handler.
-         ### how do we know if the handler can deal with this?!  */
-      svn_ra_serf__request_create(handler);
+        {
+          /* Give a handler chance to prevent request requeue. */
+          SVN_ERR(handler->response_error(request, response, 0,
+                                          handler->response_error_baton));
+
+          svn_ra_serf__request_create(handler);
+        }
+      /* Response error callback is not configured. Requeue another request
+         for this handler only if we didn't started to process body.
+         Return error otherwise. */
+      else if (!handler->reading_body)
+        {
+          svn_ra_serf__request_create(handler);
+        }
+      else
+        {
+          return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                                    _("%s request on '%s' failed"),
+                                   handler->method, handler->path);
+        }
 
       return SVN_NO_ERROR;
     }

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_ra_svn/client.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_ra_svn/client.c Mon Jul 22 11:22:18 2013
@@ -1479,16 +1479,19 @@ static svn_error_t *ra_svn_diff(svn_ra_s
 }
 
 
-static svn_error_t *ra_svn_log(svn_ra_session_t *session,
-                               const apr_array_header_t *paths,
-                               svn_revnum_t start, svn_revnum_t end,
-                               int limit,
-                               svn_boolean_t discover_changed_paths,
-                               svn_boolean_t strict_node_history,
-                               svn_boolean_t include_merged_revisions,
-                               const apr_array_header_t *revprops,
-                               svn_log_entry_receiver_t receiver,
-                               void *receiver_baton, apr_pool_t *pool)
+static svn_error_t *
+perform_ra_svn_log(svn_error_t **outer_error,
+                   svn_ra_session_t *session,
+                   const apr_array_header_t *paths,
+                   svn_revnum_t start, svn_revnum_t end,
+                   int limit,
+                   svn_boolean_t discover_changed_paths,
+                   svn_boolean_t strict_node_history,
+                   svn_boolean_t include_merged_revisions,
+                   const apr_array_header_t *revprops,
+                   svn_log_entry_receiver_t receiver,
+                   void *receiver_baton,
+                   apr_pool_t *pool)
 {
   svn_ra_svn__session_baton_t *sess_baton = session->priv;
   svn_ra_svn_conn_t *conn = sess_baton->conn;
@@ -1501,6 +1504,7 @@ static svn_error_t *ra_svn_log(svn_ra_se
   svn_boolean_t want_author = FALSE;
   svn_boolean_t want_message = FALSE;
   svn_boolean_t want_date = FALSE;
+  int nreceived = 0;
 
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w((!", "log"));
   if (paths)
@@ -1562,7 +1566,6 @@ static svn_error_t *ra_svn_log(svn_ra_se
       svn_ra_svn_item_t *item;
       apr_hash_t *cphash;
       svn_revnum_t rev;
-      int nreceived;
 
       svn_pool_clear(iterpool);
       SVN_ERR(svn_ra_svn__read_item(conn, iterpool, &item));
@@ -1645,9 +1648,14 @@ static svn_error_t *ra_svn_log(svn_ra_se
       else
         cphash = NULL;
 
-      nreceived = 0;
-      if (! (limit && (nest_level == 0) && (++nreceived > limit)))
+      /* Invoke RECEIVER
+          - Except if the server sends more than a >= 1 limit top level items
+          - Or when the callback reported a SVN_ERR_CEASE_INVOCATION
+            in an earlier invocation. */
+      if (! (limit && (nest_level == 0) && (++nreceived > limit))
+          && ! *outer_error)
         {
+          svn_error_t *err;
           log_entry = svn_log_entry_create(iterpool);
 
           log_entry->changed_paths = cphash;
@@ -1671,7 +1679,15 @@ static svn_error_t *ra_svn_log(svn_ra_se
             svn_hash_sets(log_entry->revprops,
                           SVN_PROP_REVISION_LOG, message);
 
-          SVN_ERR(receiver(receiver_baton, log_entry, iterpool));
+          err = receiver(receiver_baton, log_entry, iterpool);
+          if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
+            {
+              *outer_error = svn_error_trace(
+                                svn_error_compose_create(*outer_error, err));
+            }
+          else
+            SVN_ERR(err);
+
           if (log_entry->has_children)
             {
               nest_level++;
@@ -1686,9 +1702,40 @@ static svn_error_t *ra_svn_log(svn_ra_se
   svn_pool_destroy(iterpool);
 
   /* Read the response. */
-  return svn_ra_svn__read_cmd_response(conn, pool, "");
+  return svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, ""));
 }
 
+static svn_error_t *
+ra_svn_log(svn_ra_session_t *session,
+           const apr_array_header_t *paths,
+           svn_revnum_t start, svn_revnum_t end,
+           int limit,
+           svn_boolean_t discover_changed_paths,
+           svn_boolean_t strict_node_history,
+           svn_boolean_t include_merged_revisions,
+           const apr_array_header_t *revprops,
+           svn_log_entry_receiver_t receiver,
+           void *receiver_baton, apr_pool_t *pool)
+{
+  svn_error_t *outer_error = NULL;
+  svn_error_t *err;
+
+  err = svn_error_trace(perform_ra_svn_log(&outer_error,
+                                           session, paths,
+                                           start, end,
+                                           limit,
+                                           discover_changed_paths,
+                                           strict_node_history,
+                                           include_merged_revisions,
+                                           revprops,
+                                           receiver, receiver_baton,
+                                           pool));
+  return svn_error_trace(
+            svn_error_compose_create(outer_error,
+                                     err));
+}
+
+
 
 static svn_error_t *ra_svn_check_path(svn_ra_session_t *session,
                                       const char *path, svn_revnum_t rev,
@@ -1963,7 +2010,7 @@ static svn_error_t *ra_svn_get_file_revs
         {
           svn_stream_t *stream;
 
-          if (d_handler)
+          if (d_handler && d_handler != svn_delta_noop_window_handler)
             stream = svn_txdelta_parse_svndiff(d_handler, d_baton, TRUE,
                                                rev_pool);
           else

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_ra_svn/marshal.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_ra_svn/marshal.c Mon Jul 22 11:22:18 2013
@@ -411,7 +411,7 @@ static svn_error_t *readbuf_fill(svn_ra_
   return SVN_NO_ERROR;
 }
 
-static APR_INLINE svn_error_t *
+static SVN__FORCE_INLINE svn_error_t *
 readbuf_getchar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char *result)
 {
   if (conn->read_ptr == conn->read_end)

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_repos/load-fs-vtable.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_repos/load-fs-vtable.c Mon Jul 22 11:22:18 2013
@@ -99,6 +99,9 @@ struct revision_baton
   apr_int32_t rev_offset;
   svn_boolean_t skipped;
 
+  /* Array of svn_prop_t with revision properties. */
+  apr_array_header_t *revprops;
+
   struct parse_baton *pb;
   apr_pool_t *pool;
 };
@@ -448,6 +451,7 @@ make_revision_baton(apr_hash_t *headers,
   rb->pb = pb;
   rb->pool = pool;
   rb->rev = SVN_INVALID_REVNUM;
+  rb->revprops = apr_array_make(rb->pool, 8, sizeof(svn_prop_t));
 
   if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER)))
     {
@@ -698,10 +702,12 @@ set_revision_property(void *baton,
 
   if (rb->rev > 0)
     {
-      if (rb->pb->validate_props)
-        SVN_ERR(svn_repos_fs_change_txn_prop(rb->txn, name, value, rb->pool));
-      else
-        SVN_ERR(svn_fs_change_txn_prop(rb->txn, name, value, rb->pool));
+      svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
+
+      /* Collect property changes to apply them in one FS call in
+         close_revision. */
+      prop->name = apr_pstrdup(rb->pool, name);
+      prop->value = svn_string_dup(value, rb->pool);
 
       /* Remember any datestamp that passes through!  (See comment in
          close_revision() below.) */
@@ -920,6 +926,21 @@ close_revision(void *baton)
   if (rb->skipped || (rb->rev <= 0))
     return SVN_NO_ERROR;
 
+  if (!rb->datestamp)
+    {
+      /* Remove 'svn:date' revision property that was set by FS layer when TXN
+         created if source dump doesn't have 'svn:date' property. */
+      svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
+      prop->name = SVN_PROP_REVISION_DATE;
+      prop->value = NULL;
+    }
+
+  /* Apply revision property changes. */
+  if (rb->pb->validate_props)
+    SVN_ERR(svn_repos_fs_change_txn_props(rb->txn, rb->revprops, rb->pool));
+  else
+    SVN_ERR(svn_fs_change_txn_props(rb->txn, rb->revprops, rb->pool));
+
   /* Get the txn name and hooks environment if they will be needed. */
   if (pb->use_pre_commit_hook || pb->use_post_commit_hook)
     {
@@ -947,7 +968,8 @@ close_revision(void *baton)
     }
 
   /* Commit. */
-  err = svn_fs_commit_txn(&conflict_msg, &committed_rev, rb->txn, rb->pool);
+  err = svn_fs_commit_txn2(&conflict_msg, &committed_rev, rb->txn, FALSE,
+                           rb->pool);
   if (SVN_IS_VALID_REVNUM(committed_rev))
     {
       if (err)
@@ -1005,15 +1027,6 @@ close_revision(void *baton)
   /* Deltify the predecessors of paths changed in this revision. */
   SVN_ERR(svn_fs_deltify_revision(pb->fs, committed_rev, rb->pool));
 
-  /* Grrr, svn_fs_commit_txn rewrites the datestamp property to the
-     current clock-time.  We don't want that, we want to preserve
-     history exactly.  Good thing revision props aren't versioned!
-     Note that if rb->datestamp is NULL, that's fine -- if the dump
-     data doesn't carry a datestamp, we want to preserve that fact in
-     the load. */
-  SVN_ERR(change_rev_prop(pb->repos, committed_rev, SVN_PROP_REVISION_DATE,
-                          rb->datestamp, pb->validate_props, rb->pool));
-
   if (pb->notify_func)
     {
       pb->notify->action = svn_repos_notify_load_txn_committed;

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-inprocess.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-inprocess.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-inprocess.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-inprocess.c Mon Jul 22 11:22:18 2013
@@ -246,6 +246,37 @@ inprocess_cache_get(void **value_p,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+inprocess_cache_has_key_internal(svn_boolean_t *found,
+                                 inprocess_cache_t *cache,
+                                 const void *key,
+                                 apr_pool_t *scratch_pool)
+{
+  *found = apr_hash_get(cache->hash, key, cache->klen) != NULL;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+inprocess_cache_has_key(svn_boolean_t *found,
+                        void *cache_void,
+                        const void *key,
+                        apr_pool_t *scratch_pool)
+{
+  inprocess_cache_t *cache = cache_void;
+
+  if (key)
+    SVN_MUTEX__WITH_LOCK(cache->mutex,
+                         inprocess_cache_has_key_internal(found,
+                                                          cache,
+                                                          key,
+                                                          scratch_pool));
+  else
+    *found = FALSE;
+
+  return SVN_NO_ERROR;
+}
+
 /* Removes PAGE from the LRU list, removes all of its entries from
  * CACHE's hash, clears its pool, and sets its entry pointer to NULL.
  * Finally, puts it in the "partial page" slot in the cache and sets
@@ -604,6 +635,7 @@ inprocess_cache_get_info(void *cache_voi
 
 static svn_cache__vtable_t inprocess_cache_vtable = {
   inprocess_cache_get,
+  inprocess_cache_has_key,
   inprocess_cache_set,
   inprocess_cache_iter,
   inprocess_cache_is_cachable,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-membuffer.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-membuffer.c Mon Jul 22 11:22:18 2013
@@ -361,6 +361,10 @@ typedef struct entry_t
    */
   apr_uint32_t previous;
 
+  /* Priority of this entry.  This entry will not be replaced by lower-
+   * priority items.
+   */
+  apr_uint32_t priority;
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER
   /* Remember type, content and key hashes.
    */
@@ -1013,13 +1017,15 @@ find_entry(svn_membuffer_t *cache,
       if (group->used == GROUP_SIZE)
         {
           /* 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.
+           * Otherwise, we free the first entry, fill it and remove it
+           * again on the next occasion without considering the other
+           * entries in this group.  Also, apply priorities strictly.
            */
           entry = &group->entries[rand() % GROUP_SIZE];
           for (i = 1; i < GROUP_SIZE; ++i)
-            if (entry->hit_count > group->entries[i].hit_count)
+            if (   (entry->priority > group->entries[i].priority)
+                || (   entry->priority == group->entries[i].priority
+                    && entry->hit_count > group->entries[i].hit_count))
               entry = &group->entries[i];
 
           /* for the entries that don't have been removed,
@@ -1128,6 +1134,16 @@ ensure_data_insertable_l2(svn_membuffer_
   apr_uint64_t average_hit_value;
   apr_uint64_t threshold;
 
+  /* accumulated size of the entries that have been removed to make
+   * room for the new one.
+   */
+  apr_size_t moved_size = 0;
+
+  /* count the number of entries that got moved.  A single large entry
+   * being moved is not enough to reject an insertion.
+   */
+  apr_size_t moved_count = 0;
+
   /* accumulated "worth" of items dropped so far */
   apr_size_t drop_hits = 0;
 
@@ -1159,10 +1175,16 @@ ensure_data_insertable_l2(svn_membuffer_
       if (end >= to_fit_in->size + cache->l2.current_data)
         return TRUE;
 
+      /* Don't be too eager to cache data.  If a lot of data has been 
+       * moved around, the current item has probably a relatively low
+       * priority.  So, give up after some time.
+       */
+      if (moved_size > 8 * to_fit_in->size && moved_count > 3)
+        return FALSE;
+
       /* if the net worth (in hits) of items removed is already larger
        * than what we want to insert, reject TO_FIT_IN because it still
-       * does not fit in.
-       */
+       * does not fit in. */
       if (drop_hits > to_fit_in->hit_count)
         return FALSE;
 
@@ -1180,8 +1202,15 @@ ensure_data_insertable_l2(svn_membuffer_
         }
       else
         {
+          svn_boolean_t keep;
           entry = get_entry(cache, cache->l2.next);
 
+          /* Reject insertion for entries with low priority, if the current
+           * entry has seen recent hits. */
+          if (   entry->hit_count
+              && to_fit_in->priority < SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY)
+            return FALSE;
+
           /* Keep entries that are very small. Those are likely to be data
            * headers or similar management structures. So, they are probably
            * important while not occupying much space.
@@ -1190,56 +1219,75 @@ ensure_data_insertable_l2(svn_membuffer_
           if (   (apr_uint64_t)entry->size * cache->used_entries
                < cache->data_used / 8)
             {
-              move_entry(cache, entry);
+              keep = TRUE;
             }
           else if (cache->l2.next / GROUP_SIZE == idx / GROUP_SIZE)
             {
               /* Special case: we cannot drop entries that are in the same
-              * group as TO_FIT_IN because that might the latter to become
-              * invalidated it it happens to be the highest used entry in
-              * the group.  So, we must keep ENTRY unconditionally.
-              * (this is a very rare condition)
-              */
-              move_entry(cache, entry);
+               * group as TO_FIT_IN because that might the latter to become
+               * invalidated it it happens to be the highest used entry in
+               * the group.  So, we must keep ENTRY unconditionally.
+               * (this is a very rare condition)
+               */
+              keep = TRUE;
             }
-          else
+          else if (   entry->priority < SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY
+                   && to_fit_in->priority > entry->priority)
+            {
+              /* Be quick to evict low-priority entries if the one to insert
+               * is of higher priority.
+               */
+              keep = FALSE;
+            }
+          else if (to_fit_in->priority != entry->priority)
+            {
+              /* Not the same priority but the lower prio side is not a
+               * clear loser either (already checked those cases above).
+               * Keep the current entry if it has seen more hits recently
+               * or is smaller than the one to insert - both relative to
+               * their respective priority.
+               */
+              keep = to_fit_in->hit_count * to_fit_in->priority
+                   < entry->hit_count * entry->priority
+                  || to_fit_in->size * to_fit_in->priority
+                   < entry->size * entry->priority;
+            }
+          else if (cache->hit_count > cache->used_entries)
             {
-              svn_boolean_t keep;
+              /* 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;
 
-              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 = rand() & 1;
+            }
 
-                  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)
+            {
+              /* Moving entries around is not for free -> track costs. */
+              moved_size += entry->size;
+              moved_count++;
 
-              /* keepers or destroyers? */
-              if (keep)
-                {
-                 /* Keep ENTRY and move the insertion window.
-                  */
-                  move_entry(cache, entry);
-                }
-              else
-                {
-                 /* Drop the entry from the end of the insertion window,
-                  * because it had been hit less than the threshold.
-                  */
-                  drop_hits += entry->hit_count;
-                  drop_entry(cache, entry);
-                }
+              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_hits += entry->hit_count;
+              drop_entry(cache, entry);
             }
         }
     }
@@ -1582,6 +1630,7 @@ membuffer_cache_set_internal(svn_membuff
                              apr_uint32_t group_index,
                              char *buffer,
                              apr_size_t size,
+                             apr_uint32_t priority,
                              DEBUG_CACHE_MEMBUFFER_TAG_ARG
                              apr_pool_t *scratch_pool)
 {
@@ -1594,6 +1643,7 @@ membuffer_cache_set_internal(svn_membuff
     {
       cache->data_used += size - entry->size;
       entry->size = size;
+      entry->priority = priority;
 
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER
 
@@ -1624,6 +1674,7 @@ membuffer_cache_set_internal(svn_membuff
       entry = find_entry(cache, group_index, to_find, TRUE);
       entry->size = size;
       entry->offset = cache->l1.current_data;
+      entry->priority = priority;
 
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER
 
@@ -1673,6 +1724,7 @@ membuffer_cache_set(svn_membuffer_t *cac
                     entry_key_t key,
                     void *item,
                     svn_cache__serialize_func_t serializer,
+                    apr_uint32_t priority,
                     DEBUG_CACHE_MEMBUFFER_TAG_ARG
                     apr_pool_t *scratch_pool)
 {
@@ -1697,6 +1749,7 @@ membuffer_cache_set(svn_membuffer_t *cac
                                                group_index,
                                                buffer,
                                                size,
+                                               priority,
                                                DEBUG_CACHE_MEMBUFFER_TAG
                                                scratch_pool));
   return SVN_NO_ERROR;
@@ -1808,6 +1861,43 @@ membuffer_cache_get(svn_membuffer_t *cac
 }
 
 /* Look for the cache entry in group GROUP_INDEX of CACHE, identified
+ * by the hash value TO_FIND.  If no item has been stored for KEY, *FOUND
+ * will be FALSE and TRUE otherwise.
+ */
+static svn_error_t *
+membuffer_cache_has_key_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 an entry identified by KEY.  If no item has been stored
+ * for KEY, *FOUND will be set to FALSE and TRUE otherwise.
+ */
+/* Implements svn_cache__has_key for membuffer caches.
+ */
+static svn_error_t *
+membuffer_cache_has_key(svn_membuffer_t *cache,
+                        entry_key_t key,
+                        svn_boolean_t *found)
+{
+  /* find the entry group that will hold the key.
+   */
+  apr_uint32_t group_index = get_group_index(&cache, key);
+  WITH_READ_LOCK(cache,
+                 membuffer_cache_has_key_internal(cache,
+                                                  group_index,
+                                                  key,
+                                                  found));
+
+  return SVN_NO_ERROR;
+}
+
+/* Look for the cache entry in group GROUP_INDEX of CACHE, identified
  * by the hash value TO_FIND. FOUND indicates whether that entry exists.
  * If not found, *ITEM will be NULL.
  *
@@ -2097,6 +2187,9 @@ typedef struct svn_membuffer_cache_t
    */
   apr_ssize_t key_len;
 
+  /* priority class for all items written through this interface */
+  apr_uint32_t priority;
+  
   /* Temporary buffer containing the hash key for the current access
    */
   entry_key_t combined_key;
@@ -2291,6 +2384,39 @@ svn_membuffer_cache_get(void **value_p,
 
   /* return result */
   *found = *value_p != NULL;
+
+  return SVN_NO_ERROR;
+}
+
+/* Implement svn_cache__vtable_t.has_key (not thread-safe)
+ */
+static svn_error_t *
+svn_membuffer_cache_has_key(svn_boolean_t *found,
+                            void *cache_void,
+                            const void *key,
+                            apr_pool_t *scratch_pool)
+{
+  svn_membuffer_cache_t *cache = cache_void;
+
+  /* special case */
+  if (key == NULL)
+    {
+      *found = FALSE;
+
+      return SVN_NO_ERROR;
+    }
+
+  /* construct the full, i.e. globally unique, key by adding
+   * this cache instances' prefix
+   */
+  combine_key(cache, key, cache->key_len);
+
+  /* Look the item up. */
+  SVN_ERR(membuffer_cache_has_key(cache->membuffer,
+                                  cache->combined_key,
+                                  found));
+
+  /* return result */
   return SVN_NO_ERROR;
 }
 
@@ -2332,6 +2458,7 @@ svn_membuffer_cache_set(void *cache_void
                              cache->combined_key,
                              value,
                              cache->serializer,
+                             cache->priority,
                              DEBUG_CACHE_MEMBUFFER_TAG
                              cache->pool);
 }
@@ -2488,6 +2615,7 @@ svn_membuffer_cache_get_info(void *cache
  */
 static svn_cache__vtable_t membuffer_cache_vtable = {
   svn_membuffer_cache_get,
+  svn_membuffer_cache_has_key,
   svn_membuffer_cache_set,
   svn_membuffer_cache_iter,
   svn_membuffer_cache_is_cachable,
@@ -2516,6 +2644,24 @@ svn_membuffer_cache_get_synced(void **va
   return SVN_NO_ERROR;
 }
 
+/* Implement svn_cache__vtable_t.has_key and serialize all cache access.
+ */
+static svn_error_t *
+svn_membuffer_cache_has_key_synced(svn_boolean_t *found,
+                                   void *cache_void,
+                                   const void *key,
+                                   apr_pool_t *result_pool)
+{
+  svn_membuffer_cache_t *cache = cache_void;
+  SVN_MUTEX__WITH_LOCK(cache->mutex,
+                       svn_membuffer_cache_has_key(found,
+                                                   cache_void,
+                                                   key,
+                                                   result_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Implement svn_cache__vtable_t.set and serialize all cache access.
  */
 static svn_error_t *
@@ -2582,6 +2728,7 @@ svn_membuffer_cache_set_partial_synced(v
  */
 static svn_cache__vtable_t membuffer_cache_synced_vtable = {
   svn_membuffer_cache_get_synced,
+  svn_membuffer_cache_has_key_synced,
   svn_membuffer_cache_set_synced,
   svn_membuffer_cache_iter,               /* no sync required */
   svn_membuffer_cache_is_cachable,        /* no sync required */
@@ -2636,6 +2783,7 @@ svn_cache__create_membuffer_cache(svn_ca
                                   svn_cache__deserialize_func_t deserializer,
                                   apr_ssize_t klen,
                                   const char *prefix,
+                                  apr_uint32_t priority,
                                   svn_boolean_t thread_safe,
                                   apr_pool_t *pool)
 {
@@ -2656,6 +2804,7 @@ svn_cache__create_membuffer_cache(svn_ca
                       ? deserializer
                       : deserialize_svn_stringbuf;
   cache->full_prefix = apr_pstrdup(pool, prefix);
+  cache->priority = priority;
   cache->key_len = klen;
   cache->pool = svn_pool_create(pool);
   cache->alloc_counter = 0;

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-memcache.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-memcache.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-memcache.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache-memcache.c Mon Jul 22 11:22:18 2013
@@ -213,6 +213,26 @@ memcache_get(void **value_p,
   return SVN_NO_ERROR;
 }
 
+/* Implement vtable.has_key in terms of the getter.
+ */
+static svn_error_t *
+memcache_has_key(svn_boolean_t *found,
+                 void *cache_void,
+                 const void *key,
+                 apr_pool_t *scratch_pool)
+{
+  char *data;
+  apr_size_t data_len;
+  SVN_ERR(memcache_internal_get(&data,
+                                &data_len,
+                                found,
+                                cache_void,
+                                key,
+                                scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Core functionality of our setter functions: store LENGH bytes of DATA
  * to be identified by KEY in the memcached given by CACHE_VOID. Use POOL
  * for temporary allocations.
@@ -371,6 +391,7 @@ memcache_get_info(void *cache_void,
 
 static svn_cache__vtable_t memcache_vtable = {
   memcache_get,
+  memcache_has_key,
   memcache_set,
   memcache_iter,
   memcache_is_cachable,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache.c Mon Jul 22 11:22:18 2013
@@ -96,6 +96,21 @@ svn_cache__get(void **value_p,
 }
 
 svn_error_t *
+svn_cache__has_key(svn_boolean_t *found,
+                   svn_cache__t *cache,
+                   const void *key,
+                   apr_pool_t *scratch_pool)
+{
+  *found = FALSE;
+  return handle_error(cache,
+                      (cache->vtable->has_key)(found,
+                                               cache->cache_internal,
+                                               key,
+                                               scratch_pool),
+                      scratch_pool);
+}
+
+svn_error_t *
 svn_cache__set(svn_cache__t *cache,
                const void *key,
                void *value,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache.h?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/cache.h Mon Jul 22 11:22:18 2013
@@ -38,6 +38,12 @@ typedef struct svn_cache__vtable_t {
                       const void *key,
                       apr_pool_t *result_pool);
 
+  /* See svn_cache__has_key(). */
+  svn_error_t *(*has_key)(svn_boolean_t *found,
+                          void *cache_implementation,
+                          const void *key,
+                          apr_pool_t *scratch_pool);
+
   /* See svn_cache__set(). */
   svn_error_t *(*set)(void *cache_implementation,
                       const void *key,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/compress.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/compress.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/compress.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/compress.c Mon Jul 22 11:22:18 2013
@@ -78,7 +78,7 @@ svn__decode_uint(apr_uint64_t *val,
     end = p + SVN__MAX_ENCODED_UINT_LEN;
 
   /* Decode bytes until we're done. */
-  while SVN__PREDICT_TRUE(p < end)
+  while (SVN__PREDICT_TRUE(p < end))
     {
       unsigned int c = *p++;
 

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/io.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/io.c Mon Jul 22 11:22:18 2013
@@ -1166,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;
@@ -1178,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_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)
+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));
 }
 
 
@@ -2300,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
@@ -2345,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;

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/string.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/string.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/string.c Mon Jul 22 11:22:18 2013
@@ -1207,6 +1207,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)
@@ -1312,3 +1392,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/fsfs-improvements/subversion/libsvn_subr/subst.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/subst.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/subst.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/subst.c Mon Jul 22 11:22:18 2013
@@ -1960,7 +1960,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/fsfs-improvements/subversion/libsvn_subr/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/temp_serializer.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/temp_serializer.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/temp_serializer.c Mon Jul 22 11:22:18 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/fsfs-improvements/subversion/libsvn_subr/utf.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/utf.c Mon Jul 22 11:22:18 2013
@@ -212,6 +212,7 @@ xlate_alloc_handle(xlate_handle_node_t *
 {
   apr_status_t apr_err;
   apr_xlate_t *handle;
+  const char *name;
 
   /* The error handling doesn't support the following cases, since we don't
      use them currently.  Catch this here. */
@@ -224,8 +225,10 @@ xlate_alloc_handle(xlate_handle_node_t *
 #if defined(WIN32)
   apr_err = svn_subr__win32_xlate_open((win32_xlate_t **)&handle, topage,
                                        frompage, pool);
+  name = "win32-xlate: ";
 #else
   apr_err = apr_xlate_open(&handle, topage, frompage, pool);
+  name = "APR: ";
 #endif
 
   if (APR_STATUS_IS_EINVAL(apr_err) || APR_STATUS_IS_ENOTIMPL(apr_err))
@@ -233,6 +236,8 @@ xlate_alloc_handle(xlate_handle_node_t *
   else if (apr_err != APR_SUCCESS)
     {
       const char *errstr;
+      char apr_strerr[512];
+
       /* Can't use svn_error_wrap_apr here because it calls functions in
          this file, leading to infinite recursion. */
       if (frompage == SVN_APR_LOCALE_CHARSET)
@@ -248,7 +253,13 @@ xlate_alloc_handle(xlate_handle_node_t *
                               _("Can't create a character converter from "
                                 "'%s' to '%s'"), frompage, topage);
 
-      return svn_error_create(apr_err, NULL, errstr);
+      /* Just put the error on the stack, since svn_error_create duplicates it
+         later.  APR_STRERR will be in the local encoding, not in UTF-8, though.
+       */
+      svn_strerror(apr_err, apr_strerr, sizeof(apr_strerr));
+      return svn_error_createf(SVN_ERR_PLUGIN_LOAD_FAILURE, 
+                               svn_error_create(apr_err, NULL, apr_strerr),
+                               "%s%s", name, errstr);
     }
 
   /* Allocate and initialize the node. */

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_xlate.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_xlate.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_xlate.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_subr/win32_xlate.c Mon Jul 22 11:22:18 2013
@@ -118,11 +118,11 @@ get_page_id_from_name(UINT *page_id_p, c
     }
 
   err = svn_atomic__init_once(&com_initialized, initialize_com, NULL, pool);
-
   if (err)
     {
+      apr_status_t saved = err->apr_err;
       svn_error_clear(err);
-      return APR_EGENERAL;
+      return saved; /* probably SVN_ERR_ATOMIC_INIT_FAILURE */
     }
 
   hr = CoCreateInstance(&CLSID_CMultiLanguage, NULL, CLSCTX_INPROC_SERVER,

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_editor.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_editor.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_editor.c Mon Jul 22 11:22:18 2013
@@ -474,14 +474,18 @@ svn_wc__diff_base_working_diff(svn_wc__d
     {
       const svn_io_dirent2_t *dirent;
 
+      /* Verify truename to mimic status for iota/IOTA difference on Windows */
       SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath,
-                                  FALSE /* verify truename */,
+                                  TRUE /* verify truename */,
                                   TRUE /* ingore_enoent */,
                                   scratch_pool, scratch_pool));
 
-      if (dirent->kind == svn_node_file
-          && dirent->filesize == recorded_size
-          && dirent->mtime == recorded_time)
+      /* If a file does not exist on disk (missing/obstructed) then we
+         can't provide a text diff */
+      if (dirent->kind != svn_node_file
+          || (dirent->kind == svn_node_file
+              && dirent->filesize == recorded_size
+              && dirent->mtime == recorded_time))
         {
           files_same = TRUE;
         }

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_local.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/diff_local.c Mon Jul 22 11:22:18 2013
@@ -195,23 +195,15 @@ diff_status_callback(void *baton,
   struct diff_baton *eb = baton;
   svn_wc__db_t *db = eb->db;
 
-  switch (status->node_status)
-    {
-      case svn_wc_status_unversioned:
-      case svn_wc_status_ignored:
-        return SVN_NO_ERROR; /* No diff */
-
-      case svn_wc_status_conflicted:
-        if (status->text_status == svn_wc_status_none
-            && status->prop_status == svn_wc_status_none)
-          {
-            /* Node is an actual only node describing a tree conflict */
-            return SVN_NO_ERROR;
-          }
-        break;
+  if (! status->versioned)
+    return SVN_NO_ERROR; /* unversioned (includes dir externals) */
 
-      default:
-        break; /* Go check other conditions */
+  if (status->node_status == svn_wc_status_conflicted
+      && status->text_status == svn_wc_status_none
+      && status->prop_status == svn_wc_status_none)
+    {
+      /* Node is an actual only node describing a tree conflict */
+      return SVN_NO_ERROR;
     }
 
   /* Not text/prop modified, not copied. Easy out */

Modified: subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc_db.h?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_wc/wc_db.h Mon Jul 22 11:22:18 2013
@@ -2124,7 +2124,7 @@ svn_wc__db_read_pristine_props(apr_hash_
  * paths relative to the repository root URL for cached inherited
  * properties and absolute working copy paths otherwise.
  *
- * If ACTUAL_PROPS is not NULL, then set *ACTUAL_PROPS to the actual
+ * If ACTUAL_PROPS is not NULL, then set *ACTUAL_PROPS to ALL the actual
  * properties stored on LOCAL_ABSPATH.
  *
  * Allocate @a *iprops in @a result_pool.  Use @a scratch_pool

Modified: subversion/branches/fsfs-improvements/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/mod_dav_svn/repos.c?rev=1505660&r1=1505659&r2=1505660&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/fsfs-improvements/subversion/mod_dav_svn/repos.c Mon Jul 22 11:22:18 2013
@@ -2408,21 +2408,12 @@ get_parent_path(const char *path,
                 svn_boolean_t is_urlpath,
                 apr_pool_t *pool)
 {
-  apr_size_t len;
-  char *tmp = apr_pstrdup(pool, path);
-
-  len = strlen(tmp);
-
-  if (len > 0)
+  if (*path != '\0') /* not an empty string */
     {
-      /* Remove any trailing slash; else svn_path_dirname() asserts. */
-      if (tmp[len-1] == '/')
-        tmp[len-1] = '\0';
-
       if (is_urlpath)
-        return svn_urlpath__dirname(tmp, pool);
+        return svn_urlpath__dirname(path, pool);
       else
-        return svn_fspath__dirname(tmp, pool);
+        return svn_fspath__dirname(path, pool);
     }
 
   return path;
@@ -2458,7 +2449,9 @@ get_parent_resource(const dav_resource *
       parent->versioned = 1;
       parent->hooks = resource->hooks;
       parent->pool = resource->pool;
-      parent->uri = get_parent_path(resource->uri, TRUE, resource->pool);
+      parent->uri = get_parent_path(svn_urlpath__canonicalize(resource->uri,
+                                                              resource->pool),
+                                    TRUE, resource->pool);
       parent->info = parentinfo;
 
       parentinfo->uri_path =