This is an automated email from the ASF dual-hosted git repository.

granthenke pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/master by this push:
     new f1a3242  [util] renaming entities in cache-related files
f1a3242 is described below

commit f1a3242e650848f9dd36d00189a475a26c4d4f10
Author: Alexey Serbin <[email protected]>
AuthorDate: Tue Mar 19 12:34:02 2019 -0700

    [util] renaming entities in cache-related files
    
    This is a preparatory changelist to introduce FIFO-based
    cache in one of follow-up changelists.
    
    Change-Id: I963ef41a8097d96fd9530107495dc22066222de4
    Reviewed-on: http://gerrit.cloudera.org:8080/12796
    Reviewed-by: Adar Dembo <[email protected]>
    Tested-by: Kudu Jenkins
---
 src/kudu/cfile/block_cache-test.cc |   2 +-
 src/kudu/cfile/block_cache.cc      |  10 +-
 src/kudu/cfile/block_cache.h       |   2 +-
 src/kudu/cfile/cfile-test.cc       |  90 ++++++-------
 src/kudu/codegen/code_cache.cc     |   2 +-
 src/kudu/util/cache-bench.cc       |   2 +-
 src/kudu/util/cache-test.cc        | 228 +++++++++++++++++++++-----------
 src/kudu/util/cache.cc             | 257 ++++++++++++++++++++-----------------
 src/kudu/util/cache.h              |  26 ++--
 src/kudu/util/file_cache.cc        |   2 +-
 10 files changed, 368 insertions(+), 253 deletions(-)

