Author: stefan2
Date: Sun Apr 15 11:20:58 2012
New Revision: 1326307

URL: http://svn.apache.org/viewvc?rev=1326307&view=rev
Log:
Merge all changes (-r1298521-1326293) from branches/revprop-cache to trunk
and resolve minor conflicts.

Added:
    subversion/trunk/subversion/include/private/svn_named_atomic.h
      - copied unchanged from r1326293, 
subversion/branches/revprop-cache/subversion/include/private/svn_named_atomic.h
    subversion/trunk/subversion/libsvn_subr/svn_named_atomic.c
      - copied unchanged from r1326293, 
subversion/branches/revprop-cache/subversion/libsvn_subr/svn_named_atomic.c
    subversion/trunk/subversion/tests/libsvn_subr/named_atomic-test-common.h
      - copied unchanged from r1326293, 
subversion/branches/revprop-cache/subversion/tests/libsvn_subr/named_atomic-test-common.h
    subversion/trunk/subversion/tests/libsvn_subr/named_atomic-test-proc.c
      - copied unchanged from r1326293, 
subversion/branches/revprop-cache/subversion/tests/libsvn_subr/named_atomic-test-proc.c
    subversion/trunk/subversion/tests/libsvn_subr/named_atomic-test.c
      - copied, changed from r1326293, 
subversion/branches/revprop-cache/subversion/tests/libsvn_subr/named_atomic-test.c
Modified:
    subversion/trunk/   (props changed)
    subversion/trunk/build.conf
    subversion/trunk/build/ac-macros/svn-macros.m4
    subversion/trunk/configure.ac
    subversion/trunk/subversion/include/svn_error_codes.h
    subversion/trunk/subversion/include/svn_fs.h
    subversion/trunk/subversion/include/svn_io.h
    subversion/trunk/subversion/libsvn_fs_fs/caching.c
    subversion/trunk/subversion/libsvn_fs_fs/fs.h
    subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c
    subversion/trunk/subversion/libsvn_subr/io.c
    subversion/trunk/subversion/mod_dav_svn/dav_svn.h
    subversion/trunk/subversion/mod_dav_svn/mod_dav_svn.c
    subversion/trunk/subversion/mod_dav_svn/repos.c
    subversion/trunk/subversion/svnadmin/main.c
    subversion/trunk/subversion/svnserve/main.c
    subversion/trunk/subversion/svnserve/serve.c
    subversion/trunk/subversion/svnserve/server.h
    subversion/trunk/subversion/tests/libsvn_repos/repos-test.c
    subversion/trunk/subversion/tests/libsvn_subr/   (props changed)
    subversion/trunk/subversion/tests/svn_test.h

Propchange: subversion/trunk/
------------------------------------------------------------------------------
  Merged /subversion/branches/revprop-cache:r1298521-1326293

Modified: subversion/trunk/build.conf
URL: 
http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/build.conf (original)
+++ subversion/trunk/build.conf Sun Apr 15 11:20:58 2012
@@ -331,7 +331,7 @@ msvc-export = 
         private\svn_token.h  private\svn_adler32.h
         private\svn_temp_serializer.h private\svn_io_private.h
         private\svn_string_private.h private\svn_magic.h
-        private\svn_subr_private.h private\svn_mutex.h
+        private\svn_subr_private.h private\svn_mutex.h 
private\svn_named_atomic.h
 
 # Working copy management lib
 [libsvn_wc]
@@ -792,6 +792,22 @@ sources = mergeinfo-test.c
 install = test
 libs = libsvn_test libsvn_subr apr
 
+[named_atomic-test]
+description = Test named atomics
+type = exe
+path = subversion/tests/libsvn_subr
+sources = named_atomic-test.c
+install = test
+libs = libsvn_test libsvn_subr apr
+
+[named_atomic-test-proc]
+description = Sub-process for named atomics
+type = exe
+path = subversion/tests/libsvn_subr
+sources = named_atomic-test-proc.c
+install = sub-test
+libs = libsvn_subr apr
+
 [path-test]
 description = Test path library
 type = exe
@@ -1142,7 +1158,7 @@ libs = __ALL__
        checksum-test compat-test config-test hashdump-test mergeinfo-test
        opt-test path-test stream-test string-test time-test utf-test
        target-test error-test cache-test spillbuf-test crypto-test
-       revision-test
+       named-atomics-test-proc revision-test
        subst_translate-test
        translate-test
        random-test window-test

Modified: subversion/trunk/build/ac-macros/svn-macros.m4
URL: 
http://svn.apache.org/viewvc/subversion/trunk/build/ac-macros/svn-macros.m4?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/build/ac-macros/svn-macros.m4 (original)
+++ subversion/trunk/build/ac-macros/svn-macros.m4 Sun Apr 15 11:20:58 2012
@@ -202,3 +202,44 @@ AC_DEFUN([SVN_REMOVE_STANDARD_LIB_DIRS],
     printf "%s" "${output_flags# }"
   fi
 ])
