638d239507
Summary: For our default block cache, each additional entry has extra memory overhead. It include LRUHandle (72 bytes currently) and the cache key (two varint64, file id and offset). The usage is not negligible. For example for block_size=4k, the overhead accounts for an extra 2% memory usage for the cache. The patch charging the cache for the extra usage, reducing untracked memory usage outside block cache. The feature is enabled by default and can be disabled by passing kDontChargeCacheMetadata to the cache constructor. This PR builds up on https://github.com/facebook/rocksdb/issues/4258 Pull Request resolved: https://github.com/facebook/rocksdb/pull/5797 Test Plan: - Existing tests are updated to either disable the feature when the test has too much dependency on the old way of accounting the usage or increasing the cache capacity to account for the additional charge of metadata. - The Usage tests in cache_test.cc are augmented to test the cache usage under kFullChargeCacheMetadata. Differential Revision: D17396833 Pulled By: maysamyabandeh fbshipit-source-id: 7684ccb9f8a40ca595e4f5efcdb03623afea0c6f
112 lines
4.4 KiB
C++
112 lines
4.4 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
// (found in the LICENSE.Apache file in the root directory).
|
|
//
|
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
|
|
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <string>
|
|
|
|
#include "port/port.h"
|
|
#include "rocksdb/cache.h"
|
|
#include "util/hash.h"
|
|
|
|
namespace rocksdb {
|
|
|
|
// Single cache shard interface.
|
|
class CacheShard {
|
|
public:
|
|
CacheShard() = default;
|
|
virtual ~CacheShard() = default;
|
|
|
|
virtual Status Insert(const Slice& key, uint32_t hash, void* value,
|
|
size_t charge,
|
|
void (*deleter)(const Slice& key, void* value),
|
|
Cache::Handle** handle, Cache::Priority priority) = 0;
|
|
virtual Cache::Handle* Lookup(const Slice& key, uint32_t hash) = 0;
|
|
virtual bool Ref(Cache::Handle* handle) = 0;
|
|
virtual bool Release(Cache::Handle* handle, bool force_erase = false) = 0;
|
|
virtual void Erase(const Slice& key, uint32_t hash) = 0;
|
|
virtual void SetCapacity(size_t capacity) = 0;
|
|
virtual void SetStrictCapacityLimit(bool strict_capacity_limit) = 0;
|
|
virtual size_t GetUsage() const = 0;
|
|
virtual size_t GetPinnedUsage() const = 0;
|
|
virtual void ApplyToAllCacheEntries(void (*callback)(void*, size_t),
|
|
bool thread_safe) = 0;
|
|
virtual void EraseUnRefEntries() = 0;
|
|
virtual std::string GetPrintableOptions() const { return ""; }
|
|
void set_metadata_charge_policy(
|
|
CacheMetadataChargePolicy metadata_charge_policy) {
|
|
metadata_charge_policy_ = metadata_charge_policy;
|
|
}
|
|
|
|
protected:
|
|
CacheMetadataChargePolicy metadata_charge_policy_ = kDontChargeCacheMetadata;
|
|
};
|
|
|
|
// Generic cache interface which shards cache by hash of keys. 2^num_shard_bits
|
|
// shards will be created, with capacity split evenly to each of the shards.
|
|
// Keys are sharded by the highest num_shard_bits bits of hash value.
|
|
class ShardedCache : public Cache {
|
|
public:
|
|
ShardedCache(size_t capacity, int num_shard_bits, bool strict_capacity_limit,
|
|
std::shared_ptr<MemoryAllocator> memory_allocator = nullptr);
|
|
virtual ~ShardedCache() = default;
|
|
virtual const char* Name() const override = 0;
|
|
virtual CacheShard* GetShard(int shard) = 0;
|
|
virtual const CacheShard* GetShard(int shard) const = 0;
|
|
virtual void* Value(Handle* handle) override = 0;
|
|
virtual size_t GetCharge(Handle* handle) const override = 0;
|
|
|
|
virtual uint32_t GetHash(Handle* handle) const = 0;
|
|
virtual void DisownData() override = 0;
|
|
|
|
virtual void SetCapacity(size_t capacity) override;
|
|
virtual void SetStrictCapacityLimit(bool strict_capacity_limit) override;
|
|
|
|
virtual Status Insert(const Slice& key, void* value, size_t charge,
|
|
void (*deleter)(const Slice& key, void* value),
|
|
Handle** handle, Priority priority) override;
|
|
virtual Handle* Lookup(const Slice& key, Statistics* stats) override;
|
|
virtual bool Ref(Handle* handle) override;
|
|
virtual bool Release(Handle* handle, bool force_erase = false) override;
|
|
virtual void Erase(const Slice& key) override;
|
|
virtual uint64_t NewId() override;
|
|
virtual size_t GetCapacity() const override;
|
|
virtual bool HasStrictCapacityLimit() const override;
|
|
virtual size_t GetUsage() const override;
|
|
virtual size_t GetUsage(Handle* handle) const override;
|
|
virtual size_t GetPinnedUsage() const override;
|
|
virtual void ApplyToAllCacheEntries(void (*callback)(void*, size_t),
|
|
bool thread_safe) override;
|
|
virtual void EraseUnRefEntries() override;
|
|
virtual std::string GetPrintableOptions() const override;
|
|
|
|
int GetNumShardBits() const { return num_shard_bits_; }
|
|
|
|
private:
|
|
static inline uint32_t HashSlice(const Slice& s) {
|
|
return static_cast<uint32_t>(GetSliceNPHash64(s));
|
|
}
|
|
|
|
uint32_t Shard(uint32_t hash) {
|
|
// Note, hash >> 32 yields hash in gcc, not the zero we expect!
|
|
return (num_shard_bits_ > 0) ? (hash >> (32 - num_shard_bits_)) : 0;
|
|
}
|
|
|
|
int num_shard_bits_;
|
|
mutable port::Mutex capacity_mutex_;
|
|
size_t capacity_;
|
|
bool strict_capacity_limit_;
|
|
std::atomic<uint64_t> last_id_;
|
|
};
|
|
|
|
extern int GetDefaultCacheShardBits(size_t capacity);
|
|
|
|
} // namespace rocksdb
|