You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2012/10/25 00:19:39 UTC

svn commit: r1401904 - in /subversion/branches/ev2-export: ./ notes/ subversion/include/private/ subversion/libsvn_fs_fs/ subversion/libsvn_ra/ subversion/libsvn_subr/ subversion/svnserve/ tools/server-side/svnpubsub/

Author: hwright
Date: Wed Oct 24 22:19:38 2012
New Revision: 1401904

URL: http://svn.apache.org/viewvc?rev=1401904&view=rev
Log:
On the ev2-export branch:
Bring up-to-date with trunk.

Modified:
    subversion/branches/ev2-export/   (props changed)
    subversion/branches/ev2-export/notes/fsfs
    subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h
    subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h
    subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c
    subversion/branches/ev2-export/subversion/libsvn_fs_fs/structure
    subversion/branches/ev2-export/subversion/libsvn_ra/editor.c
    subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.c
    subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.h
    subversion/branches/ev2-export/subversion/libsvn_subr/cache-membuffer.c
    subversion/branches/ev2-export/subversion/svnserve/main.c
    subversion/branches/ev2-export/subversion/svnserve/serve.c
    subversion/branches/ev2-export/subversion/svnserve/server.h
    subversion/branches/ev2-export/tools/server-side/svnpubsub/svnwcsub.py

Propchange: subversion/branches/ev2-export/
------------------------------------------------------------------------------
  Merged /subversion/trunk:r1400559-1401903

Modified: subversion/branches/ev2-export/notes/fsfs
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/notes/fsfs?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/notes/fsfs (original)
+++ subversion/branches/ev2-export/notes/fsfs Wed Oct 24 22:19:38 2012
@@ -234,6 +234,16 @@ repository.  The backed-up "current" fil
 new revision which wasn't copied, or which was only partially
 populated when it was copied.
 
+[ Update: as of 1.6, FSFS uses an optional SQLite DB, rep-cache.db, when
+rep-sharing is enabled.  SQLite provides no guarantee that copying live
+databases will result in copies that are uncorrupt, or that are corrupt but
+will raise an error when accessed.  'svnadmin hotcopy' avoids the problem by
+establishing an appropriate SQLite lock (see svn_sqlite__hotcopy()).  User
+code should either use an atomic filesystem snapshot (as with zfs/LVM),
+refrain from copying rep-cache.db, or stop all access to that file before
+copying it (for example, by disabling commits, by establishing a lock a la
+svn_sqlite__hotcopy(), or by using 'svnadmin freeze'). ]
+
 The "svnadmin hotcopy" command avoids this problem by copying the
 "current" file before copying the revision files.  But a backup using
 the hotcopy command isn't as efficient as a straight incremental

Modified: subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h (original)
+++ subversion/branches/ev2-export/subversion/include/private/svn_ra_private.h Wed Oct 24 22:19:38 2012
@@ -257,6 +257,10 @@ svn_ra__replay_range_ev2(svn_ra_session_
                          svn_ra__replay_revstart_ev2_callback_t revstart_func,
                          svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
                          void *replay_baton,
+                         svn_ra__provide_base_cb_t provide_base_cb,
+                         svn_ra__provide_props_cb_t provide_props_cb,
+                         svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
+                         void *cb_baton,
                          apr_pool_t *scratch_pool);
 
 /* Similar to svn_ra_replay(), but with an Ev2 editor. */

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h Wed Oct 24 22:19:38 2012
@@ -315,6 +315,9 @@ typedef struct fs_fs_data_t
      if the node has mergeinfo, "0" if it doesn't. */
   svn_cache__t *mergeinfo_existence_cache;
 
+  /* TRUE while the we hold a lock on the write lock file. */
+  svn_boolean_t has_write_lock;
+
   /* If set, there are or have been more than one concurrent transaction */
   svn_boolean_t concurrent_transactions;
 

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c Wed Oct 24 22:19:38 2012
@@ -589,16 +589,29 @@ get_lock_on_filesystem(const char *lock_
   return svn_error_trace(err);
 }
 