+
+AC_DEFUN([SVN_CHECK_FOR_ATOMIC_BUILTINS],
+[
+  AC_CACHE_CHECK([whether the compiler provides atomic builtins], 
[svn_cv_atomic_builtins],
+  [AC_TRY_RUN([
+  int main()
+  {
+      unsigned long long val = 1010, tmp, *mem = &val;
+
+      if (__sync_fetch_and_add(&val, 1010) != 1010 || val != 2020)
+          return 1;
+
+      tmp = val;
+
+      if (__sync_fetch_and_sub(mem, 1010) != tmp || val != 1010)
+          return 1;
+
+      if (__sync_sub_and_fetch(&val, 1010) != 0 || val != 0)
+          return 1;
+
+      tmp = 3030;
+
+      if (__sync_val_compare_and_swap(mem, 0, tmp) != 0 || val != tmp)
+          return 1;
+
+      if (__sync_lock_test_and_set(&val, 4040) != 3030)
+          return 1;
+
+      mem = &tmp;
+
+      if (__sync_val_compare_and_swap(&mem, &tmp, &val) != &tmp)
+          return 1;
+
+      __sync_synchronize();
+
+      if (mem != &val)
+          return 1;
+
+      return 0;
+  }], [svn_cv_atomic_builtins=yes], [svn_cv_atomic_builtins=no], 
[svn_cv_atomic_builtins=no])])
+])

Modified: subversion/trunk/configure.ac
URL: 
http://svn.apache.org/viewvc/subversion/trunk/configure.ac?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/configure.ac (original)
+++ subversion/trunk/configure.ac Sun Apr 15 11:20:58 2012
@@ -184,6 +184,12 @@ if test -n "$sqlite_compat_ver" && test 
   CFLAGS="-DSVN_SQLITE_MIN_VERSION_NUMBER=$sqlite_compat_ver_num $CFLAGS"
 fi
 
+SVN_CHECK_FOR_ATOMIC_BUILTINS
+
+if test "$svn_cv_atomic_builtins" = "yes"; then
+    AC_DEFINE(SVN_HAS_ATOMIC_BUILTINS, 1, [Define if compiler provides atomic 
builtins])
+fi
+
 dnl Set up a number of directories ---------------------
 
 dnl Create SVN_BINDIR for proper substitution
@@ -825,7 +831,7 @@ dnl Build and install rules ------------
 INSTALL_STATIC_RULES="install-bin install-docs"
 INSTALL_RULES="install-fsmod-lib install-ramod-lib install-lib install-include 
install-static"
 INSTALL_RULES="$INSTALL_RULES $INSTALL_APACHE_RULE"
-BUILD_RULES="fsmod-lib ramod-lib lib bin test $BUILD_APACHE_RULE tools"
+BUILD_RULES="fsmod-lib ramod-lib lib bin test sub-test $BUILD_APACHE_RULE 
tools"
 
 if test "$svn_lib_berkeley_db" = "yes"; then
   BUILD_RULES="$BUILD_RULES bdb-lib bdb-test"

Modified: subversion/trunk/subversion/include/svn_error_codes.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_error_codes.h?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_error_codes.h (original)
+++ subversion/trunk/subversion/include/svn_error_codes.h Sun Apr 15 11:20:58 
2012
@@ -224,6 +224,11 @@ SVN_ERROR_START
              SVN_ERR_BAD_CATEGORY_START + 14,
              "Invalid changelist name")
 
