| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file. See the AUTHORS file for names of contributors.
- //
- #include "util/compression_context_cache.h"
- #include "util/compression.h"
- #include "util/core_local.h"
- #include <atomic>
- namespace ROCKSDB_NAMESPACE {
- namespace compression_cache {
- void* const SentinelValue = nullptr;
- // Cache ZSTD uncompression contexts for reads
- // if needed we can add ZSTD compression context caching
- // which is currently is not done since BlockBasedTableBuilder
- // simply creates one compression context per new SST file.
- struct ZSTDCachedData {
- // We choose to cache the below structure instead of a ptr
- // because we want to avoid a) native types leak b) make
- // cache use transparent for the user
- ZSTDUncompressCachedData uncomp_cached_data_;
- std::atomic<void*> zstd_uncomp_sentinel_;
- char
- padding[(CACHE_LINE_SIZE -
- (sizeof(ZSTDUncompressCachedData) + sizeof(std::atomic<void*>)) %
- CACHE_LINE_SIZE)]; // unused padding field
- ZSTDCachedData() : zstd_uncomp_sentinel_(&uncomp_cached_data_) {}
- ZSTDCachedData(const ZSTDCachedData&) = delete;
- ZSTDCachedData& operator=(const ZSTDCachedData&) = delete;
- ZSTDUncompressCachedData GetUncompressData(int64_t idx) {
- ZSTDUncompressCachedData result;
- void* expected = &uncomp_cached_data_;
- if (zstd_uncomp_sentinel_.compare_exchange_strong(expected,
- SentinelValue)) {
- uncomp_cached_data_.CreateIfNeeded();
- result.InitFromCache(uncomp_cached_data_, idx);
- } else {
- // Creates one time use data
- result.CreateIfNeeded();
- }
- return result;
- }
- // Return the entry back into circulation
- // This is executed only when we successfully obtained
- // in the first place
- void ReturnUncompressData() {
- if (zstd_uncomp_sentinel_.exchange(&uncomp_cached_data_) != SentinelValue) {
- // Means we are returning while not having it acquired.
- assert(false);
- }
- }
- };
- static_assert(sizeof(ZSTDCachedData) % CACHE_LINE_SIZE == 0,
- "Expected CACHE_LINE_SIZE alignment");
- } // namespace compression_cache
- using namespace compression_cache;
- class CompressionContextCache::Rep {
- public:
- Rep() {}
- ZSTDUncompressCachedData GetZSTDUncompressData() {
- auto p = per_core_uncompr_.AccessElementAndIndex();
- int64_t idx = static_cast<int64_t>(p.second);
- return p.first->GetUncompressData(idx);
- }
- void ReturnZSTDUncompressData(int64_t idx) {
- assert(idx >= 0);
- auto* cn = per_core_uncompr_.AccessAtCore(static_cast<size_t>(idx));
- cn->ReturnUncompressData();
- }
- private:
- CoreLocalArray<ZSTDCachedData> per_core_uncompr_;
- };
- CompressionContextCache::CompressionContextCache() : rep_(new Rep()) {}
- CompressionContextCache* CompressionContextCache::Instance() {
- static CompressionContextCache instance;
- return &instance;
- }
- void CompressionContextCache::InitSingleton() { Instance(); }
- ZSTDUncompressCachedData
- CompressionContextCache::GetCachedZSTDUncompressData() {
- return rep_->GetZSTDUncompressData();
- }
- void CompressionContextCache::ReturnCachedZSTDUncompressData(int64_t idx) {
- rep_->ReturnZSTDUncompressData(idx);
- }
- CompressionContextCache::~CompressionContextCache() { delete rep_; }
- } // namespace ROCKSDB_NAMESPACE
|