Coverage Report

Created: 2026-02-14 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/cache/cache.cc
Line
Count
Source
1
//  Copyright (c) 2011-present, Facebook, Inc.  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
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7
// Use of this source code is governed by a BSD-style license that can be
8
// found in the LICENSE file. See the AUTHORS file for names of contributors.
9
10
#include "rocksdb/cache.h"
11
12
#include "cache/lru_cache.h"
13
#include "rocksdb/secondary_cache.h"
14
#include "rocksdb/utilities/customizable_util.h"
15
#include "rocksdb/utilities/options_type.h"
16
#include "util/string_util.h"
17
18
namespace ROCKSDB_NAMESPACE {
19
const Cache::CacheItemHelper kNoopCacheItemHelper{};
20
21
static std::unordered_map<std::string, OptionTypeInfo>
22
    lru_cache_options_type_info = {
23
        {"capacity",
24
         {offsetof(struct LRUCacheOptions, capacity), OptionType::kSizeT,
25
          OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
26
        {"num_shard_bits",
27
         {offsetof(struct LRUCacheOptions, num_shard_bits), OptionType::kInt,
28
          OptionVerificationType::kNormal, OptionTypeFlags::kMutable}},
29
        {"strict_capacity_limit",
30
         {offsetof(struct LRUCacheOptions, strict_capacity_limit),
31
          OptionType::kBoolean, OptionVerificationType::kNormal,
32
          OptionTypeFlags::kMutable}},
33
        {"high_pri_pool_ratio",
34
         {offsetof(struct LRUCacheOptions, high_pri_pool_ratio),
35
          OptionType::kDouble, OptionVerificationType::kNormal,
36
          OptionTypeFlags::kMutable}},
37
        {"low_pri_pool_ratio",
38
         {offsetof(struct LRUCacheOptions, low_pri_pool_ratio),
39
          OptionType::kDouble, OptionVerificationType::kNormal,
40
          OptionTypeFlags::kMutable}},
41
};
42
43
static std::unordered_map<std::string, OptionTypeInfo>
44
    comp_sec_cache_options_type_info = {
45
        {"capacity",
46
         {offsetof(struct CompressedSecondaryCacheOptions, capacity),
47
          OptionType::kSizeT, OptionVerificationType::kNormal,
48
          OptionTypeFlags::kMutable}},
49
        {"num_shard_bits",
50
         {offsetof(struct CompressedSecondaryCacheOptions, num_shard_bits),
51
          OptionType::kInt, OptionVerificationType::kNormal,
52
          OptionTypeFlags::kMutable}},
53
        {"compression_type",
54
         {offsetof(struct CompressedSecondaryCacheOptions, compression_type),
55
          OptionType::kCompressionType, OptionVerificationType::kNormal,
56
          OptionTypeFlags::kMutable}},
57
        {"enable_custom_split_merge",
58
         {offsetof(struct CompressedSecondaryCacheOptions,
59
                   enable_custom_split_merge),
60
          OptionType::kBoolean, OptionVerificationType::kNormal,
61
          OptionTypeFlags::kMutable}},
62
};
63
64
namespace {
65
static void NoopDelete(Cache::ObjectPtr /*obj*/,
66
0
                       MemoryAllocator* /*allocator*/) {
67
0
  assert(false);
68
0
}
69
70
0
static size_t SliceSize(Cache::ObjectPtr obj) {
71
0
  return static_cast<Slice*>(obj)->size();
72
0
}
73
74
static Status SliceSaveTo(Cache::ObjectPtr from_obj, size_t from_offset,
75
0
                          size_t length, char* out) {
76
0
  const Slice& slice = *static_cast<Slice*>(from_obj);
77
0
  std::memcpy(out, slice.data() + from_offset, length);
78
0
  return Status::OK();
79
0
}
80
81
static Status NoopCreate(const Slice& /*data*/, CompressionType /*type*/,
82
                         CacheTier /*source*/, Cache::CreateContext* /*ctx*/,
83
                         MemoryAllocator* /*allocator*/,
84
                         Cache::ObjectPtr* /*out_obj*/,
85
0
                         size_t* /*out_charge*/) {
86
0
  assert(false);
87
0
  return Status::NotSupported();
88
0
}
89
90
static Cache::CacheItemHelper kBasicCacheItemHelper(CacheEntryRole::kMisc,
91
                                                    &NoopDelete);
92
}  // namespace
93
94
const Cache::CacheItemHelper kSliceCacheItemHelper{
95
    CacheEntryRole::kMisc, &NoopDelete, &SliceSize,
96
    &SliceSaveTo,          &NoopCreate, &kBasicCacheItemHelper,
97
};
98
99
Status SecondaryCache::CreateFromString(
100
    const ConfigOptions& config_options, const std::string& value,
101
0
    std::shared_ptr<SecondaryCache>* result) {
102
0
  if (value.find("compressed_secondary_cache://") == 0) {
103
0
    std::string args = value;
104
0
    args.erase(0, std::strlen("compressed_secondary_cache://"));
105
0
    Status status;
106
0
    std::shared_ptr<SecondaryCache> sec_cache;
107
108
0
    CompressedSecondaryCacheOptions sec_cache_opts;
109
0
    status = OptionTypeInfo::ParseStruct(config_options, "",
110
0
                                         &comp_sec_cache_options_type_info, "",
111
0
                                         args, &sec_cache_opts);
112
0
    if (status.ok()) {
113
0
      sec_cache = NewCompressedSecondaryCache(sec_cache_opts);
114
0
    }
115
116
0
    if (status.ok()) {
117
0
      result->swap(sec_cache);
118
0
    }
119
0
    return status;
120
0
  } else {
121
0
    return LoadSharedObject<SecondaryCache>(config_options, value, result);
122
0
  }
123
0
}
124
125
Status Cache::CreateFromString(const ConfigOptions& config_options,
126
                               const std::string& value,
127
0
                               std::shared_ptr<Cache>* result) {
128
0
  Status status;
129
0
  std::shared_ptr<Cache> cache;
130
0
  if (StartsWith(value, "null")) {
131
0
    cache = nullptr;
132
0
  } else if (value.find("://") == std::string::npos) {
133
0
    if (value.find('=') == std::string::npos) {
134
0
      cache = NewLRUCache(ParseSizeT(value));
135
0
    } else {
136
0
      LRUCacheOptions cache_opts;
137
0
      status = OptionTypeInfo::ParseStruct(config_options, "",
138
0
                                           &lru_cache_options_type_info, "",
139
0
                                           value, &cache_opts);
140
0
      if (status.ok()) {
141
0
        cache = NewLRUCache(cache_opts);
142
0
      }
143
0
    }
144
0
    if (status.ok()) {
145
0
      result->swap(cache);
146
0
    }
147
0
  } else {
148
0
    status = LoadSharedObject<Cache>(config_options, value, result);
149
0
  }
150
0
  return status;
151
0
}
152
153
0
bool Cache::AsyncLookupHandle::IsReady() {
154
0
  return pending_handle == nullptr || pending_handle->IsReady();
155
0
}
156
157
0
bool Cache::AsyncLookupHandle::IsPending() { return pending_handle != nullptr; }
158
159
0
Cache::Handle* Cache::AsyncLookupHandle::Result() {
160
0
  assert(!IsPending());
161
0
  return result_handle;
162
0
}
163
164
0
void Cache::StartAsyncLookup(AsyncLookupHandle& async_handle) {
165
0
  async_handle.found_dummy_entry = false;  // in case re-used
166
0
  assert(!async_handle.IsPending());
167
0
  async_handle.result_handle =
168
0
      Lookup(async_handle.key, async_handle.helper, async_handle.create_context,
169
0
             async_handle.priority, async_handle.stats);
170
0
}
171
172
0
Cache::Handle* Cache::Wait(AsyncLookupHandle& async_handle) {
173
0
  WaitAll(&async_handle, 1);
174
0
  return async_handle.Result();
175
0
}
176
177
0
void Cache::WaitAll(AsyncLookupHandle* async_handles, size_t count) {
178
0
  for (size_t i = 0; i < count; ++i) {
179
0
    if (async_handles[i].IsPending()) {
180
      // If a pending handle gets here, it should be marked at "to be handled
181
      // by a caller" by that caller erasing the pending_cache on it.
182
0
      assert(async_handles[i].pending_cache == nullptr);
183
0
    }
184
0
  }
185
0
}
186
187
0
void Cache::SetEvictionCallback(EvictionCallback&& fn) {
188
  // Overwriting non-empty with non-empty could indicate a bug
189
  assert(!eviction_callback_ || !fn);
190
0
  eviction_callback_ = std::move(fn);
191
0
}
192
193
}  // namespace ROCKSDB_NAMESPACE