+  /** @since New in 1.8. */
+  SVN_ERRDEF(SVN_ERR_BAD_ATOMIC,
+             SVN_ERR_BAD_CATEGORY_START + 15,
+             "Invalid atomic")
+
   /* xml errors */
 
   SVN_ERRDEF(SVN_ERR_XML_ATTRIB_NOT_FOUND,

Modified: subversion/trunk/subversion/include/svn_fs.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_fs.h?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_fs.h (original)
+++ subversion/trunk/subversion/include/svn_fs.h Sun Apr 15 11:20:58 2012
@@ -85,6 +85,12 @@ typedef struct svn_fs_t svn_fs_t;
  */
 #define SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS      "fsfs-cache-fulltexts"
 
+/** Enable / disable revprop caching for a FSFS repository.
+ *
+ * @since New in 1.8.
+ */
+#define SVN_FS_CONFIG_FSFS_CACHE_REVPROPS       "fsfs-cache-revprops"
+
 /* See also svn_fs_type(). */
 /** @since New in 1.1. */
 #define SVN_FS_CONFIG_FS_TYPE                   "fs-type"

Modified: subversion/trunk/subversion/include/svn_io.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_io.h?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_io.h (original)
+++ subversion/trunk/subversion/include/svn_io.h Sun Apr 15 11:20:58 2012
@@ -682,6 +682,39 @@ svn_io_file_lock2(const char *lock_file,
                   svn_boolean_t exclusive,
                   svn_boolean_t nonblocking,
                   apr_pool_t *pool);
+
+/**
+ * Lock the file @a lockfile_handle. If @a exclusive is TRUE,
+ * obtain exclusive lock, otherwise obtain shared lock.
+ *
+ * If @a nonblocking is TRUE, do not wait for the lock if it
+ * is not available: throw an error instead.
+ *
+ * Lock will be automatically released when @a pool is cleared or destroyed.
+ * You may also explicitly call @ref svn_io_unlock_open_file.
+ * Use @a pool for memory allocations. @a pool must be the pool that
+ * @a lockfile_handle has been created in or one of its sub-pools.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_io_lock_open_file(apr_file_t *lockfile_handle,
+                      svn_boolean_t exclusive,
+                      svn_boolean_t nonblocking,
+                      apr_pool_t *pool);
+
+/**
+ * Unlock the file @a lockfile_handle.
+ *
+ * Use @a pool for memory allocations. @a pool must be the pool that
+ * @a lockfile_handle has been created in or one of its sub-pools.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_io_unlock_open_file(apr_file_t *lockfile_handle,
+                        apr_pool_t *pool);
+
 /**
  * Flush any unwritten data from @a file to disk.  Use @a pool for
  * memory allocations.

Modified: subversion/trunk/subversion/libsvn_fs_fs/caching.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/caching.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/caching.c Sun Apr 15 11:20:58 2012
@@ -44,6 +44,7 @@ read_config(svn_memcache_t **memcache_p,
             svn_boolean_t *fail_stop,
             svn_boolean_t *cache_txdeltas,
             svn_boolean_t *cache_fulltexts,
+            svn_boolean_t *cache_revprops,
             svn_fs_t *fs,
             apr_pool_t *pool)
 {
@@ -74,6 +75,16 @@ read_config(svn_memcache_t **memcache_p,
                          SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
                          TRUE);
 
+  /* don't cache revprops by default.
+   * Revprop caching significantly speeds up operations like
+   * svn ls -v. However, it requires synchronization that may
+   * not be available or efficient in the current server setup.
+   */
+  *cache_revprops
+    = svn_hash__get_bool(fs->config,
+                         SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
+                         FALSE);
+
   return svn_config_get_bool(ffd->config, fail_stop,
                              CONFIG_SECTION_CACHES, CONFIG_OPTION_FAIL_STOP,
                              FALSE);
@@ -249,12 +260,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
   svn_boolean_t no_handler;
   svn_boolean_t cache_txdeltas;
   svn_boolean_t cache_fulltexts;
+  svn_boolean_t cache_revprops;
 
   /* Evaluating the cache configuration. */
   SVN_ERR(read_config(&memcache,
                       &no_handler,
                       &cache_txdeltas,
                       &cache_fulltexts,
+                      &cache_revprops,
                       fs,
                       pool));
 
@@ -339,6 +352,27 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
 
   SVN_ERR(init_callbacks(ffd->fulltext_cache, fs, no_handler, pool));
 
+  /* initialize revprop cache, if full-text caching has been enabled */
+  if (cache_revprops)
+    {
+      SVN_ERR(create_cache(&(ffd->revprop_cache),
+                           NULL,
+                           membuffer,
+                           0, 0, /* Do not use inprocess cache */
+                           svn_fs_fs__serialize_properties,
+                           svn_fs_fs__deserialize_properties,
+                           APR_HASH_KEY_STRING,
+                           apr_pstrcat(pool, prefix, "REVPROP",
+                                       (char *)NULL),
+                           fs->pool));
+    }
+  else
+    {
+      ffd->revprop_cache = NULL;
+    }
+
+  SVN_ERR(init_callbacks(ffd->revprop_cache, fs, no_handler, pool));
+
   /* initialize txdelta window cache, if that has been enabled */
   if (cache_txdeltas)
     {

Modified: subversion/trunk/subversion/libsvn_fs_fs/fs.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/fs.h?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/fs.h Sun Apr 15 11:20:58 2012
@@ -34,6 +34,7 @@
 #include "private/svn_fs_private.h"
 #include "private/svn_sqlite.h"
 #include "private/svn_mutex.h"
+#include "private/svn_named_atomic.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -207,7 +208,8 @@ typedef struct fs_fs_shared_data_t
   apr_pool_t *common_pool;
 } fs_fs_shared_data_t;
 
-/* Private (non-shared) FSFS-specific data for each svn_fs_t object. */
+/* Private (non-shared) FSFS-specific data for each svn_fs_t object.
+   Any caches in here may be NULL. */
 typedef struct fs_fs_data_t
 {
   /* The format number of this FS. */
@@ -246,6 +248,17 @@ typedef struct fs_fs_data_t
      rep key (revision/offset) to svn_string_t. */
   svn_cache__t *fulltext_cache;
 
+  /* Access object to the revprop "generation". Will be NULL until
+     the first access. */
+  svn_named_atomic__t *revprop_generation;
+  
+  /* Access object to the revprop update timeout. Will be NULL until
+     the first access. */
+  svn_named_atomic__t *revprop_timeout;
+  
+  /* Revision property cache.  Maps from (rev,generation) to apr_hash_t. */
+  svn_cache__t *revprop_cache;
+
   /* Pack manifest cache; a cache mapping (svn_revnum_t) shard number to
      a manifest; and a manifest is a mapping from (svn_revnum_t) revision
      number offset within a shard to (apr_off_t) byte-offset in the

Modified: subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c Sun Apr 15 11:20:58 2012
@@ -92,6 +92,16 @@
    Values < 1 disable deltification. */
 #define SVN_FS_FS_MAX_DELTIFICATION_WALK 1023
 
+/* Give writing processes 10 seconds to replace an existing revprop
+   file with a new one. After that time, we assume that the writing
+   process got aborted and that we have re-read revprops. */
+#define REVPROP_CHANGE_TIMEOUT 10 * 1000000
+
+/* The following are names of atomics that will be used to communicate
+ * revprop updates across all processes on this machine. */
+#define ATOMIC_REVPROP_GENERATION "RevPropGeneration"
+#define ATOMIC_REVPROP_TIMEOUT    "RevPropTimeout"
+
 /* Following are defines that specify the textual elements of the
    native filesystem directories and revision files. */
 
@@ -870,25 +880,39 @@ get_file_offset(apr_off_t *offset_p, apr
 }
 
 
-/* Check that BUF, a nul-terminated buffer of text from format file PATH,
+/* Check that BUF, a nul-terminated buffer of text from file PATH,
    contains only digits at OFFSET and beyond, raising an error if not.
+   TITLE contains a user-visible description of the file, usually the
+   short file name.
 
    Uses POOL for temporary allocation. */
 static svn_error_t *
-check_format_file_buffer_numeric(const char *buf, apr_off_t offset,
-                                 const char *path, apr_pool_t *pool)
+check_file_buffer_numeric(const char *buf, apr_off_t offset,
+                          const char *path, const char *title,
+                          apr_pool_t *pool)
 {
   const char *p;
 
   for (p = buf + offset; *p; p++)
     if (!svn_ctype_isdigit(*p))
       return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL,
-        _("Format file '%s' contains unexpected non-digit '%c' within '%s'"),
-        svn_dirent_local_style(path, pool), *p, buf);
+        _("%s file '%s' contains unexpected non-digit '%c' within '%s'"),
+        title, svn_dirent_local_style(path, pool), *p, buf);
 
   return SVN_NO_ERROR;
 }
 
