compression_context_cache.cc 3.6 KB

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