Coverage Report

Created: 2025-07-23 07:17

/src/rocksdb/util/compression_context_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
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
6
// Use of this source code is governed by a BSD-style license that can be
7
// found in the LICENSE file. See the AUTHORS file for names of contributors.
8
//
9
10
#include "util/compression_context_cache.h"
11
12
#include <atomic>
13
14
#include "util/compression.h"
15
#include "util/core_local.h"
16
17
namespace ROCKSDB_NAMESPACE {
18
namespace compression_cache {
19
20
void* const SentinelValue = nullptr;
21
// Cache ZSTD uncompression contexts for reads
22
// if needed we can add ZSTD compression context caching
23
// which is currently is not done since BlockBasedTableBuilder
24
// simply creates one compression context per new SST file.
25
struct ZSTDCachedData {
26
  // We choose to cache the below structure instead of a ptr
27
  // because we want to avoid a) native types leak b) make
28
  // cache use transparent for the user
29
  ZSTDUncompressCachedData uncomp_cached_data_;
30
  std::atomic<void*> zstd_uncomp_sentinel_;
31
32
  char
33
      padding[(CACHE_LINE_SIZE -
34
               (sizeof(ZSTDUncompressCachedData) + sizeof(std::atomic<void*>)) %
35
                   CACHE_LINE_SIZE)];  // unused padding field
36
37
64
  ZSTDCachedData() : zstd_uncomp_sentinel_(&uncomp_cached_data_) {}
38
  ZSTDCachedData(const ZSTDCachedData&) = delete;
39
  ZSTDCachedData& operator=(const ZSTDCachedData&) = delete;
40
41
0
  ZSTDUncompressCachedData GetUncompressData(int64_t idx) {
42
0
    ZSTDUncompressCachedData result;
43
0
    void* expected = &uncomp_cached_data_;
44
0
    if (zstd_uncomp_sentinel_.compare_exchange_strong(expected,
45
0
                                                      SentinelValue)) {
46
0
      uncomp_cached_data_.CreateIfNeeded();
47
0
      result.InitFromCache(uncomp_cached_data_, idx);
48
0
    } else {
49
      // Creates one time use data
50
0
      result.CreateIfNeeded();
51
0
    }
52
0
    return result;
53
0
  }
54
  // Return the entry back into circulation
55
  // This is executed only when we successfully obtained
56
  // in the first place
57
0
  void ReturnUncompressData() {
58
0
    if (zstd_uncomp_sentinel_.exchange(&uncomp_cached_data_) != SentinelValue) {
59
      // Means we are returning while not having it acquired.
60
0
      assert(false);
61
0
    }
62
0
  }
63
};
64
static_assert(sizeof(ZSTDCachedData) % CACHE_LINE_SIZE == 0,
65
              "Expected CACHE_LINE_SIZE alignment");
66
}  // namespace compression_cache
67
68
class CompressionContextCache::Rep {
69
 public:
70
2
  Rep() = default;
71
0
  ZSTDUncompressCachedData GetZSTDUncompressData() {
72
0
    auto p = per_core_uncompr_.AccessElementAndIndex();
73
0
    int64_t idx = static_cast<int64_t>(p.second);
74
0
    return p.first->GetUncompressData(idx);
75
0
  }
76
0
  void ReturnZSTDUncompressData(int64_t idx) {
77
0
    assert(idx >= 0);
78
0
    auto* cn = per_core_uncompr_.AccessAtCore(static_cast<size_t>(idx));
79
0
    cn->ReturnUncompressData();
80
0
  }
81
82
 private:
83
  CoreLocalArray<compression_cache::ZSTDCachedData> per_core_uncompr_;
84
};
85
86
2
CompressionContextCache::CompressionContextCache() : rep_(new Rep()) {}
87
88
3.73M
CompressionContextCache* CompressionContextCache::Instance() {
89
3.73M
  static CompressionContextCache instance;
90
3.73M
  return &instance;
91
3.73M
}
92
93
3.73M
void CompressionContextCache::InitSingleton() { Instance(); }
94
95
ZSTDUncompressCachedData
96
0
CompressionContextCache::GetCachedZSTDUncompressData() {
97
0
  return rep_->GetZSTDUncompressData();
98
0
}
99
100
0
void CompressionContextCache::ReturnCachedZSTDUncompressData(int64_t idx) {
101
0
  rep_->ReturnZSTDUncompressData(idx);
102
0
}
103
104
2
CompressionContextCache::~CompressionContextCache() { delete rep_; }
105
106
}  // namespace ROCKSDB_NAMESPACE