|
|
@ -228,22 +228,22 @@ struct CacheHandle { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Key of hash map. We store hash value with the key for convenience.
|
|
|
|
// Key of hash map. We store hash value with the key for convenience.
|
|
|
|
struct CacheKey { |
|
|
|
struct ClockCacheKey { |
|
|
|
Slice key; |
|
|
|
Slice key; |
|
|
|
uint32_t hash_value; |
|
|
|
uint32_t hash_value; |
|
|
|
|
|
|
|
|
|
|
|
CacheKey() = default; |
|
|
|
ClockCacheKey() = default; |
|
|
|
|
|
|
|
|
|
|
|
CacheKey(const Slice& k, uint32_t h) { |
|
|
|
ClockCacheKey(const Slice& k, uint32_t h) { |
|
|
|
key = k; |
|
|
|
key = k; |
|
|
|
hash_value = h; |
|
|
|
hash_value = h; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool equal(const CacheKey& a, const CacheKey& b) { |
|
|
|
static bool equal(const ClockCacheKey& a, const ClockCacheKey& b) { |
|
|
|
return a.hash_value == b.hash_value && a.key == b.key; |
|
|
|
return a.hash_value == b.hash_value && a.key == b.key; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static size_t hash(const CacheKey& a) { |
|
|
|
static size_t hash(const ClockCacheKey& a) { |
|
|
|
return static_cast<size_t>(a.hash_value); |
|
|
|
return static_cast<size_t>(a.hash_value); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
@ -260,7 +260,8 @@ struct CleanupContext { |
|
|
|
class ClockCacheShard final : public CacheShard { |
|
|
|
class ClockCacheShard final : public CacheShard { |
|
|
|
public: |
|
|
|
public: |
|
|
|
// Hash map type.
|
|
|
|
// Hash map type.
|
|
|
|
using HashTable = tbb::concurrent_hash_map<CacheKey, CacheHandle*, CacheKey>; |
|
|
|
using HashTable = |
|
|
|
|
|
|
|
tbb::concurrent_hash_map<ClockCacheKey, CacheHandle*, ClockCacheKey>; |
|
|
|
|
|
|
|
|
|
|
|
ClockCacheShard(); |
|
|
|
ClockCacheShard(); |
|
|
|
~ClockCacheShard() override; |
|
|
|
~ClockCacheShard() override; |
|
|
@ -559,7 +560,7 @@ bool ClockCacheShard::TryEvict(CacheHandle* handle, CleanupContext* context) { |
|
|
|
if (handle->flags.compare_exchange_strong(flags, 0, std::memory_order_acquire, |
|
|
|
if (handle->flags.compare_exchange_strong(flags, 0, std::memory_order_acquire, |
|
|
|
std::memory_order_relaxed)) { |
|
|
|
std::memory_order_relaxed)) { |
|
|
|
bool erased __attribute__((__unused__)) = |
|
|
|
bool erased __attribute__((__unused__)) = |
|
|
|
table_.erase(CacheKey(handle->key, handle->hash)); |
|
|
|
table_.erase(ClockCacheKey(handle->key, handle->hash)); |
|
|
|
assert(erased); |
|
|
|
assert(erased); |
|
|
|
RecycleHandle(handle, context); |
|
|
|
RecycleHandle(handle, context); |
|
|
|
return true; |
|
|
|
return true; |
|
|
@ -656,13 +657,13 @@ CacheHandle* ClockCacheShard::Insert( |
|
|
|
// relative updates (fetch_add, etc).
|
|
|
|
// relative updates (fetch_add, etc).
|
|
|
|
handle->flags.store(flags, std::memory_order_relaxed); |
|
|
|
handle->flags.store(flags, std::memory_order_relaxed); |
|
|
|
HashTable::accessor accessor; |
|
|
|
HashTable::accessor accessor; |
|
|
|
if (table_.find(accessor, CacheKey(key, hash))) { |
|
|
|
if (table_.find(accessor, ClockCacheKey(key, hash))) { |
|
|
|
*overwritten = true; |
|
|
|
*overwritten = true; |
|
|
|
CacheHandle* existing_handle = accessor->second; |
|
|
|
CacheHandle* existing_handle = accessor->second; |
|
|
|
table_.erase(accessor); |
|
|
|
table_.erase(accessor); |
|
|
|
UnsetInCache(existing_handle, context); |
|
|
|
UnsetInCache(existing_handle, context); |
|
|
|
} |
|
|
|
} |
|
|
|
table_.insert(HashTable::value_type(CacheKey(key, hash), handle)); |
|
|
|
table_.insert(HashTable::value_type(ClockCacheKey(key, hash), handle)); |
|
|
|
if (hold_reference) { |
|
|
|
if (hold_reference) { |
|
|
|
pinned_usage_.fetch_add(total_charge, std::memory_order_relaxed); |
|
|
|
pinned_usage_.fetch_add(total_charge, std::memory_order_relaxed); |
|
|
|
} |
|
|
|
} |
|
|
@ -701,7 +702,7 @@ Status ClockCacheShard::Insert(const Slice& key, uint32_t hash, void* value, |
|
|
|
|
|
|
|
|
|
|
|
Cache::Handle* ClockCacheShard::Lookup(const Slice& key, uint32_t hash) { |
|
|
|
Cache::Handle* ClockCacheShard::Lookup(const Slice& key, uint32_t hash) { |
|
|
|
HashTable::const_accessor accessor; |
|
|
|
HashTable::const_accessor accessor; |
|
|
|
if (!table_.find(accessor, CacheKey(key, hash))) { |
|
|
|
if (!table_.find(accessor, ClockCacheKey(key, hash))) { |
|
|
|
return nullptr; |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
} |
|
|
|
CacheHandle* handle = accessor->second; |
|
|
|
CacheHandle* handle = accessor->second; |
|
|
@ -746,7 +747,7 @@ bool ClockCacheShard::EraseAndConfirm(const Slice& key, uint32_t hash, |
|
|
|
MutexLock l(&mutex_); |
|
|
|
MutexLock l(&mutex_); |
|
|
|
HashTable::accessor accessor; |
|
|
|
HashTable::accessor accessor; |
|
|
|
bool erased = false; |
|
|
|
bool erased = false; |
|
|
|
if (table_.find(accessor, CacheKey(key, hash))) { |
|
|
|
if (table_.find(accessor, ClockCacheKey(key, hash))) { |
|
|
|
CacheHandle* handle = accessor->second; |
|
|
|
CacheHandle* handle = accessor->second; |
|
|
|
table_.erase(accessor); |
|
|
|
table_.erase(accessor); |
|
|
|
erased = UnsetInCache(handle, context); |
|
|
|
erased = UnsetInCache(handle, context); |
|
|
|