svn commit: r1936631 - in subversion/trunk: . subversion/tests/libsvn_fs_fs

[email protected] Mon, 27 Jul 2026 10:48:05 -0000
Newsgroups gmane.comp.version-control.subversion.svn
Message-ID <178514928534.3014115.14291633199914449773@svn03-he-fi>
Author: ivan
Date: Mon Jul 27 10:48:05 2026
New Revision: 1936631

Log:
Add an XFail test demonstrating 'cache pollution' problem in the revision
properties cache implementation in FSFS.

The problem is that currently FSFS uses (revision, revprop-generation) as a
key for revision properties cache. Revprop-generation counter is essentially
incremented for every new FS instance. As a result, the cache can be polluted
with multiple entries of the same data. These entries will be removed from the
cache later due to LRU logic, but until that happens they are taking place of
potentially more useful cache entries.

* build.conf
  (fs-fs-sequential-test): New test target.
  (__ALL_TESTS__): Add fs-fs-sequential-test libs list.

* subversion/tests/libsvn_fs_fs/fs-fs-sequential-test.c
  (revprop_cache_pollution): New test.
  (test_funcs): Add revprop_cache_pollution.

Added:
   subversion/trunk/subversion/tests/libsvn_fs_fs/fs-fs-sequential-test.c   (contents, props changed)
Modified:
   subversion/trunk/build.conf

Modified: subversion/trunk/build.conf
==============================================================================
--- subversion/trunk/build.conf	Mon Jul 27 10:43:53 2026	(r1936630)
+++ subversion/trunk/build.conf	Mon Jul 27 10:48:05 2026	(r1936631)
@@ -872,6 +872,14 @@ install = test
 libs = libsvn_test libsvn_wc libsvn_fs libsvn_fs_fs libsvn_delta
        libsvn_repos libsvn_subr apriconv apr
 
+[fs-fs-sequential-test]
+description = Test FSFS
+type = exe
+path = subversion/tests/libsvn_fs_fs
+sources = fs-fs-sequential-test.c
+install = test
+libs = libsvn_test libsvn_wc libsvn_fs libsvn_delta libsvn_subr apriconv apr
+
 # ----------------------------------------------------------------------------
 # Tests for libsvn_fs_x
 [fs-x-pack-test]
@@ -1614,8 +1622,8 @@ type = project
 path = build/win32
 libs = __ALL__
        fs-test fs-base-test fs-fsfs-test fs-fs-pack-test fs-fs-fuzzy-test
-       fs-fs-private-test fs-x-pack-test string-table-test fs-sequential-test
-       skel-test strings-reps-test changes-test locks-test
+       fs-fs-private-test fs-fs-sequential fs-x-pack-test string-table-test
+       fs-sequential-test skel-test strings-reps-test changes-test locks-test
        repos-test authz-test dump-load-test
        checksum-test compat-test config-test hashdump-test mergeinfo-test
        opt-test packed-data-test path-test prefix-string-test

Added: subversion/trunk/subversion/tests/libsvn_fs_fs/fs-fs-sequential-test.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ subversion/trunk/subversion/tests/libsvn_fs_fs/fs-fs-sequential-test.c	Mon Jul 27 10:48:05 2026	(r1936631)
@@ -0,0 +1,131 @@
+/* fs-fs-sequential-test.c --- tests for the FSFS filesystem
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include <apr_pools.h>
+
+#include "../svn_test.h"
+
+#include "private/svn_cache.h"
+#include "svn_fs.h"
+#include "svn_pools.h"
+#include "svn_hash.h"
+#include "svn_props.h"
+
+#include "../svn_test_fs.h"
+
+static svn_error_t *
+revprop_cache_pollution(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  int i;
+  int n;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_hash_t *config;
+  svn_cache__info_t *membuffer_cache_info;
+  apr_uint64_t used_cache_size;
+  const char *fs_name = "test-repo-revprop-cache-pollution";
+
+  config = apr_hash_make(pool);
+  svn_hash_sets(config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS, "1");
+
+  {
+    svn_fs_t *fs;
+    SVN_ERR(svn_test__create_fs2(&fs, fs_name, opts, config, pool));
+
+    /* Create 10 revisions. */
+    for (i = 1; i < 10; ++i)
+      {
+        svn_fs_txn_t *txn;
+        svn_fs_root_t *txn_root;
+        svn_revnum_t new_rev = 0;
+
+        svn_pool_clear(iterpool);
+
+        SVN_ERR(svn_fs_begin_txn(&txn, fs, new_rev, iterpool));
+        SVN_ERR(svn_fs_txn_root(&txn_root, txn, iterpool));
+        SVN_ERR(svn_fs_make_dir(txn_root, apr_itoa(pool, i), iterpool));
+        SVN_ERR(svn_fs_commit_txn(NULL, &new_rev, txn, iterpool));
+        SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(new_rev));
+      }
+  }
+
+  /* Clear membuffer cache. */
+  SVN_ERR(svn_cache__membuffer_clear(svn_cache__get_global_membuffer_cache()));
+  membuffer_cache_info = svn_cache__membuffer_get_global_info(pool);
+  SVN_TEST_INT_ASSERT(membuffer_cache_info->used_size, 0);
+
+  /* Read revision properties for all revisions. */
+  {
+    svn_fs_t *fs;
+
+    SVN_ERR(svn_fs_open2(&fs, fs_name, config, pool, pool));
+    for (i = 1; i < 10; ++i)
+      {
+        apr_hash_t *revprops;
+        svn_pool_clear(iterpool);
+
+        SVN_ERR(svn_fs_revision_proplist2(&revprops, fs, i, FALSE, iterpool,
+                                          iterpool));
+      }
+  }
+
+  membuffer_cache_info = svn_cache__membuffer_get_global_info(pool);
+  SVN_TEST_ASSERT(membuffer_cache_info->used_size > 0);
+
+  used_cache_size = membuffer_cache_info->used_size;
+
+  /* Read revision properties for all revisions 50 times. */
+  for (n = 0; n < 50; ++n)
+    {
+      svn_fs_t *fs;
+
+      SVN_ERR(svn_fs_open2(&fs, fs_name, config, pool, pool));
+
+      for (i = 1; i < 10; ++i)
+        {
+          apr_hash_t *revprops;
+          svn_pool_clear(iterpool);
+
+          SVN_ERR(svn_fs_revision_proplist2(&revprops, fs, i, FALSE, iterpool,
+                                            iterpool));
+        }
+    }
+
+  membuffer_cache_info = svn_cache__membuffer_get_global_info(pool);
+  SVN_TEST_ASSERT(membuffer_cache_info->used_size <= used_cache_size);
+
+  return SVN_NO_ERROR;
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* The test table.  */
+
+static int max_threads = 1; /* Run tests sequentially. */
+
+static struct svn_test_descriptor_t test_funcs[] = {
+  SVN_TEST_NULL,
+  SVN_TEST_OPTS_XFAIL(revprop_cache_pollution,
+                      "cache pollution in revprop caching"),
+  SVN_TEST_NULL
+};
+
+SVN_TEST_MAIN