This is an automated email from the ASF dual-hosted git repository.
masaori pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new e084750c69 Convert CacheDir regression tests into unit tests (#10635)
e084750c69 is described below
commit e084750c6943920cae0fe611d9ebf416c09d2c97
Author: Masaori Koshiba <[email protected]>
AuthorDate: Thu Oct 19 10:11:20 2023 +0900
Convert CacheDir regression tests into unit tests (#10635)
* Convert CacheDir regression tests into unit tests
* Fix clang-format
* Fix LOOP_CHECK_MODE
---
src/iocore/cache/CacheDir.cc | 217 +--------------------------
src/iocore/cache/Makefile.am | 8 +
src/iocore/cache/P_CacheDir.h | 6 +
src/iocore/cache/test/test_CacheDir.cc | 262 +++++++++++++++++++++++++++++++++
src/tests/CMakeLists.txt | 1 +
5 files changed, 278 insertions(+), 216 deletions(-)
diff --git a/src/iocore/cache/CacheDir.cc b/src/iocore/cache/CacheDir.cc
index 97e309b810..ea7ea0d732 100644
--- a/src/iocore/cache/CacheDir.cc
+++ b/src/iocore/cache/CacheDir.cc
@@ -22,12 +22,11 @@
*/
#include "P_Cache.h"
+#include "P_CacheDir.h"
#include "tscore/hugepages.h"
-#include "tscore/Regression.h"
#include "tscore/Random.h"
-// #define LOOP_CHECK_MODE 1
#ifdef LOOP_CHECK_MODE
#define DIR_LOOP_THRESHOLD 1000
#endif
@@ -1241,217 +1240,3 @@ const uint8_t CacheKey_prev_table[256] = {
209, 247, 189, 72, 69, 238, 133, 13, 167, 31, 235, 116, 201, 190, 213,
203, 104, 115, 12, 212, 52, 63, 149, 135, 183, 84,
147, 163, 249, 65, 217, 174, 70, 6, 64, 90, 155, 177, 185, 182, 108,
121, 164, 136, 58, 220, 241, 4,
};
-
-//
-// Regression
-//
-unsigned int regress_rand_seed = 0;
-void
-regress_rand_init(unsigned int i)
-{
- regress_rand_seed = i;
-}
-
-static void
-regress_rand_CacheKey(const CacheKey *key)
-{
- unsigned int *x = (unsigned int *)key;
- for (int i = 0; i < 4; i++) {
- x[i] = next_rand(®ress_rand_seed);
- }
-}
-
-void
-dir_corrupt_bucket(Dir *b, int s, Vol *vol)
-{
- int l = (static_cast<int>(dir_bucket_length(b, s, vol) *
ts::Random::drandom()));
- Dir *e = b;
- Dir *seg = vol->dir_segment(s);
- for (int i = 0; i < l; i++) {
- ink_release_assert(e);
- e = next_dir(e, seg);
- }
- ink_release_assert(e);
- dir_set_next(e, dir_to_offset(e, seg));
-}
-
-EXCLUSIVE_REGRESSION_TEST(Cache_dir)(RegressionTest *t, int /* atype
ATS_UNUSED */, int *status)
-{
- ink_hrtime ttime;
- int ret = REGRESSION_TEST_PASSED;
-
- if ((CacheProcessor::IsCacheEnabled() != CACHE_INITIALIZED) || gnvol < 1) {
- rprintf(t, "cache not ready/configured");
- *status = REGRESSION_TEST_FAILED;
- return;
- }
- Vol *vol = gvol[0];
- EThread *thread = this_ethread();
- MUTEX_TRY_LOCK(lock, vol->mutex, thread);
- ink_release_assert(lock.is_locked());
- rprintf(t, "clearing vol 0\n", free);
- vol_dir_clear(vol);
-
- // coverity[var_decl]
- Dir dir;
- dir_clear(&dir);
- dir_set_phase(&dir, 0);
- dir_set_head(&dir, true);
- dir_set_offset(&dir, 1);
-
- vol->header->agg_pos = vol->header->write_pos += 1024;
-
- CacheKey key;
- rand_CacheKey(&key, thread->mutex);
-
- int s = key.slice32(0) % vol->segments, i, j;
- Dir *seg = vol->dir_segment(s);
-
- // test insert
- rprintf(t, "insert test\n", free);
- int inserted = 0;
- int free = dir_freelist_length(vol, s);
- int n = free;
- rprintf(t, "free: %d\n", free);
- while (n--) {
- if (!dir_insert(&key, vol, &dir)) {
- break;
- }
- inserted++;
- }
- rprintf(t, "inserted: %d\n", inserted);
- if (static_cast<unsigned int>(inserted - free) > 1) {
- ret = REGRESSION_TEST_FAILED;
- }
-
- // test delete
- rprintf(t, "delete test\n");
- for (i = 0; i < vol->buckets; i++) {
- for (j = 0; j < DIR_DEPTH; j++) {
- dir_set_offset(dir_bucket_row(dir_bucket(i, seg), j), 0); // delete
- }
- }
- dir_clean_segment(s, vol);
- int newfree = dir_freelist_length(vol, s);
- rprintf(t, "newfree: %d\n", newfree);
- if (static_cast<unsigned int>(newfree - free) > 1) {
- ret = REGRESSION_TEST_FAILED;
- }
-
- // test insert-delete
- rprintf(t, "insert-delete test\n");
- regress_rand_init(13);
- ttime = ink_get_hrtime();
- for (i = 0; i < newfree; i++) {
- regress_rand_CacheKey(&key);
- dir_insert(&key, vol, &dir);
- }
- uint64_t us = (ink_get_hrtime() - ttime) / HRTIME_USECOND;
- // On windows us is sometimes 0. I don't know why.
- // printout the insert rate only if its not 0
- if (us) {
- rprintf(t, "insert rate = %d / second\n", static_cast<int>((newfree *
static_cast<uint64_t>(1000000)) / us));
- }
- regress_rand_init(13);
- ttime = ink_get_hrtime();
- for (i = 0; i < newfree; i++) {
- Dir *last_collision = nullptr;
- regress_rand_CacheKey(&key);
- if (!dir_probe(&key, vol, &dir, &last_collision)) {
- ret = REGRESSION_TEST_FAILED;
- }
- }
- us = (ink_get_hrtime() - ttime) / HRTIME_USECOND;
- // On windows us is sometimes 0. I don't know why.
- // printout the probe rate only if its not 0
- if (us) {
- rprintf(t, "probe rate = %d / second\n", static_cast<int>((newfree *
static_cast<uint64_t>(1000000)) / us));
- }
-
- for (int c = 0; c < vol->direntries() * 0.75; c++) {
- regress_rand_CacheKey(&key);
- dir_insert(&key, vol, &dir);
- }
-
- Dir dir1;
- memset(static_cast<void *>(&dir1), 0, sizeof(dir1));
- int s1, b1;
-
- rprintf(t, "corrupt_bucket test\n");
- for (int ntimes = 0; ntimes < 10; ntimes++) {
-#ifdef LOOP_CHECK_MODE
- // dir_probe in bucket with loop
- rand_CacheKey(&key, thread->mutex);
- s1 = key.slice32(0) % vol->segments;
- b1 = key.slice32(1) % vol->buckets;
- dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
- dir_insert(&key, vol, &dir);
- Dir *last_collision = 0;
- dir_probe(&key, vol, &dir, &last_collision);
-
- rand_CacheKey(&key, thread->mutex);
- s1 = key.slice32(0) % vol->segments;
- b1 = key.slice32(1) % vol->buckets;
- dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
-
- last_collision = 0;
- dir_probe(&key, vol, &dir, &last_collision);
-
- // dir_overwrite in bucket with loop
- rand_CacheKey(&key, thread->mutex);
- s1 = key.slice32(0) % vol->segments;
- b1 = key.slice32(1) % vol->buckets;
- CacheKey key1;
- key1.b[1] = 127;
- dir1 = dir;
- dir_set_offset(&dir1, 23);
- dir_insert(&key1, vol, &dir1);
- dir_insert(&key, vol, &dir);
- key1.b[1] = 80;
- dir_insert(&key1, vol, &dir1);
- dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
- dir_overwrite(&key, vol, &dir, &dir, 1);
-
- rand_CacheKey(&key, thread->mutex);
- s1 = key.slice32(0) % vol->segments;
- b1 = key.slice32(1) % vol->buckets;
- key.b[1] = 23;
- dir_insert(&key, vol, &dir1);
- dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
- dir_overwrite(&key, vol, &dir, &dir, 0);
-
- rand_CacheKey(&key, thread->mutex);
- s1 = key.slice32(0) % vol->segments;
- Dir *seg1 = vol->dir_segment(s1);
- // dir_freelist_length in freelist with loop
- dir_corrupt_bucket(dir_from_offset(vol->header->freelist[s], seg1), s1,
vol);
- dir_freelist_length(vol, s1);
-
- rand_CacheKey(&key, thread->mutex);
- s1 = key.slice32(0) % vol->segments;
- b1 = key.slice32(1) % vol->buckets;
- // dir_bucket_length in bucket with loop
- dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
- dir_bucket_length(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
- if (!check_dir(vol))
- ret = REGRESSION_TEST_FAILED;
-#else
- // test corruption detection
- rand_CacheKey(&key, thread->mutex);
- s1 = key.slice32(0) % vol->segments;
- b1 = key.slice32(1) % vol->buckets;
-
- dir_insert(&key, vol, &dir1);
- dir_insert(&key, vol, &dir1);
- dir_insert(&key, vol, &dir1);
- dir_insert(&key, vol, &dir1);
- dir_insert(&key, vol, &dir1);
- dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
- if (check_dir(vol)) {
- ret = REGRESSION_TEST_FAILED;
- }
-#endif
- }
- vol_dir_clear(vol);
- *status = ret;
-}
diff --git a/src/iocore/cache/Makefile.am b/src/iocore/cache/Makefile.am
index 99c9e8fcd6..ac8190f883 100644
--- a/src/iocore/cache/Makefile.am
+++ b/src/iocore/cache/Makefile.am
@@ -131,6 +131,7 @@ endif
check_PROGRAMS = \
test_Cache \
+ test_CacheDir \
test_RWW \
test_Alternate_L_to_S \
test_Alternate_S_to_L \
@@ -311,6 +312,13 @@ test_Cache_SOURCES = \
$(test_main_SOURCES) \
./test/test_Cache.cc
+test_CacheDir_CPPFLAGS = $(test_CPPFLAGS)
+test_CacheDir_LDFLAGS = @AM_LDFLAGS@
+test_CacheDir_LDADD = $(test_LDADD)
+test_CacheDir_SOURCES = \
+ $(test_main_SOURCES) \
+ ./test/test_CacheDir.cc
+
test_RWW_CPPFLAGS = $(test_CPPFLAGS)
test_RWW_LDFLAGS = @AM_LDFLAGS@
test_RWW_LDADD = $(test_LDADD)
diff --git a/src/iocore/cache/P_CacheDir.h b/src/iocore/cache/P_CacheDir.h
index ef717eba4e..27b5068728 100644
--- a/src/iocore/cache/P_CacheDir.h
+++ b/src/iocore/cache/P_CacheDir.h
@@ -36,6 +36,8 @@ struct InterimCacheVol;
struct CacheVC;
class CacheEvacuateDocVC;
+// #define LOOP_CHECK_MODE 1
+
/*
Directory layout
*/
@@ -282,6 +284,10 @@ uint64_t dir_entries_used(Vol *vol);
void sync_cache_dir_on_shutdown();
int dir_freelist_length(Vol *vol, int s);
+int dir_bucket_length(Dir *b, int s, Vol *vol);
+int dir_freelist_length(Vol *vol, int s);
+void dir_clean_segment(int s, Vol *vol);
+
// Inline Functions
#define dir_in_seg(_s, _i) ((Dir *)(((char *)(_s)) + (SIZEOF_DIR * (_i))))
diff --git a/src/iocore/cache/test/test_CacheDir.cc
b/src/iocore/cache/test/test_CacheDir.cc
new file mode 100644
index 0000000000..a6d29140c8
--- /dev/null
+++ b/src/iocore/cache/test/test_CacheDir.cc
@@ -0,0 +1,262 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ 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 "main.h"
+
+#include "P_CacheDir.h"
+
+#include "tscore/Random.h"
+
+// Required by main.h
+int cache_vols = 1;
+bool reuse_existing_cache = false;
+
+namespace
+{
+DbgCtl dbg_ctl_cache_dir_test{"cache_dir_test"};
+
+unsigned int regress_rand_seed = 0;
+
+void
+regress_rand_init(unsigned int i)
+{
+ regress_rand_seed = i;
+}
+
+static void
+regress_rand_CacheKey(const CacheKey *key)
+{
+ unsigned int *x = (unsigned int *)key;
+ for (int i = 0; i < 4; i++) {
+ x[i] = next_rand(®ress_rand_seed);
+ }
+}
+
+void
+dir_corrupt_bucket(Dir *b, int s, Vol *vol)
+{
+ int l = (static_cast<int>(dir_bucket_length(b, s, vol) *
ts::Random::drandom()));
+ Dir *e = b;
+ Dir *seg = vol->dir_segment(s);
+ for (int i = 0; i < l; i++) {
+ ink_release_assert(e);
+ e = next_dir(e, seg);
+ }
+ ink_release_assert(e);
+ dir_set_next(e, dir_to_offset(e, seg));
+}
+
+} // namespace
+
+class CacheDirTest : public CacheInit
+{
+public:
+ int
+ cache_init_success_callback(int event, void *e) override
+ {
+ // Test
+ _run();
+
+ // Teardown
+ TerminalTest *tt = new TerminalTest;
+ this_ethread()->schedule_imm(tt);
+ delete this;
+
+ return 0;
+ }
+
+private:
+ void
+ _run()
+ {
+ ink_hrtime ttime;
+
+ REQUIRE(CacheProcessor::IsCacheEnabled() == CACHE_INITIALIZED);
+ REQUIRE(gnvol >= 1);
+
+ Vol *vol = gvol[0];
+ EThread *thread = this_ethread();
+ MUTEX_TRY_LOCK(lock, vol->mutex, thread);
+ ink_release_assert(lock.is_locked());
+ vol_dir_clear(vol);
+
+ // coverity[var_decl]
+ Dir dir;
+ dir_clear(&dir);
+ dir_set_phase(&dir, 0);
+ dir_set_head(&dir, true);
+ dir_set_offset(&dir, 1);
+
+ vol->header->agg_pos = vol->header->write_pos += 1024;
+
+ CacheKey key;
+ rand_CacheKey(&key, thread->mutex);
+
+ int s = key.slice32(0) % vol->segments, i, j;
+ Dir *seg = vol->dir_segment(s);
+
+ // test insert
+ int inserted = 0;
+ int free = dir_freelist_length(vol, s);
+ int n = free;
+ while (n--) {
+ if (!dir_insert(&key, vol, &dir)) {
+ break;
+ }
+ inserted++;
+ }
+ CHECK(static_cast<unsigned int>(inserted - free) <= 1);
+
+ // test delete
+ for (i = 0; i < vol->buckets; i++) {
+ for (j = 0; j < DIR_DEPTH; j++) {
+ dir_set_offset(dir_bucket_row(dir_bucket(i, seg), j), 0); // delete
+ }
+ }
+ dir_clean_segment(s, vol);
+ int newfree = dir_freelist_length(vol, s);
+ CHECK(static_cast<unsigned int>(newfree - free) <= 1);
+
+ // test insert-delete
+ regress_rand_init(13);
+ ttime = ink_get_hrtime();
+ for (i = 0; i < newfree; i++) {
+ regress_rand_CacheKey(&key);
+ dir_insert(&key, vol, &dir);
+ }
+ uint64_t us = (ink_get_hrtime() - ttime) / HRTIME_USECOND;
+ // On windows us is sometimes 0. I don't know why.
+ // printout the insert rate only if its not 0
+ if (us) {
+ Dbg(dbg_ctl_cache_dir_test, "insert rate = %d / second",
static_cast<int>((newfree * static_cast<uint64_t>(1000000)) / us));
+ }
+ regress_rand_init(13);
+ ttime = ink_get_hrtime();
+ for (i = 0; i < newfree; i++) {
+ Dir *last_collision = nullptr;
+ regress_rand_CacheKey(&key);
+ CHECK(dir_probe(&key, vol, &dir, &last_collision));
+ }
+ us = (ink_get_hrtime() - ttime) / HRTIME_USECOND;
+ // On windows us is sometimes 0. I don't know why.
+ // printout the probe rate only if its not 0
+ if (us) {
+ Dbg(dbg_ctl_cache_dir_test, "probe rate = %d / second",
static_cast<int>((newfree * static_cast<uint64_t>(1000000)) / us));
+ }
+
+ for (int c = 0; c < vol->direntries() * 0.75; c++) {
+ regress_rand_CacheKey(&key);
+ dir_insert(&key, vol, &dir);
+ }
+
+ Dir dir1;
+ memset(static_cast<void *>(&dir1), 0, sizeof(dir1));
+ int s1, b1;
+
+ Dbg(dbg_ctl_cache_dir_test, "corrupt_bucket test");
+ for (int ntimes = 0; ntimes < 10; ntimes++) {
+#ifdef LOOP_CHECK_MODE
+ // dir_probe in bucket with loop
+ rand_CacheKey(&key, thread->mutex);
+ s1 = key.slice32(0) % vol->segments;
+ b1 = key.slice32(1) % vol->buckets;
+ dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
+ dir_insert(&key, vol, &dir);
+ Dir *last_collision = 0;
+ dir_probe(&key, vol, &dir, &last_collision);
+
+ rand_CacheKey(&key, thread->mutex);
+ s1 = key.slice32(0) % vol->segments;
+ b1 = key.slice32(1) % vol->buckets;
+ dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
+
+ last_collision = 0;
+ dir_probe(&key, vol, &dir, &last_collision);
+
+ // dir_overwrite in bucket with loop
+ rand_CacheKey(&key, thread->mutex);
+ s1 = key.slice32(0) % vol->segments;
+ b1 = key.slice32(1) % vol->buckets;
+ CacheKey key1;
+ key1.b[1] = 127;
+ dir1 = dir;
+ dir_set_offset(&dir1, 23);
+ dir_insert(&key1, vol, &dir1);
+ dir_insert(&key, vol, &dir);
+ key1.b[1] = 80;
+ dir_insert(&key1, vol, &dir1);
+ dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
+ dir_overwrite(&key, vol, &dir, &dir, 1);
+
+ rand_CacheKey(&key, thread->mutex);
+ s1 = key.slice32(0) % vol->segments;
+ b1 = key.slice32(1) % vol->buckets;
+ key.b[1] = 23;
+ dir_insert(&key, vol, &dir1);
+ dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
+ dir_overwrite(&key, vol, &dir, &dir, 0);
+
+ rand_CacheKey(&key, thread->mutex);
+ s1 = key.slice32(0) % vol->segments;
+ Dir *seg1 = vol->dir_segment(s1);
+ // dir_freelist_length in freelist with loop
+ dir_corrupt_bucket(dir_from_offset(vol->header->freelist[s], seg1), s1,
vol);
+ dir_freelist_length(vol, s1);
+
+ rand_CacheKey(&key, thread->mutex);
+ s1 = key.slice32(0) % vol->segments;
+ b1 = key.slice32(1) % vol->buckets;
+ // dir_bucket_length in bucket with loop
+ dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
+ dir_bucket_length(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
+ CHECK(check_dir(vol));
+#else
+ // test corruption detection
+ rand_CacheKey(&key, thread->mutex);
+ s1 = key.slice32(0) % vol->segments;
+ b1 = key.slice32(1) % vol->buckets;
+
+ dir_insert(&key, vol, &dir1);
+ dir_insert(&key, vol, &dir1);
+ dir_insert(&key, vol, &dir1);
+ dir_insert(&key, vol, &dir1);
+ dir_insert(&key, vol, &dir1);
+ dir_corrupt_bucket(dir_bucket(b1, vol->dir_segment(s1)), s1, vol);
+ CHECK(!check_dir(vol));
+#endif
+ }
+ vol_dir_clear(vol);
+ }
+};
+
+TEST_CASE("CacheDir")
+{
+ init_cache(0);
+
+ CacheDirTest *init = new CacheDirTest;
+
+ this_ethread()->schedule_imm(init);
+ this_thread()->execute();
+
+ return;
+}
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 4627281dd5..d6c2e672ae 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -102,6 +102,7 @@ if(ENABLE_DISK_FAILURE_TESTS)
Populated_Cache_Disk_Failure
${CMAKE_SOURCE_DIR}/src/iocore/cache/test/test_Populated_Cache_Disk_Failure.cc
)
endif()
+add_cache_test(CacheDir
${CMAKE_SOURCE_DIR}/src/iocore/cache/test/test_CacheDir.cc)
add_cache_test(RWW ${CMAKE_SOURCE_DIR}/src/iocore/cache/test/test_RWW.cc)
add_cache_test(Alternate_L_to_S
${CMAKE_SOURCE_DIR}/src/iocore/cache/test/test_Alternate_L_to_S.cc)
add_cache_test(Alternate_S_to_L
${CMAKE_SOURCE_DIR}/src/iocore/cache/test/test_Alternate_S_to_L.cc)