subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From v...@apache.org
Subject svn commit: r1426116 [5/16] - in /subversion/branches/javahl-ra: ./ build/ build/ac-macros/ build/generator/ build/win32/ contrib/server-side/svncutter/ notes/ subversion/bindings/cxxhl/ subversion/bindings/swig/ subversion/bindings/swig/perl/native/ s...
Date Thu, 27 Dec 2012 04:03:55 GMT
Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/fs_fs.c Thu Dec 27 04:03:49 2012
@@ -360,6 +360,18 @@ path_txn_dir(svn_fs_t *fs, const char *t
                               NULL);
 }
 
+/* Return the name of the sha1->rep mapping file in transaction TXN_ID
+ * within FS for the given SHA1 checksum.  Use POOL for allocations.
+ */
+static APR_INLINE const char *
+path_txn_sha1(svn_fs_t *fs, const char *txn_id, svn_checksum_t *sha1,
+              apr_pool_t *pool)
+{
+  return svn_dirent_join(path_txn_dir(fs, txn_id, pool),
+                         svn_checksum_to_cstring(sha1, pool),
+                         pool);
+}
+
 static APR_INLINE const char *
 path_txn_changes(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
 {
@@ -2226,8 +2238,10 @@ get_cached_node_revision_body(node_revis
     }
   else
     {
-      pair_cache_key_t key = { svn_fs_fs__id_rev(id),
-                               svn_fs_fs__id_offset(id) };
+      pair_cache_key_t key;
+
+      key.revision = svn_fs_fs__id_rev(id);
+      key.second = svn_fs_fs__id_offset(id);
       SVN_ERR(svn_cache__get((void **) noderev_p,
                             is_cached,
                             ffd->node_revision_cache,
@@ -2253,8 +2267,10 @@ set_cached_node_revision_body(node_revis
 
   if (ffd->node_revision_cache && !svn_fs_fs__id_txn_id(id))
     {
-      pair_cache_key_t key = { svn_fs_fs__id_rev(id),
-                               svn_fs_fs__id_offset(id) };
+      pair_cache_key_t key;
+
+      key.revision = svn_fs_fs__id_rev(id);
+      key.second = svn_fs_fs__id_offset(id);
       return svn_cache__set(ffd->node_revision_cache,
                             &key,
                             noderev_p,
@@ -2313,10 +2329,6 @@ get_node_revision_body(node_revision_t *
                                   svn_stream_from_aprfile2(revision_file, FALSE,
                                                            pool),
                                   pool));
-  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
-  if (svn_fs_fs__id_txn_id(id) == NULL)
-    (*noderev_p)->is_fresh_txn_root = FALSE;
-
 
   /* The noderev is not in cache, yet. Add it, if caching has been enabled. */
   return set_cached_node_revision_body(*noderev_p, fs, id, pool);
@@ -2613,10 +2625,6 @@ svn_fs_fs__put_node_revision(svn_fs_t *f
   fs_fs_data_t *ffd = fs->fsap_data;
   apr_file_t *noderev_file;
   const char *txn_id = svn_fs_fs__id_txn_id(id);
-  const char *sha1 = ffd->rep_sharing_allowed && noderev->data_rep
-                   ? svn_checksum_to_cstring(noderev->data_rep->sha1_checksum,
-                                             pool)
-                   : NULL;
 
   noderev->is_fresh_txn_root = fresh_txn_root;
 
@@ -2637,13 +2645,31 @@ svn_fs_fs__put_node_revision(svn_fs_t *f
 
   SVN_ERR(svn_io_file_close(noderev_file, pool));
 
+  return SVN_NO_ERROR;
+}
+
+/* For the in-transaction NODEREV within FS, write the sha1->rep mapping
+ * file in the respective transaction, if rep sharing has been enabled etc.
+ * Use POOL for temporary allocations.
+ */
+static svn_error_t *
+store_sha1_rep_mapping(svn_fs_t *fs,
+                       node_revision_t *noderev,
+                       apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
   /* if rep sharing has been enabled and the noderev has a data rep and
    * its SHA-1 is known, store the rep struct under its SHA1. */
-  if (sha1)
+  if (   ffd->rep_sharing_allowed
+      && noderev->data_rep
+      && noderev->data_rep->sha1_checksum)
     {
       apr_file_t *rep_file;
-      const char *file_name = svn_dirent_join(path_txn_dir(fs, txn_id, pool),
-                                              sha1, pool);
+      const char *file_name = path_txn_sha1(fs,
+                                            svn_fs_fs__id_txn_id(noderev->id),
+                                            noderev->data_rep->sha1_checksum,
+                                            pool);
       const char *rep_string = representation_string(noderev->data_rep,
                                                      ffd->format,
                                                      (noderev->kind
@@ -3503,9 +3529,11 @@ parse_revprop(apr_hash_t **properties,
   SVN_ERR(svn_hash_read2(*properties, stream, SVN_HASH_TERMINATOR, pool));
   if (has_revprop_cache(fs, pool))
     {
-      pair_cache_key_t key = {revision, generation};
       fs_fs_data_t *ffd = fs->fsap_data;
+      pair_cache_key_t key;
 
+      key.revision = revision;
+      key.second = generation;
       SVN_ERR(svn_cache__set(ffd->revprop_cache, &key, *properties,
                              scratch_pool));
     }
@@ -3805,10 +3833,11 @@ get_revision_proplist(apr_hash_t **propl
   if (has_revprop_cache(fs, pool))
     {
       svn_boolean_t is_cached;
-      pair_cache_key_t key = { rev, 0};
+      pair_cache_key_t key;
 
       SVN_ERR(read_revprop_generation(&generation, fs, pool));
 
+      key.revision = rev;
       key.second = generation;
       SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
                              ffd->revprop_cache, &key, pool));
@@ -4822,8 +4851,8 @@ rep_read_get_baton(struct rep_read_baton
 /* Skip forwards to THIS_CHUNK in REP_STATE and then read the next delta
    window into *NWIN. */
 static svn_error_t *
-read_window(svn_txdelta_window_t **nwin, int this_chunk, struct rep_state *rs,
-            apr_pool_t *pool)
+read_delta_window(svn_txdelta_window_t **nwin, int this_chunk,
+                  struct rep_state *rs, apr_pool_t *pool)
 {
   svn_stream_t *stream;
   svn_boolean_t is_cached;
@@ -4870,6 +4899,27 @@ read_window(svn_txdelta_window_t **nwin,
   return set_cached_window(*nwin, rs, old_offset, pool);
 }
 
+/* Read SIZE bytes from the representation RS and return it in *NWIN. */
+static svn_error_t *
+read_plain_window(svn_stringbuf_t **nwin, struct rep_state *rs,
+                  apr_size_t size, apr_pool_t *pool)
+{
+  /* RS->FILE may be shared between RS instances -> make sure we point
+   * to the right data. */
+  SVN_ERR(svn_io_file_seek(rs->file, APR_SET, &rs->off, pool));
+
+  /* Read the plain data. */
+  *nwin = svn_stringbuf_create_ensure(size, pool);
+  SVN_ERR(svn_io_file_read_full2(rs->file, (*nwin)->data, size, NULL, NULL,
+                                 pool));
+  (*nwin)->data[size] = 0;
+
+  /* Update RS. */
+  rs->off += (apr_off_t)size;
+
+  return SVN_NO_ERROR;
+}
+
 /* Get the undeltified window that is a result of combining all deltas
    from the current desired representation identified in *RB with its
    base representation.  Store the window in *RESULT. */
@@ -4893,7 +4943,7 @@ get_combined_window(svn_stringbuf_t **re
   for (i = 0; i < rb->rs_list->nelts; ++i)
     {
       rs = APR_ARRAY_IDX(rb->rs_list, i, struct rep_state *);
-      SVN_ERR(read_window(&window, rb->chunk_index, rs, window_pool));
+      SVN_ERR(read_delta_window(&window, rb->chunk_index, rs, window_pool));
 
       APR_ARRAY_PUSH(windows, svn_txdelta_window_t *) = window;
       if (window->src_ops == 0)
@@ -4907,11 +4957,20 @@ get_combined_window(svn_stringbuf_t **re
   pool = svn_pool_create(rb->pool);
   for (--i; i >= 0; --i)
     {
+
       rs = APR_ARRAY_IDX(rb->rs_list, i, struct rep_state *);
       window = APR_ARRAY_IDX(windows, i, svn_txdelta_window_t *);
 
-      /* Combine this window with the current one. */
+      /* Maybe, we've got a PLAIN start representation.  If we do, read
+         as much data from it as the needed for the txdelta window's source
+         view.
+         Note that BUF / SOURCE may only be NULL in the first iteration. */
       source = buf;
+      if (source == NULL && rb->src_state != NULL)
+        SVN_ERR(read_plain_window(&source, rb->src_state, window->sview_len,
+                                  pool));
+
+      /* Combine this window with the current one. */
       new_pool = svn_pool_create(rb->pool);
       buf = svn_stringbuf_create_ensure(window->tview_len, new_pool);
       buf->len = window->tview_len;
@@ -5127,10 +5186,12 @@ read_representation(svn_stream_t **conte
   else
     {
       fs_fs_data_t *ffd = fs->fsap_data;
-      pair_cache_key_t fulltext_cache_key = {rep->revision, rep->offset};
+      pair_cache_key_t fulltext_cache_key;
       svn_filesize_t len = rep->expanded_size ? rep->expanded_size : rep->size;
       struct rep_read_baton *rb;
 
+      fulltext_cache_key.revision = rep->revision;
+      fulltext_cache_key.second = rep->offset;
       if (ffd->fulltext_cache && SVN_IS_VALID_REVNUM(rep->revision)
           && fulltext_size_is_cachable(ffd, len))
         {
@@ -5187,7 +5248,7 @@ delta_read_next_window(svn_txdelta_windo
       return SVN_NO_ERROR;
     }
 
-  return read_window(window, drb->rs->chunk_index, drb->rs, pool);
+  return read_delta_window(window, drb->rs->chunk_index, drb->rs, pool);
 }
 
 /* This implements the svn_txdelta_md5_digest_fn_t interface. */
@@ -5299,14 +5360,18 @@ svn_fs_fs__try_process_file_contents(svn
   if (rep)
     {
       fs_fs_data_t *ffd = fs->fsap_data;
-      pair_cache_key_t fulltext_cache_key = {rep->revision, rep->offset};
+      pair_cache_key_t fulltext_cache_key;
 
+      fulltext_cache_key.revision = rep->revision;
+      fulltext_cache_key.second = rep->offset;
       if (ffd->fulltext_cache && SVN_IS_VALID_REVNUM(rep->revision)
           && fulltext_size_is_cachable(ffd, rep->expanded_size))
         {
-          cache_access_wrapper_baton_t wrapper_baton = {processor, baton};
+          cache_access_wrapper_baton_t wrapper_baton;
           void *dummy = NULL;
 
+          wrapper_baton.func = processor;
+          wrapper_baton.baton = baton;
           return svn_cache__get_partial(&dummy, success,
                                         ffd->fulltext_cache,
                                         &fulltext_cache_key,
@@ -5602,8 +5667,10 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
     {
       fs_fs_data_t *ffd = fs->fsap_data;
       representation_t *rep = noderev->prop_rep;
-      
-      pair_cache_key_t key = { rep->revision, rep->offset };
+      pair_cache_key_t key;
+
+      key.revision = rep->revision;
+      key.second = rep->offset;
       if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
         {
           svn_boolean_t is_cached;
@@ -7039,6 +7106,7 @@ choose_delta_base(representation_t **rep
   int walk;
   node_revision_t *base;
   fs_fs_data_t *ffd = fs->fsap_data;
+  svn_boolean_t maybe_shared_rep = FALSE;
 
   /* If we have no predecessors, then use the empty stream as a
      base. */
@@ -7078,12 +7146,83 @@ choose_delta_base(representation_t **rep
      walk back two predecessors.) */
   base = noderev;
   while ((count++) < noderev->predecessor_count)
-    SVN_ERR(svn_fs_fs__get_node_revision(&base, fs,
-                                         base->predecessor_id, pool));
+    {
+      SVN_ERR(svn_fs_fs__get_node_revision(&base, fs,
+                                           base->predecessor_id, pool));
+
+      /* If there is a shared rep along the way, we need to limit the
+       * length of the deltification chain.
+       * 
+       * Please note that copied nodes - such as branch directories - will
+       * look the same (false positive) while reps shared within the same
+       * revision will not be caught (false negative).
+       */
+      if (props)
+        {
+          if (   base->prop_rep
+              && svn_fs_fs__id_rev(base->id) > base->prop_rep->revision)
+            maybe_shared_rep = TRUE;
+        }
+      else
+        {
+          if (   base->data_rep
+              && svn_fs_fs__id_rev(base->id) > base->data_rep->revision)
+            maybe_shared_rep = TRUE;
+        }
+    }
 
   /* return a suitable base representation */
   *rep = props ? base->prop_rep : base->data_rep;
 
+  /* if we encountered a shared rep, it's parent chain may be different
+   * from the node-rev parent chain. */
+  if (*rep && maybe_shared_rep)
+    {
+      /* Check whether the length of the deltification chain is acceptable.
+       * Otherwise, shared reps may form a non-skipping delta chain in
+       * extreme cases. */
+      apr_pool_t *sub_pool = svn_pool_create(pool);
+      representation_t base_rep = **rep;
+      
+      /* Some reasonable limit, depending on how acceptable longer linear
+       * chains are in this repo.  Also, allow for some minimal chain. */
+      int max_chain_length = 2 * (int)ffd->max_linear_deltification + 2;
+
+      /* re-use open files between iterations */
+      svn_revnum_t rev_hint = SVN_INVALID_REVNUM;
+      apr_file_t *file_hint = NULL;
+
+      /* follow the delta chain towards the end but for at most
+       * MAX_CHAIN_LENGTH steps. */
+      for (; max_chain_length; --max_chain_length)
+        {
+          struct rep_state *rep_state;
+          struct rep_args *rep_args;
+
+          SVN_ERR(create_rep_state_body(&rep_state,
+                                        &rep_args,
+                                        &file_hint,
+                                        &rev_hint,
+                                        &base_rep,
+                                        fs,
+                                        sub_pool));
+          if (!rep_args->is_delta  || !rep_args->base_revision)
+            break;
+
+          base_rep.revision = rep_args->base_revision;
+          base_rep.offset = rep_args->base_offset;
+          base_rep.size = rep_args->base_length;
+          base_rep.txn_id = NULL;
+        }
+
+      /* start new delta chain if the current one has grown too long */
+      if (max_chain_length == 0)
+        *rep = NULL;
+
+      apr_pool_destroy(sub_pool);
+    }
+
+  /* verify that the reps don't form a degenerated '*/
   return SVN_NO_ERROR;
 }
 
@@ -7100,22 +7239,14 @@ rep_write_cleanup(void *data)
   
   /* Truncate and close the protorevfile. */
   err = svn_io_file_trunc(b->file, b->rep_offset, b->pool);
-  if (err)
-    {
-      apr_status_t rc = err->apr_err;
-      svn_error_clear(err);
-      return rc;
-    }
-  err = svn_io_file_close(b->file, b->pool);
-  if (err)
-    {
-      apr_status_t rc = err->apr_err;
-      svn_error_clear(err);
-      return rc;
-    }
+  err = svn_error_compose_create(err, svn_io_file_close(b->file, b->pool));
 
-  /* Remove our lock */
-  err = unlock_proto_rev(b->fs, txn_id, b->lockcookie, b->pool);
+  /* Remove our lock regardless of any preceeding errors so that the 
+     being_written flag is always removed and stays consistent with the
+     file lock which will be removed no matter what since the pool is
+     going away. */
+  err = svn_error_compose_create(err, unlock_proto_rev(b->fs, txn_id,
+                                                       b->lockcookie, b->pool));
   if (err)
     {
       apr_status_t rc = err->apr_err;
@@ -7279,9 +7410,7 @@ get_shared_rep(representation_t **old_re
     {
       svn_node_kind_t kind;
       const char *file_name
-        = svn_dirent_join(path_txn_dir(fs, rep->txn_id, pool),
-                          svn_checksum_to_cstring(rep->sha1_checksum, pool),
-                          pool);
+        = path_txn_sha1(fs, rep->txn_id, rep->sha1_checksum, pool);
 
       /* in our txn, is there a rep file named with the wanted SHA1?
          If so, read it and use that rep.
@@ -7371,6 +7500,8 @@ rep_write_contents_close(void *baton)
   /* Write out the new node-rev information. */
   SVN_ERR(svn_fs_fs__put_node_revision(b->fs, b->noderev->id, b->noderev, FALSE,
                                        b->pool));
+  if (!old_rep)
+    SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->pool));
 
   SVN_ERR(svn_io_file_close(b->file, b->pool));
   SVN_ERR(unlock_proto_rev(b->fs, rep->txn_id, b->lockcookie, b->pool));
@@ -8004,9 +8135,13 @@ write_final_rev(const svn_fs_id_t **new_
   if (noderev->prop_rep)
     noderev->prop_rep->sha1_checksum = NULL;
 
+  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
+  noderev->is_fresh_txn_root = FALSE;
+
   /* Write out our new node-revision. */
   if (at_root)
     SVN_ERR(validate_root_noderev(fs, noderev, rev, pool));
+
   SVN_ERR(svn_fs_fs__write_noderev(svn_stream_from_aprfile2(file, TRUE, pool),
                                    noderev, ffd->format,
                                    svn_fs_fs__fs_supports_mergeinfo(fs),

Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/rep-cache.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/rep-cache.c Thu Dec 27 04:03:49 2012
@@ -76,26 +76,30 @@ open_rep_cache(void *baton,
 {
   svn_fs_t *fs = baton;
   fs_fs_data_t *ffd = fs->fsap_data;
+  svn_sqlite__db_t *sdb;
   const char *db_path;
   int version;
 
   /* Open (or create) the sqlite database.  It will be automatically
      closed when fs->pool is destoyed. */
   db_path = path_rep_cache_db(fs->path, pool);
-  SVN_ERR(svn_sqlite__open(&ffd->rep_cache_db, db_path,
+  SVN_ERR(svn_sqlite__open(&sdb, db_path,
                            svn_sqlite__mode_rwcreate, statements,
                            0, NULL,
                            fs->pool, pool));
 
-  SVN_ERR(svn_sqlite__read_schema_version(&version, ffd->rep_cache_db, pool));
+  SVN_ERR(svn_sqlite__read_schema_version(&version, sdb, pool));
   if (version < REP_CACHE_SCHEMA_FORMAT)
     {
       /* Must be 0 -- an uninitialized (no schema) database. Create
          the schema. Results in schema version of 1.  */
-      SVN_ERR(svn_sqlite__exec_statements(ffd->rep_cache_db,
-                                          STMT_CREATE_SCHEMA));
+      SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_SCHEMA));
     }
 
+  /* This is used as a flag that the database is available so don't
+     set it earlier. */
+  ffd->rep_cache_db = sdb;
+
   return SVN_NO_ERROR;
 }
 
@@ -151,16 +155,15 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
   /* Check global invariants. */
   if (start == 0)
     {
-      svn_sqlite__stmt_t *stmt2;
       svn_revnum_t max;
 
-      SVN_ERR(svn_sqlite__get_statement(&stmt2, ffd->rep_cache_db,
+      SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db,
                                         STMT_GET_MAX_REV));
-      SVN_ERR(svn_sqlite__step(&have_row, stmt2));
-      max = svn_sqlite__column_revnum(stmt2, 0);
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      max = svn_sqlite__column_revnum(stmt, 0);
+      SVN_ERR(svn_sqlite__reset(stmt));
       if (SVN_IS_VALID_REVNUM(max))  /* The rep-cache could be empty. */
         SVN_ERR(svn_fs_fs__revision_exists(max, fs, iterpool));
-      SVN_ERR(svn_sqlite__reset(stmt2));
     }
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db,
@@ -174,6 +177,7 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
     {
       representation_t *rep;
       const char *sha1_digest;
+      svn_error_t *err;
 
       /* Clear ITERPOOL occasionally. */
       if (iterations++ % 16 == 0)
@@ -181,21 +185,29 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
 
       /* Check for cancellation. */
       if (cancel_func)
-        SVN_ERR(cancel_func(cancel_baton));
+        {
+          err = cancel_func(cancel_baton);
+          if (err)
+            return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+        }
 
       /* Construct a representation_t. */
       rep = apr_pcalloc(iterpool, sizeof(*rep));
       sha1_digest = svn_sqlite__column_text(stmt, 0, iterpool);
-      SVN_ERR(svn_checksum_parse_hex(&rep->sha1_checksum,
-                                     svn_checksum_sha1, sha1_digest,
-                                     iterpool));
+      err = svn_checksum_parse_hex(&rep->sha1_checksum,
+                                   svn_checksum_sha1, sha1_digest,
+                                   iterpool);
+      if (err)
+        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
       rep->revision = svn_sqlite__column_revnum(stmt, 1);
       rep->offset = svn_sqlite__column_int64(stmt, 2);
       rep->size = svn_sqlite__column_int64(stmt, 3);
       rep->expanded_size = svn_sqlite__column_int64(stmt, 4);
 
       /* Walk. */
-      SVN_ERR(walker(rep, walker_baton, fs, iterpool));
+      err = walker(rep, walker_baton, fs, iterpool);
+      if (err)
+        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
@@ -247,10 +259,12 @@ svn_fs_fs__get_rep_reference(representat
   else
     *rep = NULL;
 
+  SVN_ERR(svn_sqlite__reset(stmt));
+
   if (*rep)
     SVN_ERR(rep_has_been_born(*rep, fs, pool));
 
-  return svn_sqlite__reset(stmt);
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/structure?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/structure Thu Dec 27 04:03:49 2012
@@ -526,6 +526,7 @@ A transaction directory has the followin
   node.<nid>.<cid>           New node-rev data for node
   node.<nid>.<cid>.props     Props for new node-rev, if changed
   node.<nid>.<cid>.children  Directory contents for node-rev
+  <sha1>                     Text representation of that sha1
 
 In FS formats 1 and 2, it also contains:
 
@@ -543,6 +544,11 @@ The two kinds of props files are all in 
 file will always be present.  The "node.<nid>.<cid>.props" file will
 only be present if the node-rev properties have been changed.
 
+The <sha1> files have been introduced in FS format 6. Their content
+is that of text rep references: "<rev> <offset> <length> <size> <digest>"
+They will be written for text reps in the current transaction and be
+used to eliminate duplicate reps within that transaction.
+
 The "next-ids" file contains a single line "<next-temp-node-id>
 <next-temp-copy-id>\n" giving the next temporary node-ID and copy-ID
 assignments (without the leading underscores).  The next node-ID is

Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/temp_serializer.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/temp_serializer.c Thu Dec 27 04:03:49 2012
@@ -88,27 +88,6 @@ svn_fs_fs__combine_number_and_string(apr
   return key;
 }
 
-const char*
-svn_fs_fs__combine_two_numbers(apr_int64_t a,
-                               apr_int64_t b,
-                               apr_pool_t *pool)
-{
-  /* encode numbers as 2x 10x7 bits + 1 space + 1 terminating \0*/
-  char *key_buffer = apr_palloc(pool, 22);
-  const char *key = key_buffer;
-
-  /* combine the numbers. Since the separator is disjoint from any part
-   * of the encoded numbers, there is no other combination that can yield
-   * the same result */
-  key_buffer = encode_number(a, key_buffer);
-  *++key_buffer = ' ';
-  key_buffer = encode_number(b, ++key_buffer);
-  *++key_buffer = '\0';
-
-  /* return the start of the key */
-  return key;
-}
-
 /* Utility function to serialize string S in the given serialization CONTEXT.
  */
 static void

Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/temp_serializer.h?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/temp_serializer.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/temp_serializer.h Thu Dec 27 04:03:49 2012
@@ -36,16 +36,6 @@ svn_fs_fs__combine_number_and_string(apr
                                      apr_pool_t *pool);
 
 /**
- * Combine the numbers @a a and @a b in a space efficient way such that no
- * other combination of numbers can produce the same result.
- * Allocate temporaries as well as the result from @a pool.
- */
-const char*
-svn_fs_fs__combine_two_numbers(apr_int64_t a,
-                               apr_int64_t b,
-                               apr_pool_t *pool);
-
-/**
  * Serialize a @a noderev_p within the serialization @a context.
  */
 void

Modified: subversion/branches/javahl-ra/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_fs_fs/tree.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_fs_fs/tree.c Thu Dec 27 04:03:49 2012
@@ -3243,7 +3243,7 @@ prev_location(const char **prev_path,
   */
   SVN_ERR(fs_copied_from(&copy_src_rev, &copy_src_path,
                          copy_root, copy_path, pool));
-  remainder_path = svn_relpath_skip_ancestor(copy_path, path);
+  remainder_path = svn_fspath__skip_ancestor(copy_path, path);
   *prev_path = svn_fspath__join(copy_src_path, remainder_path, pool);
   *prev_rev = copy_src_rev;
   return SVN_NO_ERROR;

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra/compat.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra/compat.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra/compat.c Thu Dec 27 04:03:49 2012
@@ -630,7 +630,6 @@ fr_log_message_receiver(void *baton,
 {
   struct fr_log_message_baton *lmb = baton;
   struct rev *rev;
-  apr_hash_index_t *hi;
 
   rev = apr_palloc(lmb->pool, sizeof(*rev));
   rev->revision = log_entry->revision;
@@ -639,17 +638,7 @@ fr_log_message_receiver(void *baton,
   lmb->eldest = rev;
 
   /* Duplicate log_entry revprops into rev->props */
-  rev->props = apr_hash_make(lmb->pool);
-  for (hi = apr_hash_first(pool, log_entry->revprops); hi;
-       hi = apr_hash_next(hi))
-    {
-      void *val;
-      const void *key;
-
-      apr_hash_this(hi, &key, NULL, &val);
-      apr_hash_set(rev->props, apr_pstrdup(lmb->pool, key), APR_HASH_KEY_STRING,
-                   svn_string_dup(val, lmb->pool));
-    }
+  rev->props = svn_prop_hash_dup(log_entry->revprops, lmb->pool);
 
   return prev_log_path(&lmb->path, &lmb->action,
                        &lmb->copyrev, log_entry->changed_paths2,

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra/ra_loader.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra/ra_loader.c Thu Dec 27 04:03:49 2012
@@ -140,8 +140,8 @@ load_ra_module(svn_ra__init_func_t *func
     const char *compat_funcname;
     apr_status_t status;
 
-    libname = apr_psprintf(pool, "libsvn_ra_%s-%d.so.0",
-                           ra_name, SVN_VER_MAJOR);
+    libname = apr_psprintf(pool, "libsvn_ra_%s-%d.so.%d",
+                           ra_name, SVN_VER_MAJOR, SVN_SOVERSION);
     funcname = apr_psprintf(pool, "svn_ra_%s__init", ra_name);
     compat_funcname = apr_psprintf(pool, "svn_ra_%s_init", ra_name);
 

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_local/ra_plugin.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_local/ra_plugin.c Thu Dec 27 04:03:49 2012
@@ -1064,7 +1064,7 @@ get_node_props(apr_hash_t **props,
       int i;
 
       SVN_ERR(svn_repos_fs_get_inherited_props(inherited_props, root, path,
-                                               NULL, NULL,
+                                               NULL, NULL, NULL,
                                                result_pool, scratch_pool));
 
       for (i = 0; i < (*inherited_props)->nelts; i++)

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/commit.c Thu Dec 27 04:03:49 2012
@@ -1466,16 +1466,10 @@ open_root(void *edit_baton,
       for (hi = apr_hash_first(ctx->pool, ctx->revprop_table); hi;
            hi = apr_hash_next(hi))
         {
-          const void *key;
-          void *val;
-          const char *name;
-          svn_string_t *value;
+          const char *name = svn__apr_hash_index_key(hi);
+          svn_string_t *value = svn__apr_hash_index_val(hi);
           const char *ns;
 
-          apr_hash_this(hi, &key, NULL, &val);
-          name = key;
-          value = val;
-
           if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)
             {
               ns = SVN_DAV_PROP_NS_SVN;
@@ -2267,7 +2261,6 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_delta_editor_t *editor;
   commit_context_t *ctx;
-  apr_hash_index_t *hi;
   const char *repos_root;
   const char *base_relpath;
   svn_boolean_t supports_ephemeral_props;
@@ -2279,17 +2272,7 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   ctx->session = session;
   ctx->conn = session->conns[0];
 
-  ctx->revprop_table = apr_hash_make(pool);
-  for (hi = apr_hash_first(pool, revprop_table); hi; hi = apr_hash_next(hi))
-    {
-      const void *key;
-      apr_ssize_t klen;
-      void *val;
-
-      apr_hash_this(hi, &key, &klen, &val);
-      apr_hash_set(ctx->revprop_table, apr_pstrdup(pool, key), klen,
-                   svn_string_dup(val, pool));
-    }
+  ctx->revprop_table = svn_prop_hash_dup(revprop_table, pool);
 
   /* If the server supports ephemeral properties, add some carrying
      interesting version information. */

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/inherited_props.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/inherited_props.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/inherited_props.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/inherited_props.c Thu Dec 27 04:03:49 2012
@@ -277,8 +277,7 @@ svn_ra_serf__get_inherited_props(svn_ra_
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
 {
-  svn_error_t *err, *err2;
-
+  svn_error_t *err;
   iprops_context_t *iprops_ctx;
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
@@ -293,6 +292,8 @@ svn_ra_serf__get_inherited_props(svn_ra_
                                       revision,
                                       result_pool, scratch_pool));
 
+  SVN_ERR_ASSERT(session->repos_root_str);
+
   iprops_ctx = apr_pcalloc(scratch_pool, sizeof(*iprops_ctx));
   iprops_ctx->done = FALSE;
   iprops_ctx->repos_root_url = session->repos_root_str;
@@ -329,20 +330,12 @@ svn_ra_serf__get_inherited_props(svn_ra_
   handler->response_handler = svn_ra_serf__handle_xml_parser;
   handler->response_baton = parser_ctx;
 
-  svn_ra_serf__request_create(handler);
-
-  err = svn_ra_serf__context_run_wait(&iprops_ctx->done, session,
-                                      scratch_pool);
-
-  err2 = svn_ra_serf__error_on_status(handler->sline.code, handler->path,
-                                      handler->location);
-  if (err2)
-    {
-      svn_error_clear(err);
-      return err2;
-    }
-
-  SVN_ERR(err);
+  err = svn_ra_serf__context_run_one(handler, scratch_pool);
+  SVN_ERR(svn_error_compose_create(
+                    svn_ra_serf__error_on_status(handler->sline.code,
+                                                 handler->path,
+                                                 handler->location),
+                    err));
 
   if (iprops_ctx->done)
     *iprops = iprops_ctx->iprops;

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/options.c Thu Dec 27 04:03:49 2012
@@ -280,6 +280,10 @@ capabilities_headers_iterator_callback(v
         {
           opt_ctx->youngest_rev = SVN_STR_TO_REV(val);
         }
+      else if (svn_cstring_casecmp(key, SVN_DAV_ALLOW_BULK_UPDATES) == 0)
+        {
+          session->server_allows_bulk = apr_pstrdup(session->pool, val);
+        }
       else if (svn_cstring_casecmp(key, SVN_DAV_SUPPORTED_POSTS_HEADER) == 0)
         {
           /* May contain multiple values, separated by commas. */

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/ra_serf.h Thu Dec 27 04:03:49 2012
@@ -94,10 +94,12 @@ typedef struct svn_ra_serf__connection_t
 
 } svn_ra_serf__connection_t;
 
-/** Max. number of connctions we'll open to the server. 
- *  Note: minimum 2 connections are required for ra_serf to function correctly!
+/** Maximum value we'll allow for the http-max-connections config option.
+ *
+ * Note: minimum 2 connections are required for ra_serf to function
+ * correctly!
  */
-#define MAX_NR_OF_CONNS 4
+#define SVN_RA_SERF__MAX_CONNECTIONS_LIMIT 8
 
 /*
  * The master serf RA session.
@@ -111,6 +113,10 @@ struct svn_ra_serf__session_t {
   /* The current context */
   serf_context_t *context;
 
+  /* The maximum number of connections we'll use for parallelized
+     fetch operations (updates, etc.) */
+  apr_int64_t max_connections;
+
   /* Are we using ssl */
   svn_boolean_t using_ssl;
 
@@ -121,7 +127,7 @@ struct svn_ra_serf__session_t {
   const char *useragent;
 
   /* The current connection */
-  svn_ra_serf__connection_t *conns[MAX_NR_OF_CONNS];
+  svn_ra_serf__connection_t *conns[SVN_RA_SERF__MAX_CONNECTIONS_LIMIT];
   int num_conns;
   int cur_conn;
 
@@ -189,7 +195,7 @@ struct svn_ra_serf__session_t {
   const char *uuid;
 
   /* Connection timeout value */
-  apr_short_interval_time_t timeout;
+  apr_interval_time_t timeout;
 
   /* HTTPv1 flags */
   svn_tristate_t supports_deadprop_count;
@@ -223,6 +229,16 @@ struct svn_ra_serf__session_t {
   /*** End HTTP v2 stuff ***/
 
   svn_ra_serf__blncache_t *blncache;
+
+  /* Flag that indicates if we request the server for bulk updates (TRUE) with
+     all the properties and content in the update-report response. If FALSE,
+     request a skelta update-report with inlined properties. */
+  svn_boolean_t bulk_updates;
+
+  /* Indicates if the server wants bulk update requests (Prefer) or only
+     accepts skelta requests (Off). If this value is On both options are 
+     allowed. */
+  const char *server_allows_bulk;
 };
 
 #define SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(sess) ((sess)->me_resource != NULL)

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/replay.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/replay.c Thu Dec 27 04:03:49 2012
@@ -655,7 +655,7 @@ svn_ra_serf__replay(svn_ra_session_t *ra
 
   handler->handler_pool = pool;
   handler->method = "REPORT";
-  handler->path = session->session_url_str;
+  handler->path = session->session_url.path;
   handler->body_delegate = create_replay_body;
   handler->body_delegate_baton = replay_ctx;
   handler->body_type = "text/xml";
@@ -698,8 +698,8 @@ svn_ra_serf__replay(svn_ra_session_t *ra
  * optimally. Originally we used 5 as the max. number of outstanding
  * requests, but this turned out to be too low.
  *
- * Serf doesn't exit out of the serf_context_run loop as long as it
- * has data to send or receive. With small responses (revs of a few
+ * Serf doesn't exit out of the svn_ra_serf__context_run_wait loop as long as
+ * it has data to send or receive. With small responses (revs of a few
  * kB), serf doesn't come out of this loop at all. So with
  * MAX_OUTSTANDING_REQUESTS set to a low number, there's a big chance
  * that serf handles those requests completely in its internal loop,
@@ -732,14 +732,11 @@ svn_ra_serf__replay_range(svn_ra_session
   svn_revnum_t rev = start_revision;
   const char *report_target;
   int active_reports = 0;
-  apr_short_interval_time_t waittime_left = session->timeout;
 
   SVN_ERR(svn_ra_serf__report_resource(&report_target, session, NULL, pool));
 
   while (active_reports || rev <= end_revision)
     {
-      apr_status_t status;
-      svn_error_t *err;
       svn_ra_serf__list_t *done_list;
       svn_ra_serf__list_t *done_reports = NULL;
       replay_context_t *replay_ctx;
@@ -798,7 +795,7 @@ svn_ra_serf__replay_range(svn_ra_session
 
           handler->handler_pool = replay_ctx->src_rev_pool;
           handler->method = "REPORT";
-          handler->path = session->session_url_str;
+          handler->path = session->session_url.path;
           handler->body_delegate = create_replay_body;
           handler->body_delegate_baton = replay_ctx;
           handler->conn = session->conns[0];
@@ -834,59 +831,8 @@ svn_ra_serf__replay_range(svn_ra_session
           active_reports++;
         }
 
-      /* Run the serf loop, send outgoing and process incoming requests.
-         This request will block when there are no more requests to send or
-         responses to receive, so we have to be careful on our bookkeeping.
-
-         ### we should probably adjust this timeout. if we get (say) 3
-         ### requests completed, then we want to exit immediately rather
-         ### than block for a few seconds. that will allow us to clear up
-         ### those 3 requests. if we have queued all of our revisions,
-         ### then we may want to block until timeout since we really don't
-         ### have much work other than destroying memory. (though that
-         ### is important, as we could end up with 50 src_rev_pool pools)
-
-         ### idea: when a revision is marked DONE, we can probably destroy
-         ### most of the memory. that will reduce pressue to have serf
-         ### return control to us, to complete the major memory disposal.
-
-         ### theoretically, we should use an iterpool here, but it turns
-         ### out that serf doesn't even use the pool param. if we grow
-         ### an iterpool in this loop for other purposes, then yeah: go
-         ### ahead and apply it here, too, in case serf eventually uses
-         ### that parameter.
-      */
-      status = serf_context_run(session->context,
-                                SVN_RA_SERF__CONTEXT_RUN_DURATION,
-                                pool);
-
-      err = session->pending_error;
-      session->pending_error = NULL;
-
-      /* If the context duration timeout is up, we'll subtract that
-         duration from the total time alloted for such things.  If
-         there's no time left, we fail with a message indicating that
-         the connection timed out.  */
-      if (APR_STATUS_IS_TIMEUP(status))
-        {
-          svn_error_clear(err);
-          err = SVN_NO_ERROR;
-          status = 0;
-
-          if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
-            {
-              waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
-            }
-          else
-            {
-              return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
-                                      _("Connection timed out"));
-            }
-        }
-      else
-        {
-          waittime_left = session->timeout;
-        }
+      /* Run the serf loop. */
+      SVN_ERR(svn_ra_serf__context_run_wait(&replay_ctx->done, session, pool));
 
       /* Substract the number of completely handled responses from our
          total nr. of open requests', so we'll know when to stop this loop.
@@ -901,12 +847,6 @@ svn_ra_serf__replay_range(svn_ra_session
           active_reports--;
         }
 
-      SVN_ERR(err);
-      if (status)
-        {
-          return svn_ra_serf__wrap_err(status,
-                                       _("Error retrieving replay REPORT"));
-        }
       done_reports = NULL;
     }
 

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/serf.c Thu Dec 27 04:03:49 2012
@@ -131,7 +131,11 @@ load_http_auth_types(apr_pool_t *pool, s
 
   return SVN_NO_ERROR;
 }
-#define DEFAULT_HTTP_TIMEOUT 3600
+
+/* Default HTTP timeout (in seconds); overridden by the 'http-timeout'
+   runtime configuration variable. */
+#define DEFAULT_HTTP_TIMEOUT 600
+
 static svn_error_t *
 load_config(svn_ra_serf__session_t *session,
             apr_hash_t *config_hash,
@@ -144,7 +148,6 @@ load_config(svn_ra_serf__session_t *sess
   const char *timeout_str = NULL;
   const char *exceptions;
   apr_port_t proxy_port;
-  svn_boolean_t is_exception = FALSE;
 
   if (config_hash)
     {
@@ -187,23 +190,21 @@ load_config(svn_ra_serf__session_t *sess
                  SVN_CONFIG_OPTION_HTTP_PROXY_EXCEPTIONS, NULL);
   if (exceptions)
     {
-      apr_array_header_t *l = svn_cstring_split(exceptions, ",", TRUE, pool);
-      is_exception = svn_cstring_match_glob_list(session->session_url.hostname,
-                                                 l);
-    }
-  if (! is_exception)
-    {
-      /* Load the global proxy server settings, if set. */
-      svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
-      svn_config_get(config, &port_str, SVN_CONFIG_SECTION_GLOBAL,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
-      svn_config_get(config, &session->proxy_username,
-                     SVN_CONFIG_SECTION_GLOBAL,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
-      svn_config_get(config, &session->proxy_password,
-                     SVN_CONFIG_SECTION_GLOBAL,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
+      if (! svn_cstring_match_glob_list(session->session_url.hostname,
+                                        svn_cstring_split(exceptions, ",",
+                                                          TRUE, pool)))
+        {
+          svn_config_get(config, &proxy_host, SVN_CONFIG_SECTION_GLOBAL,
+                         SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
+          svn_config_get(config, &port_str, SVN_CONFIG_SECTION_GLOBAL,
+                         SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
+          svn_config_get(config, &session->proxy_username,
+                         SVN_CONFIG_SECTION_GLOBAL,
+                         SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
+          svn_config_get(config, &session->proxy_password,
+                         SVN_CONFIG_SECTION_GLOBAL,
+                         SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
+        }
     }
 
   /* Load the global ssl settings, if set. */
@@ -214,6 +215,19 @@ load_config(svn_ra_serf__session_t *sess
   svn_config_get(config, &session->ssl_authorities, SVN_CONFIG_SECTION_GLOBAL,
                  SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES, NULL);
 
+  /* If set, read the flag that tells us to do bulk updates or not. Defaults
+     to skelta updates. */
+  SVN_ERR(svn_config_get_bool(config, &session->bulk_updates,
+                              SVN_CONFIG_SECTION_GLOBAL,
+                              SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
+                              FALSE));
+
+  /* Load the maximum number of parallel session connections. */
+  svn_config_get_int64(config, &session->max_connections,
+                       SVN_CONFIG_SECTION_GLOBAL,
+                       SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS,
+                       SVN_CONFIG_DEFAULT_OPTION_HTTP_MAX_CONNECTIONS);
+
   if (config)
     server_group = svn_config_find_group(config,
                                          session->session_url.hostname,
@@ -233,26 +247,53 @@ load_config(svn_ra_serf__session_t *sess
       svn_auth_set_parameter(session->wc_callbacks->auth_baton,
                              SVN_AUTH_PARAM_SERVER_GROUP, server_group);
 
-      /* Load the group proxy server settings, overriding global settings. */
+      /* Load the group proxy server settings, overriding global
+         settings.  We intentionally ignore 'http-proxy-exceptions'
+         here because, well, if this site was an exception, why is
+         there a per-server proxy configuration for it?  */
       svn_config_get(config, &proxy_host, server_group,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_HOST, NULL);
+                     SVN_CONFIG_OPTION_HTTP_PROXY_HOST, proxy_host);
       svn_config_get(config, &port_str, server_group,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_PORT, NULL);
+                     SVN_CONFIG_OPTION_HTTP_PROXY_PORT, port_str);
       svn_config_get(config, &session->proxy_username, server_group,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME, NULL);
+                     SVN_CONFIG_OPTION_HTTP_PROXY_USERNAME,
+                     session->proxy_username);
       svn_config_get(config, &session->proxy_password, server_group,
-                     SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD, NULL);
+                     SVN_CONFIG_OPTION_HTTP_PROXY_PASSWORD,
+                     session->proxy_password);
 
       /* Load the group ssl settings. */
       SVN_ERR(svn_config_get_bool(config, &session->trust_default_ca,
                                   server_group,
                                   SVN_CONFIG_OPTION_SSL_TRUST_DEFAULT_CA,
-                                  TRUE));
+                                  session->trust_default_ca));
       svn_config_get(config, &session->ssl_authorities, server_group,
-                     SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES, NULL);
-    }
+                     SVN_CONFIG_OPTION_SSL_AUTHORITY_FILES,
+                     session->ssl_authorities);
+
+      /* Load the group bulk updates flag. */
+      SVN_ERR(svn_config_get_bool(config, &session->bulk_updates,
+                                  server_group,
+                                  SVN_CONFIG_OPTION_HTTP_BULK_UPDATES,
+                                  session->bulk_updates));
+
+      /* Load the maximum number of parallel session connections,
+         overriding global values. */
+      svn_config_get_int64(config, &session->max_connections,
+                           server_group, SVN_CONFIG_OPTION_HTTP_MAX_CONNECTIONS,
+                           session->max_connections);
+    }
+
+  /* Don't allow the http-max-connections value to be larger than our
+     compiled-in limit, or to be too small to operate.  Broken
+     functionality and angry administrators are equally undesirable. */
+  if (session->max_connections > SVN_RA_SERF__MAX_CONNECTIONS_LIMIT)
+    session->max_connections = SVN_RA_SERF__MAX_CONNECTIONS_LIMIT;
+  if (session->max_connections < 2)
+    session->max_connections = 2;
 
   /* Parse the connection timeout value, if any. */
+  session->timeout = apr_time_from_sec(DEFAULT_HTTP_TIMEOUT);
   if (timeout_str)
     {
       char *endstr;
@@ -267,13 +308,7 @@ load_config(svn_ra_serf__session_t *sess
                                 _("Invalid config: negative timeout value"));
       session->timeout = apr_time_from_sec(timeout);
     }
-  else
-    session->timeout = apr_time_from_sec(DEFAULT_HTTP_TIMEOUT);
-
-  if (session->timeout < 0) /* Always true for DEFAULT_HTTP_TIMEOUT */
-    session->timeout = apr_time_from_sec(600); /* 10 min */
-
-  SVN_ERR_ASSERT(session->timeout > 0);
+  SVN_ERR_ASSERT(session->timeout >= 0);
 
   /* Convert the proxy port value, if any. */
   if (port_str)
@@ -295,7 +330,9 @@ load_config(svn_ra_serf__session_t *sess
       proxy_port = (apr_port_t) port;
     }
   else
-    proxy_port = 80;
+    {
+      proxy_port = 80;
+    }
 
   if (proxy_host)
     {
@@ -315,7 +352,9 @@ load_config(svn_ra_serf__session_t *sess
       serf_config_proxy(session->context, proxy_addr);
     }
   else
-    session->using_proxy = FALSE;
+    {
+      session->using_proxy = FALSE;
+    }
 
   /* Setup authentication. */
   SVN_ERR(load_http_auth_types(pool, config, server_group,

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/update.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/update.c Thu Dec 27 04:03:49 2012
@@ -63,13 +63,19 @@
  */
 typedef enum report_state_e {
     NONE = 0,
+    INITIAL = 0,
+    UPDATE_REPORT,
+    TARGET_REVISION,
     OPEN_DIR,
     ADD_DIR,
+    ABSENT_DIR,
     OPEN_FILE,
     ADD_FILE,
+    ABSENT_FILE,
     PROP,
     IGNORE_PROP_NAME,
-    NEED_PROP_NAME
+    NEED_PROP_NAME,
+    TXDELTA
 } report_state_e;
 
 
@@ -223,6 +229,8 @@ typedef struct report_info_t
   const char *final_sha1_checksum;
   svn_txdelta_window_handler_t textdelta;
   void *textdelta_baton;
+  svn_stream_t *svndiff_decoder;
+  svn_stream_t *base64_decoder;
 
   /* Checksum for close_file */
   const char *final_checksum;
@@ -313,6 +321,9 @@ struct report_context_t {
   /* Do we want the server to send copyfrom args or not? */
   svn_boolean_t send_copyfrom_args;
 
+  /* Is the server sending everything in one response? */
+  svn_boolean_t send_all_mode;
+
   /* Is the server including properties inline for newly added
      files/dirs? */
   svn_boolean_t add_props_included;
@@ -352,6 +363,10 @@ struct report_context_t {
 
   /* completed PROPFIND requests (contains svn_ra_serf__handler_t) */
   svn_ra_serf__list_t *done_propfinds;
+  svn_ra_serf__list_t *done_dir_propfinds;
+
+  /* list of outstanding prop changes (contains report_dir_t) */
+  svn_ra_serf__list_t *active_dir_propfinds;
 
   /* list of files that only have prop changes (contains report_info_t) */
   svn_ra_serf__list_t *file_propchanges_only;
@@ -370,32 +385,160 @@ struct report_context_t {
 
   /* The XML parser context for the REPORT response.  */
   svn_ra_serf__xml_parser_t *parser_ctx;
+
+  /* Did we close the root directory? */
+  svn_boolean_t closed_root;
 };
 
-/* Returns best connection for fetching files/properties. */
-static svn_ra_serf__connection_t *
-get_best_connection(report_context_t *ctx)
+
+#ifdef NOT_USED_YET
+
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t update_ttable[] = {
+  { INITIAL, S_, "update-report", UPDATE_REPORT,
+    FALSE, { NULL }, FALSE },
+
+  { UPDATE_REPORT, S_, "target-revision", TARGET_REVISION,
+    FALSE, { "rev", NULL }, TRUE },
+
+  { UPDATE_REPORT, S_, "open-directory", OPEN_DIR,
+    FALSE, { "rev", NULL }, TRUE },
+
+  { OPEN_DIR, S_, "open-directory", OPEN_DIR,
+    FALSE, { "rev", "name", NULL }, TRUE },
+
+  { OPEN_DIR, S_, "add-directory", ADD_DIR,
+    FALSE, { "rev", "name", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
+
+  { ADD_DIR, S_, "add-directory", ADD_DIR,
+    FALSE, { "rev", "name", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
+
+  { OPEN_DIR, S_, "open-file", OPEN_FILE,
+    FALSE, { "rev", "name", NULL }, TRUE },
+
+  { OPEN_DIR, S_, "add-file", ADD_FILE,
+    FALSE, { "rev", "name", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
+
+  { ADD_DIR, S_, "add-file", ADD_FILE,
+    FALSE, { "rev", "name", "?copyfrom-path", "?copyfrom-rev", NULL }, TRUE },
+
+  { OPEN_DIR, S_, "delete-entry", OPEN_FILE,
+    FALSE, { "?rev", "name", NULL }, TRUE },
+
+  { OPEN_DIR, S_, "absent-directory", ABSENT_DIR,
+    FALSE, { "name", NULL }, TRUE },
+
+  { ADD_DIR, S_, "absent-directory", ABSENT_DIR,
+    FALSE, { "name", NULL }, TRUE },
+
+  { OPEN_DIR, S_, "absent-file", ABSENT_FILE,
+    FALSE, { "name", NULL }, TRUE },
+
+  { ADD_DIR, S_, "absent-file", ABSENT_FILE,
+    FALSE, { "name", NULL }, TRUE },
+
+  { 0 }
+};
+
+
+
+/* Conforms to svn_ra_serf__xml_opened_t  */
+static svn_error_t *
+update_opened(svn_ra_serf__xml_estate_t *xes,
+              void *baton,
+              int entered_state,
+              const svn_ra_serf__dav_props_t *tag,
+              apr_pool_t *scratch_pool)
 {
-  svn_ra_serf__connection_t * conn;
-  int first_conn;
+  report_context_t *ctx = baton;
 
-  /* Skip the first connection if the REPORT response hasn't been completely
-     received yet. */
-  first_conn = ctx->report_received ? 0: 1;
+  return SVN_NO_ERROR;
+}
 
-  if (ctx->sess->num_conns - first_conn == 1)
-    return ctx->sess->conns[first_conn];
 
-  /* Currently just cycle connections. In future we could store number of
-   * pending requests on each connection for better connection usage. */
-  conn = ctx->sess->conns[ctx->sess->cur_conn];
 
-  /* Switch our connection. */
-  ctx->sess->cur_conn++;
+/* Conforms to svn_ra_serf__xml_closed_t  */
+static svn_error_t *
+update_closed(svn_ra_serf__xml_estate_t *xes,
+              void *baton,
+              int leaving_state,
+              const svn_string_t *cdata,
+              apr_hash_t *attrs,
+              apr_pool_t *scratch_pool)
+{
+  report_context_t *ctx = baton;
+
+  if (leaving_state == TARGET_REVISION)
+    {
+      const char *rev = apr_hash_get(attrs, "rev", APR_HASH_KEY_STRING);
+
+      SVN_ERR(ctx->update_editor->set_target_revision(ctx->update_baton,
+                                                      SVN_STR_TO_REV(rev),
+                                                      ctx->sess->pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Conforms to svn_ra_serf__xml_cdata_t  */
+static svn_error_t *
+update_cdata(svn_ra_serf__xml_estate_t *xes,
+             void *baton,
+             int current_state,
+             const char *data,
+             apr_size_t len,
+             apr_pool_t *scratch_pool)
+{
+  report_context_t *ctx = baton;
+
+  return SVN_NO_ERROR;
+}
+
+#endif /* NOT_USED_YET */
+
 
-  if (ctx->sess->cur_conn >= ctx->sess->num_conns)
-      ctx->sess->cur_conn = first_conn;
+/* Returns best connection for fetching files/properties. */
+static svn_ra_serf__connection_t *
+get_best_connection(report_context_t *ctx)
+{
+  svn_ra_serf__connection_t *conn;
+  int first_conn = 1;
 
+  /* Skip the first connection if the REPORT response hasn't been completely
+     received yet or if we're being told to limit our connections to
+     2 (because this could be an attempt to ensure that we do all our
+     auxiliary GETs/PROPFINDs on a single connection).
+
+     ### FIXME: This latter requirement (max_connections > 2) is
+     ### really just a hack to work around the fact that some update
+     ### editor implementations (such as svnrdump's dump editor)
+     ### simply can't handle the way ra_serf violates the editor v1
+     ### drive ordering requirements.
+     ### 
+     ### See http://subversion.tigris.org/issues/show_bug.cgi?id=4116.
+  */
+  if (ctx->report_received && (ctx->sess->max_connections > 2))
+    first_conn = 0;
+
+  /* Currently, we just cycle connections.  In the future we could
+     store the number of pending requests on each connection, or
+     perform other heuristics, to achieve better connection usage.
+     (As an optimization, if there's only one available auxiliary
+     connection to use, don't bother doing all the cur_conn math --
+     just return that one connection.)  */
+  if (ctx->sess->num_conns - first_conn == 1)
+    {
+      conn = ctx->sess->conns[first_conn];
+    }
+  else
+    {
+      conn = ctx->sess->conns[ctx->sess->cur_conn];
+      ctx->sess->cur_conn++;
+      if (ctx->sess->cur_conn >= ctx->sess->num_conns)
+        ctx->sess->cur_conn = first_conn;
+    }
   return conn;
 }
 
@@ -1206,6 +1349,67 @@ handle_stream(serf_request_t *request,
   /* not reached */
 }
 
+/* Close the directory represented by DIR -- and any suitable parents
+   thereof -- if we are able to do so.  This is the case whenever:
+
+     - there are no remaining open items within the directory, and
+     - the directory's XML close tag has been processed (so we know
+       there are no more children to worry about in the future), and
+     - either:
+         - we aren't fetching properties for this directory, or
+         - we've already finished fetching those properties.
+*/
+static svn_error_t *
+maybe_close_dir_chain(report_dir_t *dir)
+{
+  report_dir_t *cur_dir = dir;
+
+  SVN_ERR(ensure_dir_opened(cur_dir));
+                  
+  while (cur_dir
+         && !cur_dir->ref_count
+         && cur_dir->tag_closed
+         && (!cur_dir->fetch_props || cur_dir->propfind_handler->done))
+    {
+      report_dir_t *parent = cur_dir->parent_dir;
+      report_context_t *report_context = cur_dir->report_context;
+      svn_boolean_t propfind_in_done_list = FALSE;
+      svn_ra_serf__list_t *done_list;
+
+      /* Make sure there are no references to this dir in the
+         active_dir_propfinds list.  If there are, don't close the
+         directory -- which would delete the pool from which the
+         relevant active_dir_propfinds list item is allocated -- and
+         of course don't crawl upward to check the parents for
+         a closure opportunity, either.  */
+      done_list = report_context->active_dir_propfinds;
+      while (done_list)
+        {
+          if (done_list->data == cur_dir)
+            {
+              propfind_in_done_list = TRUE;
+              break;
+            }
+          done_list = done_list->next;
+        }
+      if (propfind_in_done_list)
+        break;
+
+      SVN_ERR(close_dir(cur_dir));
+      if (parent)
+        {
+          parent->ref_count--;
+        }
+      else
+        {
+          report_context->closed_root = TRUE;
+        }
+      cur_dir = parent;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Open the file associated with INFO for editing, pass along any
    propchanges we've recorded for it, and then close the file. */
 static svn_error_t *
@@ -1220,6 +1424,10 @@ handle_propchange_only(report_info_t *in
 
   info->dir->ref_count--;
 
+  /* See if the parent directory of this file (and perhaps even
+     parents of that) can be closed now.  */
+  SVN_ERR(maybe_close_dir_chain(info->dir));
+
   return SVN_NO_ERROR;
 }
 
@@ -1244,6 +1452,10 @@ handle_local_content(report_info_t *info
 
   info->dir->ref_count--;
 
+  /* See if the parent directory of this fetched item (and
+     perhaps even parents of that) can be closed now. */
+  SVN_ERR(maybe_close_dir_chain(info->dir));
+
   return SVN_NO_ERROR;
 }
 
@@ -1258,17 +1470,6 @@ fetch_file(report_context_t *ctx, report
   /* What connection should we go on? */
   conn = get_best_connection(ctx);
 
-  /* go fetch info->name from DAV:checked-in */
-  info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
-                                        info->base_rev, "DAV:", "checked-in");
-
-  if (!info->url)
-    {
-      return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
-                              _("The REPORT or PROPFIND response did not "
-                                "include the requested checked-in value"));
-    }
-
   /* If needed, create the PROPFIND to retrieve the file's properties. */
   info->propfind_handler = NULL;
   if (info->fetch_props)
@@ -1408,12 +1609,7 @@ fetch_file(report_context_t *ctx, report
     }
   else
     {
-      /* No propfind or GET request.  Just handle the prop changes now.
-
-         Note: we'll use INFO->POOL for the scratch_pool here since it will
-         be destroyed at the end of handle_propchange_only(). That pool
-         would be quite fine, but it is unclear how long INFO->POOL will
-         stick around since its lifetime and usage are unclear.  */
+      /* No propfind or GET request.  Just handle the prop changes now. */
       SVN_ERR(handle_propchange_only(info, info->pool));
     }
 
@@ -1440,9 +1636,15 @@ start_report(svn_ra_serf__xml_parser_t *
 
   if (state == NONE && strcmp(name.name, "update-report") == 0)
     {
-      const char *val = svn_xml_get_attr_value("inline-props", attrs);
+      const char *val;
+
+      val = svn_xml_get_attr_value("inline-props", attrs);
       if (val && (strcmp(val, "true") == 0))
         ctx->add_props_included = TRUE;
+
+      val = svn_xml_get_attr_value("send-all", attrs);
+      if (val && (strcmp(val, "true") == 0))
+        ctx->send_all_mode = TRUE;
     }
   else if (state == NONE && strcmp(name.name, "target-revision") == 0)
     {
@@ -1645,7 +1847,11 @@ start_report(svn_ra_serf__xml_parser_t *
       info = push_state(parser, ctx, ADD_FILE);
 
       info->base_rev = SVN_INVALID_REVNUM;
-      info->fetch_file = TRUE;
+
+      /* If the server isn't in "send-all" mode, we should expect to
+         fetch contents for added files. */
+      if (! ctx->send_all_mode)
+        info->fetch_file = TRUE;
 
       /* If the server isn't included properties for added items,
          we'll need to fetch them ourselves. */
@@ -1885,7 +2091,31 @@ start_report(svn_ra_serf__xml_parser_t *
              addition to <fetch-file>s and such) when *not* in
              "send-all" mode.  As a client, we're smart enough to know
              that's wrong, so we'll just ignore these tags. */
-          ;
+          if (ctx->send_all_mode)
+            {
+              const svn_delta_editor_t *update_editor = ctx->update_editor;
+
+              info = push_state(parser, ctx, TXDELTA);
+
+              if (! info->file_baton)
+                {
+                  SVN_ERR(open_updated_file(info, FALSE, info->pool));
+                }
+
+              info->base_checksum = svn_xml_get_attr_value("base-checksum",
+                                                           attrs);
+              SVN_ERR(update_editor->apply_textdelta(info->file_baton,
+                                                     info->base_checksum,
+                                                     info->editor_pool,
+                                                     &info->textdelta,
+                                                     &info->textdelta_baton));
+              info->svndiff_decoder = svn_txdelta_parse_svndiff(
+                                          info->textdelta,
+                                          info->textdelta_baton,
+                                          TRUE, info->pool);
+              info->base64_decoder = svn_base64_decode(info->svndiff_decoder,
+                                                       info->pool);
+            }
         }
       else
         {
@@ -1969,13 +2199,15 @@ end_report(svn_ra_serf__xml_parser_t *pa
        */
       if (info->dir->fetch_props)
         {
+          svn_ra_serf__list_t *list_item;
+ 
           SVN_ERR(svn_ra_serf__deliver_props(&info->dir->propfind_handler,
                                              info->dir->props, ctx->sess,
                                              get_best_connection(ctx),
                                              info->dir->url,
                                              ctx->target_rev, "0",
                                              all_props,
-                                             &ctx->done_propfinds,
+                                             &ctx->done_dir_propfinds,
                                              info->dir->pool));
           SVN_ERR_ASSERT(info->dir->propfind_handler);
 
@@ -1984,6 +2216,11 @@ end_report(svn_ra_serf__xml_parser_t *pa
 
           ctx->num_active_propfinds++;
 
+          list_item = apr_pcalloc(info->dir->pool, sizeof(*list_item));
+          list_item->data = info->dir;
+          list_item->next = ctx->active_dir_propfinds;
+          ctx->active_dir_propfinds = list_item;
+
           if (ctx->num_active_fetches + ctx->num_active_propfinds
               > REQUEST_COUNT_TO_PAUSE)
             ctx->parser_ctx->paused = TRUE;
@@ -1993,6 +2230,12 @@ end_report(svn_ra_serf__xml_parser_t *pa
           info->dir->propfind_handler = NULL;
         }
 
+      /* See if this directory (and perhaps even parents of that) can
+         be closed now.  This is likely to be the case only if we
+         didn't need to contact the server for supplemental
+         information required to handle any of this directory's
+         children.  */
+      SVN_ERR(maybe_close_dir_chain(info->dir));
       svn_ra_serf__xml_pop_state(parser);
     }
   else if (state == OPEN_FILE && strcmp(name.name, "open-file") == 0)
@@ -2066,13 +2309,89 @@ end_report(svn_ra_serf__xml_parser_t *pa
           info->delta_base = value ? value->data : NULL;
         }
 
-      SVN_ERR(fetch_file(ctx, info));
+      /* go fetch info->name from DAV:checked-in */
+      info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+                                            info->base_rev, "DAV:", "checked-in");
+      if (!info->url)
+        {
+          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+                                  _("The REPORT or PROPFIND response did not "
+                                    "include the requested checked-in value"));
+        }
+
+      /* If the server is in "send-all" mode, we might have opened the
+         file when we started seeing content for it.  If we didn't get
+         any content for it, we still need to open the file.  But in
+         any case, we can then immediately close it.  */
+      if (ctx->send_all_mode)
+        {
+          if (! info->file_baton)
+            {
+              SVN_ERR(open_updated_file(info, FALSE, info->pool));
+            }
+          SVN_ERR(close_updated_file(info, info->pool));
+          info->dir->ref_count--;
+        }
+      /* Otherwise, if the server is *not* in "send-all" mode, we
+         should be at a point where we can queue up any auxiliary
+         content-fetching requests.  */
+      else
+        {
+          SVN_ERR(fetch_file(ctx, info));
+        }
+
       svn_ra_serf__xml_pop_state(parser);
     }
   else if (state == ADD_FILE && strcmp(name.name, "add-file") == 0)
     {
-      /* We should have everything we need to fetch the file. */
-      SVN_ERR(fetch_file(ctx, parser->state->private));
+      report_info_t *info = parser->state->private;
+
+      /* go fetch info->name from DAV:checked-in */
+      info->url = svn_ra_serf__get_ver_prop(info->props, info->base_name,
+                                            info->base_rev, "DAV:", "checked-in");
+      if (!info->url)
+        {
+          return svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+                                  _("The REPORT or PROPFIND response did not "
+                                    "include the requested checked-in value"));
+        }
+
+      /* If the server is in "send-all" mode, we might have opened the
+         file when we started seeing content for it.  If we didn't get
+         any content for it, we still need to open the file.  But in
+         any case, we can then immediately close it.  */
+      if (ctx->send_all_mode)
+        {
+          if (! info->file_baton)
+            {
+              SVN_ERR(open_updated_file(info, FALSE, info->pool));
+            }
+          SVN_ERR(close_updated_file(info, info->pool));
+          info->dir->ref_count--;
+        }
+      /* Otherwise, if the server is *not* in "send-all" mode, we
+         should be at a point where we can queue up any auxiliary
+         content-fetching requests.  */
+      else
+        {
+          SVN_ERR(fetch_file(ctx, info));
+        }
+
+      svn_ra_serf__xml_pop_state(parser);
+    }
+  else if (state == TXDELTA && strcmp(name.name, "txdelta") == 0)
+    {
+      report_info_t *info = parser->state->private;
+
+      /* Pre 1.2, mod_dav_svn was using <txdelta> tags (in addition to
+         <fetch-file>s and such) when *not* in "send-all" mode.  As a
+         client, we're smart enough to know that's wrong, so when not
+         in "receiving-all" mode, we'll ignore these tags. */
+      if (ctx->send_all_mode)
+        {
+          SVN_ERR(svn_stream_close(info->base64_decoder));
+        }
+
       svn_ra_serf__xml_pop_state(parser);
     }
   else if (state == PROP)
@@ -2199,6 +2518,27 @@ cdata_report(svn_ra_serf__xml_parser_t *
 
       svn_stringbuf_appendbytes(info->prop_value, data, len);
     }
+  else if (parser->state->current_state == TXDELTA)
+    {
+      /* Pre 1.2, mod_dav_svn was using <txdelta> tags (in addition to
+         <fetch-file>s and such) when *not* in "send-all" mode.  As a
+         client, we're smart enough to know that's wrong, so when not
+         in "receiving-all" mode, we'll ignore these tags. */
+      if (ctx->send_all_mode)
+        {
+          apr_size_t nlen = len;
+          report_info_t *info = parser->state->private;
+
+          SVN_ERR(svn_stream_write(info->base64_decoder, data, &nlen));
+          if (nlen != len)
+            {
+              /* Short write without associated error?  "Can't happen." */
+              return svn_error_createf(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL,
+                                       _("Error writing to '%s': unexpected EOF"),
+                                       info->name);
+            }
+        }
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2402,11 +2742,10 @@ finish_report(void *report_baton,
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
   const char *report_target;
-  svn_boolean_t closed_root;
   svn_stringbuf_t *buf = NULL;
   apr_pool_t *iterpool = svn_pool_create(pool);
   svn_error_t *err;
-  apr_short_interval_time_t waittime_left = sess->timeout;
+  apr_interval_time_t waittime_left = sess->timeout;
 
   svn_xml_make_close_tag(&buf, iterpool, "S:update-report");
   SVN_ERR(svn_io_file_write_full(report->body_file, buf->data, buf->len,
@@ -2463,7 +2802,6 @@ finish_report(void *report_baton,
   SVN_ERR(open_connection_if_needed(sess, 0));
 
   sess->cur_conn = 1;
-  closed_root = FALSE;
 
   /* Note that we may have no active GET or PROPFIND requests, yet the
      processing has not been completed. This could be from a delay on the
@@ -2511,14 +2849,17 @@ finish_report(void *report_baton,
           err = SVN_NO_ERROR;
           status = 0;
 
-          if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
-            {
-              waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
-            }
-          else
+          if (sess->timeout)
             {
-              return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
-                                      _("Connection timed out"));
+              if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
+                {
+                  waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
+                }
+              else
+                {
+                  return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+                                          _("Connection timed out"));
+                }
             }
         }
       else
@@ -2533,14 +2874,16 @@ finish_report(void *report_baton,
         }
 
       /* Open extra connections if we have enough requests to send. */
-      if (sess->num_conns < MAX_NR_OF_CONNS)
+      if (sess->num_conns < sess->max_connections)
         SVN_ERR(open_connection_if_needed(sess, report->num_active_fetches +
                                           report->num_active_propfinds));
 
-      /* prune our propfind list if they are done. */
+      /* Prune completed file PROPFINDs. */
       done_list = report->done_propfinds;
       while (done_list)
         {
+          svn_ra_serf__list_t *next_done = done_list->next;
+
           svn_pool_clear(iterpool_inner);
 
           report->num_active_propfinds--;
@@ -2575,39 +2918,46 @@ finish_report(void *report_baton,
                 {
                   report_info_t *info = cur->data;
 
-                  /* If we've got cached file content for this file,
-                     take care of the locally collected properties and
-                     file content at once.  Otherwise, just deal with
-                     the collected properties. */
-                  if (info->cached_contents)
+                  if (!prev)
                     {
-                      SVN_ERR(handle_local_content(info, iterpool_inner));
+                      report->file_propchanges_only = cur->next;
                     }
                   else
                     {
-                      SVN_ERR(handle_propchange_only(info, iterpool_inner));
+                      prev->next = cur->next;
                     }
 
-                  if (!prev)
+                  /* If we've got cached file content for this file,
+                     take care of the locally collected properties and
+                     file content at once.  Otherwise, just deal with
+                     the collected properties.
+
+                     NOTE:  These functions below could delete
+                     info->dir->pool (via maybe_close_dir_chain()),
+                     from which is allocated the list item in
+                     report->file_propchanges_only.
+                  */
+                  if (info->cached_contents)
                     {
-                      report->file_propchanges_only = cur->next;
+                      SVN_ERR(handle_local_content(info, iterpool_inner));
                     }
                   else
                     {
-                      prev->next = cur->next;
+                      SVN_ERR(handle_propchange_only(info, iterpool_inner));
                     }
                 }
             }
 
-          done_list = done_list->next;
+          done_list = next_done;
         }
       report->done_propfinds = NULL;
 
-      /* Prune completely fetches from our list. */
+      /* Prune completed fetches from our list. */
       done_list = report->done_fetches;
       while (done_list)
         {
           report_fetch_t *done_fetch = done_list->data;
+          svn_ra_serf__list_t *next_done = done_list->next;
           report_dir_t *cur_dir;
 
           /* Decrease the refcount in the parent directory of the file
@@ -2618,35 +2968,76 @@ finish_report(void *report_baton,
           /* Decrement our active fetch count. */
           report->num_active_fetches--;
 
-          done_list = done_list->next;
+          /* See if the parent directory of this fetched item (and
+             perhaps even parents of that) can be closed now. 
 
-          /* If we have a valid directory and
-           * we have no open items in this dir and
-           * we've closed the directory tag (no more children can be added)
-           * and either:
-           *   we know we won't be fetching props or
-           *   we've already completed the propfind
-           * then, we know it's time for us to close this directory.
-           */
-          while (cur_dir && !cur_dir->ref_count && cur_dir->tag_closed
-                 && (!cur_dir->fetch_props
-                     || cur_dir->propfind_handler->done))
+             NOTE:  This could delete cur_dir->pool, from which is
+             allocated the list item in report->done_fetches.
+          */
+          SVN_ERR(maybe_close_dir_chain(cur_dir));
+
+          done_list = next_done;
+        }
+      report->done_fetches = NULL;
+
+      /* Prune completed directory PROPFINDs. */
+      done_list = report->done_dir_propfinds;
+      while (done_list)
+        {
+          svn_ra_serf__list_t *next_done = done_list->next;
+
+          report->num_active_propfinds--;
+
+          if (report->active_dir_propfinds)
             {
-              report_dir_t *parent = cur_dir->parent_dir;
+              svn_ra_serf__list_t *cur, *prev;
+
+              prev = NULL;
+              cur = report->active_dir_propfinds;
 
-              SVN_ERR(close_dir(cur_dir));
-              if (parent)
+              while (cur)
                 {
-                  parent->ref_count--;
+                  report_dir_t *item = cur->data;
+
+                  if (item->propfind_handler == done_list->data)
+                    {
+                      break;
+                    }
+
+                  prev = cur;
+                  cur = cur->next;
                 }
-              else
+              SVN_ERR_ASSERT(cur); /* we expect to find a matching propfind! */
+
+              /* If we found a match, set the new props and remove this
+               * propchange from our list.
+               */
+              if (cur)
                 {
-                  closed_root = TRUE;
+                  report_dir_t *cur_dir = cur->data;
+
+                  if (!prev)
+                    {
+                      report->active_dir_propfinds = cur->next;
+                    }
+                  else
+                    {
+                      prev->next = cur->next;
+                    }
+
+                  /* See if this directory (and perhaps even parents of that)
+                     can be closed now.
+
+                     NOTE:  This could delete cur_dir->pool, from which is
+                     allocated the list item in report->active_dir_propfinds.
+                  */
+                  SVN_ERR(maybe_close_dir_chain(cur_dir));
                 }
-              cur_dir = parent;
             }
+
+          done_list = next_done;
         }
-      report->done_fetches = NULL;
+      report->done_dir_propfinds = NULL;
 
       /* If the parser is paused, and the number of active requests has
          dropped far enough, then resume parsing.  */
@@ -2675,7 +3066,7 @@ finish_report(void *report_baton,
     {
       /* Ensure that we opened and closed our root dir and that we closed
        * all of our children. */
-      if (closed_root == FALSE && report->root_dir != NULL)
+      if (report->closed_root == FALSE && report->root_dir != NULL)
         {
           SVN_ERR(close_all_dirs(report->root_dir));
         }
@@ -2786,9 +3177,47 @@ make_update_reporter(svn_ra_session_t *r
                                    svn_io_file_del_on_pool_cleanup,
                                    report->pool, scratch_pool));
 
-  svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal, "S:update-report",
-                        "xmlns:S", SVN_XML_NAMESPACE,
-                        NULL);
+  if (sess->server_allows_bulk)
+    {
+      if (apr_strnatcasecmp(sess->server_allows_bulk, "off") == 0)
+        {
+          /* Server doesn't want bulk updates */
+          sess->bulk_updates = FALSE;
+        }
+      else if (apr_strnatcasecmp(sess->server_allows_bulk, "prefer") == 0)
+        {
+          /* Server prefers bulk updates, and we respect that */
+          sess->bulk_updates = TRUE;
+        }
+      else
+        {
+          /* Server allows bulk updates, but doesn't dictate its use. Do
+             whatever is the default or what the user defined in the config. */
+        }
+    }
+  else
+    {
+      /* Pre-1.8 server didn't send the bulk_updates header. Do
+         whatever is the default or what the user defined in the config. */
+    }
+
+  if (sess->bulk_updates)
+    {
+      svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
+                            "S:update-report",
+                            "xmlns:S", SVN_XML_NAMESPACE, "send-all", "true",
+                            NULL);
+    }
+  else
+    {
+      svn_xml_make_open_tag(&buf, scratch_pool, svn_xml_normal,
+                            "S:update-report",
+                            "xmlns:S", SVN_XML_NAMESPACE,
+                            NULL);
+      /* Subversion 1.8+ servers can be told to send properties for newly
+         added items inline even when doing a skelta response. */
+      make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+    }
 
   make_simple_xml_tag(&buf, "S:src-path", report->source, scratch_pool);
 
@@ -2827,9 +3256,20 @@ make_update_reporter(svn_ra_session_t *r
       make_simple_xml_tag(&buf, "S:recursive", "no", scratch_pool);
     }
 
-  /* Subversion 1.8+ servers can be told to send properties for newly
-     added items inline even when doing a skelta response. */
-  make_simple_xml_tag(&buf, "S:include-props", "yes", scratch_pool);
+  /* When in 'send-all' mode, mod_dav_svn will assume that it should
+     calculate and transmit real text-deltas (instead of empty windows
+     that merely indicate "text is changed") unless it finds this
+     element.
+
+     NOTE: Do NOT count on servers actually obeying this, as some exist
+     which obey send-all, but do not check for this directive at all!
+
+     NOTE 2: When not in 'send-all' mode, mod_dav_svn can still be configured to
+     override our request and send text-deltas. */
+  if (! text_deltas)
+    {
+      make_simple_xml_tag(&buf, "S:text-deltas", "no", scratch_pool);
+    }
 
   make_simple_xml_tag(&buf, "S:depth", svn_depth_to_word(depth), scratch_pool);
 

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_serf/util.c Thu Dec 27 04:03:49 2012
@@ -657,6 +657,10 @@ setup_serf_req(serf_request_t *request,
       SVN_ERR(svn_ra_serf__copy_into_spillbuf(&buf, body_bkt,
                                               request_pool,
                                               scratch_pool));
+      /* Destroy original bucket since it content is already copied 
+         to spillbuf. */
+      serf_bucket_destroy(body_bkt);
+
       body_bkt = svn_ra_serf__create_sb_bucket(buf, allocator,
                                                request_pool,
                                                scratch_pool);
@@ -718,7 +722,7 @@ svn_ra_serf__context_run_wait(svn_boolea
                               apr_pool_t *scratch_pool)
 {
   apr_pool_t *iterpool;
-  apr_short_interval_time_t waittime_left = sess->timeout;
+  apr_interval_time_t waittime_left = sess->timeout;
   
   assert(sess->pending_error == SVN_NO_ERROR);
 
@@ -751,14 +755,17 @@ svn_ra_serf__context_run_wait(svn_boolea
           err = SVN_NO_ERROR;
           status = 0;
 
-          if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
-            {
-              waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
-            }
-          else
+          if (sess->timeout)
             {
-              return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
-                                      _("Connection timed out"));
+              if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
+                {
+                  waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
+                }
+              else 
+                {
+                  return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+                                          _("Connection timed out"));
+                }
             }
         }
       else
@@ -1903,10 +1910,12 @@ handle_response(serf_request_t *request,
   handler->conn->last_status_code = handler->sline.code;
 
   if (handler->sline.code == 405
+      || handler->sline.code == 408
       || handler->sline.code == 409
       || handler->sline.code >= 500)
     {
       /* 405 Method Not allowed.
+         408 Request Timeout
          409 Conflict: can indicate a hook error.
          5xx (Internal) Server error. */
       serf_bucket_t *hdrs;

Modified: subversion/branches/javahl-ra/subversion/libsvn_ra_svn/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_ra_svn/cyrus_auth.c?rev=1426116&r1=1426115&r2=1426116&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_ra_svn/cyrus_auth.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_ra_svn/cyrus_auth.c Thu Dec 27 04:03:49 2012
@@ -179,7 +179,7 @@ svn_ra_svn__sasl_common_init(apr_pool_t 
                  sasl_mutex_unlock_cb,
                  sasl_mutex_free_cb);
   free_mutexes = apr_array_make(sasl_pool, 0, sizeof(svn_mutex__t *));
-  return svn_mutex__init(&array_mutex, TRUE, sasl_pool);
+  SVN_ERR(svn_mutex__init(&array_mutex, TRUE, sasl_pool));
 
 #endif /* APR_HAS_THREADS */
 
@@ -871,12 +871,12 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__se
 
   /* The username callback. */
   callbacks[0].id = SASL_CB_AUTHNAME;
-  callbacks[0].proc = (void*)get_username_cb;
+  callbacks[0].proc = (int (*)(void))get_username_cb;
   callbacks[0].context = &cred_baton;
 
   /* The password callback. */
   callbacks[1].id = SASL_CB_PASS;
-  callbacks[1].proc = (void*)get_password_cb;
+  callbacks[1].proc = (int (*)(void))get_password_cb;
   callbacks[1].context = &cred_baton;
 
   /* Mark the end of the array. */



Mime
View raw message