@nxtedition/rocksdb 8.1.17 → 8.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/binding.cc +32 -2
  2. package/binding.gyp +8 -0
  3. package/deps/liburing/liburing.gyp +20 -0
  4. package/deps/rocksdb/rocksdb/CMakeLists.txt +4 -0
  5. package/deps/rocksdb/rocksdb/TARGETS +7 -0
  6. package/deps/rocksdb/rocksdb/cache/cache.cc +43 -0
  7. package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +8 -5
  8. package/deps/rocksdb/rocksdb/cache/cache_entry_stats.h +1 -1
  9. package/deps/rocksdb/rocksdb/cache/cache_reservation_manager.cc +1 -1
  10. package/deps/rocksdb/rocksdb/cache/cache_test.cc +12 -48
  11. package/deps/rocksdb/rocksdb/cache/charged_cache.cc +26 -18
  12. package/deps/rocksdb/rocksdb/cache/charged_cache.h +5 -62
  13. package/deps/rocksdb/rocksdb/cache/clock_cache.cc +119 -44
  14. package/deps/rocksdb/rocksdb/cache/clock_cache.h +34 -29
  15. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache.cc +3 -3
  16. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache.h +2 -2
  17. package/deps/rocksdb/rocksdb/cache/compressed_secondary_cache_test.cc +148 -209
  18. package/deps/rocksdb/rocksdb/cache/lru_cache.cc +118 -284
  19. package/deps/rocksdb/rocksdb/cache/lru_cache.h +23 -71
  20. package/deps/rocksdb/rocksdb/cache/lru_cache_test.cc +351 -392
  21. package/deps/rocksdb/rocksdb/cache/secondary_cache.cc +5 -2
  22. package/deps/rocksdb/rocksdb/cache/secondary_cache_adapter.cc +296 -0
  23. package/deps/rocksdb/rocksdb/cache/secondary_cache_adapter.h +52 -0
  24. package/deps/rocksdb/rocksdb/cache/sharded_cache.h +22 -19
  25. package/deps/rocksdb/rocksdb/cache/typed_cache.h +56 -20
  26. package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.cc +3 -0
  27. package/deps/rocksdb/rocksdb/db/blob/blob_counting_iterator.h +4 -0
  28. package/deps/rocksdb/rocksdb/db/blob/blob_source.cc +3 -3
  29. package/deps/rocksdb/rocksdb/db/blob/blob_source_test.cc +19 -25
  30. package/deps/rocksdb/rocksdb/db/blob/db_blob_basic_test.cc +216 -0
  31. package/deps/rocksdb/rocksdb/db/c.cc +90 -1
  32. package/deps/rocksdb/rocksdb/db/column_family.cc +8 -7
  33. package/deps/rocksdb/rocksdb/db/column_family.h +0 -6
  34. package/deps/rocksdb/rocksdb/db/compaction/clipping_iterator.h +5 -0
  35. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +24 -7
  36. package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +17 -1
  37. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +18 -12
  38. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +3 -1
  39. package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.cc +245 -302
  40. package/deps/rocksdb/rocksdb/db/compaction/compaction_outputs.h +13 -2
  41. package/deps/rocksdb/rocksdb/db/compaction/subcompaction_state.h +5 -0
  42. package/deps/rocksdb/rocksdb/db/db_basic_test.cc +75 -15
  43. package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +2 -3
  44. package/deps/rocksdb/rocksdb/db/db_filesnapshot.cc +1 -5
  45. package/deps/rocksdb/rocksdb/db/db_flush_test.cc +91 -1
  46. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +5 -12
  47. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +16 -4
  48. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +47 -24
  49. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_debug.cc +4 -2
  50. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +1 -1
  51. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +32 -3
  52. package/deps/rocksdb/rocksdb/db/db_iter.cc +28 -29
  53. package/deps/rocksdb/rocksdb/db/db_iter.h +0 -3
  54. package/deps/rocksdb/rocksdb/db/db_properties_test.cc +176 -0
  55. package/deps/rocksdb/rocksdb/db/db_range_del_test.cc +391 -2
  56. package/deps/rocksdb/rocksdb/db/db_with_timestamp_basic_test.cc +26 -0
  57. package/deps/rocksdb/rocksdb/db/db_write_test.cc +13 -5
  58. package/deps/rocksdb/rocksdb/db/dbformat.h +3 -1
  59. package/deps/rocksdb/rocksdb/db/error_handler_fs_test.cc +0 -1
  60. package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +0 -6
  61. package/deps/rocksdb/rocksdb/db/forward_iterator.cc +3 -0
  62. package/deps/rocksdb/rocksdb/db/forward_iterator.h +1 -1
  63. package/deps/rocksdb/rocksdb/db/history_trimming_iterator.h +4 -0
  64. package/deps/rocksdb/rocksdb/db/import_column_family_job.cc +68 -40
  65. package/deps/rocksdb/rocksdb/db/import_column_family_job.h +3 -3
  66. package/deps/rocksdb/rocksdb/db/import_column_family_test.cc +115 -0
  67. package/deps/rocksdb/rocksdb/db/internal_stats.cc +169 -72
  68. package/deps/rocksdb/rocksdb/db/internal_stats.h +36 -7
  69. package/deps/rocksdb/rocksdb/db/memtable.cc +6 -4
  70. package/deps/rocksdb/rocksdb/db/merge_helper.cc +4 -0
  71. package/deps/rocksdb/rocksdb/db/perf_context_test.cc +151 -0
  72. package/deps/rocksdb/rocksdb/db/range_del_aggregator.cc +47 -16
  73. package/deps/rocksdb/rocksdb/db/range_del_aggregator.h +10 -8
  74. package/deps/rocksdb/rocksdb/db/range_del_aggregator_test.cc +91 -93
  75. package/deps/rocksdb/rocksdb/db/range_tombstone_fragmenter.h +1 -2
  76. package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +1 -1
  77. package/deps/rocksdb/rocksdb/db/version_set.cc +30 -14
  78. package/deps/rocksdb/rocksdb/db/version_set.h +1 -0
  79. package/deps/rocksdb/rocksdb/db/write_stall_stats.cc +179 -0
  80. package/deps/rocksdb/rocksdb/db/write_stall_stats.h +47 -0
  81. package/deps/rocksdb/rocksdb/db_stress_tool/batched_ops_stress.cc +109 -7
  82. package/deps/rocksdb/rocksdb/db_stress_tool/cf_consistency_stress.cc +147 -12
  83. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.cc +31 -0
  84. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +22 -0
  85. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +4 -1
  86. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +42 -59
  87. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.h +7 -4
  88. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +7 -0
  89. package/deps/rocksdb/rocksdb/db_stress_tool/expected_state.cc +6 -10
  90. package/deps/rocksdb/rocksdb/db_stress_tool/multi_ops_txns_stress.cc +6 -0
  91. package/deps/rocksdb/rocksdb/db_stress_tool/multi_ops_txns_stress.h +4 -0
  92. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +127 -36
  93. package/deps/rocksdb/rocksdb/env/fs_posix.cc +8 -0
  94. package/deps/rocksdb/rocksdb/file/file_prefetch_buffer.cc +35 -0
  95. package/deps/rocksdb/rocksdb/file/file_prefetch_buffer.h +29 -8
  96. package/deps/rocksdb/rocksdb/file/file_util.cc +14 -10
  97. package/deps/rocksdb/rocksdb/file/prefetch_test.cc +183 -63
  98. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_cache.h +159 -66
  99. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +3 -1
  100. package/deps/rocksdb/rocksdb/include/rocksdb/c.h +52 -5
  101. package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +3 -3
  102. package/deps/rocksdb/rocksdb/include/rocksdb/compaction_filter.h +134 -73
  103. package/deps/rocksdb/rocksdb/include/rocksdb/db.h +46 -3
  104. package/deps/rocksdb/rocksdb/include/rocksdb/file_system.h +6 -0
  105. package/deps/rocksdb/rocksdb/include/rocksdb/listener.h +0 -6
  106. package/deps/rocksdb/rocksdb/include/rocksdb/metadata.h +7 -0
  107. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +2 -2
  108. package/deps/rocksdb/rocksdb/include/rocksdb/perf_context.h +6 -1
  109. package/deps/rocksdb/rocksdb/include/rocksdb/secondary_cache.h +3 -3
  110. package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +18 -0
  111. package/deps/rocksdb/rocksdb/include/rocksdb/types.h +28 -0
  112. package/deps/rocksdb/rocksdb/include/rocksdb/version.h +2 -2
  113. package/deps/rocksdb/rocksdb/include/rocksdb/wide_columns.h +39 -0
  114. package/deps/rocksdb/rocksdb/monitoring/perf_context.cc +5 -0
  115. package/deps/rocksdb/rocksdb/monitoring/statistics.cc +9 -1
  116. package/deps/rocksdb/rocksdb/options/customizable_test.cc +2 -2
  117. package/deps/rocksdb/rocksdb/port/stack_trace.cc +17 -7
  118. package/deps/rocksdb/rocksdb/port/win/env_win.h +1 -0
  119. package/deps/rocksdb/rocksdb/src.mk +4 -0
  120. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +38 -34
  121. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +11 -12
  122. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_impl.h +5 -5
  123. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +126 -132
  124. package/deps/rocksdb/rocksdb/table/block_based/block_cache.cc +16 -16
  125. package/deps/rocksdb/rocksdb/table/block_based/cachable_entry.h +0 -16
  126. package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.cc +1 -1
  127. package/deps/rocksdb/rocksdb/table/block_based/index_reader_common.cc +1 -1
  128. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +3 -4
  129. package/deps/rocksdb/rocksdb/table/block_based/partitioned_index_reader.cc +1 -1
  130. package/deps/rocksdb/rocksdb/table/block_based/uncompression_dict_reader.cc +1 -1
  131. package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.cc +370 -0
  132. package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.h +44 -0
  133. package/deps/rocksdb/rocksdb/table/get_context.cc +4 -2
  134. package/deps/rocksdb/rocksdb/table/merging_iterator.cc +555 -267
  135. package/deps/rocksdb/rocksdb/table/merging_iterator.h +10 -5
  136. package/deps/rocksdb/rocksdb/table/table_test.cc +113 -70
  137. package/deps/rocksdb/rocksdb/test_util/secondary_cache_test_util.cc +96 -0
  138. package/deps/rocksdb/rocksdb/test_util/secondary_cache_test_util.h +117 -0
  139. package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_impl.cc +5 -3
  140. package/deps/rocksdb/rocksdb/utilities/fault_injection_secondary_cache.cc +3 -3
  141. package/deps/rocksdb/rocksdb/utilities/fault_injection_secondary_cache.h +1 -1
  142. package/deps/rocksdb/rocksdb/utilities/simulator_cache/sim_cache.cc +9 -2
  143. package/deps/rocksdb/rocksdb/utilities/ttl/db_ttl_impl.cc +5 -1
  144. package/deps/rocksdb/rocksdb/utilities/ttl/ttl_test.cc +11 -0
  145. package/deps/rocksdb/rocksdb.gyp +7 -1
  146. package/package.json +1 -1
  147. package/prebuilds/linux-x64/node.napi.node +0 -0
