@ -207,6 +207,9 @@ TEST_F(LRUCacheTest, EntriesWithPriority) {
ValidateLRUList ( { " e " , " f " , " g " , " Z " , " d " } , 2 ) ;
}
// TODO: FastLRUCache and ClockCache use the same tests. We can probably remove
// them from FastLRUCache after ClockCache becomes productive, and we don't plan
// to use or maintain FastLRUCache any more.
namespace fast_lru_cache {
// TODO(guido) Replicate LRU policy tests from LRUCache here.
@ -225,10 +228,10 @@ class FastLRUCacheTest : public testing::Test {
void NewCache ( size_t capacity ) {
DeleteCache ( ) ;
cache_ = reinterpret_cast < fast_lru_cache : : LRUCacheShard * > (
port : : cacheline_aligned_alloc ( sizeof ( fast_lru_cache : : LRUCacheShard ) ) ) ;
new ( cache_ ) fast_lru_cache : : LRUCacheShard (
capacity , 1 /*estimated_value_size*/ , false /*strict_capacity_limit*/ ,
cache_ = reinterpret_cast < LRUCacheShard * > (
port : : cacheline_aligned_alloc ( sizeof ( LRUCacheShard ) ) ) ;
new ( cache_ ) LRUCacheShard ( capacity , 1 /*estimated_value_size*/ ,
false /*strict_capacity_limit*/ ,
kDontChargeCacheMetadata ) ;
}
@ -243,25 +246,23 @@ class FastLRUCacheTest : public testing::Test {
size_t CalcEstimatedHandleChargeWrapper (
size_t estimated_value_size ,
CacheMetadataChargePolicy metadata_charge_policy ) {
return fast_lru_cache : : LRUCacheShard : : CalcEstimatedHandleCharge (
estimated_value_size , metadata_charge_policy ) ;
return LRUCacheShard : : CalcEstimatedHandleCharge ( estimated_value_size ,
metadata_charge_policy ) ;
}
int CalcHashBitsWrapper ( size_t capacity , size_t estimated_value_size ,
CacheMetadataChargePolicy metadata_charge_policy ) {
return fast_lru_cache : : LRUCacheShard : : CalcHashBits (
capacity , estimated_value_size , metadata_charge_policy ) ;
return LRUCacheShard : : CalcHashBits ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
}
// Maximum number of items that a shard can hold.
double CalcMaxOccupancy ( size_t capacity , size_t estimated_value_size ,
CacheMetadataChargePolicy metadata_charge_policy ) {
size_t handle_charge =
fast_lru_cache : : LRUCacheShard : : CalcEstimatedHandleCharge (
size_t handle_charge = LRUCacheShard : : CalcEstimatedHandleCharge (
estimated_value_size , metadata_charge_policy ) ;
return capacity / ( fast_lru_cache : : kLoadFactor * handle_charge ) ;
return capacity / ( kLoadFactor * handle_charge ) ;
}
bool TableSizeIsAppropriate ( int hash_bits , double max_occupancy ) {
if ( hash_bits = = 0 ) {
return max_occupancy < = 1 ;
@ -272,7 +273,7 @@ class FastLRUCacheTest : public testing::Test {
}
private :
fast_lru_cache : : LRUCacheShard * cache_ = nullptr ;
LRUCacheShard * cache_ = nullptr ;
} ;
TEST_F ( FastLRUCacheTest , ValidateKeySize ) {
@ -292,7 +293,6 @@ TEST_F(FastLRUCacheTest, CalcHashBitsTest) {
double max_occupancy ;
int hash_bits ;
CacheMetadataChargePolicy metadata_charge_policy ;
// Vary the cache capacity, fix the element charge.
for ( int i = 0 ; i < 2048 ; i + + ) {
capacity = i ;
@ -304,7 +304,6 @@ TEST_F(FastLRUCacheTest, CalcHashBitsTest) {
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , max_occupancy ) ) ;
}
// Fix the cache capacity, vary the element charge.
for ( int i = 0 ; i < 1024 ; i + + ) {
capacity = 1024 ;
@ -316,7 +315,6 @@ TEST_F(FastLRUCacheTest, CalcHashBitsTest) {
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , max_occupancy ) ) ;
}
// Zero-capacity cache, and only values have charge.
capacity = 0 ;
estimated_value_size = 1 ;
@ -324,7 +322,6 @@ TEST_F(FastLRUCacheTest, CalcHashBitsTest) {
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , 0 /* max_occupancy */ ) ) ;
// Zero-capacity cache, and only metadata has charge.
capacity = 0 ;
estimated_value_size = 0 ;
@ -332,7 +329,6 @@ TEST_F(FastLRUCacheTest, CalcHashBitsTest) {
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , 0 /* max_occupancy */ ) ) ;
// Small cache, large elements.
capacity = 1024 ;
estimated_value_size = 8192 ;
@ -340,7 +336,6 @@ TEST_F(FastLRUCacheTest, CalcHashBitsTest) {
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , 0 /* max_occupancy */ ) ) ;
// Large capacity.
capacity = 31924172 ;
estimated_value_size = 8192 ;
@ -402,37 +397,38 @@ class ClockCacheTest : public testing::Test {
void Erase ( const std : : string & key ) { shard_ - > Erase ( key , 0 /*hash*/ ) ; }
// void ValidateLRUList(std::vector<std::string> keys,
// size_t num_high_pri_pool_keys = 0) {
// LRUHandle* lru;
// LRUHandle* lru_low_pri;
// cache_->TEST_GetLRUList(&lru, &lru_low_pri);
// LRUHandle* iter = lru;
// bool in_high_pri_pool = false;
// size_t high_pri_pool_keys = 0;
// if (iter == lru_low_pri) {
// in_high_pri_pool = true;
// }
// for (const auto& key : keys) {
// iter = iter->next;
// ASSERT_NE(lru, iter);
// ASSERT_EQ(key, iter->key().ToString());
// ASSERT_EQ(in_high_pri_pool, iter->InHighPriPool());
// if (in_high_pri_pool) {
// high_pri_pool_keys++;
// }
// if (iter == lru_low_pri) {
// ASSERT_FALSE(in_high_pri_pool);
// in_high_pri_pool = true;
// }
// }
// ASSERT_EQ(lru, iter->next);
// ASSERT_TRUE(in_high_pri_pool);
// ASSERT_EQ(num_high_pri_pool_keys, high_pri_pool_keys);
// }
size_t CalcEstimatedHandleChargeWrapper (
size_t estimated_value_size ,
CacheMetadataChargePolicy metadata_charge_policy ) {
return ClockCacheShard : : CalcEstimatedHandleCharge ( estimated_value_size ,
metadata_charge_policy ) ;
}
int CalcHashBitsWrapper ( size_t capacity , size_t estimated_value_size ,
CacheMetadataChargePolicy metadata_charge_policy ) {
return ClockCacheShard : : CalcHashBits ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
}
// Maximum number of items that a shard can hold.
double CalcMaxOccupancy ( size_t capacity , size_t estimated_value_size ,
CacheMetadataChargePolicy metadata_charge_policy ) {
size_t handle_charge = ClockCacheShard : : CalcEstimatedHandleCharge (
estimated_value_size , metadata_charge_policy ) ;
return capacity / ( kLoadFactor * handle_charge ) ;
}
bool TableSizeIsAppropriate ( int hash_bits , double max_occupancy ) {
if ( hash_bits = = 0 ) {
return max_occupancy < = 1 ;
} else {
return ( 1 < < hash_bits > = max_occupancy ) & &
( 1 < < ( hash_bits - 1 ) < = max_occupancy ) ;
}
}
private :
clock_cache : : ClockCacheShard * shard_ = nullptr ;
ClockCacheShard * shard_ = nullptr ;
} ;
TEST_F ( ClockCacheTest , Validate ) {
@ -447,31 +443,89 @@ TEST_F(ClockCacheTest, Validate) {
}
TEST_F ( ClockCacheTest , ClockPriorityTest ) {
clock_cache : : ClockHandle handle ;
EXPECT_EQ ( handle . GetClockPriority ( ) ,
clock_cache : : ClockHandle : : ClockPriority : : NONE ) ;
handle . SetClockPriority ( clock_cache : : ClockHandle : : ClockPriority : : HIGH ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) ,
clock_cache : : ClockHandle : : ClockPriority : : HIGH ) ;
ClockHandle handle ;
EXPECT_EQ ( handle . GetClockPriority ( ) , ClockHandle : : ClockPriority : : NONE ) ;
handle . SetClockPriority ( ClockHandle : : ClockPriority : : HIGH ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) , ClockHandle : : ClockPriority : : HIGH ) ;
handle . DecreaseClockPriority ( ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) ,
clock_cache : : ClockHandle : : ClockPriority : : MEDIUM ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) , ClockHandle : : ClockPriority : : MEDIUM ) ;
handle . DecreaseClockPriority ( ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) ,
clock_cache : : ClockHandle : : ClockPriority : : LOW ) ;
handle . SetClockPriority ( clock_cache : : ClockHandle : : ClockPriority : : MEDIUM ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) ,
clock_cache : : ClockHandle : : ClockPriority : : MEDIUM ) ;
handle . SetClockPriority ( clock_cache : : ClockHandle : : ClockPriority : : NONE ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) ,
clock_cache : : ClockHandle : : ClockPriority : : NONE ) ;
handle . SetClockPriority ( clock_cache : : ClockHandle : : ClockPriority : : MEDIUM ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) ,
clock_cache : : ClockHandle : : ClockPriority : : MEDIUM ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) , ClockHandle : : ClockPriority : : LOW ) ;
handle . SetClockPriority ( ClockHandle : : ClockPriority : : MEDIUM ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) , ClockHandle : : ClockPriority : : MEDIUM ) ;
handle . SetClockPriority ( ClockHandle : : ClockPriority : : NONE ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) , ClockHandle : : ClockPriority : : NONE ) ;
handle . SetClockPriority ( ClockHandle : : ClockPriority : : MEDIUM ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) , ClockHandle : : ClockPriority : : MEDIUM ) ;
handle . DecreaseClockPriority ( ) ;
handle . DecreaseClockPriority ( ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) ,
clock_cache : : ClockHandle : : ClockPriority : : NONE ) ;
EXPECT_EQ ( handle . GetClockPriority ( ) , ClockHandle : : ClockPriority : : NONE ) ;
}
TEST_F ( ClockCacheTest , CalcHashBitsTest ) {
size_t capacity ;
size_t estimated_value_size ;
double max_occupancy ;
int hash_bits ;
CacheMetadataChargePolicy metadata_charge_policy ;
// Vary the cache capacity, fix the element charge.
for ( int i = 0 ; i < 2048 ; i + + ) {
capacity = i ;
estimated_value_size = 0 ;
metadata_charge_policy = kFullChargeCacheMetadata ;
max_occupancy = CalcMaxOccupancy ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , max_occupancy ) ) ;
}
// Fix the cache capacity, vary the element charge.
for ( int i = 0 ; i < 1024 ; i + + ) {
capacity = 1024 ;
estimated_value_size = i ;
metadata_charge_policy = kFullChargeCacheMetadata ;
max_occupancy = CalcMaxOccupancy ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , max_occupancy ) ) ;
}
// Zero-capacity cache, and only values have charge.
capacity = 0 ;
estimated_value_size = 1 ;
metadata_charge_policy = kDontChargeCacheMetadata ;
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , 0 /* max_occupancy */ ) ) ;
// Zero-capacity cache, and only metadata has charge.
capacity = 0 ;
estimated_value_size = 0 ;
metadata_charge_policy = kFullChargeCacheMetadata ;
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , 0 /* max_occupancy */ ) ) ;
// Small cache, large elements.
capacity = 1024 ;
estimated_value_size = 8192 ;
metadata_charge_policy = kFullChargeCacheMetadata ;
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , 0 /* max_occupancy */ ) ) ;
// Large capacity.
capacity = 31924172 ;
estimated_value_size = 8192 ;
metadata_charge_policy = kFullChargeCacheMetadata ;
max_occupancy =
CalcMaxOccupancy ( capacity , estimated_value_size , metadata_charge_policy ) ;
hash_bits = CalcHashBitsWrapper ( capacity , estimated_value_size ,
metadata_charge_policy ) ;
EXPECT_TRUE ( TableSizeIsAppropriate ( hash_bits , max_occupancy ) ) ;
}
} // namespace clock_cache