@ -18,15 +18,17 @@
# include "port/lang.h"
# include "util/mutexlock.h"
# define KEY_LENGTH \
16 // TODO(guido) Make use of this symbol in other parts of the source code
// (e.g., cache_key.h, cache_test.cc, etc.)
namespace ROCKSDB_NAMESPACE {
namespace fast_lru_cache {
LRUHandleTable : : LRUHandleTable ( int max_upper_hash_bits )
: length_bits_ ( /* historical starting size*/ 4 ) ,
list_ ( new LRUHandle * [ size_t { 1 } < < length_bits_ ] { } ) ,
elems_ ( 0 ) ,
max_length_bits_ ( max_upper_hash_bits ) { }
LRUHandleTable : : LRUHandleTable ( int hash_bits )
: length_bits_ ( hash_bits ) ,
list_ ( new LRUHandle * [ size_t { 1 } < < length_bits_ ] { } ) { }
LRUHandleTable : : ~ LRUHandleTable ( ) {
ApplyToEntriesRange (
@ -42,19 +44,15 @@ LRUHandle* LRUHandleTable::Lookup(const Slice& key, uint32_t hash) {
return * FindPointer ( key , hash ) ;
}
inline LRUHandle * * LRUHandleTable : : Head ( uint32_t hash ) {
return & list_ [ hash > > ( 32 - length_bits_ ) ] ;
}
LRUHandle * LRUHandleTable : : Insert ( LRUHandle * h ) {
LRUHandle * * ptr = FindPointer ( h - > key ( ) , h - > hash ) ;
LRUHandle * old = * ptr ;
h - > next_hash = ( old = = nullptr ? nullptr : old - > next_hash ) ;
* ptr = h ;
if ( old = = nullptr ) {
+ + elems_ ;
if ( ( elems_ > > length_bits_ ) > 0 ) { // elems_ >= length
// Since each cache entry is fairly large, we aim for a small
// average linked list length (<= 1).
Resize ( ) ;
}
}
return old ;
}
@ -63,7 +61,6 @@ LRUHandle* LRUHandleTable::Remove(const Slice& key, uint32_t hash) {
LRUHandle * result = * ptr ;
if ( result ! = nullptr ) {
* ptr = result - > next_hash ;
- - elems_ ;
}
return result ;
}
@ -76,46 +73,13 @@ LRUHandle** LRUHandleTable::FindPointer(const Slice& key, uint32_t hash) {
return ptr ;
}
void LRUHandleTable : : Resize ( ) {
if ( length_bits_ > = max_length_bits_ ) {
// Due to reaching limit of hash information, if we made the table bigger,
// we would allocate more addresses but only the same number would be used.
return ;
}
if ( length_bits_ > = 31 ) {
// Avoid undefined behavior shifting uint32_t by 32.
return ;
}
uint32_t old_length = uint32_t { 1 } < < length_bits_ ;
int new_length_bits = length_bits_ + 1 ;
std : : unique_ptr < LRUHandle * [ ] > new_list {
new LRUHandle * [ size_t { 1 } < < new_length_bits ] { }
} ;
uint32_t count = 0 ;
for ( uint32_t i = 0 ; i < old_length ; i + + ) {
LRUHandle * h = list_ [ i ] ;
while ( h ! = nullptr ) {
LRUHandle * next = h - > next_hash ;
uint32_t hash = h - > hash ;
LRUHandle * * ptr = & new_list [ hash > > ( 32 - new_length_bits ) ] ;
h - > next_hash = * ptr ;
* ptr = h ;
h = next ;
count + + ;
}
}
assert ( elems_ = = count ) ;
list_ = std : : move ( new_list ) ;
length_bits_ = new_length_bits ;
}
LRUCacheShard : : LRUCacheShard ( size_t capacity , bool strict_capacity_limit ,
CacheMetadataChargePolicy metadata_charge_policy ,
int max_upper_hash_bits )
LRUCacheShard : : LRUCacheShard ( size_t capacity , size_t estimated_value_size ,
bool strict_capacity_limit ,
CacheMetadataChargePolicy metadata_charge_policy )
: capacity_ ( 0 ) ,
strict_capacity_limit_ ( strict_capacity_limit ) ,
table_ ( max_upper_hash_bits ) ,
table_ (
GetHashBits ( capacity , estimated_value_size , metadata_charge_policy ) ) ,
usage_ ( 0 ) ,
lru_usage_ ( 0 ) {
set_metadata_charge_policy ( metadata_charge_policy ) ;
@ -220,6 +184,27 @@ void LRUCacheShard::EvictFromLRU(size_t charge,
}
}
int LRUCacheShard : : GetHashBits (
size_t capacity , size_t estimated_value_size ,
CacheMetadataChargePolicy metadata_charge_policy ) {
LRUHandle * e = reinterpret_cast < LRUHandle * > (
new char [ sizeof ( LRUHandle ) - 1 + KEY_LENGTH ] ) ;
e - > key_length = KEY_LENGTH ;
e - > deleter = nullptr ;
e - > refs = 0 ;
e - > flags = 0 ;
e - > refs = 0 ;
e - > CalcTotalCharge ( estimated_value_size , metadata_charge_policy ) ;
size_t num_entries = capacity / e - > total_charge ;
e - > Free ( ) ;
int num_hash_bits = 0 ;
while ( num_entries > > = 1 ) {
+ + num_hash_bits ;
}
return num_hash_bits ;
}
void LRUCacheShard : : SetCapacity ( size_t capacity ) {
autovector < LRUHandle * > last_reference_list ;
{
@ -368,8 +353,9 @@ Status LRUCacheShard::Insert(const Slice& key, uint32_t hash, void* value,
size_t charge , Cache : : DeleterFn deleter ,
Cache : : Handle * * handle ,
Cache : : Priority /*priority*/ ) {
if ( key . size ( ) ! = 16 ) {
return Status : : NotSupported ( " FastLRUCache only supports key size 16B. " ) ;
if ( key . size ( ) ! = KEY_LENGTH ) {
return Status : : NotSupported ( " FastLRUCache only supports key size " +
std : : to_string ( KEY_LENGTH ) + " B " ) ;
}
// Allocate the memory here outside of the mutex.
@ -431,8 +417,8 @@ size_t LRUCacheShard::GetPinnedUsage() const {
std : : string LRUCacheShard : : GetPrintableOptions ( ) const { return std : : string { } ; }
LRUCache : : LRUCache ( size_t capacity , int num_shard_bits ,
bool strict_capacity_limit ,
LRUCache : : LRUCache ( size_t capacity , size_t estimated_value_size ,
int num_shard_bits , bool strict_capacity_limit ,
CacheMetadataChargePolicy metadata_charge_policy )
: ShardedCache ( capacity , num_shard_bits , strict_capacity_limit ) {
num_shards_ = 1 < < num_shard_bits ;
@ -441,8 +427,8 @@ LRUCache::LRUCache(size_t capacity, int num_shard_bits,
size_t per_shard = ( capacity + ( num_shards_ - 1 ) ) / num_shards_ ;
for ( int i = 0 ; i < num_shards_ ; i + + ) {
new ( & shards_ [ i ] )
LRUCacheShard ( per_shard , strict_capacity_limit , metadata_charge_policy ,
/* max_upper_hash_bits */ 32 - num_shard_bits ) ;
LRUCacheShard ( per_shard , estimated_value_size , strict_capacity_limit ,
metadata_charge_policy ) ;
}
}
@ -497,7 +483,8 @@ void LRUCache::DisownData() {
} // namespace fast_lru_cache
std : : shared_ptr < Cache > NewFastLRUCache (
size_t capacity , int num_shard_bits , bool strict_capacity_limit ,
size_t capacity , size_t estimated_value_size , int num_shard_bits ,
bool strict_capacity_limit ,
CacheMetadataChargePolicy metadata_charge_policy ) {
if ( num_shard_bits > = 20 ) {
return nullptr ; // The cache cannot be sharded into too many fine pieces.
@ -506,7 +493,8 @@ std::shared_ptr<Cache> NewFastLRUCache(
num_shard_bits = GetDefaultCacheShardBits ( capacity ) ;
}
return std : : make_shared < fast_lru_cache : : LRUCache > (
capacity , num_shard_bits , strict_capacity_limit , metadata_charge_policy ) ;
capacity , estimated_value_size , num_shard_bits , strict_capacity_limit ,
metadata_charge_policy ) ;
}
} // namespace ROCKSDB_NAMESPACE