diff --git a/src/kudu/cfile/block_cache-test.cc 
b/src/kudu/cfile/block_cache-test.cc
index 5caebce..3430180 100644
--- a/src/kudu/cfile/block_cache-test.cc
+++ b/src/kudu/cfile/block_cache-test.cc
@@ -47,7 +47,7 @@ TEST(TestBlockCache, TestBasics) {
   BlockCache::CacheKey key(id, 1);
 
   std::shared_ptr<MemTracker> mem_tracker;
-  if (BlockCache::GetConfiguredCacheTypeOrDie() == DRAM_CACHE) {
+  if (BlockCache::GetConfiguredCacheMemoryTypeOrDie() == 
Cache::MemoryType::DRAM) {
     ASSERT_TRUE(MemTracker::FindTracker("block_cache-sharded_lru_cache", 
&mem_tracker));
   }
 
diff --git a/src/kudu/cfile/block_cache.cc b/src/kudu/cfile/block_cache.cc
index 1df5c19..ce11c2f 100644
--- a/src/kudu/cfile/block_cache.cc
+++ b/src/kudu/cfile/block_cache.cc
@@ -70,8 +70,8 @@ namespace cfile {
 namespace {
 
 Cache* CreateCache(int64_t capacity) {
-  CacheType t = BlockCache::GetConfiguredCacheTypeOrDie();
-  return NewLRUCache(t, capacity, "block_cache");
+  auto mem_type = BlockCache::GetConfiguredCacheMemoryTypeOrDie();
+  return NewLRUCache(mem_type, capacity, "block_cache");
 }
 
 // Validates the block cache capacity won't permit the cache to grow large 
enough
@@ -106,13 +106,13 @@ bool ValidateBlockCacheCapacity() {
 
 GROUP_FLAG_VALIDATOR(block_cache_capacity_mb, ValidateBlockCacheCapacity);
 
-CacheType BlockCache::GetConfiguredCacheTypeOrDie() {
+Cache::MemoryType BlockCache::GetConfiguredCacheMemoryTypeOrDie() {
     ToUpperCase(FLAGS_block_cache_type, &FLAGS_block_cache_type);
   if (FLAGS_block_cache_type == "NVM") {
-    return NVM_CACHE;
+    return Cache::MemoryType::NVM;
   }
   if (FLAGS_block_cache_type == "DRAM") {
-    return DRAM_CACHE;
+    return Cache::MemoryType::DRAM;
   }
 
   LOG(FATAL) << "Unknown block cache type: '" << FLAGS_block_cache_type
diff --git a/src/kudu/cfile/block_cache.h b/src/kudu/cfile/block_cache.h
index 2122522..381758b 100644
--- a/src/kudu/cfile/block_cache.h
+++ b/src/kudu/cfile/block_cache.h
@@ -50,7 +50,7 @@ class BlockCache {
  public:
   // Parse the gflag which configures the block cache. FATALs if the flag is
   // invalid.
-  static CacheType GetConfiguredCacheTypeOrDie();
+  static Cache::MemoryType GetConfiguredCacheMemoryTypeOrDie();
 
   // BlockId refers to the unique identifier for a Kudu block, that is, for an
   // entire CFile. This is different than the block cache's notion of a block,
diff --git a/src/kudu/cfile/cfile-test.cc b/src/kudu/cfile/cfile-test.cc
index 78bdefd..82535fe 100644
--- a/src/kudu/cfile/cfile-test.cc
+++ b/src/kudu/cfile/cfile-test.cc
@@ -394,10 +394,11 @@ class TestCFile : public CFileTestBase {
 };
 
 // Subclass of TestCFile which is parameterized on the block cache type.
-// Tests that use TEST_P(TestCFileBothCacheTypes, ...) will run twice --
-// once for each cache type (DRAM, NVM).
-class TestCFileBothCacheTypes : public TestCFile,
-                                public 
::testing::WithParamInterface<CacheType> {
+// Tests that use TEST_P(TestCFileBothCacheMemoryTypes, ...) will run twice --
+// once for each cache memory type (DRAM, NVM).
+class TestCFileBothCacheMemoryTypes :
+    public TestCFile,
+    public ::testing::WithParamInterface<Cache::MemoryType> {
  public:
   void SetUp() OVERRIDE {
 #if defined(HAVE_LIB_VMEM)
@@ -410,16 +411,17 @@ class TestCFileBothCacheTypes : public TestCFile,
     }
 #endif
     switch (GetParam()) {
-      case DRAM_CACHE:
+      case Cache::MemoryType::DRAM:
         FLAGS_block_cache_type = "DRAM";
         break;
 #if defined(HAVE_LIB_VMEM)
-      case NVM_CACHE:
+      case Cache::MemoryType::NVM:
         FLAGS_block_cache_type = "NVM";
         break;
 #endif
       default:
-        LOG(FATAL) << "Unknown block cache type: '" << GetParam();
+        LOG(FATAL) << "Unknown block cache type: '"
+                   << static_cast<int16_t>(GetParam());
     }
     CFileTestBase::SetUp();
   }
@@ -430,10 +432,12 @@ class TestCFileBothCacheTypes : public TestCFile,
 };
 
 #if defined(__linux__)
-INSTANTIATE_TEST_CASE_P(CacheTypes, TestCFileBothCacheTypes,
-                        ::testing::Values(DRAM_CACHE, NVM_CACHE));
+INSTANTIATE_TEST_CASE_P(CacheMemoryTypes, TestCFileBothCacheMemoryTypes,
+                        ::testing::Values(Cache::MemoryType::DRAM,
+                                          Cache::MemoryType::NVM));
 #else
-INSTANTIATE_TEST_CASE_P(CacheTypes, TestCFileBothCacheTypes, 
::testing::Values(DRAM_CACHE));
+INSTANTIATE_TEST_CASE_P(CacheMemoryTypes, TestCFileBothCacheMemoryTypes,
+                        ::testing::Values(Cache::MemoryType::DRAM));
 #endif
 
 template<DataType type>
@@ -453,7 +457,7 @@ void CopyOne(CFileIterator *it,
 // Only run the 100M entry tests in non-debug mode.
 // They take way too long with debugging enabled.
 
-TEST_P(TestCFileBothCacheTypes, TestWrite100MFileInts) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestWrite100MFileInts) {
   BlockId block_id;
   LOG_TIMING(INFO, "writing 100m ints") {
     LOG(INFO) << "Starting writefile";
@@ -471,7 +475,7 @@ TEST_P(TestCFileBothCacheTypes, TestWrite100MFileInts) {
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestWrite100MFileNullableInts) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestWrite100MFileNullableInts) {
   BlockId block_id;
   LOG_TIMING(INFO, "writing 100m nullable ints") {
     LOG(INFO) << "Starting writefile";
@@ -489,26 +493,26 @@ TEST_P(TestCFileBothCacheTypes, 
TestWrite100MFileNullableInts) {
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestWrite100MFileStringsPrefixEncoding) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestWrite100MFileStringsPrefixEncoding) {
   TestWrite100MFileStrings(PREFIX_ENCODING);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestWrite100MUniqueStringsDictEncoding) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestWrite100MUniqueStringsDictEncoding) {
   TestWrite100MFileStrings(DICT_ENCODING);
 }
 
-TEST_P(TestCFileBothCacheTypes, 
TestWrite100MLowCardinalityStringsDictEncoding) {
+TEST_P(TestCFileBothCacheMemoryTypes, 
TestWrite100MLowCardinalityStringsDictEncoding) {
   TestWriteDictEncodingLowCardinalityStrings(100 * 1e6);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestWrite100MFileStringsPlainEncoding) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestWrite100MFileStringsPlainEncoding) {
   TestWrite100MFileStrings(PLAIN_ENCODING);
 }
 
 #endif
 
 // Write and Read 1 million unique strings with dictionary encoding
-TEST_P(TestCFileBothCacheTypes, TestWrite1MUniqueFileStringsDictEncoding) {
+TEST_P(TestCFileBothCacheMemoryTypes, 
TestWrite1MUniqueFileStringsDictEncoding) {
   BlockId block_id;
   LOG_TIMING(INFO, "writing 1M unique strings") {
     LOG(INFO) << "Starting writefile";
@@ -527,42 +531,42 @@ TEST_P(TestCFileBothCacheTypes, 
TestWrite1MUniqueFileStringsDictEncoding) {
 }
 
 // Write and Read 1 million strings, which contains duplicates with dictionary 
encoding
-TEST_P(TestCFileBothCacheTypes, TestWrite1MLowCardinalityStringsDictEncoding) {
+TEST_P(TestCFileBothCacheMemoryTypes, 
TestWrite1MLowCardinalityStringsDictEncoding) {
   TestWriteDictEncodingLowCardinalityStrings(1000000);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestReadWriteUInt32) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReadWriteUInt32) {
   for (auto enc : { PLAIN_ENCODING, RLE }) {
     TestReadWriteFixedSizeTypes<UInt32DataGenerator<false>>(enc);
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestReadWriteInt32) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReadWriteInt32) {
   for (auto enc : { PLAIN_ENCODING, RLE }) {
     TestReadWriteFixedSizeTypes<Int32DataGenerator<false>>(enc);
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestReadWriteUInt64) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReadWriteUInt64) {
   for (auto enc : { PLAIN_ENCODING, RLE, BIT_SHUFFLE }) {
     TestReadWriteFixedSizeTypes<UInt64DataGenerator<false>>(enc);
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestReadWriteInt64) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReadWriteInt64) {
   for (auto enc : { PLAIN_ENCODING, RLE, BIT_SHUFFLE }) {
     TestReadWriteFixedSizeTypes<Int64DataGenerator<false>>(enc);
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestReadWriteInt128) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReadWriteInt128) {
   TestReadWriteFixedSizeTypes<Int128DataGenerator<false>>(PLAIN_ENCODING);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestFixedSizeReadWritePlainEncodingFloat) {
+TEST_P(TestCFileBothCacheMemoryTypes, 
TestFixedSizeReadWritePlainEncodingFloat) {
   TestReadWriteFixedSizeTypes<FPDataGenerator<FLOAT, false>>(PLAIN_ENCODING);
 }
-TEST_P(TestCFileBothCacheTypes, TestFixedSizeReadWritePlainEncodingDouble) {
+TEST_P(TestCFileBothCacheMemoryTypes, 
TestFixedSizeReadWritePlainEncodingDouble) {
   TestReadWriteFixedSizeTypes<FPDataGenerator<DOUBLE, false>>(PLAIN_ENCODING);
 }
 
@@ -717,12 +721,12 @@ void TestCFile::TestReadWriteStrings(EncodingType 
encoding,
 }
 
 
-TEST_P(TestCFileBothCacheTypes, TestReadWriteStringsPrefixEncoding) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReadWriteStringsPrefixEncoding) {
   TestReadWriteStrings(PREFIX_ENCODING);
 }
 
 // Read/Write test for dictionary encoded blocks
-TEST_P(TestCFileBothCacheTypes, TestReadWriteStringsDictEncoding) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReadWriteStringsDictEncoding) {
   TestReadWriteStrings(DICT_ENCODING);
 }
 
@@ -732,7 +736,7 @@ TEST_P(TestCFileBothCacheTypes, 
TestReadWriteStringsDictEncoding) {
 // This test is disabled in TSAN because it's single-threaded anyway
 // and runs extremely slowly with TSAN enabled.
 #ifndef THREAD_SANITIZER
-TEST_P(TestCFileBothCacheTypes, TestReadWriteLargeStrings) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReadWriteLargeStrings) {
   // Pad the values out to a length of ~65KB.
   // We use this method instead of just a longer sprintf format since
   // this is much more CPU-efficient (speeds up the test).
@@ -750,7 +754,7 @@ TEST_P(TestCFileBothCacheTypes, TestReadWriteLargeStrings) {
 #endif
 
 // Test that metadata entries stored in the cfile are persisted.
-TEST_P(TestCFileBothCacheTypes, TestMetadata) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestMetadata) {
   BlockId block_id;
 
   // Write the file.
@@ -791,7 +795,7 @@ TEST_P(TestCFileBothCacheTypes, TestMetadata) {
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestDefaultColumnIter) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestDefaultColumnIter) {
   const int kNumItems = 64;
   uint8_t null_bitmap[BitmapSize(kNumItems)];
   uint32_t data[kNumItems];
@@ -840,14 +844,14 @@ TEST_P(TestCFileBothCacheTypes, TestDefaultColumnIter) {
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestAppendRaw) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestAppendRaw) {
   TestReadWriteRawBlocks(NO_COMPRESSION, 1000);
   TestReadWriteRawBlocks(SNAPPY, 1000);
   TestReadWriteRawBlocks(LZ4, 1000);
   TestReadWriteRawBlocks(ZLIB, 1000);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestChecksumFlags) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestChecksumFlags) {
   for (bool write_checksums : {false, true}) {
     for (bool verify_checksums : {false, true}) {
       FLAGS_cfile_write_checksums = write_checksums;
@@ -858,7 +862,7 @@ TEST_P(TestCFileBothCacheTypes, TestChecksumFlags) {
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestDataCorruption) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestDataCorruption) {
   FLAGS_cfile_write_checksums = true;
   FLAGS_cfile_verify_checksums = true;
 
@@ -895,7 +899,7 @@ TEST_P(TestCFileBothCacheTypes, TestDataCorruption) {
   }
 }
 
-TEST_P(TestCFileBothCacheTypes, TestNullInts) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestNullInts) {
   UInt32DataGenerator<true> generator;
   TestNullTypes(&generator, PLAIN_ENCODING, NO_COMPRESSION);
   TestNullTypes(&generator, PLAIN_ENCODING, LZ4);
@@ -905,32 +909,32 @@ TEST_P(TestCFileBothCacheTypes, TestNullInts) {
   TestNullTypes(&generator, RLE, LZ4);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestNullFloats) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestNullFloats) {
   FPDataGenerator<FLOAT, true> generator;
   TestNullTypes(&generator, PLAIN_ENCODING, NO_COMPRESSION);
   TestNullTypes(&generator, BIT_SHUFFLE, NO_COMPRESSION);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestNullPrefixStrings) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestNullPrefixStrings) {
   StringDataGenerator<true> generator("hello %zu");
   TestNullTypes(&generator, PLAIN_ENCODING, NO_COMPRESSION);
   TestNullTypes(&generator, PLAIN_ENCODING, LZ4);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestNullPlainStrings) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestNullPlainStrings) {
   StringDataGenerator<true> generator("hello %zu");
   TestNullTypes(&generator, PREFIX_ENCODING, NO_COMPRESSION);
   TestNullTypes(&generator, PREFIX_ENCODING, LZ4);
 }
 
 // Test for dictionary encoding
-TEST_P(TestCFileBothCacheTypes, TestNullDictStrings) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestNullDictStrings) {
   StringDataGenerator<true> generator("hello %zu");
   TestNullTypes(&generator, DICT_ENCODING, NO_COMPRESSION);
   TestNullTypes(&generator, DICT_ENCODING, LZ4);
 }
 
-TEST_P(TestCFileBothCacheTypes, TestReleaseBlock) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestReleaseBlock) {
   unique_ptr<WritableBlock> sink;
   ASSERT_OK(fs_manager_->CreateNewBlock({}, &sink));
   ASSERT_EQ(WritableBlock::CLEAN, sink->state());
@@ -943,7 +947,7 @@ TEST_P(TestCFileBothCacheTypes, TestReleaseBlock) {
   ASSERT_OK(transaction->CommitCreatedBlocks());
 }
 
-TEST_P(TestCFileBothCacheTypes, TestLazyInit) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestLazyInit) {
   // Create a small test file.
   BlockId block_id;
   {
@@ -994,7 +998,7 @@ TEST_P(TestCFileBothCacheTypes, TestLazyInit) {
 // Tests that the block cache keys used by CFileReaders are stable. That is,
 // different reader instances operating on the same block should use the same
 // block cache keys.
-TEST_P(TestCFileBothCacheTypes, TestCacheKeysAreStable) {
+TEST_P(TestCFileBothCacheMemoryTypes, TestCacheKeysAreStable) {
   // Set up block cache instrumentation.
   MetricRegistry registry;
   scoped_refptr<MetricEntity> 
entity(METRIC_ENTITY_server.Instantiate(&registry, "test_entity"));
@@ -1036,8 +1040,8 @@ TEST_P(TestCFileBothCacheTypes, TestCacheKeysAreStable) {
 
 #if defined(HAVE_LIB_VMEM)
 // Inject failures in nvm allocation and ensure that we can still read a file.
-TEST_P(TestCFileBothCacheTypes, TestNvmAllocationFailure) {
-  if (GetParam() != NVM_CACHE) return;
+TEST_P(TestCFileBothCacheMemoryTypes, TestNvmAllocationFailure) {
+  if (GetParam() != Cache::MemoryType::NVM) return;
   FLAGS_nvm_cache_simulate_allocation_failure = true;
   TestReadWriteFixedSizeTypes<UInt32DataGenerator<false> >(PLAIN_ENCODING);
 }
diff --git a/src/kudu/codegen/code_cache.cc b/src/kudu/codegen/code_cache.cc
index bd3b17d..8dafebe 100644
--- a/src/kudu/codegen/code_cache.cc
+++ b/src/kudu/codegen/code_cache.cc
@@ -60,7 +60,7 @@ class CodeCache::EvictionCallback : public 
Cache::EvictionCallback {
 };
 
 CodeCache::CodeCache(size_t capacity)
-  : cache_(NewLRUCache(DRAM_CACHE, capacity, "code_cache")) {
+  : cache_(NewLRUCache(Cache::MemoryType::DRAM, capacity, "code_cache")) {
   eviction_callback_.reset(new EvictionCallback());
 }
 
diff --git a/src/kudu/util/cache-bench.cc b/src/kudu/util/cache-bench.cc
index 1e705be..a73800d 100644
--- a/src/kudu/util/cache-bench.cc
+++ b/src/kudu/util/cache-bench.cc
@@ -97,7 +97,7 @@ class CacheBench : public KuduTest,
   void SetUp() override {
     KuduTest::SetUp();
 
-    cache_.reset(NewLRUCache(DRAM_CACHE, kCacheCapacity, "test-cache"));
+    cache_.reset(NewLRUCache(Cache::MemoryType::DRAM, kCacheCapacity, 
"test-cache"));
   }
 
   // Run queries against the cache until '*done' becomes true.
diff --git a/src/kudu/util/cache-test.cc b/src/kudu/util/cache-test.cc
index 38d4f03..c9d40e4 100644
--- a/src/kudu/util/cache-test.cc
+++ b/src/kudu/util/cache-test.cc
@@ -4,7 +4,6 @@
 
 #include "kudu/util/cache.h"
 
-#include <cassert>
 #include <cstring>
 #include <memory>
 #include <string>
@@ -16,8 +15,6 @@
 #include <glog/logging.h>
 #include <gtest/gtest.h>
 
-#include "kudu/gutil/gscoped_ptr.h"
-#include "kudu/gutil/port.h"
 #include "kudu/gutil/ref_counted.h"
 #include "kudu/util/block_cache_metrics.h"
 #include "kudu/util/cache_metrics.h"
@@ -30,12 +27,18 @@
 #include "kudu/util/test_macros.h"
 #include "kudu/util/test_util.h"
 
-#if defined(__linux__)
+DECLARE_bool(cache_force_single_shard);
+#if defined(HAVE_LIB_VMEM)
 DECLARE_string(nvm_cache_path);
-#endif // defined(__linux__)
+#endif // #if defined(HAVE_LIB_VMEM)
 
 DECLARE_double(cache_memtracker_approximation_ratio);
 
+using std::tuple;
+using std::shared_ptr;
+using std::unique_ptr;
+using std::vector;
+
 namespace kudu {
 
 // Conversions between numeric keys/values and the types expected by Cache.
@@ -45,84 +48,129 @@ static std::string EncodeInt(int k) {
   return result.ToString();
 }
 static int DecodeInt(const Slice& k) {
-  assert(k.size() == 4);
+  CHECK_EQ(4, k.size());
   return DecodeFixed32(k.data());
 }
 
-class CacheTest : public KuduTest,
-                  public ::testing::WithParamInterface<CacheType>,
-                  public Cache::EvictionCallback {
+// Cache composition type: some test scenarios assume cache is single-sharded
+// to keep the logic simpler.
+enum class CacheComposition {
+  MultiShard,
+  SingleShard,
+};
+
+class CacheBaseTest : public KuduTest,
+                      public Cache::EvictionCallback {
  public:
+  explicit CacheBaseTest(size_t cache_size)
+      : cache_size_(cache_size) {
+  }
+
+  size_t cache_size() const {
+    return cache_size_;
+  }
 
-  // Implementation of the EvictionCallback interface
+  // Implementation of the EvictionCallback interface.
   void EvictedEntry(Slice key, Slice val) override {
     evicted_keys_.push_back(DecodeInt(key));
     evicted_values_.push_back(DecodeInt(val));
   }
-  std::vector<int> evicted_keys_;
-  std::vector<int> evicted_values_;
-  std::shared_ptr<MemTracker> mem_tracker_;
-  gscoped_ptr<Cache> cache_;
-  MetricRegistry metric_registry_;
 
-  static const int kCacheSize = 14*1024*1024;
+  int Lookup(int key) {
+    Cache::Handle* handle = cache_->Lookup(EncodeInt(key), 
Cache::EXPECT_IN_CACHE);
+    const int r = (handle == nullptr) ? -1 : DecodeInt(cache_->Value(handle));
+    if (handle != nullptr) {
+      cache_->Release(handle);
+    }
+    return r;
+  }
 
-  virtual void SetUp() OVERRIDE {
+  void Insert(int key, int value, int charge = 1) {
+    std::string key_str = EncodeInt(key);
+    std::string val_str = EncodeInt(value);
+    Cache::PendingHandle* handle = CHECK_NOTNULL(
+        cache_->Allocate(key_str, val_str.size(), charge));
+    memcpy(cache_->MutableValue(handle), val_str.data(), val_str.size());
 
-#if defined(HAVE_LIB_VMEM)
-    if (google::GetCommandLineFlagInfoOrDie("nvm_cache_path").is_default) {
-      FLAGS_nvm_cache_path = GetTestPath("nvm-cache");
-      ASSERT_OK(Env::Default()->CreateDir(FLAGS_nvm_cache_path));
-    }
-#endif // defined(HAVE_LIB_VMEM)
+    cache_->Release(cache_->Insert(handle, this));
+  }
+
+  void Erase(int key) {
+    cache_->Erase(EncodeInt(key));
+  }
 
+ protected:
+  void SetupWithParameters(Cache::MemoryType mem_type,
+                           CacheComposition cache_composition) {
     // Disable approximate tracking of cache memory since we make specific
     // assertions on the MemTracker in this test.
     FLAGS_cache_memtracker_approximation_ratio = 0;
 
-    cache_.reset(NewLRUCache(GetParam(), kCacheSize, "cache_test"));
+    // Using single shard makes the logic of scenarios simple for capacity-
+    // and eviction-related behavior.
+    FLAGS_cache_force_single_shard =
+        (cache_composition == CacheComposition::SingleShard);
+
+#if defined(HAVE_LIB_VMEM)
+    if (google::GetCommandLineFlagInfoOrDie("nvm_cache_path").is_default) {
+      FLAGS_nvm_cache_path = GetTestPath("nvm-cache");
+      ASSERT_OK(Env::Default()->CreateDir(FLAGS_nvm_cache_path));
+    }
+#endif // #if defined(HAVE_LIB_VMEM)
 
+    cache_.reset(NewLRUCache(mem_type, cache_size(), "cache_test"));
     MemTracker::FindTracker("cache_test-sharded_lru_cache", &mem_tracker_);
+
     // Since nvm cache does not have memtracker due to the use of
     // tcmalloc for this we only check for it in the DRAM case.
-    if (GetParam() == DRAM_CACHE) {
+    if (mem_type == Cache::MemoryType::DRAM) {
       ASSERT_TRUE(mem_tracker_.get());
     }
 
     scoped_refptr<MetricEntity> entity = METRIC_ENTITY_server.Instantiate(
         &metric_registry_, "test");
-    std::unique_ptr<BlockCacheMetrics> metrics(new BlockCacheMetrics(entity));
+    unique_ptr<BlockCacheMetrics> metrics(new BlockCacheMetrics(entity));
     cache_->SetMetrics(std::move(metrics));
   }
 
-  int Lookup(int key) {
-    Cache::Handle* handle = cache_->Lookup(EncodeInt(key), 
Cache::EXPECT_IN_CACHE);
-    const int r = (handle == nullptr) ? -1 : DecodeInt(cache_->Value(handle));
-    if (handle != nullptr) {
-      cache_->Release(handle);
-    }
-    return r;
-  }
-
-  void Insert(int key, int value, int charge = 1) {
-    std::string key_str = EncodeInt(key);
-    std::string val_str = EncodeInt(value);
-    Cache::PendingHandle* handle = CHECK_NOTNULL(cache_->Allocate(key_str, 
val_str.size(), charge));
-    memcpy(cache_->MutableValue(handle), val_str.data(), val_str.size());
+  const size_t cache_size_;
+  vector<int> evicted_keys_;
+  vector<int> evicted_values_;
+  shared_ptr<MemTracker> mem_tracker_;
+  unique_ptr<Cache> cache_;
+  MetricRegistry metric_registry_;
+};
 
-    cache_->Release(cache_->Insert(handle, this));
+class CacheTest :
+    public CacheBaseTest,
+    public ::testing::WithParamInterface<tuple<Cache::MemoryType,
+                                               CacheComposition>> {
+ public:
+  CacheTest()
+      : CacheBaseTest(14 * 1024 * 1024) {
   }
 
-  void Erase(int key) {
-    cache_->Erase(EncodeInt(key));
+  void SetUp() override {
+    const auto& param = GetParam();
+    SetupWithParameters(std::get<0>(param),
+                        std::get<1>(param));
   }
 };
 
-#if defined(__linux__)
-INSTANTIATE_TEST_CASE_P(CacheTypes, CacheTest, ::testing::Values(DRAM_CACHE, 
NVM_CACHE));
+#if defined(HAVE_LIB_VMEM)
+INSTANTIATE_TEST_CASE_P(
+    CacheTypes, CacheTest,
+    ::testing::Combine(::testing::Values(Cache::MemoryType::DRAM,
+                                         Cache::MemoryType::NVM),
+                       ::testing::Values(CacheComposition::MultiShard,
+                                         CacheComposition::SingleShard)));
 #else
-INSTANTIATE_TEST_CASE_P(CacheTypes, CacheTest, ::testing::Values(DRAM_CACHE));
-#endif // defined(__linux__)
+INSTANTIATE_TEST_CASE_P(
+    CacheTypes, CacheTest,
+    ::testing::Combine(::testing::Values(Cache::MemoryType::DRAM),
+                       ::testing::Values(CacheComposition::MultiShard,
+                                         CacheComposition::SingleShard)));
+#endif // #if defined(HAVE_LIB_VMEM) ... #else ...
 
 TEST_P(CacheTest, TrackMemory) {
   if (mem_tracker_) {
@@ -201,35 +249,15 @@ TEST_P(CacheTest, EntriesArePinned) {
   ASSERT_EQ(102, evicted_values_[1]);
 }
 
-TEST_P(CacheTest, EvictionPolicy) {
-  Insert(100, 101);
-  Insert(200, 201);
-
-  const int kNumElems = 1000;
-  const int kSizePerElem = kCacheSize / kNumElems;
-
-  // Loop adding and looking up new entries, but repeatedly accessing key 101. 
This
-  // frequently-used entry should not be evicted.
-  for (int i = 0; i < kNumElems + 1000; i++) {
-    Insert(1000+i, 2000+i, kSizePerElem);
-    ASSERT_EQ(2000+i, Lookup(1000+i));
-    ASSERT_EQ(101, Lookup(100));
-  }
-  ASSERT_EQ(101, Lookup(100));
-  // Since '200' wasn't accessed in the loop above, it should have
-  // been evicted.
-  ASSERT_EQ(-1, Lookup(200));
-}
-
+// Add a bunch of light and heavy entries and then count the combined
+// size of items still in the cache, which must be approximately the
+// same as the total capacity.
 TEST_P(CacheTest, HeavyEntries) {
-  // Add a bunch of light and heavy entries and then count the combined
-  // size of items still in the cache, which must be approximately the
-  // same as the total capacity.
-  const int kLight = kCacheSize/1000;
-  const int kHeavy = kCacheSize/100;
+  const int kLight = cache_size() / 1000;
+  const int kHeavy = cache_size() / 100;
   int added = 0;
   int index = 0;
-  while (added < 2*kCacheSize) {
+  while (added < 2 * cache_size()) {
     const int weight = (index & 1) ? kLight : kHeavy;
     Insert(index, 1000+index, weight);
     added += weight;
@@ -245,7 +273,59 @@ TEST_P(CacheTest, HeavyEntries) {
       ASSERT_EQ(1000+i, r);
     }
   }
-  ASSERT_LE(cached_weight, kCacheSize + kCacheSize/10);
+  ASSERT_LE(cached_weight, cache_size() + cache_size() / 10);
+}
+
+// This class is dedicated for scenarios specific for LRUCache.
+class LRUCacheTest :
+    public CacheBaseTest,
+    public ::testing::WithParamInterface<tuple<Cache::MemoryType,
+                                               CacheComposition>> {
+ public:
+  LRUCacheTest()
+      : CacheBaseTest(14 * 1024 * 1024) {
+  }
+
+  void SetUp() override {
+    const auto& param = GetParam();
+    SetupWithParameters(std::get<0>(param),
+                        std::get<1>(param));
+  }
+};
+
+#if defined(HAVE_LIB_VMEM)
+INSTANTIATE_TEST_CASE_P(
+    CacheTypes, LRUCacheTest,
+    ::testing::Combine(::testing::Values(Cache::MemoryType::DRAM,
+                                         Cache::MemoryType::NVM),
+                       ::testing::Values(CacheComposition::MultiShard,
+                                         CacheComposition::SingleShard)));
+#else
+INSTANTIATE_TEST_CASE_P(
+    CacheTypes, LRUCacheTest,
+    ::testing::Combine(::testing::Values(Cache::MemoryType::DRAM),
+                       ::testing::Values(CacheComposition::MultiShard,
+                                         CacheComposition::SingleShard)));
+#endif // #if defined(HAVE_LIB_VMEM) ... #else ...
+
+TEST_P(LRUCacheTest, EvictionPolicy) {
+  static constexpr int kNumElems = 1000;
+  const int size_per_elem = cache_size() / kNumElems;
+
+  Insert(100, 101);
+  Insert(200, 201);
+
+  // Loop adding and looking up new entries, but repeatedly accessing key 101.
+  // This frequently-used entry should not be evicted.
+  for (int i = 0; i < kNumElems + 1000; i++) {
+    Insert(1000+i, 2000+i, size_per_elem);
+    ASSERT_EQ(2000+i, Lookup(1000+i));
+    ASSERT_EQ(101, Lookup(100));
+  }
+  ASSERT_EQ(101, Lookup(100));
+  // Since '200' wasn't accessed in the loop above, it should have
+  // been evicted.
+  ASSERT_EQ(-1, Lookup(200));
 }
 
 }  // namespace kudu
diff --git a/src/kudu/util/cache.cc b/src/kudu/util/cache.cc
index 5c10702..ef8a9d7 100644
--- a/src/kudu/util/cache.cc
+++ b/src/kudu/util/cache.cc
@@ -18,7 +18,6 @@
 #include <glog/logging.h>
 
 #include "kudu/gutil/bits.h"
-#include "kudu/gutil/gscoped_ptr.h"
 #include "kudu/gutil/hash/city.h"
 #include "kudu/gutil/macros.h"
 #include "kudu/gutil/port.h"
@@ -65,15 +64,16 @@ namespace {
 
 typedef simple_spinlock MutexType;
 
-// LRU cache implementation
+// Recency list cache implementation (LRU, etc.)
 
-// An entry is a variable length heap-allocated structure.  Entries
-// are kept in a circular doubly linked list ordered by access time.
-struct LRUHandle {
+// Recency list handle. An entry is a variable length heap-allocated structure.
+// Entries are kept in a circular doubly linked list ordered by some recency
+// criterion (e.g., access time for LRU policy).
+struct RLHandle {
   Cache::EvictionCallback* eviction_callback;
-  LRUHandle* next_hash;
-  LRUHandle* next;
-  LRUHandle* prev;
+  RLHandle* next_hash;
+  RLHandle* next;
+  RLHandle* prev;
   size_t charge;      // TODO(opt): Only allow uint32_t?
   uint32_t key_length;
   uint32_t val_length;
@@ -94,7 +94,7 @@ struct LRUHandle {
   }
 
   const uint8_t* val_ptr() const {
-    return const_cast<LRUHandle*>(this)->mutable_val_ptr();
+    return const_cast<RLHandle*>(this)->mutable_val_ptr();
   }
 
   Slice value() const {
@@ -112,13 +112,13 @@ class HandleTable {
   HandleTable() : length_(0), elems_(0), list_(nullptr) { Resize(); }
   ~HandleTable() { delete[] list_; }
 
-  LRUHandle* Lookup(const Slice& key, uint32_t hash) {
+  RLHandle* Lookup(const Slice& key, uint32_t hash) {
     return *FindPointer(key, hash);
   }
 
-  LRUHandle* Insert(LRUHandle* h) {
-    LRUHandle** ptr = FindPointer(h->key(), h->hash);
-    LRUHandle* old = *ptr;
+  RLHandle* Insert(RLHandle* h) {
+    RLHandle** ptr = FindPointer(h->key(), h->hash);
+    RLHandle* old = *ptr;
     h->next_hash = (old == nullptr ? nullptr : old->next_hash);
     *ptr = h;
     if (old == nullptr) {
@@ -132,9 +132,9 @@ class HandleTable {
     return old;
   }
 
-  LRUHandle* Remove(const Slice& key, uint32_t hash) {
-    LRUHandle** ptr = FindPointer(key, hash);
-    LRUHandle* result = *ptr;
+  RLHandle* Remove(const Slice& key, uint32_t hash) {
+    RLHandle** ptr = FindPointer(key, hash);
+    RLHandle* result = *ptr;
     if (result != nullptr) {
       *ptr = result->next_hash;
       --elems_;
@@ -147,13 +147,13 @@ class HandleTable {
   // a linked list of cache entries that hash into the bucket.
   uint32_t length_;
   uint32_t elems_;
-  LRUHandle** list_;
+  RLHandle** list_;
 
   // Return a pointer to slot that points to a cache entry that
   // matches key/hash.  If there is no such cache entry, return a
   // pointer to the trailing slot in the corresponding linked list.
-  LRUHandle** FindPointer(const Slice& key, uint32_t hash) {
-    LRUHandle** ptr = &list_[hash & (length_ - 1)];
+  RLHandle** FindPointer(const Slice& key, uint32_t hash) {
+    RLHandle** ptr = &list_[hash & (length_ - 1)];
     while (*ptr != nullptr &&
            ((*ptr)->hash != hash || key != (*ptr)->key())) {
       ptr = &(*ptr)->next_hash;
@@ -166,15 +166,15 @@ class HandleTable {
     while (new_length < elems_ * 1.5) {
       new_length *= 2;
     }
-    auto new_list = new LRUHandle*[new_length];
+    auto new_list = new RLHandle*[new_length];
     memset(new_list, 0, sizeof(new_list[0]) * new_length);
     uint32_t count = 0;
     for (uint32_t i = 0; i < length_; i++) {
-      LRUHandle* h = list_[i];
+      RLHandle* h = list_[i];
       while (h != nullptr) {
-        LRUHandle* next = h->next_hash;
+        RLHandle* next = h->next_hash;
         uint32_t hash = h->hash;
-        LRUHandle** ptr = &new_list[hash & (new_length - 1)];
+        RLHandle** ptr = &new_list[hash & (new_length - 1)];
         h->next_hash = *ptr;
         *ptr = h;
         h = next;
@@ -189,12 +189,12 @@ class HandleTable {
 };
 
 // A single shard of sharded cache.
-class LRUCache {
+class CacheShard {
  public:
-  explicit LRUCache(MemTracker* tracker);
-  ~LRUCache();
+  explicit CacheShard(MemTracker* tracker);
+  ~CacheShard();
 
-  // Separate from constructor so caller can easily make an array of LRUCache
+  // Separate from constructor so caller can easily make an array of CacheShard
   void SetCapacity(size_t capacity) {
     capacity_ = capacity;
     max_deferred_consumption_ = capacity * 
FLAGS_cache_memtracker_approximation_ratio;
@@ -202,20 +202,21 @@ class LRUCache {
 
   void SetMetrics(CacheMetrics* metrics) { metrics_ = metrics; }
 
-  Cache::Handle* Insert(LRUHandle* handle, Cache::EvictionCallback* 
eviction_callback);
+  Cache::Handle* Insert(RLHandle* handle, Cache::EvictionCallback* 
eviction_callback);
   // Like Cache::Lookup, but with an extra "hash" parameter.
   Cache::Handle* Lookup(const Slice& key, uint32_t hash, bool caching);
   void Release(Cache::Handle* handle);
   void Erase(const Slice& key, uint32_t hash);
 
  private:
-  void LRU_Remove(LRUHandle* e);
-  void LRU_Append(LRUHandle* e);
+  void RL_Remove(RLHandle* e);
+  void RL_Append(RLHandle* e);
   // Just reduce the reference count by 1.
   // Return true if last reference
-  bool Unref(LRUHandle* e);
+  bool Unref(RLHandle* e);
   // Call the user's eviction callback, if it exists, and free the entry.
-  void FreeEntry(LRUHandle* e);
+  void FreeEntry(RLHandle* e);
+
 
   // Update the memtracker's consumption by the given amount.
   //
@@ -237,6 +238,9 @@ class LRUCache {
   // Positive delta indicates an increased memory consumption.
   void UpdateMemTracker(int64_t delta);
 
+  // Update the metrics for a lookup operation in the cache.
+  void UpdateMetricsLookup(bool was_hit, bool caching);
+
   // Initialized before use.
   size_t capacity_;
 
@@ -244,9 +248,9 @@ class LRUCache {
   MutexType mutex_;
   size_t usage_;
 
-  // Dummy head of LRU list.
-  // lru.prev is newest entry, lru.next is oldest entry.
-  LRUHandle lru_;
+  // Dummy head of recency list.
+  // rl.prev is newest entry, rl.next is oldest entry.
+  RLHandle rl_;
 
   HandleTable table_;
 
@@ -260,18 +264,18 @@ class LRUCache {
   CacheMetrics* metrics_;
 };
 
-LRUCache::LRUCache(MemTracker* tracker)
- : usage_(0),
-   mem_tracker_(tracker),
-   metrics_(nullptr) {
-  // Make empty circular linked list
-  lru_.next = &lru_;
-  lru_.prev = &lru_;
+CacheShard::CacheShard(MemTracker* tracker)
+    : usage_(0),
+      mem_tracker_(tracker),
+      metrics_(nullptr) {
+  // Make empty circular linked list.
+  rl_.next = &rl_;
+  rl_.prev = &rl_;
 }
 
-LRUCache::~LRUCache() {
-  for (LRUHandle* e = lru_.next; e != &lru_; ) {
-    LRUHandle* next = e->next;
+CacheShard::~CacheShard() {
+  for (RLHandle* e = rl_.next; e != &rl_; ) {
+    RLHandle* next = e->next;
     DCHECK_EQ(e->refs.load(std::memory_order_relaxed), 1)
         << "caller has an unreleased handle";
     if (Unref(e)) {
@@ -282,12 +286,12 @@ LRUCache::~LRUCache() {
   mem_tracker_->Consume(deferred_consumption_);
 }
 
-bool LRUCache::Unref(LRUHandle* e) {
+bool CacheShard::Unref(RLHandle* e) {
   DCHECK_GT(e->refs.load(std::memory_order_relaxed), 0);
   return e->refs.fetch_sub(1) == 1;
 }
 
-void LRUCache::FreeEntry(LRUHandle* e) {
+void CacheShard::FreeEntry(RLHandle* e) {
   DCHECK_EQ(e->refs.load(std::memory_order_relaxed), 0);
   if (e->eviction_callback) {
     e->eviction_callback->EvictedEntry(e->key(), e->value());
@@ -300,7 +304,7 @@ void LRUCache::FreeEntry(LRUHandle* e) {
   delete [] e;
 }
 
-void LRUCache::UpdateMemTracker(int64_t delta) {
+void CacheShard::UpdateMemTracker(int64_t delta) {
   int64_t old_deferred = deferred_consumption_.fetch_add(delta);
   int64_t new_deferred = old_deferred + delta;
 
@@ -311,93 +315,100 @@ void LRUCache::UpdateMemTracker(int64_t delta) {
   }
 }
 
-void LRUCache::LRU_Remove(LRUHandle* e) {
+void CacheShard::UpdateMetricsLookup(bool was_hit, bool caching) {
+  if (PREDICT_TRUE(metrics_)) {
+    metrics_->lookups->Increment();
+    if (was_hit) {
+      if (caching) {
+        metrics_->cache_hits_caching->Increment();
+      } else {
+        metrics_->cache_hits->Increment();
+      }
+    } else {
+      if (caching) {
+        metrics_->cache_misses_caching->Increment();
+      } else {
+        metrics_->cache_misses->Increment();
+      }
+    }
+  }
+}
+
+void CacheShard::RL_Remove(RLHandle* e) {
   e->next->prev = e->prev;
   e->prev->next = e->next;
   usage_ -= e->charge;
 }
 
-void LRUCache::LRU_Append(LRUHandle* e) {
-  // Make "e" newest entry by inserting just before lru_
-  e->next = &lru_;
-  e->prev = lru_.prev;
+void CacheShard::RL_Append(RLHandle* e) {
+  // Make "e" newest entry by inserting just before rl_.
+  e->next = &rl_;
+  e->prev = rl_.prev;
   e->prev->next = e;
   e->next->prev = e;
   usage_ += e->charge;
 }
 
-Cache::Handle* LRUCache::Lookup(const Slice& key, uint32_t hash, bool caching) 
{
-  LRUHandle* e;
+Cache::Handle* CacheShard::Lookup(const Slice& key,
+                                  uint32_t hash,
+                                  bool caching) {
+  RLHandle* e;
   {
     std::lock_guard<MutexType> l(mutex_);
     e = table_.Lookup(key, hash);
     if (e != nullptr) {
       e->refs.fetch_add(1, std::memory_order_relaxed);
-      LRU_Remove(e);
-      LRU_Append(e);
+      RL_Remove(e);
+      RL_Append(e);
     }
   }
 
   // Do the metrics outside of the lock.
-  if (metrics_) {
-    metrics_->lookups->Increment();
-    bool was_hit = (e != nullptr);
-    if (was_hit) {
-      if (caching) {
-        metrics_->cache_hits_caching->Increment();
-      } else {
-        metrics_->cache_hits->Increment();
-      }
-    } else {
-      if (caching) {
-        metrics_->cache_misses_caching->Increment();
-      } else {
-        metrics_->cache_misses->Increment();
-      }
-    }
-  }
+  UpdateMetricsLookup(e != nullptr, caching);
 
   return reinterpret_cast<Cache::Handle*>(e);
 }
 
-void LRUCache::Release(Cache::Handle* handle) {
-  LRUHandle* e = reinterpret_cast<LRUHandle*>(handle);
+void CacheShard::Release(Cache::Handle* handle) {
+  RLHandle* e = reinterpret_cast<RLHandle*>(handle);
   bool last_reference = Unref(e);
   if (last_reference) {
     FreeEntry(e);
   }
 }
 
-Cache::Handle* LRUCache::Insert(LRUHandle* e, Cache::EvictionCallback 
*eviction_callback) {
-
-  // Set the remaining LRUHandle members which were not already allocated 
during
+Cache::Handle* CacheShard::Insert(
+    RLHandle* handle,
+    Cache::EvictionCallback* eviction_callback) {
+  // Set the remaining RLHandle members which were not already allocated during
   // Allocate().
-  e->eviction_callback = eviction_callback;
-  e->refs.store(2, std::memory_order_relaxed);  // One from LRUCache, one for 
the returned handle
-  UpdateMemTracker(e->charge);
+  handle->eviction_callback = eviction_callback;
+  // Two refs for the handle: one from CacheShard, one for the returned handle.
+  handle->refs.store(2, std::memory_order_relaxed);
+  UpdateMemTracker(handle->charge);
   if (PREDICT_TRUE(metrics_)) {
-    metrics_->cache_usage->IncrementBy(e->charge);
+    metrics_->cache_usage->IncrementBy(handle->charge);
     metrics_->inserts->Increment();
   }
 
-  LRUHandle* to_remove_head = nullptr;
+  RLHandle* to_remove_head = nullptr;
   {
     std::lock_guard<MutexType> l(mutex_);
 
-    LRU_Append(e);
+    RL_Append(handle);
 
-    LRUHandle* old = table_.Insert(e);
+    RLHandle* old = table_.Insert(handle);
     if (old != nullptr) {
-      LRU_Remove(old);
+      RL_Remove(old);
       if (Unref(old)) {
         old->next = to_remove_head;
         to_remove_head = old;
       }
     }
 
-    while (usage_ > capacity_ && lru_.next != &lru_) {
-      LRUHandle* old = lru_.next;
-      LRU_Remove(old);
+    while (usage_ > capacity_ && rl_.next != &rl_) {
+      RLHandle* old = rl_.next;
+      RL_Remove(old);
       table_.Remove(old->key(), old->hash);
       if (Unref(old)) {
         old->next = to_remove_head;
@@ -409,22 +420,22 @@ Cache::Handle* LRUCache::Insert(LRUHandle* e, 
Cache::EvictionCallback *eviction_
   // we free the entries here outside of mutex for
   // performance reasons
   while (to_remove_head != nullptr) {
-    LRUHandle* next = to_remove_head->next;
+    RLHandle* next = to_remove_head->next;
     FreeEntry(to_remove_head);
     to_remove_head = next;
   }
 
-  return reinterpret_cast<Cache::Handle*>(e);
+  return reinterpret_cast<Cache::Handle*>(handle);
 }
 
-void LRUCache::Erase(const Slice& key, uint32_t hash) {
-  LRUHandle* e;
+void CacheShard::Erase(const Slice& key, uint32_t hash) {
+  RLHandle* e;
   bool last_reference = false;
   {
     std::lock_guard<MutexType> l(mutex_);
     e = table_.Remove(key, hash);
     if (e != nullptr) {
-      LRU_Remove(e);
+      RL_Remove(e);
       last_reference = Unref(e);
     }
   }
@@ -440,15 +451,15 @@ void LRUCache::Erase(const Slice& key, uint32_t hash) {
 int DetermineShardBits() {
   int bits = PREDICT_FALSE(FLAGS_cache_force_single_shard) ?
       0 : Bits::Log2Ceiling(base::NumCPUs());
-  VLOG(1) << "Will use " << (1 << bits) << " shards for LRU cache.";
+  VLOG(1) << "Will use " << (1 << bits) << " shards for recency list cache.";
   return bits;
 }
 
-class ShardedLRUCache : public Cache {
+class ShardedCache : public Cache {
  private:
   shared_ptr<MemTracker> mem_tracker_;
   unique_ptr<CacheMetrics> metrics_;
-  vector<LRUCache*> shards_;
+  vector<CacheShard*> shards_;
 
   // Number of bits of hash used to determine the shard.
   const int shard_bits_;
@@ -469,8 +480,8 @@ class ShardedLRUCache : public Cache {
   }
 
  public:
-  explicit ShardedLRUCache(size_t capacity, const string& id)
-      : shard_bits_(DetermineShardBits()) {
+  explicit ShardedCache(size_t capacity, const string& id)
+        : shard_bits_(DetermineShardBits()) {
     // A cache is often a singleton, so:
     // 1. We reuse its MemTracker if one already exists, and
     // 2. It is directly parented to the root MemTracker.
@@ -480,19 +491,19 @@ class ShardedLRUCache : public Cache {
     int num_shards = 1 << shard_bits_;
     const size_t per_shard = (capacity + (num_shards - 1)) / num_shards;
     for (int s = 0; s < num_shards; s++) {
-      gscoped_ptr<LRUCache> shard(new LRUCache(mem_tracker_.get()));
+      unique_ptr<CacheShard> shard(new CacheShard(mem_tracker_.get()));
       shard->SetCapacity(per_shard);
       shards_.push_back(shard.release());
     }
   }
 
-  virtual ~ShardedLRUCache() {
+  virtual ~ShardedCache() {
     STLDeleteElements(&shards_);
   }
 
   Handle* Insert(PendingHandle* handle,
                  Cache::EvictionCallback* eviction_callback) override {
-    LRUHandle* h = reinterpret_cast<LRUHandle*>(DCHECK_NOTNULL(handle));
+    RLHandle* h = reinterpret_cast<RLHandle*>(DCHECK_NOTNULL(handle));
     return shards_[Shard(h->hash)]->Insert(h, eviction_callback);
   }
   Handle* Lookup(const Slice& key, CacheBehavior caching) override {
@@ -500,7 +511,7 @@ class ShardedLRUCache : public Cache {
     return shards_[Shard(hash)]->Lookup(key, hash, caching == EXPECT_IN_CACHE);
   }
   void Release(Handle* handle) override {
-    LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);
+    RLHandle* h = reinterpret_cast<RLHandle*>(handle);
     shards_[Shard(h->hash)]->Release(handle);
   }
   void Erase(const Slice& key) override {
@@ -508,7 +519,7 @@ class ShardedLRUCache : public Cache {
     shards_[Shard(hash)]->Erase(key, hash);
   }
   Slice Value(Handle* handle) override {
-    return reinterpret_cast<LRUHandle*>(handle)->value();
+    return reinterpret_cast<RLHandle*>(handle)->value();
   }
   void SetMetrics(std::unique_ptr<CacheMetrics> metrics) override {
     // TODO(KUDU-2165): reuse of the Cache singleton across multiple 
MiniCluster servers
@@ -521,7 +532,7 @@ class ShardedLRUCache : public Cache {
       return;
     }
     metrics_ = std::move(metrics);
-    for (LRUCache* cache : shards_) {
+    for (auto* cache : shards_) {
       cache->SetMetrics(metrics_.get());
     }
   }
@@ -531,11 +542,11 @@ class ShardedLRUCache : public Cache {
     DCHECK_GE(key_len, 0);
     DCHECK_GE(val_len, 0);
     int key_len_padded = KUDU_ALIGN_UP(key_len, sizeof(void*));
-    uint8_t* buf = new uint8_t[sizeof(LRUHandle)
+    uint8_t* buf = new uint8_t[sizeof(RLHandle)
                                + key_len_padded + val_len // the kv_data VLA 
data
                                - 1 // (the VLA has a 1-byte placeholder)
                                ];
-    LRUHandle* handle = reinterpret_cast<LRUHandle*>(buf);
+    RLHandle* handle = reinterpret_cast<RLHandle*>(buf);
     handle->key_length = key_len;
     handle->val_length = val_len;
     handle->charge = (charge == kAutomaticCharge) ? 
kudu_malloc_usable_size(buf) : charge;
@@ -551,24 +562,38 @@ class ShardedLRUCache : public Cache {
   }
 
   uint8_t* MutableValue(PendingHandle* h) override {
-    return reinterpret_cast<LRUHandle*>(h)->mutable_val_ptr();
+    return reinterpret_cast<RLHandle*>(h)->mutable_val_ptr();
   }
-
 };
 
 }  // end anonymous namespace
 
-Cache* NewLRUCache(CacheType type, size_t capacity, const string& id) {
-  switch (type) {
-    case DRAM_CACHE:
-      return new ShardedLRUCache(capacity, id);
+Cache* NewLRUCache(Cache::MemoryType mem_type, size_t capacity, const string& 
id) {
+  switch (mem_type) {
+    case Cache::MemoryType::DRAM:
+      return new ShardedCache(capacity, id);
 #if defined(HAVE_LIB_VMEM)
-    case NVM_CACHE:
+    case Cache::MemoryType::NVM:
       return NewLRUNvmCache(capacity, id);
 #endif
     default:
-      LOG(FATAL) << "Unsupported LRU cache type: " << type;
+      LOG(FATAL) << "unsupported memory type for LRU cache: " << mem_type;
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, Cache::MemoryType mem_type) {
+  switch (mem_type) {
+    case Cache::MemoryType::DRAM:
+      os << "DRAM";
+      break;
+    case Cache::MemoryType::NVM:
+      os << "NVM";
+      break;
+    default:
+      os << "unknown (" << static_cast<int>(mem_type) << ")";
+      break;
   }
+  return os;
 }
 
 }  // namespace kudu
diff --git a/src/kudu/util/cache.h b/src/kudu/util/cache.h
index 4c0c7eb..83e3684 100644
--- a/src/kudu/util/cache.h
+++ b/src/kudu/util/cache.h
@@ -20,6 +20,7 @@
 
 #include <cstddef>
 #include <cstdint>
+#include <iosfwd>
 #include <memory>
 #include <string>
 
@@ -28,20 +29,17 @@
 
 namespace kudu {
 
-class Cache;
 struct CacheMetrics;
 
-enum CacheType {
-  DRAM_CACHE,
-  NVM_CACHE
-};
-
-// Create a new cache with a fixed size capacity.  This implementation
-// of Cache uses a least-recently-used eviction policy.
-Cache* NewLRUCache(CacheType type, size_t capacity, const std::string& id);
-
 class Cache {
  public:
+
+  // Type of memory backing the cache's storage.
+  enum class MemoryType {
+    DRAM,
+    NVM,
+  };
+
   // Callback interface which is called when an entry is evicted from the
   // cache.
   class EvictionCallback {
@@ -210,6 +208,14 @@ class Cache {
   DISALLOW_COPY_AND_ASSIGN(Cache);
 };
 
+// Create a new cache with a fixed size capacity. This implementation
+// of Cache uses a least-recently-used eviction policy.
+Cache* NewLRUCache(Cache::MemoryType mem_type,
+                   size_t capacity,
+                   const std::string& id);
+
+std::ostream& operator<<(std::ostream& os, Cache::MemoryType mem_type);
+
 }  // namespace kudu
 
 #endif
diff --git a/src/kudu/util/file_cache.cc b/src/kudu/util/file_cache.cc
index d1bb92f..3ff22b0 100644
--- a/src/kudu/util/file_cache.cc
+++ b/src/kudu/util/file_cache.cc
@@ -459,7 +459,7 @@ FileCache<FileType>::FileCache(const string& cache_name,
     : env_(env),
       cache_name_(cache_name),
       eviction_cb_(new EvictionCallback<FileType>()),
-      cache_(NewLRUCache(DRAM_CACHE, max_open_files, cache_name)),
+      cache_(NewLRUCache(Cache::MemoryType::DRAM, max_open_files, cache_name)),
       running_(1) {
   if (entity) {
     unique_ptr<FileCacheMetrics> metrics(new FileCacheMetrics(entity));

Reply via email to