diff options
Diffstat (limited to 'src/rocksdb/cache/cache_key.h')
-rw-r--r-- | src/rocksdb/cache/cache_key.h | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/src/rocksdb/cache/cache_key.h b/src/rocksdb/cache/cache_key.h new file mode 100644 index 000000000..0b93c6bd9 --- /dev/null +++ b/src/rocksdb/cache/cache_key.h @@ -0,0 +1,143 @@ +// Copyright (c) Facebook, Inc. and its affiliates. 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). + +#pragma once + +#include <cstdint> + +#include "rocksdb/rocksdb_namespace.h" +#include "rocksdb/slice.h" +#include "table/unique_id_impl.h" + +namespace ROCKSDB_NAMESPACE { + +class Cache; + +// A standard holder for fixed-size block cache keys (and for related caches). +// They are created through one of these, each using its own range of values: +// * CacheKey::CreateUniqueForCacheLifetime +// * CacheKey::CreateUniqueForProcessLifetime +// * Default ctor ("empty" cache key) +// * OffsetableCacheKey->WithOffset +// +// The first two use atomic counters to guarantee uniqueness over the given +// lifetime and the last uses a form of universally unique identifier for +// uniqueness with very high probabilty (and guaranteed for files generated +// during a single process lifetime). +// +// CacheKeys are currently used by calling AsSlice() to pass as a key to +// Cache. For performance, the keys are endianness-dependent (though otherwise +// portable). (Persistable cache entries are not intended to cross platforms.) +class CacheKey { + public: + // For convenience, constructs an "empty" cache key that is never returned + // by other means. + inline CacheKey() : file_num_etc64_(), offset_etc64_() {} + + inline bool IsEmpty() const { + return (file_num_etc64_ == 0) & (offset_etc64_ == 0); + } + + // Use this cache key as a Slice (byte order is endianness-dependent) + inline Slice AsSlice() const { + static_assert(sizeof(*this) == 16, "Standardized on 16-byte cache key"); + assert(!IsEmpty()); + return Slice(reinterpret_cast<const char *>(this), sizeof(*this)); + } + + // Create a CacheKey that is unique among others associated with this Cache + // instance. Depends on Cache::NewId. This is useful for block cache + // "reservations". + static CacheKey CreateUniqueForCacheLifetime(Cache *cache); + + // Create a CacheKey that is unique among others for the lifetime of this + // process. This is useful for saving in a static data member so that + // different DB instances can agree on a cache key for shared entities, + // such as for CacheEntryStatsCollector. + static CacheKey CreateUniqueForProcessLifetime(); + + protected: + friend class OffsetableCacheKey; + CacheKey(uint64_t file_num_etc64, uint64_t offset_etc64) + : file_num_etc64_(file_num_etc64), offset_etc64_(offset_etc64) {} + uint64_t file_num_etc64_; + uint64_t offset_etc64_; +}; + +constexpr uint8_t kCacheKeySize = static_cast<uint8_t>(sizeof(CacheKey)); + +// A file-specific generator of cache keys, sometimes referred to as the +// "base" cache key for a file because all the cache keys for various offsets +// within the file are computed using simple arithmetic. The basis for the +// general approach is dicussed here: https://github.com/pdillinger/unique_id +// Heavily related to GetUniqueIdFromTableProperties. +// +// If the db_id, db_session_id, and file_number come from the file's table +// properties, then the keys will be stable across DB::Open/Close, backup/ +// restore, import/export, etc. +// +// This class "is a" CacheKey only privately so that it is not misused as +// a ready-to-use CacheKey. +class OffsetableCacheKey : private CacheKey { + public: + // For convenience, constructs an "empty" cache key that should not be used. + inline OffsetableCacheKey() : CacheKey() {} + + // Constructs an OffsetableCacheKey with the given information about a file. + // This constructor never generates an "empty" base key. + OffsetableCacheKey(const std::string &db_id, const std::string &db_session_id, + uint64_t file_number); + + // Creates an OffsetableCacheKey from an SST unique ID, so that cache keys + // can be derived from DB manifest data before reading the file from + // storage--so that every part of the file can potentially go in a persistent + // cache. + // + // Calling GetSstInternalUniqueId() on a db_id, db_session_id, and + // file_number and passing the result to this function produces the same + // base cache key as feeding those inputs directly to the constructor. + // + // This is a bijective transformation assuming either id is empty or + // lower 64 bits is non-zero: + // * Empty (all zeros) input -> empty (all zeros) output + // * Lower 64 input is non-zero -> lower 64 output (file_num_etc64_) is + // non-zero + static OffsetableCacheKey FromInternalUniqueId(UniqueIdPtr id); + + // This is the inverse transformation to the above, assuming either empty + // or lower 64 bits (file_num_etc64_) is non-zero. Perhaps only useful for + // testing. + UniqueId64x2 ToInternalUniqueId(); + + inline bool IsEmpty() const { + bool result = file_num_etc64_ == 0; + assert(!(offset_etc64_ > 0 && result)); + return result; + } + + // Construct a CacheKey for an offset within a file. An offset is not + // necessarily a byte offset if a smaller unique identifier of keyable + // offsets is used. + // + // This class was designed to make this hot code extremely fast. + inline CacheKey WithOffset(uint64_t offset) const { + assert(!IsEmpty()); + return CacheKey(file_num_etc64_, offset_etc64_ ^ offset); + } + + // The "common prefix" is a shared prefix for all the returned CacheKeys. + // It is specific to the file but the same for all offsets within the file. + static constexpr size_t kCommonPrefixSize = 8; + inline Slice CommonPrefixSlice() const { + static_assert(sizeof(file_num_etc64_) == kCommonPrefixSize, + "8 byte common prefix expected"); + assert(!IsEmpty()); + assert(&this->file_num_etc64_ == static_cast<const void *>(this)); + + return Slice(reinterpret_cast<const char *>(this), kCommonPrefixSize); + } +}; + +} // namespace ROCKSDB_NAMESPACE |