+/* Check that BUF, a nul-terminated buffer of text from format file PATH,
+   contains only digits at OFFSET and beyond, raising an error if not.
+
+   Uses POOL for temporary allocation. */
+static svn_error_t *
+check_format_file_buffer_numeric(const char *buf, apr_off_t offset,
+                                 const char *path, apr_pool_t *pool)
+{
+  return check_file_buffer_numeric(buf, offset, path, "Format", pool);
+}
+
 /* Read the format number and maximum number of files per directory
    from PATH and return them in *PFORMAT and *MAX_FILES_PER_DIR
    respectively.
@@ -2775,6 +2799,160 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro
   return SVN_NO_ERROR;
 }
 
+/* Make sure the revprop_generation member in FS is set. */
+static svn_error_t *
+ensure_revprop_generation(svn_fs_t *fs)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  
+  return ffd->revprop_generation == NULL
+    ? svn_named_atomic__get(&ffd->revprop_generation,
+                            NULL,
+                            ATOMIC_REVPROP_GENERATION,
+                            TRUE)
+    : SVN_NO_ERROR;
+}
+
+/* Make sure the revprop_timeout member in FS is set. */
+static svn_error_t *
+ensure_revprop_timeout(svn_fs_t *fs)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  
+  return ffd->revprop_timeout == NULL
+    ? svn_named_atomic__get(&ffd->revprop_timeout,
+                            NULL,
+                            ATOMIC_REVPROP_TIMEOUT,
+                            TRUE)
+    : SVN_NO_ERROR;
+}
+
+/* Test whether revprop cache and necessary infrastructure are
+   available in FS. */
+static svn_boolean_t
+has_revprop_cache(svn_fs_t *fs)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  svn_error_t *error;
+
+  /* is the cache (still) enabled? */
+  if (ffd->revprop_cache == NULL)
+    return FALSE;
+
+  /* try to access our SHM-backed infrastructure */
+  error = ensure_revprop_generation(fs);
+  if (error)
+    {
+      /* failure -> disable revprop cache for good */
+
+      svn_error_clear(error);
+      ffd->revprop_cache = NULL;
+
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/* 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. */
+static svn_error_t *
+read_revprop_generation(svn_fs_t *fs,
+                        apr_int64_t *generation)
+{
+  apr_int64_t current = 0;
+  fs_fs_data_t *ffd = fs->fsap_data;
+  
+  /* read the current revprop generation number */
+  SVN_ERR(ensure_revprop_generation(fs));
+  SVN_ERR(svn_named_atomic__read(&current, ffd->revprop_generation));
+
+  /* is an unfinished revprop write under the way? */
+  if (current % 2)
+    {
+      apr_int64_t timeout = 0;
+
+      /* read timeout for the write operation */
+      SVN_ERR(ensure_revprop_timeout(fs));
+      SVN_ERR(svn_named_atomic__read(&timeout, ffd->revprop_timeout));
+
+      /* has the writer process been aborted,
+       * i.e. has the timeout been reached?
+       */
+      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.
+           */
+          while (current % 2)
+            SVN_ERR(svn_named_atomic__add(&current,
+                                          1,
+                                          ffd->revprop_generation));
+        }
+    }
+
+  /* return the value we just got */
+  *generation = current;
+  return SVN_NO_ERROR;
+}
+
+/* Set the revprop generation to the next odd number to indicate that
+   there is a revprop write process under way. If that times out,
+   readers shall recover from that state & re-read revprops.
+   Use the access object in FS to set the shared mem value. */
+static svn_error_t *
+begin_revprop_change(svn_fs_t *fs)
+{
+  apr_int64_t current;
+  fs_fs_data_t *ffd = fs->fsap_data;
+  
+  /* set the timeout for the write operation */
+  SVN_ERR(ensure_revprop_timeout(fs));
+  SVN_ERR(svn_named_atomic__write(NULL,
+                                  apr_time_now() + REVPROP_CHANGE_TIMEOUT,
+                                  ffd->revprop_timeout));
+
+  /* set the revprop generation to an odd value to indicate
+   * that a write is in progress
+   */
+  SVN_ERR(ensure_revprop_generation(fs));
+  do
+    {
+      SVN_ERR(svn_named_atomic__add(&current,
+                                    1,
+                                    ffd->revprop_generation));
+    }
+  while (current % 2 == 0);
+
+  return SVN_NO_ERROR;
+}
+
+/* Set the revprop generation to the next even number to indicate that
+   a) readers shall re-read revprops, and
+   b) the write process has been completed (no recovery required)
+   Use the access object in FS to set the shared mem value. */
+static svn_error_t *
+end_revprop_change(svn_fs_t *fs)
+{
+  apr_int64_t current = 1;
+  fs_fs_data_t *ffd = fs->fsap_data;
+  
+  /* set the revprop generation to an even value to indicate
+   * that a write has been completed
+   */
+  SVN_ERR(ensure_revprop_generation(fs));
+  do
+    {
+      SVN_ERR(svn_named_atomic__add(&current,
+                                    1,
+                                    ffd->revprop_generation));
+    }
+  while (current % 2);
+
+  return SVN_NO_ERROR;
+}
+
 /* Set the revision property list of revision REV in filesystem FS to
    PROPLIST.  Use POOL for temporary allocations. */
 static svn_error_t *