@@ -14,6 +14,7 @@
14
14
  #include <cstdio>
15
15
  #include <cstdlib>
16
16
 
17
+ #include "cache/secondary_cache_adapter.h"
17
18
  #include "monitoring/perf_context_imp.h"
18
19
  #include "monitoring/statistics.h"
19
20
  #include "port/lang.h"
@@ -22,14 +23,6 @@
22
23
  namespace ROCKSDB_NAMESPACE {
23
24
  namespace lru_cache {
24
25
 
25
- namespace {
26
- // A distinct pointer value for marking "dummy" cache entries
27
- struct DummyValue {
28
- char val[12] = "kDummyValue";
29
- };
30
- DummyValue kDummyValue{};
31
- } // namespace
32
-
33
26
  LRUHandleTable::LRUHandleTable(int max_upper_hash_bits,
34
27
  MemoryAllocator* allocator)
35
28
  : length_bits_(/* historical starting size*/ 4),
@@ -103,7 +96,7 @@ void LRUHandleTable::Resize() {
103
96
  std::unique_ptr<LRUHandle* []> new_list {
104
97
  new LRUHandle* [size_t{1} << new_length_bits] {}
105
98
  };
106
- uint32_t count = 0;
99
+ [[maybe_unused]] uint32_t count = 0;
107
100
  for (uint32_t i = 0; i < old_length; i++) {
108
101
  LRUHandle* h = list_[i];
109
102
  while (h != nullptr) {
@@ -127,7 +120,7 @@ LRUCacheShard::LRUCacheShard(size_t capacity, bool strict_capacity_limit,
127
120
  CacheMetadataChargePolicy metadata_charge_policy,
128
121
  int max_upper_hash_bits,
129
122
  MemoryAllocator* allocator,
130
- SecondaryCache* secondary_cache)
123
+ const Cache::EvictionCallback* eviction_callback)
131
124
  : CacheShardBase(metadata_charge_policy),
132
125
  capacity_(0),
133
126
  high_pri_pool_usage_(0),
@@ -141,7 +134,7 @@ LRUCacheShard::LRUCacheShard(size_t capacity, bool strict_capacity_limit,
141
134
  usage_(0),
142
135
  lru_usage_(0),
143
136
  mutex_(use_adaptive_mutex),
144
- secondary_cache_(secondary_cache) {
137
+ eviction_callback_(*eviction_callback) {
145
138
  // Make empty circular linked list.
146
139
  lru_.next = &lru_;
147
140
  lru_.prev = &lru_;
@@ -341,16 +334,19 @@ void LRUCacheShard::EvictFromLRU(size_t charge,
341
334
  }
342
335
  }
343
336
 
344
- void LRUCacheShard::TryInsertIntoSecondaryCache(
345
- autovector<LRUHandle*> evicted_handles) {
346
- for (auto entry : evicted_handles) {
347
- if (secondary_cache_ && entry->IsSecondaryCacheCompatible() &&
348
- !entry->IsInSecondaryCache()) {
349
- secondary_cache_->Insert(entry->key(), entry->value, entry->helper)
350
- .PermitUncheckedError();
337
+ void LRUCacheShard::NotifyEvicted(
338
+ const autovector<LRUHandle*>& evicted_handles) {
339
+ MemoryAllocator* alloc = table_.GetAllocator();
340
+ for (LRUHandle* entry : evicted_handles) {
341
+ if (eviction_callback_ &&
342
+ eviction_callback_(entry->key(),
343
+ reinterpret_cast<Cache::Handle*>(entry))) {
344
+ // Callback took ownership of obj; just free handle
345
+ free(entry);
346
+ } else {
347
+ // Free the entries here outside of mutex for performance reasons.
348
+ entry->Free(alloc);
351
349
  }
352
- // Free the entries here outside of mutex for performance reasons.
353
- entry->Free(table_.GetAllocator());
354
350
  }
355
351
  }
356
352
 
@@ -364,7 +360,7 @@ void LRUCacheShard::SetCapacity(size_t capacity) {
364
360
  EvictFromLRU(0, &last_reference_list);
365
361
  }
366
362
 
367
- TryInsertIntoSecondaryCache(last_reference_list);
363
+ NotifyEvicted(last_reference_list);
368
364
  }
369
365
 
370
366
  void LRUCacheShard::SetStrictCapacityLimit(bool strict_capacity_limit) {
@@ -372,8 +368,7 @@ void LRUCacheShard::SetStrictCapacityLimit(bool strict_capacity_limit) {
372
368
  strict_capacity_limit_ = strict_capacity_limit;
373
369
  }
374
370
 
375
- Status LRUCacheShard::InsertItem(LRUHandle* e, LRUHandle** handle,
376
- bool free_handle_on_fail) {
371
+ Status LRUCacheShard::InsertItem(LRUHandle* e, LRUHandle** handle) {
377
372
  Status s = Status::OK();
378
373
  autovector<LRUHandle*> last_reference_list;
379
374
 
@@ -392,10 +387,9 @@ Status LRUCacheShard::InsertItem(LRUHandle* e, LRUHandle** handle,
392
387
  // into cache and get evicted immediately.
393
388
  last_reference_list.push_back(e);
394
389
  } else {
395
- if (free_handle_on_fail) {
396
- free(e);
397
- *handle = nullptr;
398
- }
390
+ free(e);
391
+ e = nullptr;
392
+ *handle = nullptr;
399
393
  s = Status::MemoryLimit("Insert failed due to LRU cache being full.");
400
394
  }
401
395
  } else {
@@ -427,185 +421,27 @@ Status LRUCacheShard::InsertItem(LRUHandle* e, LRUHandle** handle,
427
421
  }
428
422
  }
429
423
 
430
- TryInsertIntoSecondaryCache(last_reference_list);
424
+ NotifyEvicted(last_reference_list);
431
425
 
432
426
  return s;
433
427
  }
434
428
 
435
- void LRUCacheShard::Promote(LRUHandle* e) {
436
- SecondaryCacheResultHandle* secondary_handle = e->sec_handle;
437
-
438
- assert(secondary_handle->IsReady());
439
- // e is not thread-shared here; OK to modify "immutable" fields as well as
440
- // "mutable" (normally requiring mutex)
441
- e->SetIsPending(false);
442
- e->value = secondary_handle->Value();
443
- assert(e->total_charge == 0);
444
- size_t value_size = secondary_handle->Size();
445
- delete secondary_handle;
446
-
447
- if (e->value) {
448
- e->CalcTotalCharge(value_size, metadata_charge_policy_);
449
- Status s;
450
- if (e->IsStandalone()) {
451
- assert(secondary_cache_ && secondary_cache_->SupportForceErase());
452
-
453
- // Insert a dummy handle and return a standalone handle to caller.
454
- // Charge the standalone handle.
455
- autovector<LRUHandle*> last_reference_list;
456
- bool free_standalone_handle{false};
457
- {
458
- DMutexLock l(mutex_);
459
-
460
- // Free the space following strict LRU policy until enough space
461
- // is freed or the lru list is empty.
462
- EvictFromLRU(e->total_charge, &last_reference_list);
463
-
464
- if ((usage_ + e->total_charge) > capacity_ && strict_capacity_limit_) {
465
- free_standalone_handle = true;
466
- } else {
467
- usage_ += e->total_charge;
468
- }
469
- }
470
-
471
- TryInsertIntoSecondaryCache(last_reference_list);
472
- if (free_standalone_handle) {
473
- e->Unref();
474
- e->Free(table_.GetAllocator());
475
- e = nullptr;
476
- } else {
477
- PERF_COUNTER_ADD(block_cache_standalone_handle_count, 1);
478
- }
479
-
480
- // Insert a dummy handle into the primary cache. This dummy handle is
481
- // not IsSecondaryCacheCompatible().
482
- // FIXME? This should not overwrite an existing non-dummy entry in the
483
- // rare case that one exists
484
- Cache::Priority priority =
485
- e->IsHighPri() ? Cache::Priority::HIGH : Cache::Priority::LOW;
486
- s = Insert(e->key(), e->hash, &kDummyValue, &kNoopCacheItemHelper,
487
- /*charge=*/0,
488
- /*handle=*/nullptr, priority);
489
- } else {
490
- e->SetInCache(true);
491
- LRUHandle* handle = e;
492
- // This InsertItem() could fail if the cache is over capacity and
493
- // strict_capacity_limit_ is true. In such a case, we don't want
494
- // InsertItem() to free the handle, since the item is already in memory
495
- // and the caller will most likely just read it from disk if we erase it
496
- // here.
497
- s = InsertItem(e, &handle, /*free_handle_on_fail=*/false);
498
- if (s.ok()) {
499
- PERF_COUNTER_ADD(block_cache_real_handle_count, 1);
500
- }
501
- }
502
-
503
- if (!s.ok()) {
504
- // Item is in memory, but not accounted against the cache capacity.
505
- // When the handle is released, the item should get deleted.
506
- assert(!e->InCache());
507
- }
508
- } else {
509
- // Secondary cache lookup failed. The caller will take care of detecting
510
- // this and eventually releasing e.
511
- assert(!e->value);
512
- assert(!e->InCache());
513
- }
514
- }
515
-
516
429
  LRUHandle* LRUCacheShard::Lookup(const Slice& key, uint32_t hash,
517
- const Cache::CacheItemHelper* helper,
518
- Cache::CreateContext* create_context,
519
- Cache::Priority priority, bool wait,
520
- Statistics* stats) {
521
- LRUHandle* e = nullptr;
522
- bool found_dummy_entry{false};
523
- {
524
- DMutexLock l(mutex_);
525
- e = table_.Lookup(key, hash);
526
- if (e != nullptr) {
527
- assert(e->InCache());
528
- if (e->value == &kDummyValue) {
529
- // For a dummy handle, if it was retrieved from secondary cache,
530
- // it may still exist in secondary cache.
531
- // If the handle exists in secondary cache, the value should be
532
- // erased from sec cache and be inserted into primary cache.
533
- found_dummy_entry = true;
534
- // Let the dummy entry be overwritten
535
- e = nullptr;
536
- } else {
537
- if (!e->HasRefs()) {
538
- // The entry is in LRU since it's in hash and has no external
539
- // references.
540
- LRU_Remove(e);
541
- }
542
- e->Ref();
543
- e->SetHit();
544
- }
545
- }
546
- }
547
-
548
- // If handle table lookup failed or the handle is a dummy one, allocate
549
- // a handle outside the mutex if we re going to lookup in the secondary cache.
550
- //
551
- // When a block is firstly Lookup from CompressedSecondaryCache, we just
552
- // insert a dummy block into the primary cache (charging the actual size of
553
- // the block) and don't erase the block from CompressedSecondaryCache. A
554
- // standalone handle is returned to the caller. Only if the block is hit
555
- // again, we erase it from CompressedSecondaryCache and add it into the
556
- // primary cache.
557
- if (!e && secondary_cache_ && helper && helper->create_cb) {
558
- bool is_in_sec_cache{false};
559
- std::unique_ptr<SecondaryCacheResultHandle> secondary_handle =
560
- secondary_cache_->Lookup(key, helper, create_context, wait,
561
- found_dummy_entry, is_in_sec_cache);
562
- if (secondary_handle != nullptr) {
563
- e = static_cast<LRUHandle*>(malloc(sizeof(LRUHandle) - 1 + key.size()));
564
-
565
- e->m_flags = 0;
566
- e->im_flags = 0;
567
- e->helper = helper;
568
- e->key_length = key.size();
569
- e->hash = hash;
570
- e->refs = 0;
571
- e->next = e->prev = nullptr;
572
- e->SetPriority(priority);
573
- memcpy(e->key_data, key.data(), key.size());
574
- e->value = nullptr;
575
- e->sec_handle = secondary_handle.release();
576
- e->total_charge = 0;
577
- e->Ref();
578
- e->SetIsInSecondaryCache(is_in_sec_cache);
579
- e->SetIsStandalone(secondary_cache_->SupportForceErase() &&
580
- !found_dummy_entry);
581
-
582
- if (wait) {
583
- Promote(e);
584
- if (e) {
585
- if (!e->value) {
586
- // The secondary cache returned a handle, but the lookup failed.
587
- e->Unref();
588
- e->Free(table_.GetAllocator());
589
- e = nullptr;
590
- } else {
591
- PERF_COUNTER_ADD(secondary_cache_hit_count, 1);
592
- RecordTick(stats, SECONDARY_CACHE_HITS);
593
- }
594
- }
595
- } else {
596
- // If wait is false, we always return a handle and let the caller
597
- // release the handle after checking for success or failure.
598
- e->SetIsPending(true);
599
- // This may be slightly inaccurate, if the lookup eventually fails.
600
- // But the probability is very low.
601
- PERF_COUNTER_ADD(secondary_cache_hit_count, 1);
602
- RecordTick(stats, SECONDARY_CACHE_HITS);
603
- }
604
- } else {
605
- // Caller will most likely overwrite the dummy entry with an Insert
606
- // after this Lookup fails
607
- assert(e == nullptr);
430
+ const Cache::CacheItemHelper* /*helper*/,
431
+ Cache::CreateContext* /*create_context*/,
432
+ Cache::Priority /*priority*/,
433
+ Statistics* /*stats*/) {
434
+ DMutexLock l(mutex_);
435
+ LRUHandle* e = table_.Lookup(key, hash);
436
+ if (e != nullptr) {
437
+ assert(e->InCache());
438
+ if (!e->HasRefs()) {
439
+ // The entry is in LRU since it's in hash and has no external
440
+ // references.
441
+ LRU_Remove(e);
608
442
  }
443
+ e->Ref();
444
+ e->SetHit();
609
445
  }
610
446
  return e;
611
447
  }
@@ -614,8 +450,6 @@ bool LRUCacheShard::Ref(LRUHandle* e) {
614
450
  DMutexLock l(mutex_);
615
451
  // To create another reference - entry must be already externally referenced.
616
452
  assert(e->HasRefs());
617
- // Pending handles are not for sharing
618
- assert(!e->IsPending());
619
453
  e->Ref();
620
454
  return true;
621
455
  }
@@ -639,14 +473,13 @@ bool LRUCacheShard::Release(LRUHandle* e, bool /*useful*/,
639
473
  if (e == nullptr) {
640
474
  return false;
641
475
  }
642
- bool last_reference = false;
643
- // Must Wait or WaitAll first on pending handles. Otherwise, would leak
644
- // a secondary cache handle.
645
- assert(!e->IsPending());
476
+ bool must_free;
477
+ bool was_in_cache;
646
478
  {
647
479
  DMutexLock l(mutex_);
648
- last_reference = e->Unref();
649
- if (last_reference && e->InCache()) {
480
+ must_free = e->Unref();
481
+ was_in_cache = e->InCache();
482
+ if (must_free && was_in_cache) {
650
483
  // The item is still in cache, and nobody else holds a reference to it.
651
484
  if (usage_ > capacity_ || erase_if_last_ref) {
652
485
  // The LRU list must be empty since the cache is full.
@@ -657,29 +490,38 @@ bool LRUCacheShard::Release(LRUHandle* e, bool /*useful*/,
657
490
  } else {
658
491
  // Put the item back on the LRU list, and don't free it.
659
492
  LRU_Insert(e);
660
- last_reference = false;
493
+ must_free = false;
661
494
  }
662
495
  }
663
- // If it was the last reference, then decrement the cache usage.
664
- if (last_reference) {
496
+ // If about to be freed, then decrement the cache usage.
497
+ if (must_free) {
665
498
  assert(usage_ >= e->total_charge);
666
499
  usage_ -= e->total_charge;
667
500
  }
668
501
  }
669
502
 
670
503
  // Free the entry here outside of mutex for performance reasons.
671
- if (last_reference) {
672
- e->Free(table_.GetAllocator());
504
+ if (must_free) {
505
+ // Only call eviction callback if we're sure no one requested erasure
506
+ // FIXME: disabled because of test churn
507
+ if (false && was_in_cache && !erase_if_last_ref && eviction_callback_ &&
508
+ eviction_callback_(e->key(), reinterpret_cast<Cache::Handle*>(e))) {
509
+ // Callback took ownership of obj; just free handle
510
+ free(e);
511
+ } else {
512
+ e->Free(table_.GetAllocator());
513
+ }
673
514
  }
674
- return last_reference;
515
+ return must_free;
675
516
  }
676
517
 
677
- Status LRUCacheShard::Insert(const Slice& key, uint32_t hash,
678
- Cache::ObjectPtr value,
679
- const Cache::CacheItemHelper* helper,
680
- size_t charge, LRUHandle** handle,
681
- Cache::Priority priority) {
518
+ LRUHandle* LRUCacheShard::CreateHandle(const Slice& key, uint32_t hash,
519
+ Cache::ObjectPtr value,
520
+ const Cache::CacheItemHelper* helper,
521
+ size_t charge) {
682
522
  assert(helper);
523
+ // value == nullptr is reserved for indicating failure in SecondaryCache
524
+ assert(!(helper->IsSecondaryCacheCompatible() && value == nullptr));
683
525
 
684
526
  // Allocate the memory here outside of the mutex.
685
527
  // If the cache is full, we'll have to release it.
@@ -695,16 +537,53 @@ Status LRUCacheShard::Insert(const Slice& key, uint32_t hash,
695
537
  e->hash = hash;
696
538
  e->refs = 0;
697
539
  e->next = e->prev = nullptr;
698
- e->SetInCache(true);
699
- e->SetPriority(priority);
700
540
  memcpy(e->key_data, key.data(), key.size());
701
541
  e->CalcTotalCharge(charge, metadata_charge_policy_);
702
542
 
703
- // value == nullptr is reserved for indicating failure for when secondary
704
- // cache compatible
705
- assert(!(e->IsSecondaryCacheCompatible() && value == nullptr));
543
+ return e;
544
+ }
706
545
 
707
- return InsertItem(e, handle, /* free_handle_on_fail */ true);
546
+ Status LRUCacheShard::Insert(const Slice& key, uint32_t hash,
547
+ Cache::ObjectPtr value,
548
+ const Cache::CacheItemHelper* helper,
549
+ size_t charge, LRUHandle** handle,
550
+ Cache::Priority priority) {
551
+ LRUHandle* e = CreateHandle(key, hash, value, helper, charge);
552
+ e->SetPriority(priority);
553
+ e->SetInCache(true);
554
+ return InsertItem(e, handle);
555
+ }
556
+
557
+ LRUHandle* LRUCacheShard::CreateStandalone(const Slice& key, uint32_t hash,
558
+ Cache::ObjectPtr value,
559
+ const Cache::CacheItemHelper* helper,
560
+ size_t charge,
561
+ bool allow_uncharged) {
562
+ LRUHandle* e = CreateHandle(key, hash, value, helper, charge);
563
+ e->SetIsStandalone(true);
564
+ e->Ref();
565
+
566
+ autovector<LRUHandle*> last_reference_list;
567
+
568
+ {
569
+ DMutexLock l(mutex_);
570
+
571
+ EvictFromLRU(e->total_charge, &last_reference_list);
572
+
573
+ if (strict_capacity_limit_ && (usage_ + e->total_charge) > capacity_) {
574
+ if (allow_uncharged) {
575
+ e->total_charge = 0;
576
+ } else {
577
+ free(e);
578
+ e = nullptr;
579
+ }
580
+ } else {
581
+ usage_ += e->total_charge;
582
+ }
583
+ }
584
+
585
+ NotifyEvicted(last_reference_list);
586
+ return e;
708
587
  }
709
588
 
710
589
  void LRUCacheShard::Erase(const Slice& key, uint32_t hash) {
@@ -733,16 +612,6 @@ void LRUCacheShard::Erase(const Slice& key, uint32_t hash) {
733
612
  }
734
613
  }
735
614
 
736
- bool LRUCacheShard::IsReady(LRUHandle* e) {
737
- bool ready = true;
738
- if (e->IsPending()) {
739
- assert(secondary_cache_);
740
- assert(e->sec_handle);
741
- ready = e->sec_handle->IsReady();
742
- }
743
- return ready;
744
- }
745
-
746
615
  size_t LRUCacheShard::GetUsage() const {
747
616
  DMutexLock l(mutex_);
748
617
  return usage_;
@@ -782,26 +651,23 @@ LRUCache::LRUCache(size_t capacity, int num_shard_bits,
782
651
  double low_pri_pool_ratio,
783
652
  std::shared_ptr<MemoryAllocator> allocator,
784
653
  bool use_adaptive_mutex,
785
- CacheMetadataChargePolicy metadata_charge_policy,
786
- std::shared_ptr<SecondaryCache> _secondary_cache)
654
+ CacheMetadataChargePolicy metadata_charge_policy)
787
655
  : ShardedCache(capacity, num_shard_bits, strict_capacity_limit,
788
- std::move(allocator)),
789
- secondary_cache_(std::move(_secondary_cache)) {
656
+ std::move(allocator)) {
790
657
  size_t per_shard = GetPerShardCapacity();
791
- SecondaryCache* secondary_cache = secondary_cache_.get();
792
658
  MemoryAllocator* alloc = memory_allocator();
659
+ const EvictionCallback* eviction_callback = &eviction_callback_;
793
660
  InitShards([=](LRUCacheShard* cs) {
794
- new (cs) LRUCacheShard(
795
- per_shard, strict_capacity_limit, high_pri_pool_ratio,
796
- low_pri_pool_ratio, use_adaptive_mutex, metadata_charge_policy,
797
- /* max_upper_hash_bits */ 32 - num_shard_bits, alloc, secondary_cache);
661
+ new (cs) LRUCacheShard(per_shard, strict_capacity_limit,
662
+ high_pri_pool_ratio, low_pri_pool_ratio,
663
+ use_adaptive_mutex, metadata_charge_policy,
664
+ /* max_upper_hash_bits */ 32 - num_shard_bits, alloc,
665
+ eviction_callback);
798
666
  });
799
667
  }
800
668
 
801
669
  Cache::ObjectPtr LRUCache::Value(Handle* handle) {
802
670
  auto h = reinterpret_cast<const LRUHandle*>(handle);
803
- assert(!h->IsPending() || h->value == nullptr);
804
- assert(h->value != &kDummyValue);
805
671
  return h->value;
806
672
  }
807
673
 
@@ -824,42 +690,6 @@ double LRUCache::GetHighPriPoolRatio() {
824
690
  return GetShard(0).GetHighPriPoolRatio();
825
691
  }
826
692
 
827
- void LRUCache::WaitAll(std::vector<Handle*>& handles) {
828
- if (secondary_cache_) {
829
- std::vector<SecondaryCacheResultHandle*> sec_handles;
830
- sec_handles.reserve(handles.size());
831
- for (Handle* handle : handles) {
832
- if (!handle) {
833
- continue;
834
- }
835
- LRUHandle* lru_handle = reinterpret_cast<LRUHandle*>(handle);
836
- if (!lru_handle->IsPending()) {
837
- continue;
838
- }
839
- sec_handles.emplace_back(lru_handle->sec_handle);
840
- }
841
- secondary_cache_->WaitAll(sec_handles);
842
- for (Handle* handle : handles) {
843
- if (!handle) {
844
- continue;
845
- }
846
- LRUHandle* lru_handle = reinterpret_cast<LRUHandle*>(handle);
847
- if (!lru_handle->IsPending()) {
848
- continue;
849
- }
850
- GetShard(lru_handle->hash).Promote(lru_handle);
851
- }
852
- }
853
- }
854
-
855
- void LRUCache::AppendPrintableOptions(std::string& str) const {
856
- ShardedCache::AppendPrintableOptions(str); // options from shard
857
- if (secondary_cache_) {
858
- str.append(" secondary_cache:\n");
859
- str.append(secondary_cache_->GetPrintableOptions());
860
- }
861
- }
862
-
863
693
  } // namespace lru_cache
864
694
 
865
695
  std::shared_ptr<Cache> NewLRUCache(
@@ -887,10 +717,14 @@ std::shared_ptr<Cache> NewLRUCache(
887
717
  if (num_shard_bits < 0) {
888
718
  num_shard_bits = GetDefaultCacheShardBits(capacity);
889
719
  }
890
- return std::make_shared<LRUCache>(
720
+ std::shared_ptr<Cache> cache = std::make_shared<LRUCache>(
891
721
  capacity, num_shard_bits, strict_capacity_limit, high_pri_pool_ratio,
892
722
  low_pri_pool_ratio, std::move(memory_allocator), use_adaptive_mutex,
893
- metadata_charge_policy, secondary_cache);
723
+ metadata_charge_policy);
724
+ if (secondary_cache) {
725
+ cache = std::make_shared<CacheWithSecondaryAdapter>(cache, secondary_cache);
726
+ }
727
+ return cache;
894
728
  }
895
729
 
896
730
  std::shared_ptr<Cache> NewLRUCache(const LRUCacheOptions& cache_opts) {