/src/rocksdb/cache/cache_key.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. |
2 | | // This source code is licensed under both the GPLv2 (found in the |
3 | | // COPYING file in the root directory) and Apache 2.0 License |
4 | | // (found in the LICENSE.Apache file in the root directory). |
5 | | |
6 | | #pragma once |
7 | | |
8 | | #include <cstdint> |
9 | | |
10 | | #include "rocksdb/rocksdb_namespace.h" |
11 | | #include "rocksdb/slice.h" |
12 | | #include "table/unique_id_impl.h" |
13 | | |
14 | | namespace ROCKSDB_NAMESPACE { |
15 | | |
16 | | class Cache; |
17 | | |
18 | | // A standard holder for fixed-size block cache keys (and for related caches). |
19 | | // They are created through one of these, each using its own range of values: |
20 | | // * CacheKey::CreateUniqueForCacheLifetime |
21 | | // * CacheKey::CreateUniqueForProcessLifetime |
22 | | // * Default ctor ("empty" cache key) |
23 | | // * OffsetableCacheKey->WithOffset |
24 | | // |
25 | | // The first two use atomic counters to guarantee uniqueness over the given |
26 | | // lifetime and the last uses a form of universally unique identifier for |
27 | | // uniqueness with very high probabilty (and guaranteed for files generated |
28 | | // during a single process lifetime). |
29 | | // |
30 | | // CacheKeys are currently used by calling AsSlice() to pass as a key to |
31 | | // Cache. For performance, the keys are endianness-dependent (though otherwise |
32 | | // portable). (Persistable cache entries are not intended to cross platforms.) |
33 | | class CacheKey { |
34 | | public: |
35 | | // For convenience, constructs an "empty" cache key that is never returned |
36 | | // by other means. |
37 | 227k | inline CacheKey() : file_num_etc64_(), offset_etc64_() {} |
38 | | |
39 | 0 | inline bool IsEmpty() const { |
40 | 0 | return (file_num_etc64_ == 0) & (offset_etc64_ == 0); |
41 | 0 | } |
42 | | |
43 | | // Use this cache key as a Slice (byte order is endianness-dependent) |
44 | 33.5k | inline Slice AsSlice() const { |
45 | 33.5k | static_assert(sizeof(*this) == 16, "Standardized on 16-byte cache key"); |
46 | 33.5k | assert(!IsEmpty()); |
47 | 33.5k | return Slice(reinterpret_cast<const char *>(this), sizeof(*this)); |
48 | 33.5k | } |
49 | | |
50 | | // Create a CacheKey that is unique among others associated with this Cache |
51 | | // instance. Depends on Cache::NewId. This is useful for block cache |
52 | | // "reservations". |
53 | | static CacheKey CreateUniqueForCacheLifetime(Cache *cache); |
54 | | |
55 | | // Create a CacheKey that is unique among others for the lifetime of this |
56 | | // process. This is useful for saving in a static data member so that |
57 | | // different DB instances can agree on a cache key for shared entities, |
58 | | // such as for CacheEntryStatsCollector. |
59 | | static CacheKey CreateUniqueForProcessLifetime(); |
60 | | |
61 | | protected: |
62 | | friend class OffsetableCacheKey; |
63 | | CacheKey(uint64_t file_num_etc64, uint64_t offset_etc64) |
64 | 33.5k | : file_num_etc64_(file_num_etc64), offset_etc64_(offset_etc64) {} |
65 | | uint64_t file_num_etc64_; |
66 | | uint64_t offset_etc64_; |
67 | | }; |
68 | | |
69 | | constexpr uint8_t kCacheKeySize = static_cast<uint8_t>(sizeof(CacheKey)); |
70 | | |
71 | | // A file-specific generator of cache keys, sometimes referred to as the |
72 | | // "base" cache key for a file because all the cache keys for various offsets |
73 | | // within the file are computed using simple arithmetic. The basis for the |
74 | | // general approach is dicussed here: https://github.com/pdillinger/unique_id |
75 | | // Heavily related to GetUniqueIdFromTableProperties. |
76 | | // |
77 | | // If the db_id, db_session_id, and file_number come from the file's table |
78 | | // properties, then the keys will be stable across DB::Open/Close, backup/ |
79 | | // restore, import/export, etc. |
80 | | // |
81 | | // This class "is a" CacheKey only privately so that it is not misused as |
82 | | // a ready-to-use CacheKey. |
83 | | class OffsetableCacheKey : private CacheKey { |
84 | | public: |
85 | | // For convenience, constructs an "empty" cache key that should not be used. |
86 | 144k | inline OffsetableCacheKey() : CacheKey() {} |
87 | | |
88 | | // Constructs an OffsetableCacheKey with the given information about a file. |
89 | | // This constructor never generates an "empty" base key. |
90 | | OffsetableCacheKey(const std::string &db_id, const std::string &db_session_id, |
91 | | uint64_t file_number); |
92 | | |
93 | | // Creates an OffsetableCacheKey from an SST unique ID, so that cache keys |
94 | | // can be derived from DB manifest data before reading the file from |
95 | | // storage--so that every part of the file can potentially go in a persistent |
96 | | // cache. |
97 | | // |
98 | | // Calling GetSstInternalUniqueId() on a db_id, db_session_id, and |
99 | | // file_number and passing the result to this function produces the same |
100 | | // base cache key as feeding those inputs directly to the constructor. |
101 | | // |
102 | | // This is a bijective transformation assuming either id is empty or |
103 | | // lower 64 bits is non-zero: |
104 | | // * Empty (all zeros) input -> empty (all zeros) output |
105 | | // * Lower 64 input is non-zero -> lower 64 output (file_num_etc64_) is |
106 | | // non-zero |
107 | | static OffsetableCacheKey FromInternalUniqueId(UniqueIdPtr id); |
108 | | |
109 | | // This is the inverse transformation to the above, assuming either empty |
110 | | // or lower 64 bits (file_num_etc64_) is non-zero. Perhaps only useful for |
111 | | // testing. |
112 | | UniqueId64x2 ToInternalUniqueId(); |
113 | | |
114 | 0 | inline bool IsEmpty() const { |
115 | 0 | bool result = file_num_etc64_ == 0; |
116 | 0 | assert(!(offset_etc64_ > 0 && result)); |
117 | 0 | return result; |
118 | 0 | } |
119 | | |
120 | | // Construct a CacheKey for an offset within a file. An offset is not |
121 | | // necessarily a byte offset if a smaller unique identifier of keyable |
122 | | // offsets is used. |
123 | | // |
124 | | // This class was designed to make this hot code extremely fast. |
125 | 30.6k | inline CacheKey WithOffset(uint64_t offset) const { |
126 | 30.6k | assert(!IsEmpty()); |
127 | 30.6k | return CacheKey(file_num_etc64_, offset_etc64_ ^ offset); |
128 | 30.6k | } |
129 | | |
130 | | // The "common prefix" is a shared prefix for all the returned CacheKeys. |
131 | | // It is specific to the file but the same for all offsets within the file. |
132 | | static constexpr size_t kCommonPrefixSize = 8; |
133 | 0 | inline Slice CommonPrefixSlice() const { |
134 | 0 | static_assert(sizeof(file_num_etc64_) == kCommonPrefixSize, |
135 | 0 | "8 byte common prefix expected"); |
136 | 0 | assert(!IsEmpty()); |
137 | 0 | assert(&this->file_num_etc64_ == static_cast<const void *>(this)); |
138 | 0 |
|
139 | 0 | return Slice(reinterpret_cast<const char *>(this), kCommonPrefixSize); |
140 | 0 | } |
141 | | }; |
142 | | |
143 | | } // namespace ROCKSDB_NAMESPACE |