compression_context_cache.cc 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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 "util/compression.h"
  11. #include "util/core_local.h"
  12. #include <atomic>
  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. using namespace compression_cache;
  60. class CompressionContextCache::Rep {
  61. public:
  62. Rep() {}
  63. ZSTDUncompressCachedData GetZSTDUncompressData() {
  64. auto p = per_core_uncompr_.AccessElementAndIndex();
  65. int64_t idx = static_cast<int64_t>(p.second);
  66. return p.first->GetUncompressData(idx);
  67. }
  68. void ReturnZSTDUncompressData(int64_t idx) {
  69. assert(idx >= 0);
  70. auto* cn = per_core_uncompr_.AccessAtCore(static_cast<size_t>(idx));
  71. cn->ReturnUncompressData();
  72. }
  73. private:
  74. CoreLocalArray<ZSTDCachedData> per_core_uncompr_;
  75. };
  76. CompressionContextCache::CompressionContextCache() : rep_(new Rep()) {}
  77. CompressionContextCache* CompressionContextCache::Instance() {
  78. static CompressionContextCache instance;
  79. return &instance;
  80. }
  81. void CompressionContextCache::InitSingleton() { Instance(); }
  82. ZSTDUncompressCachedData
  83. CompressionContextCache::GetCachedZSTDUncompressData() {
  84. return rep_->GetZSTDUncompressData();
  85. }
  86. void CompressionContextCache::ReturnCachedZSTDUncompressData(int64_t idx) {
  87. rep_->ReturnZSTDUncompressData(idx);
  88. }
  89. CompressionContextCache::~CompressionContextCache() { delete rep_; }
  90. } // namespace ROCKSDB_NAMESPACE