table_cache_sync_and_async.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright (c) Meta Platforms, Inc. and affiliates.
  2. //
  3. // This source code is licensed under both the GPLv2 (found in the
  4. // COPYING file in the root directory) and Apache 2.0 License
  5. // (found in the LICENSE.Apache file in the root directory).
  6. #include "util/coro_utils.h"
  7. #if defined(WITHOUT_COROUTINES) || \
  8. (defined(USE_COROUTINES) && defined(WITH_COROUTINES))
  9. namespace ROCKSDB_NAMESPACE {
  10. #if defined(WITHOUT_COROUTINES)
  11. #endif
  12. // Batched version of TableCache::MultiGet.
  13. DEFINE_SYNC_AND_ASYNC(Status, TableCache::MultiGet)
  14. (const ReadOptions& options, const InternalKeyComparator& internal_comparator,
  15. const FileMetaData& file_meta, const MultiGetContext::Range* mget_range,
  16. const MutableCFOptions& mutable_cf_options, HistogramImpl* file_read_hist,
  17. bool skip_filters, bool skip_range_deletions, int level, TypedHandle* handle) {
  18. auto& fd = file_meta.fd;
  19. Status s;
  20. TableReader* t = fd.table_reader;
  21. MultiGetRange table_range(*mget_range, mget_range->begin(),
  22. mget_range->end());
  23. if (handle != nullptr && t == nullptr) {
  24. t = cache_.Value(handle);
  25. }
  26. autovector<std::string, MultiGetContext::MAX_BATCH_SIZE> row_cache_entries;
  27. IterKey row_cache_key;
  28. size_t row_cache_key_prefix_size = 0;
  29. KeyContext& first_key = *table_range.begin();
  30. bool lookup_row_cache =
  31. ioptions_.row_cache && !first_key.get_context->NeedToReadSequence();
  32. // Check row cache if enabled. Since row cache does not currently store
  33. // sequence numbers, we cannot use it if we need to fetch the sequence.
  34. if (lookup_row_cache) {
  35. GetContext* first_context = first_key.get_context;
  36. CreateRowCacheKeyPrefix(options, fd, first_key.ikey, first_context,
  37. row_cache_key);
  38. row_cache_key_prefix_size = row_cache_key.Size();
  39. for (auto miter = table_range.begin(); miter != table_range.end();
  40. ++miter) {
  41. const Slice& user_key = miter->ukey_with_ts;
  42. GetContext* get_context = miter->get_context;
  43. Status read_status;
  44. bool ret =
  45. GetFromRowCache(user_key, row_cache_key, row_cache_key_prefix_size,
  46. get_context, &read_status);
  47. if (!read_status.ok()) {
  48. CO_RETURN read_status;
  49. }
  50. if (ret) {
  51. table_range.SkipKey(miter);
  52. } else {
  53. row_cache_entries.emplace_back();
  54. get_context->SetReplayLog(&(row_cache_entries.back()));
  55. }
  56. }
  57. }
  58. // Check that table_range is not empty. Its possible all keys may have been
  59. // found in the row cache and thus the range may now be empty
  60. if (s.ok() && !table_range.empty()) {
  61. if (t == nullptr) {
  62. assert(handle == nullptr);
  63. s = FindTable(options, file_options_, internal_comparator, file_meta,
  64. &handle, mutable_cf_options,
  65. options.read_tier == kBlockCacheTier /* no_io */,
  66. file_read_hist, skip_filters, level,
  67. true /* prefetch_index_and_filter_in_cache */,
  68. 0 /*max_file_size_for_l0_meta_pin*/, file_meta.temperature);
  69. TEST_SYNC_POINT_CALLBACK("TableCache::MultiGet:FindTable", &s);
  70. if (s.ok()) {
  71. t = cache_.Value(handle);
  72. assert(t);
  73. }
  74. }
  75. if (s.ok() && !options.ignore_range_deletions && !skip_range_deletions) {
  76. UpdateRangeTombstoneSeqnums(options, t, table_range);
  77. }
  78. if (s.ok()) {
  79. CO_AWAIT(t->MultiGet)
  80. (options, &table_range, mutable_cf_options.prefix_extractor.get(),
  81. skip_filters);
  82. } else if (options.read_tier == kBlockCacheTier && s.IsIncomplete()) {
  83. for (auto iter = table_range.begin(); iter != table_range.end(); ++iter) {
  84. Status* status = iter->s;
  85. if (status->IsIncomplete()) {
  86. // Couldn't find Table in cache but treat as kFound if no_io set
  87. iter->get_context->MarkKeyMayExist();
  88. s = Status::OK();
  89. }
  90. }
  91. }
  92. }
  93. if (lookup_row_cache) {
  94. size_t row_idx = 0;
  95. RowCacheInterface row_cache{ioptions_.row_cache.get()};
  96. for (auto miter = table_range.begin(); miter != table_range.end();
  97. ++miter) {
  98. std::string& row_cache_entry = row_cache_entries[row_idx++];
  99. const Slice& user_key = miter->ukey_with_ts;
  100. GetContext* get_context = miter->get_context;
  101. get_context->SetReplayLog(nullptr);
  102. // Compute row cache key.
  103. row_cache_key.TrimAppend(row_cache_key_prefix_size, user_key.data(),
  104. user_key.size());
  105. // Put the replay log in row cache only if something was found.
  106. if (s.ok() && !row_cache_entry.empty()) {
  107. size_t charge = row_cache_entry.capacity() + sizeof(std::string);
  108. auto row_ptr = new std::string(std::move(row_cache_entry));
  109. // If row cache is full, it's OK.
  110. row_cache.Insert(row_cache_key.GetUserKey(), row_ptr, charge)
  111. .PermitUncheckedError();
  112. }
  113. }
  114. }
  115. if (handle != nullptr) {
  116. cache_.Release(handle);
  117. }
  118. CO_RETURN s;
  119. }
  120. } // namespace ROCKSDB_NAMESPACE
  121. #endif