@@ -2791,6 +2969,11 @@ set_revision_proplist(svn_fs_t *fs,
       const char *tmp_path;
       const char *perms_reference;
       svn_stream_t *stream;
+      svn_node_kind_t kind = svn_node_none;
+
+      /* test whether revprops already exist for this revision */
+      if (has_revprop_cache(fs))
+        SVN_ERR(svn_io_check_path(final_path, &kind, pool));
 
       /* ### do we have a directory sitting around already? we really shouldn't
          ### have to get the dirname here. */
@@ -2805,7 +2988,17 @@ set_revision_proplist(svn_fs_t *fs,
          file won't exist and therefore can't serve as its own reference.
          (Whereas the rev file should already exist at this point.) */
       SVN_ERR(svn_fs_fs__path_rev_absolute(&perms_reference, fs, rev, pool));
+
+      /* Now, we may actually be replacing revprops. Make sure that all other
+         threads and processes will know about this. */
+      if (kind != svn_node_none)
+        SVN_ERR(begin_revprop_change(fs));
+
       SVN_ERR(move_into_place(tmp_path, final_path, perms_reference, pool));
+
+      /* Indicate that the update (if relevant) has been completed. */
+      if (kind != svn_node_none)
+        SVN_ERR(end_revprop_change(fs));
     }
 
   return SVN_NO_ERROR;
@@ -2818,9 +3011,26 @@ revision_proplist(apr_hash_t **proplist_
                   apr_pool_t *pool)
 {
   apr_hash_t *proplist;
+  fs_fs_data_t *ffd = fs->fsap_data;
+  const char *key;
 
   SVN_ERR(ensure_revision_exists(fs, rev, pool));
 
+  /* Try cache lookup first. */
+  if (has_revprop_cache(fs))
+    {
+      apr_int64_t generation;
+      svn_boolean_t is_cached;
+
+      SVN_ERR(read_revprop_generation(fs, &generation));
+
+      key = svn_fs_fs__combine_two_numbers(rev, generation, pool);
+      SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
+                             ffd->revprop_cache, key, pool));
+      if (is_cached)
+        return SVN_NO_ERROR;
+    }
+
   /* if (1); null condition for easier merging to revprop-packing */
     {
       apr_file_t *revprop_file = NULL;
@@ -2875,6 +3085,10 @@ revision_proplist(apr_hash_t **proplist_
       svn_pool_destroy(iterpool);
     }
 
+  /* Cache the result, if caching has been activated. */
+  if (has_revprop_cache(fs))
+    SVN_ERR(svn_cache__set(ffd->revprop_cache, key, proplist, pool));
+
   *proplist_p = proplist;
 
   return SVN_NO_ERROR;

Modified: subversion/trunk/subversion/libsvn_subr/io.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/io.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/io.c (original)
+++ subversion/trunk/subversion/libsvn_subr/io.c Sun Apr 15 11:20:58 2012
@@ -1866,29 +1866,23 @@ file_clear_locks(void *arg)
 #endif
 
 svn_error_t *
-svn_io_file_lock2(const char *lock_file,
-                  svn_boolean_t exclusive,
-                  svn_boolean_t nonblocking,
-                  apr_pool_t *pool)
+svn_io_lock_open_file(apr_file_t *lockfile_handle,
+                      svn_boolean_t exclusive,
+                      svn_boolean_t nonblocking,
+                      apr_pool_t *pool)
 {
   int locktype = APR_FLOCK_SHARED;
-  apr_file_t *lockfile_handle;
-  apr_int32_t flags;
   apr_status_t apr_err;
+  const char *fname;
 
   if (exclusive)
     locktype = APR_FLOCK_EXCLUSIVE;
-
-  flags = APR_READ;
-  if (locktype == APR_FLOCK_EXCLUSIVE)
-    flags |= APR_WRITE;
-
   if (nonblocking)
     locktype |= APR_FLOCK_NONBLOCK;
 
-  SVN_ERR(svn_io_file_open(&lockfile_handle, lock_file, flags,
-                           APR_OS_DEFAULT,
-                           pool));
+  /* We need this only in case of an error but this is cheap to get -
+   * so we do it here for clarity. */
+  apr_err = apr_file_name_get(&fname, lockfile_handle);
 
   /* Get lock on the filehandle. */
   apr_err = apr_file_lock(lockfile_handle, locktype);
@@ -1915,11 +1909,11 @@ svn_io_file_lock2(const char *lock_file,
         case APR_FLOCK_SHARED:
           return svn_error_wrap_apr(apr_err,
                                     _("Can't get shared lock on file '%s'"),
-                                    svn_dirent_local_style(lock_file, pool));
+                                    svn_dirent_local_style(fname, pool));
         case APR_FLOCK_EXCLUSIVE:
           return svn_error_wrap_apr(apr_err,
                                     _("Can't get exclusive lock on file '%s'"),
-                                    svn_dirent_local_style(lock_file, pool));
+                                    svn_dirent_local_style(fname, pool));
         default:
           SVN_ERR_MALFUNCTION();
         }
