/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 |