Coverage Report

Created: 2024-07-27 06:53

/src/rocksdb/cache/cache.cc
Line
Count
Source (jump to first uncovered line)
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
        {"compress_format_version",
58
         {offsetof(struct CompressedSecondaryCacheOptions,
59
                   compress_format_version),
60
          OptionType::kUInt32T, OptionVerificationType::kNormal,
61
          OptionTypeFlags::kMutable}},
62
        {"enable_custom_split_merge",
63
         {offsetof(struct CompressedSecondaryCacheOptions,
64
                   enable_custom_split_merge),
65
          OptionType::kBoolean, OptionVerificationType::kNormal,
66
          OptionTypeFlags::kMutable}},
67
};
68
69
namespace {
70
static void NoopDelete(Cache::ObjectPtr /*obj*/,
71
0
                       MemoryAllocator* /*allocator*/) {
72
0
  assert(false);
73
0
}
74
75
0
static size_t SliceSize(Cache::ObjectPtr obj) {
76
0
  return static_cast<Slice*>(obj)->size();
77
0
}
78
79
static Status SliceSaveTo(Cache::ObjectPtr from_obj, size_t from_offset,
80
0
                          size_t length, char* out) {
81
0
  const Slice& slice = *static_cast<Slice*>(from_obj);
82
0
  std::memcpy(out, slice.data() + from_offset, length);
83
0
  return Status::OK();
84
0
}
85
86
static Status NoopCreate(const Slice& /*data*/, CompressionType /*type*/,
87
                         CacheTier /*source*/, Cache::CreateContext* /*ctx*/,
88
                         MemoryAllocator* /*allocator*/,
89
                         Cache::ObjectPtr* /*out_obj*/,
90
0
                         size_t* /*out_charge*/) {
91
0
  assert(false);
92
0
  return Status::NotSupported();
93
0
}
94
95
static Cache::CacheItemHelper kBasicCacheItemHelper(CacheEntryRole::kMisc,
96
                                                    &NoopDelete);
97
}  // namespace
98
99
const Cache::CacheItemHelper kSliceCacheItemHelper{
100
    CacheEntryRole::kMisc, &NoopDelete, &SliceSize,
101
    &SliceSaveTo,          &NoopCreate, &kBasicCacheItemHelper,
102
};
103
104
Status SecondaryCache::CreateFromString(
105
    const ConfigOptions& config_options, const std::string& value,
106
0
    std::shared_ptr<SecondaryCache>* result) {
107
0
  if (value.find("compressed_secondary_cache://") == 0) {
108
0
    std::string args = value;
109
0
    args.erase(0, std::strlen("compressed_secondary_cache://"));
110
0
    Status status;
111
0
    std::shared_ptr<SecondaryCache> sec_cache;
112
113
0
    CompressedSecondaryCacheOptions sec_cache_opts;
114
0
    status = OptionTypeInfo::ParseStruct(config_options, "",
115
0
                                         &comp_sec_cache_options_type_info, "",
116
0
                                         args, &sec_cache_opts);
117
0
    if (status.ok()) {
118
0
      sec_cache = NewCompressedSecondaryCache(sec_cache_opts);
119
0
    }
120
121
122
0
    if (status.ok()) {
123
0
      result->swap(sec_cache);
124
0
    }
125
0
    return status;
126
0
  } else {
127
0
    return LoadSharedObject<SecondaryCache>(config_options, value, result);
128
0
  }
129
0
}
130
131
Status Cache::CreateFromString(const ConfigOptions& config_options,
132
                               const std::string& value,
133
0
                               std::shared_ptr<Cache>* result) {
134
0
  Status status;
135
0
  std::shared_ptr<Cache> cache;
136
0
  if (value.find('=') == std::string::npos) {
137
0
    cache = NewLRUCache(ParseSizeT(value));
138
0
  } else {
139
0
    LRUCacheOptions cache_opts;
140
0
    status = OptionTypeInfo::ParseStruct(config_options, "",
141
0
                                         &lru_cache_options_type_info, "",
142
0
                                         value, &cache_opts);
143
0
    if (status.ok()) {
144
0
      cache = NewLRUCache(cache_opts);
145
0
    }
146
0
  }
147
0
  if (status.ok()) {
148
0
    result->swap(cache);
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
0
  assert(!eviction_callback_ || !fn);
190
0
  eviction_callback_ = std::move(fn);
191
0
}
192
193
}  // namespace ROCKSDB_NAMESPACE