@@ -1936,6 +1930,58 @@ svn_io_file_lock2(const char *lock_file,
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_io_unlock_open_file(apr_file_t *lockfile_handle,
+                        apr_pool_t *pool)
+{
+  const char *fname;
+  apr_status_t apr_err = apr_file_unlock(lockfile_handle);
+
+  /* We need this only in case of an error but this is cheap to get -
+   * so we do it here for clarity. */
+  apr_err = apr_file_name_get(&fname, lockfile_handle);
+
+/* On Windows and OS/2 file locks are automatically released when
+   the file handle closes */
+#if !defined(WIN32) && !defined(__OS2__)
+  apr_pool_cleanup_kill(pool, lockfile_handle, file_clear_locks);
+#endif
+
+  return apr_err
+    ? svn_error_wrap_apr(apr_err, _("Can't unlock file '%s'"),
+                                  svn_dirent_local_style(fname, pool))
+    : SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_io_file_lock2(const char *lock_file,
+                  svn_boolean_t exclusive,
+                  svn_boolean_t nonblocking,
+                  apr_pool_t *pool)
+{
+  int locktype = APR_FLOCK_SHARED;
+  apr_file_t *lockfile_handle;
+  apr_int32_t flags;
+  apr_status_t apr_err;
+
+  if (exclusive)
+    locktype = APR_FLOCK_EXCLUSIVE;
+
+  flags = APR_READ;
+  if (locktype == APR_FLOCK_EXCLUSIVE)
+    flags |= APR_WRITE;
+
+  if (nonblocking)
+    locktype |= APR_FLOCK_NONBLOCK;
+
+  SVN_ERR(svn_io_file_open(&lockfile_handle, lock_file, flags,
+                           APR_OS_DEFAULT,
+                           pool));
+
+  /* Get lock on the filehandle. */
+  return svn_io_lock_open_file(lockfile_handle, exclusive, nonblocking, pool);
+}
+
 
 
 /* Data consistency/coherency operations. */

Modified: subversion/trunk/subversion/mod_dav_svn/dav_svn.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/dav_svn.h?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/dav_svn.h (original)
+++ subversion/trunk/subversion/mod_dav_svn/dav_svn.h Sun Apr 15 11:20:58 2012
@@ -316,6 +316,9 @@ svn_boolean_t dav_svn__get_txdelta_cache
 /* for the repository referred to by this request, is fulltext caching active? 
*/
 svn_boolean_t dav_svn__get_fulltext_cache_flag(request_rec *r);
 
+/* for the repository referred to by this request, is revprop caching active? 
*/
+svn_boolean_t dav_svn__get_revprop_cache_flag(request_rec *r);
+
 /* for the repository referred to by this request, are subrequests bypassed?
  * A function pointer if yes, NULL if not.
  */

Modified: subversion/trunk/subversion/mod_dav_svn/mod_dav_svn.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/mod_dav_svn.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/mod_dav_svn.c (original)
+++ subversion/trunk/subversion/mod_dav_svn/mod_dav_svn.c Sun Apr 15 11:20:58 
2012
@@ -95,6 +95,7 @@ typedef struct dir_conf_t {
   const char *activities_db;         /* path to activities database(s) */
   enum conf_flag txdelta_cache;      /* whether to enable txdelta caching */
   enum conf_flag fulltext_cache;     /* whether to enable fulltext caching */
+  enum conf_flag revprop_cache;      /* whether to enable revprop caching */
   apr_hash_t *hooks_env;             /* environment for hook scripts */
 } dir_conf_t;
 
@@ -224,6 +225,7 @@ merge_dir_config(apr_pool_t *p, void *ba
   newconf->list_parentpath = INHERIT_VALUE(parent, child, list_parentpath);
   newconf->txdelta_cache = INHERIT_VALUE(parent, child, txdelta_cache);
   newconf->fulltext_cache = INHERIT_VALUE(parent, child, fulltext_cache);
+  newconf->revprop_cache = INHERIT_VALUE(parent, child, revprop_cache);
   newconf->root_dir = INHERIT_VALUE(parent, child, root_dir);
   newconf->hooks_env = INHERIT_VALUE(parent, child, hooks_env);
 
@@ -476,6 +478,19 @@ SVNCacheFullTexts_cmd(cmd_parms *cmd, vo
 }
 
 static const char *
+SVNCacheRevProps_cmd(cmd_parms *cmd, void *config, int arg)
+{
+  dir_conf_t *conf = config;
+
+  if (arg)
+    conf->revprop_cache = CONF_FLAG_ON;
+  else
+    conf->revprop_cache = CONF_FLAG_OFF;
+
+  return NULL;
+}
+
+static const char *
 SVNInMemoryCacheSize_cmd(cmd_parms *cmd, void *config, const char *arg1)
 {
   svn_cache_config_t settings = *svn_cache_config_get();
@@ -847,6 +862,16 @@ dav_svn__get_fulltext_cache_flag(request
 }
 
 
+svn_boolean_t
+dav_svn__get_revprop_cache_flag(request_rec *r)
+{
+  dir_conf_t *conf;
+
+  conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
+  return conf->revprop_cache == CONF_FLAG_ON;
+}
+
+
 int
 dav_svn__get_compression_level(void)
 {
@@ -1083,6 +1108,14 @@ static const command_rec cmds[] =
                "if sufficient in-memory cache is available "
                "(default is Off)."),
 
+  /* per directory/location */
+  AP_INIT_FLAG("SVNCacheRevProps", SVNCacheRevProps_cmd, NULL,
+               ACCESS_CONF|RSRC_CONF,
+               "speeds up 'svn ls -v', export and checkout operations"
+               "but should only be enabled under the conditions described"
+               "in the documentation"
+               "(default is Off)."),
+
   /* per server */
   AP_INIT_TAKE1("SVNInMemoryCacheSize", SVNInMemoryCacheSize_cmd, NULL,
                 RSRC_CONF,

Modified: subversion/trunk/subversion/mod_dav_svn/repos.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/repos.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/repos.c (original)
+++ subversion/trunk/subversion/mod_dav_svn/repos.c Sun Apr 15 11:20:58 2012
@@ -2154,6 +2154,10 @@ get_resource(request_rec *r,
                    SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
                    APR_HASH_KEY_STRING,
                    dav_svn__get_fulltext_cache_flag(r) ? "1" : "0");
+      apr_hash_set(fs_config,
+                   SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
+                   APR_HASH_KEY_STRING,
+                   dav_svn__get_revprop_cache_flag(r) ? "1" : "0");
 
       /* open the FS */
       serr = svn_repos_open2(&(repos->repos), fs_path, fs_config,

Modified: subversion/trunk/subversion/svnadmin/main.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnadmin/main.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/svnadmin/main.c (original)
+++ subversion/trunk/subversion/svnadmin/main.c Sun Apr 15 11:20:58 2012
@@ -108,12 +108,14 @@ open_repos(svn_repos_t **repos,
            const char *path,
            apr_pool_t *pool)
 {
-  /* construct FS configuration parameters: enable all available caches */
+  /* construct FS configuration parameters: enable caches for r/o data */
   apr_hash_t *fs_config = apr_hash_make(pool);
   apr_hash_set(fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS,
                APR_HASH_KEY_STRING, "1");
   apr_hash_set(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
                APR_HASH_KEY_STRING, "1");
+  apr_hash_set(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
+               APR_HASH_KEY_STRING, "0");
 
   /* now, open the requested repository */
   SVN_ERR(svn_repos_open2(repos, path, fs_config, pool));

Modified: subversion/trunk/subversion/svnserve/main.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/main.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/main.c (original)
+++ subversion/trunk/subversion/svnserve/main.c Sun Apr 15 11:20:58 2012
@@ -147,7 +147,8 @@ void winservice_notify_stop(void)
 #define SVNSERVE_OPT_LOG_FILE        264
 #define SVNSERVE_OPT_CACHE_TXDELTAS  265
 #define SVNSERVE_OPT_CACHE_FULLTEXTS 266
-#define SVNSERVE_OPT_SINGLE_CONN     267
+#define SVNSERVE_OPT_CACHE_REVPROPS  267
+#define SVNSERVE_OPT_SINGLE_CONN     268
 
 static const apr_getopt_option_t svnserve__options[] =
   {
@@ -222,6 +223,14 @@ static const apr_getopt_option_t svnserv
         "Default is yes.\n"
         "                             "
         "[used for FSFS repositories only]")},
+    {"cache-revprops", SVNSERVE_OPT_CACHE_REVPROPS, 1,
+     N_("enable or disable caching of revision properties.\n"
+        "                             "
+        "Consult the documentation before activating this.\n"
+        "                             "
+        "Default is no.\n"
+        "                             "
+        "[used for FSFS repositories only]")},
 #ifdef CONNECTION_HAVE_THREAD_OPTION
     /* ### Making the assumption here that WIN32 never has fork and so
      * ### this option never exists when --service exists. */
@@ -482,6 +491,7 @@ int main(int argc, const char *argv[])
   params.memory_cache_size = (apr_uint64_t)-1;
   params.cache_fulltexts = TRUE;
   params.cache_txdeltas = FALSE;
+  params.cache_revprops = FALSE;
 
   while (1)
     {
@@ -625,6 +635,11 @@ int main(int argc, const char *argv[])
              = svn_tristate__from_word(arg) == svn_tristate_true;
           break;
 
+        case SVNSERVE_OPT_CACHE_REVPROPS:
+          params.cache_revprops
+             = svn_tristate__from_word(arg) == svn_tristate_true;
+          break;
+
 #ifdef WIN32
         case SVNSERVE_OPT_SERVICE:
           if (run_mode != run_mode_service)

Modified: subversion/trunk/subversion/svnserve/serve.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/serve.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/serve.c (original)
+++ subversion/trunk/subversion/svnserve/serve.c Sun Apr 15 11:20:58 2012
@@ -3249,6 +3249,8 @@ svn_error_t *serve(svn_ra_svn_conn_t *co
                APR_HASH_KEY_STRING, params->cache_txdeltas ? "1" : "0");
   apr_hash_set(b.fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
                APR_HASH_KEY_STRING, params->cache_fulltexts ? "1" : "0");
+  apr_hash_set(b.fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
+               APR_HASH_KEY_STRING, params->cache_revprops ? "1" : "0");
 
   /* Send greeting.  We don't support version 1 any more, so we can
    * send an empty mechlist. */

Modified: subversion/trunk/subversion/svnserve/server.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/server.h?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/server.h (original)
+++ subversion/trunk/subversion/svnserve/server.h Sun Apr 15 11:20:58 2012
@@ -116,6 +116,9 @@ typedef struct serve_params_t {
   /* Enable full-text caching for all FSFS repositories. */
   svn_boolean_t cache_fulltexts;
 
+  /* Enable revprop caching for all FSFS repositories. */
+  svn_boolean_t cache_revprops;
+
   /* Size of the in-memory cache (used by FSFS only). */
   apr_uint64_t memory_cache_size;
 

Modified: subversion/trunk/subversion/tests/libsvn_repos/repos-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_repos/repos-test.c?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_repos/repos-test.c Sun Apr 15 
11:20:58 2012
@@ -1318,9 +1318,8 @@ authz(apr_pool_t *pool)
   contents =
     "[greek:/dir2//secret]"                                                  NL
     "* ="                                                                    
NL;
-  err = authz_get_handle(&authz_cfg, contents, subpool);
-  SVN_TEST_ASSERT_ERROR(err, SVN_ERR_AUTHZ_INVALID_CONFIG);
-  svn_error_clear(err);
+  SVN_TEST_ASSERT_ERROR(authz_get_handle(&authz_cfg, contents, subpool),
+                        SVN_ERR_AUTHZ_INVALID_CONFIG);
 
   /* That's a wrap! */
   svn_pool_destroy(subpool);
@@ -1480,10 +1479,7 @@ test_path_authz(svn_repos_t *repos,
 
   /* Check for potential errors. */
   if (path_action->authz_error_expected)
-    {
-      SVN_TEST_ASSERT_ERROR(err, SVN_ERR_AUTHZ_UNWRITABLE);
-      svn_error_clear(err);
-    }
+    SVN_TEST_ASSERT_ERROR(err, SVN_ERR_AUTHZ_UNWRITABLE);
   else
     SVN_ERR(err);
 

Propchange: subversion/trunk/subversion/tests/libsvn_subr/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Apr 15 11:20:58 2012
@@ -36,3 +36,5 @@ auth-test
 eol-test
 subst_translate-test
 spillbuf-test
+named_atomic-test
+named_atomic-test-proc

Copied: subversion/trunk/subversion/tests/libsvn_subr/named_atomic-test.c (from 
r1326293, 
subversion/branches/revprop-cache/subversion/tests/libsvn_subr/named_atomic-test.c)
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/named_atomic-test.c?p2=subversion/trunk/subversion/tests/libsvn_subr/named_atomic-test.c&p1=subversion/branches/revprop-cache/subversion/tests/libsvn_subr/named_atomic-test.c&r1=1326293&r2=1326307&rev=1326307&view=diff
==============================================================================
--- 
subversion/branches/revprop-cache/subversion/tests/libsvn_subr/named_atomic-test.c
 (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/named_atomic-test.c Sun Apr 
15 11:20:58 2012
@@ -289,6 +289,13 @@ calibrate_concurrency(apr_pool_t *pool)
 {
   if (hw_thread_count == 0)
     {
+      int i = 0;
+      for (i = 0; i < 100000; ++i)
+        {
+          printf("%8d", i);
+          SVN_ERR(init_concurrency_test_shm(pool, 2));
+          SVN_ERR(run_procs(pool, TEST_PROC, 2, 100000));
+        }
       SVN_ERR(calibrate_iterations(pool, 2));
       for (hw_thread_count = 2; hw_thread_count < 32; hw_thread_count *= 2)
         {

Modified: subversion/trunk/subversion/tests/svn_test.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/svn_test.h?rev=1326307&r1=1326306&r2=1326307&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/svn_test.h (original)
+++ subversion/trunk/subversion/tests/svn_test.h Sun Apr 15 11:20:58 2012
@@ -54,7 +54,9 @@ extern "C" {
   } while (0)
 
 /** Handy macro for testing an expected svn_error_t return value.
- * EXPECTED must be a real error (neither SVN_NO_ERROR nor APR_SUCCESS). */
+ * EXPECTED must be a real error (neither SVN_NO_ERROR nor APR_SUCCESS).
+ * The error returned by EXPR will be cleared.
+ */
 #define SVN_TEST_ASSERT_ERROR(expr, expected)                             \
   do {                                                                    \
     svn_error_t *err__ = (expr);                                          \
@@ -68,6 +70,7 @@ extern "C" {
                                         "Expected error %d but got %s",   \
                                         (expected),                       \
                                         "SVN_NO_ERROR");                  \
+    svn_error_clear(err__);                                               \
   } while (0)
 
 /** Handy macro for testing string equality.


Reply via email to