+/* Reset the HAS_WRITE_LOCK member in the FFD given as BATON_VOID.
+   When registered with the pool holding the lock on the lock file,
+   this makes sure the flag gets reset just before we release the lock. */
+static apr_status_t
+reset_lock_flag(void *baton_void)
+{
+  fs_fs_data_t *ffd = baton_void;
+  ffd->has_write_lock = FALSE;
+  return APR_SUCCESS;
+}
+
 /* Obtain a write lock on the file LOCK_FILENAME (protecting with
    LOCK_MUTEX if APR is threaded) in a subpool of POOL, call BODY with
    BATON and that subpool, destroy the subpool (releasing the write
-   lock) and return what BODY returned. */
+   lock) and return what BODY returned.  If IS_GLOBAL_LOCK is set,
+   set the HAS_WRITE_LOCK flag while we keep the write lock. */
 static svn_error_t *
 with_some_lock_file(svn_fs_t *fs,
                     svn_error_t *(*body)(void *baton,
                                          apr_pool_t *pool),
                     void *baton,
                     const char *lock_filename,
+                    svn_boolean_t is_global_lock,
                     apr_pool_t *pool)
 {
   apr_pool_t *subpool = svn_pool_create(pool);
@@ -607,6 +620,19 @@ with_some_lock_file(svn_fs_t *fs,
   if (!err)
     {
       fs_fs_data_t *ffd = fs->fsap_data;
+
+      if (is_global_lock)
+        {
+          /* set the "got the lock" flag and register reset function */
+          apr_pool_cleanup_register(subpool,
+                                    ffd,
+                                    reset_lock_flag,
+                                    apr_pool_cleanup_null);
+          ffd->has_write_lock = TRUE;
+        }
+
+      /* nobody else will modify the repo state
+         => read HEAD & pack info once */
       if (ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
         SVN_ERR(update_min_unpacked_rev(fs, pool));
       SVN_ERR(get_youngest(&ffd->youngest_rev_cache, fs->path,
@@ -632,6 +658,7 @@ svn_fs_fs__with_write_lock(svn_fs_t *fs,
   SVN_MUTEX__WITH_LOCK(ffsd->fs_write_lock,
                        with_some_lock_file(fs, body, baton,
                                            path_lock(fs, pool),
+                                           TRUE,
                                            pool));
 
   return SVN_NO_ERROR;
@@ -652,6 +679,7 @@ with_txn_current_lock(svn_fs_t *fs,
   SVN_MUTEX__WITH_LOCK(ffsd->txn_current_lock,
                        with_some_lock_file(fs, body, baton,
                                            path_txn_current_lock(fs, pool),
+                                           FALSE,
                                            pool));
 
   return SVN_NO_ERROR;
@@ -3216,8 +3244,8 @@ has_revprop_cache(svn_fs_t *fs, apr_pool
        * -> disable the revprop cache for good
        */
       ffd->revprop_cache = NULL;
-      log_revprop_cache_init_warning(fs, "Disable revprop caching for '%s'"
-                                         " because it is inefficient.");
+      log_revprop_cache_init_warning(fs, "Revprop caching for '%s' disabled"
+                                         " because it would be inefficient.");
       
       return FALSE;
     }
@@ -3230,9 +3258,10 @@ has_revprop_cache(svn_fs_t *fs, apr_pool
 
       svn_error_clear(error);
       ffd->revprop_cache = NULL;
-      log_revprop_cache_init_warning(fs, "Failed to initialize SHM "
+      log_revprop_cache_init_warning(fs, "Revprop caching for '%s' disabled "
+                                         "because SHM "
                                          "infrastructure for revprop "
-                                         "caching in '%s'.");
+                                         "caching failed to initialize.");
 
       return FALSE;
     }
@@ -3240,6 +3269,46 @@ has_revprop_cache(svn_fs_t *fs, apr_pool
   return TRUE;
 }
 
+/* Baton structure for revprop_generation_fixup. */
+typedef struct revprop_generation_fixup_t
+{
+  /* revprop generation to read */
+  apr_int64_t *generation;
+
+  /* containing the revprop_generation member to query */
+  fs_fs_data_t *ffd;
+} revprop_generation_upgrade_t;
+
+/* If the revprop generation has an odd value, it means the original writer
+   of the revprop got killed. We don't know whether that process as able
+   to change the revprop data but we assume that it was. Therefore, we
+   increase the generation in that case to basically invalidate everyones
+   cache content.
+   Execute this onlx while holding the write lock to the repo in baton->FFD.
+ */
+static svn_error_t *
+revprop_generation_fixup(void *void_baton,
+                         apr_pool_t *pool)
+{
+  revprop_generation_upgrade_t *baton = void_baton;
+  assert(baton->ffd->has_write_lock);
+  
+  /* Maybe, either the original revprop writer or some other reader has
+     already corrected / bumped the revprop generation.  Thus, we need
+     to read it again. */
+  SVN_ERR(svn_named_atomic__read(baton->generation,
+                                 baton->ffd->revprop_generation));
+
+  /* Cause everyone to re-read revprops upon their next access, if the
+     last revprop write did not complete properly. */
+  while (*baton->generation % 2)
+    SVN_ERR(svn_named_atomic__add(baton->generation,
+                                  1,
+                                  baton->ffd->revprop_generation));
+
+  return SVN_NO_ERROR;
+}
+
 /* Read the current revprop generation and return it in *GENERATION.
    Also, detect aborted / crashed writers and recover from that.
    Use the access object in FS to set the shared mem values. */
@@ -3269,13 +3338,19 @@ read_revprop_generation(apr_int64_t *gen
        */
       if (apr_time_now() > timeout)
         {
-          /* Cause everyone to re-read revprops upon their next access.
-           * Keep in mind that we may not be the only one trying to do it.
+          revprop_generation_upgrade_t baton;
+          baton.generation = &current;
+          baton.ffd = ffd;
+
+          /* Ensure that the original writer process no longer exists by
+           * acquiring the write lock to this repository.  Then, fix up
+           * the revprop generation.
            */
-          while (current % 2)
-            SVN_ERR(svn_named_atomic__add(&current,
-                                          1,
-                                          ffd->revprop_generation));
+          if (ffd->has_write_lock)
+            SVN_ERR(revprop_generation_fixup(&baton, pool));
+          else
+            SVN_ERR(svn_fs_fs__with_write_lock(fs, revprop_generation_fixup,
+                                               &baton, pool));
         }
     }
 

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/structure?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/structure Wed Oct 24 22:19:38 2012
@@ -273,14 +273,13 @@ in revprops/0/0.
 
 Pack file format
 
-  Top level: <length><packed container>
+  Top level: <packed container>
 
   We always apply data compression to the pack file - using the
   SVN_DELTA_COMPRESSION_LEVEL_NONE level if compression is disabled.
-  <length> is being encoded using the variable-length svndiff unsigned
-  integer format (see svndiff.c): 7 bits / byte in little endian order
-  with the MSB of each byte indicating whether there is a another byte
-  to read.
+  (Note that compression at SVN_DELTA_COMPRESSION_LEVEL_NONE is not
+  a no-op stream transformation although most of the data will remain
+  human readable.)
 
   container := header '\n' (revprops)+
   header    := start_rev '\n' rev_count '\n' (size '\n')+

Modified: subversion/branches/ev2-export/subversion/libsvn_ra/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra/editor.c?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra/editor.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra/editor.c Wed Oct 24 22:19:38 2012
@@ -42,6 +42,11 @@ struct fp_baton {
   void *cb_baton;
 };
 
+struct fb_baton {
+  svn_ra__provide_base_cb_t provide_base_cb;
+  void *cb_baton;
+};
+
 /* The shims currently want a callback that provides props for a given
    REPOS_RELPATH at a given BASE_REVISION. However, the RA Ev2 interface
    has a callback that provides properties for the REPOS_RELPATH from any
@@ -72,6 +77,42 @@ fetch_props(apr_hash_t **props,
                                                result_pool, scratch_pool));
 }
 
+/* See note above regarding BASE_REVISION.
+   This also pulls down the entire contents of the file stream from the
+   RA layer and stores them in a local file, returning the path.
+*/
+static svn_error_t *
+fetch_base(const char **filename,
+           void *baton,
+           const char *repos_relpath,
+           svn_revnum_t base_revision,
+           apr_pool_t *result_pool,
+           apr_pool_t *scratch_pool)
+{
+  struct fb_baton *fbb = baton;
+  svn_revnum_t unused_revision;
+  svn_stream_t *contents;
+  svn_stream_t *file_stream;
+  const char *tmp_filename;
+
+  /* Ignored: BASE_REVISION.  */
+
+  SVN_ERR(fbb->provide_base_cb(&contents, &unused_revision, fbb->cb_baton,
+                               repos_relpath, result_pool, scratch_pool));
+
+  SVN_ERR(svn_stream_open_unique(&file_stream, &tmp_filename, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 scratch_pool, scratch_pool));
+  SVN_ERR(svn_stream_copy3(contents, file_stream, NULL, NULL, scratch_pool));
+
+  *filename = apr_pstrdup(result_pool, tmp_filename);
+
+ 
+
+  return SVN_NO_ERROR;
+}
+
+
 
 svn_error_t *
 svn_ra__use_commit_shim(svn_editor_t **editor,
@@ -173,3 +214,126 @@ svn_ra__use_commit_shim(svn_editor_t **e
 
   return SVN_NO_ERROR;
 }
+
+
+struct wrapped_replay_baton_t {
+  svn_ra__replay_revstart_ev2_callback_t revstart_func;
+  svn_ra__replay_revfinish_ev2_callback_t revfinish_func;
+  void *replay_baton;
+
+  svn_ra_session_t *session;
+
+  svn_ra__provide_base_cb_t provide_base_cb;
+  svn_ra__provide_props_cb_t provide_props_cb;
+  void *cb_baton;
+
+  /* This will be populated by the revstart wrapper. */
+  svn_editor_t *editor;
+};
+
+static svn_error_t *
+revstart_func_wrapper(svn_revnum_t revision,
+                      void *replay_baton,
+                      const svn_delta_editor_t **deditor,
+                      void **dedit_baton,
+                      apr_hash_t *rev_props,
+                      apr_pool_t *result_pool)
+{
+  struct wrapped_replay_baton_t *wrb = replay_baton;
+  const char *repos_root;
+  const char *session_url;
+  const char *base_relpath;
+  svn_boolean_t *found_abs_paths;
+  struct fp_baton *fpb;
+  struct svn_delta__extra_baton *exb;
+
+  /* Get the Ev2 editor from the original revstart func. */
+  SVN_ERR(wrb->revstart_func(revision, wrb->replay_baton, &wrb->editor,
+                             rev_props, result_pool));
+
+  /* Get or calculate the appropriate repos root and base relpath. */
+  SVN_ERR(svn_ra_get_repos_root2(wrb->session, &repos_root, result_pool));
+  SVN_ERR(svn_ra_get_session_url(wrb->session, &session_url, result_pool));
+  base_relpath = svn_uri_skip_ancestor(repos_root, session_url, result_pool);
+
+  /* We will assume that when the underlying Ev1 editor is finally driven
+     by the shim, that we will not need to prepend "/" to the paths. Place
+     this on the heap because it is examined much later. Set to FALSE.  */
+  found_abs_paths = apr_pcalloc(result_pool, sizeof(*found_abs_paths));
+
+  /* The PROVIDE_PROPS_CB callback does not match what the shims want.
+     Let's jigger things around a little bit here.  */
+  fpb = apr_palloc(result_pool, sizeof(*fpb));
+  fpb->provide_props_cb = wrb->provide_props_cb;
+  fpb->cb_baton = wrb->cb_baton;
+
+  /* Create the extra baton. */
+  exb = apr_pcalloc(result_pool, sizeof(*exb));
+
+  /* Create the Ev1 editor from the Ev2 editor provided by the RA layer.
+
+     Note: GET_COPYSRC_KIND_CB is compatible in type/semantics with the
+     shim's FETCH_KIND_FUNC parameter.  */
+  SVN_ERR(svn_delta__delta_from_editor(deditor, dedit_baton, wrb->editor,
+                                       NULL, NULL,
+                                       found_abs_paths,
+                                       repos_root, base_relpath,
+                                       fetch_props, wrb->cb_baton,
+                                       fetch_base, wrb->cb_baton,
+                                       exb, result_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+revfinish_func_wrapper(svn_revnum_t revision,
+                       void *replay_baton,
+                       const svn_delta_editor_t *editor,
+                       void *edit_baton,
+                       apr_hash_t *rev_props,
+                       apr_pool_t *pool)
+{
+  struct wrapped_replay_baton_t *wrb = replay_baton;
+
+  SVN_ERR(wrb->revfinish_func(revision, replay_baton, wrb->editor, rev_props,
+                              pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_ra__use_replay_range_shim(svn_ra_session_t *session,
+                              svn_revnum_t start_revision,
+                              svn_revnum_t end_revision,
+                              svn_revnum_t low_water_mark,
+                              svn_boolean_t send_deltas,
+                              svn_ra__replay_revstart_ev2_callback_t revstart_func,
+                              svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
+                              void *replay_baton,
+                              svn_ra__provide_base_cb_t provide_base_cb,
+                              svn_ra__provide_props_cb_t provide_props_cb,
+                              void *cb_baton,
+                              apr_pool_t *scratch_pool)
+{
+  /* The basic strategy here is to wrap the callback start and finish
+     functions to appropriately return an Ev1 editor which is itself wrapped
+     from the Ev2 one the provided callbacks will give us. */
+
+  struct wrapped_replay_baton_t *wrb = apr_pcalloc(scratch_pool, sizeof(*wrb));
+
+  wrb->revstart_func = revstart_func;
+  wrb->revfinish_func = revfinish_func;
+  wrb->replay_baton = replay_baton;
+  wrb->session = session;
+
+  wrb->provide_base_cb = provide_base_cb;
+  wrb->provide_props_cb = provide_props_cb;
+  wrb->cb_baton = cb_baton;
+
+  return svn_error_trace(svn_ra_replay_range(session, start_revision,
+                                             end_revision, low_water_mark,
+                                             send_deltas,
+                                             revstart_func_wrapper,
+                                             revfinish_func_wrapper,
+                                             wrb, scratch_pool));
+}

Modified: subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.c?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.c Wed Oct 24 22:19:38 2012
@@ -1190,7 +1190,7 @@ svn_ra_replay_range(svn_ra_session_t *se
                                   revstart_func, revfinish_func,
                                   replay_baton, pool);
 
-  if (err && (err->apr_err != SVN_ERR_RA_NOT_IMPLEMENTED))
+  if (!err || (err && (err->apr_err != SVN_ERR_RA_NOT_IMPLEMENTED)))
     return svn_error_trace(err);
 
   svn_error_clear(err);
@@ -1212,9 +1212,38 @@ svn_ra__replay_range_ev2(svn_ra_session_
                          svn_ra__replay_revstart_ev2_callback_t revstart_func,
                          svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
                          void *replay_baton,
+                         svn_ra__provide_base_cb_t provide_base_cb,
+                         svn_ra__provide_props_cb_t provide_props_cb,
+                         svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
+                         void *cb_baton,
                          apr_pool_t *scratch_pool)
 {
-  SVN__NOT_IMPLEMENTED();
+  if (session->vtable->replay_range_ev2 == NULL)
+    {
+      /* The specific RA layer does not have an implementation. Use our
+         default shim over the normal replay editor.  */
+
+      /* This will call the Ev1 replay range handler with modified
+         callbacks. */
+      return svn_error_trace(svn_ra__use_replay_range_shim(
+                                session,
+                                start_revision,
+                                end_revision,
+                                low_water_mark,
+                                send_deltas,
+                                revstart_func,
+                                revfinish_func,
+                                replay_baton,
+                                provide_base_cb,
+                                provide_props_cb,
+                                cb_baton,
+                                scratch_pool));
+    }
+
+  return svn_error_trace(session->vtable->replay_range_ev2(
+                            session, start_revision, end_revision,
+                            low_water_mark, send_deltas, revstart_func,
+                            revfinish_func, replay_baton, scratch_pool));
 }
 
 svn_error_t *svn_ra_has_capability(svn_ra_session_t *session,

Modified: subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.h?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra/ra_loader.h Wed Oct 24 22:19:38 2012
@@ -324,6 +324,18 @@ typedef struct svn_ra__vtable_t {
     apr_pool_t *result_pool,
     apr_pool_t *scratch_pool);
 
+  /* See svn_ra__replay_range_ev2() */
+  svn_error_t *(*replay_range_ev2)(
+    svn_ra_session_t *session,
+    svn_revnum_t start_revision,
+    svn_revnum_t end_revision,
+    svn_revnum_t low_water_mark,
+    svn_boolean_t send_deltas,
+    svn_ra__replay_revstart_ev2_callback_t revstart_func,
+    svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
+    void *replay_baton,
+    apr_pool_t *scratch_pool);
+
 } svn_ra__vtable_t;
 
 /* The RA session object. */
@@ -519,6 +531,24 @@ svn_ra__use_commit_shim(svn_editor_t **e
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool);
 
+/* Utility function to provide a shim between a returned Ev2 and an RA
+   provider's Ev1-based commit editor.
+
+   See svn_ra__replay_range_ev2() for parameter semantics.  */
+svn_error_t *
+svn_ra__use_replay_range_shim(svn_ra_session_t *session,
+                              svn_revnum_t start_revision,
+                              svn_revnum_t end_revision,
+                              svn_revnum_t low_water_mark,
+                              svn_boolean_t send_deltas,
+                              svn_ra__replay_revstart_ev2_callback_t revstart_func,
+                              svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
+                              void *replay_baton,
+                              svn_ra__provide_base_cb_t provide_base_cb,
+                              svn_ra__provide_props_cb_t provide_props_cb,
+                              void *cb_baton,
+                              apr_pool_t *scratch_pool);
+
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/ev2-export/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_subr/cache-membuffer.c?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_subr/cache-membuffer.c Wed Oct 24 22:19:38 2012
@@ -1753,12 +1753,13 @@ membuffer_cache_set_partial_internal(svn
             {
               /* Remove the old entry and try to make space for the new one.
                */
-              entry = find_entry(cache, group_index, to_find, TRUE);
+              drop_entry(cache, entry);
               if (   (cache->max_entry_size >= size)
                   && ensure_data_insertable(cache, size))
                 {
                   /* Write the new entry.
                    */
+                  entry = find_entry(cache, group_index, to_find, TRUE);
                   entry->size = size;
                   entry->offset = cache->current_data;
                   if (size)

Modified: subversion/branches/ev2-export/subversion/svnserve/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/svnserve/main.c?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/svnserve/main.c (original)
+++ subversion/branches/ev2-export/subversion/svnserve/main.c Wed Oct 24 22:19:38 2012
@@ -150,6 +150,7 @@ void winservice_notify_stop(void)
 #define SVNSERVE_OPT_CACHE_REVPROPS  267
 #define SVNSERVE_OPT_SINGLE_CONN     268
 #define SVNSERVE_OPT_CLIENT_SPEED    269
+#define SVNSERVE_OPT_VIRTUAL_HOST    270
 
 static const apr_getopt_option_t svnserve__options[] =
   {
@@ -277,6 +278,10 @@ static const apr_getopt_option_t svnserv
         "                             "
         "[mode: tunnel]")},
     {"help",             'h', 0, N_("display this help")},
+    {"virtual-host",     SVNSERVE_OPT_VIRTUAL_HOST, 0,
+     N_("virtual host mode (look for repo in directory\n"
+        "                             "
+        "of provided hostname)")},
     {"version",           SVNSERVE_OPT_VERSION, 0,
      N_("show program version information")},
     {"quiet",            'q', 0,
@@ -503,6 +508,7 @@ int main(int argc, const char *argv[])
   params.authzdb = NULL;
   params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
   params.log_file = NULL;
+  params.vhost = FALSE;
   params.username_case = CASE_ASIS;
   params.memory_cache_size = (apr_uint64_t)-1;
   params.cache_fulltexts = TRUE;
@@ -694,7 +700,11 @@ int main(int argc, const char *argv[])
                                               pool));
           break;
 
-        case SVNSERVE_OPT_LOG_FILE:
+         case SVNSERVE_OPT_VIRTUAL_HOST:
+           params.vhost = TRUE;
+           break;
+
+         case SVNSERVE_OPT_LOG_FILE:
           SVN_INT_ERR(svn_utf_cstring_to_utf8(&log_filename, arg, pool));
           log_filename = svn_dirent_internal_style(log_filename, pool);
           SVN_INT_ERR(svn_dirent_get_absolute(&log_filename, log_filename,

Modified: subversion/branches/ev2-export/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/svnserve/serve.c?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/svnserve/serve.c (original)
+++ subversion/branches/ev2-export/subversion/svnserve/serve.c Wed Oct 24 22:19:38 2012
@@ -3096,9 +3096,13 @@ static svn_error_t *find_repos(const cha
     return svn_error_createf(SVN_ERR_BAD_URL, NULL,
                              "Non-svn URL passed to svn server: '%s'", url);
 
-
-  path = strchr(path, '/');
-  path = (path == NULL) ? "" : svn_relpath_canonicalize(path, pool);
+  if (! b->vhost)
+    {
+      path = strchr(path, '/');
+      if (path == NULL)
+        path = "";
+    }
+  path = svn_relpath_canonicalize(path, pool);
   path = svn_path_uri_decode(path, pool);
 
   /* Ensure that it isn't possible to escape the root by disallowing
@@ -3352,6 +3356,7 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
   b.log_file = params->log_file;
   b.pool = pool;
   b.use_sasl = FALSE;
+  b.vhost = params->vhost;
 
   /* construct FS configuration parameters */
   b.fs_config = apr_hash_make(pool);

Modified: subversion/branches/ev2-export/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/svnserve/server.h?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/svnserve/server.h (original)
+++ subversion/branches/ev2-export/subversion/svnserve/server.h Wed Oct 24 22:19:38 2012
@@ -59,6 +59,7 @@ typedef struct server_baton_t {
   svn_boolean_t use_sasl;  /* Use Cyrus SASL for authentication;
                               always false if SVN_HAVE_SASL not defined */
   apr_file_t *log_file;    /* Log filehandle. */
+  svn_boolean_t vhost;     /* Use virtual-host-based path to repo. */
   apr_pool_t *pool;
 } server_baton_t;
 
@@ -135,6 +136,9 @@ typedef struct serve_params_t {
   /* Amount of data to send between checks for cancellation requests
      coming in from the client. */
   apr_size_t error_check_interval;
+
+  /* Use virtual-host-based path to repo. */
+  svn_boolean_t vhost;
 } serve_params_t;
 
 /* Serve the connection CONN according to the parameters PARAMS. */

Modified: subversion/branches/ev2-export/tools/server-side/svnpubsub/svnwcsub.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/tools/server-side/svnpubsub/svnwcsub.py?rev=1401904&r1=1401903&r2=1401904&view=diff
==============================================================================
--- subversion/branches/ev2-export/tools/server-side/svnpubsub/svnwcsub.py (original)
+++ subversion/branches/ev2-export/tools/server-side/svnpubsub/svnwcsub.py Wed Oct 24 22:19:38 2012
@@ -267,13 +267,15 @@ class BackgroundWorker(threading.Thread)
 
         ### we need to move some of these args into the config. these are
         ### still specific to the ASF setup.
-        args = [self.svnbin, 'update',
+        args = [self.svnbin, 'switch',
                 '--quiet',
                 '--non-interactive',
                 '--trust-server-cert',
                 '--ignore-externals',
                 '--config-option',
                 'config:miscellany:use-commit-times=on',
+                '--',
+                wc.url,
                 wc.path]
         subprocess.check_call(args, env=self.env)