Coverage Report

Created: 2024-07-27 06:53

/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