@nxtedition/rocksdb 7.0.4 → 7.0.7

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 (128) hide show
  1. package/binding.cc +320 -324
  2. package/chained-batch.js +6 -1
  3. package/deps/rocksdb/rocksdb/CMakeLists.txt +8 -3
  4. package/deps/rocksdb/rocksdb/Makefile +10 -4
  5. package/deps/rocksdb/rocksdb/TARGETS +6 -4
  6. package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +9 -0
  7. package/deps/rocksdb/rocksdb/cache/cache_test.cc +14 -0
  8. package/deps/rocksdb/rocksdb/cache/clock_cache.cc +8 -8
  9. package/deps/rocksdb/rocksdb/cache/fast_lru_cache.cc +272 -174
  10. package/deps/rocksdb/rocksdb/cache/fast_lru_cache.h +201 -57
  11. package/deps/rocksdb/rocksdb/cache/lru_cache.cc +19 -19
  12. package/deps/rocksdb/rocksdb/cache/lru_cache.h +2 -1
  13. package/deps/rocksdb/rocksdb/db/blob/blob_source.cc +170 -0
  14. package/deps/rocksdb/rocksdb/db/blob/blob_source.h +95 -0
  15. package/deps/rocksdb/rocksdb/db/blob/blob_source_test.cc +298 -0
  16. package/deps/rocksdb/rocksdb/db/blob/db_blob_basic_test.cc +172 -0
  17. package/deps/rocksdb/rocksdb/db/column_family.cc +8 -3
  18. package/deps/rocksdb/rocksdb/db/column_family.h +6 -3
  19. package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +10 -0
  20. package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +6 -6
  21. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +22 -2
  22. package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +38 -0
  23. package/deps/rocksdb/rocksdb/db/db_basic_test.cc +17 -5
  24. package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +4 -7
  25. package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +74 -71
  26. package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +70 -1
  27. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +13 -12
  28. package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +36 -0
  29. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +11 -4
  30. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +1 -1
  31. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +139 -91
  32. package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +48 -14
  33. package/deps/rocksdb/rocksdb/db/db_kv_checksum_test.cc +90 -55
  34. package/deps/rocksdb/rocksdb/db/db_rate_limiter_test.cc +9 -4
  35. package/deps/rocksdb/rocksdb/db/db_test.cc +3 -1
  36. package/deps/rocksdb/rocksdb/db/db_wal_test.cc +12 -7
  37. package/deps/rocksdb/rocksdb/db/db_write_test.cc +35 -0
  38. package/deps/rocksdb/rocksdb/db/dbformat.cc +3 -1
  39. package/deps/rocksdb/rocksdb/db/dbformat.h +5 -3
  40. package/deps/rocksdb/rocksdb/db/flush_job_test.cc +1 -1
  41. package/deps/rocksdb/rocksdb/db/memtable.cc +1 -0
  42. package/deps/rocksdb/rocksdb/db/memtable_list_test.cc +4 -2
  43. package/deps/rocksdb/rocksdb/db/repair.cc +1 -1
  44. package/deps/rocksdb/rocksdb/db/version_builder.cc +43 -1
  45. package/deps/rocksdb/rocksdb/db/version_edit.cc +13 -5
  46. package/deps/rocksdb/rocksdb/db/version_edit.h +22 -1
  47. package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +4 -5
  48. package/deps/rocksdb/rocksdb/db/version_set.cc +109 -41
  49. package/deps/rocksdb/rocksdb/db/version_set.h +36 -3
  50. package/deps/rocksdb/rocksdb/db/version_set_sync_and_async.h +1 -4
  51. package/deps/rocksdb/rocksdb/db/version_set_test.cc +10 -10
  52. package/deps/rocksdb/rocksdb/db/version_util.h +1 -1
  53. package/deps/rocksdb/rocksdb/db/wal_manager_test.cc +1 -1
  54. package/deps/rocksdb/rocksdb/db/write_batch.cc +34 -10
  55. package/deps/rocksdb/rocksdb/db/write_batch_internal.h +2 -0
  56. package/deps/rocksdb/rocksdb/db/write_callback_test.cc +4 -0
  57. package/deps/rocksdb/rocksdb/db_stress_tool/batched_ops_stress.cc +2 -0
  58. package/deps/rocksdb/rocksdb/db_stress_tool/cf_consistency_stress.cc +4 -1
  59. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +1 -1
  60. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +7 -5
  61. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +5 -10
  62. package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +0 -7
  63. package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +2 -0
  64. package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +24 -3
  65. package/deps/rocksdb/rocksdb/file/writable_file_writer.cc +8 -0
  66. package/deps/rocksdb/rocksdb/file/writable_file_writer.h +10 -0
  67. package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +5 -0
  68. package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +4 -4
  69. package/deps/rocksdb/rocksdb/include/rocksdb/options.h +9 -5
  70. package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +5 -0
  71. package/deps/rocksdb/rocksdb/include/rocksdb/types.h +1 -0
  72. package/deps/rocksdb/rocksdb/include/rocksdb/utilities/write_batch_with_index.h +1 -1
  73. package/deps/rocksdb/rocksdb/include/rocksdb/version.h +1 -1
  74. package/deps/rocksdb/rocksdb/include/rocksdb/write_batch.h +0 -3
  75. package/deps/rocksdb/rocksdb/microbench/ribbon_bench.cc +8 -6
  76. package/deps/rocksdb/rocksdb/monitoring/statistics.cc +3 -1
  77. package/deps/rocksdb/rocksdb/options/options_helper.cc +4 -2
  78. package/deps/rocksdb/rocksdb/options/options_test.cc +1 -11
  79. package/deps/rocksdb/rocksdb/port/port_posix.h +7 -0
  80. package/deps/rocksdb/rocksdb/port/win/port_win.h +11 -3
  81. package/deps/rocksdb/rocksdb/src.mk +6 -2
  82. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +4 -33
  83. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.h +3 -3
  84. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +38 -118
  85. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +6 -8
  86. package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +10 -13
  87. package/deps/rocksdb/rocksdb/table/block_based/block_like_traits.h +4 -9
  88. package/deps/rocksdb/rocksdb/table/block_based/block_type.h +0 -1
  89. package/deps/rocksdb/rocksdb/table/block_based/filter_block.h +10 -28
  90. package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.cc +2 -3
  91. package/deps/rocksdb/rocksdb/table/block_based/filter_policy.cc +0 -91
  92. package/deps/rocksdb/rocksdb/table/block_based/filter_policy_internal.h +2 -30
  93. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.cc +6 -27
  94. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.h +11 -13
  95. package/deps/rocksdb/rocksdb/table/block_based/full_filter_block_test.cc +28 -40
  96. package/deps/rocksdb/rocksdb/table/block_based/mock_block_based_table.h +0 -1
  97. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +22 -43
  98. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.h +11 -22
  99. package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block_test.cc +24 -25
  100. package/deps/rocksdb/rocksdb/table/block_fetcher.cc +0 -1
  101. package/deps/rocksdb/rocksdb/table/get_context.h +0 -1
  102. package/deps/rocksdb/rocksdb/table/table_test.cc +3 -18
  103. package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +3 -16
  104. package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +3 -3
  105. package/deps/rocksdb/rocksdb/tools/ldb_cmd_test.cc +1 -1
  106. package/deps/rocksdb/rocksdb/util/bloom_test.cc +0 -201
  107. package/deps/rocksdb/rocksdb/util/distributed_mutex.h +48 -0
  108. package/deps/rocksdb/rocksdb/util/filter_bench.cc +5 -11
  109. package/deps/rocksdb/rocksdb/utilities/backup/backup_engine.cc +3 -0
  110. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +7 -21
  111. package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.h +1 -1
  112. package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_test.cc +45 -0
  113. package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction_db.h +21 -14
  114. package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.cc +10 -1
  115. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn.cc +3 -1
  116. package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn_db.cc +9 -0
  117. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn.cc +3 -2
  118. package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn_db.cc +3 -1
  119. package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index.cc +5 -4
  120. package/deps/rocksdb/rocksdb.gyp +1 -1
  121. package/index.js +36 -14
  122. package/package-lock.json +2 -2
  123. package/package.json +1 -1
  124. package/prebuilds/darwin-arm64/node.napi.node +0 -0
  125. package/prebuilds/linux-x64/node.napi.node +0 -0
  126. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block.cc +0 -358
  127. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block.h +0 -127
  128. package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block_test.cc +0 -219
@@ -9,77 +9,191 @@
9
9
 
10
10
  #include "cache/fast_lru_cache.h"
11
11
 
12
+ #include <math.h>
13
+
12
14
  #include <cassert>
13
15
  #include <cstdint>
14
16
  #include <cstdio>
17
+ #include <functional>
15
18
 
16
19
  #include "monitoring/perf_context_imp.h"
17
20
  #include "monitoring/statistics.h"
18
21
  #include "port/lang.h"
19
- #include "util/mutexlock.h"
20
-
21
- #define KEY_LENGTH \
22
- 16 // TODO(guido) Make use of this symbol in other parts of the source code
23
- // (e.g., cache_key.h, cache_test.cc, etc.)
22
+ #include "util/distributed_mutex.h"
23
+ #include "util/hash.h"
24
+ #include "util/random.h"
24
25
 
25
26
  namespace ROCKSDB_NAMESPACE {
26
27
 
27
28
  namespace fast_lru_cache {
28
29
 
29
- LRUHandleTable::LRUHandleTable(int hash_bits)
30
+ namespace {
31
+ // Returns x % 2^{bits}.
32
+ inline uint32_t BinaryMod(uint32_t x, uint8_t bits) {
33
+ assert(bits <= 32);
34
+ return (x << (32 - bits)) >> (32 - bits);
35
+ }
36
+ } // anonymous namespace
37
+
38
+ LRUHandleTable::LRUHandleTable(uint8_t hash_bits)
30
39
  : length_bits_(hash_bits),
31
- list_(new LRUHandle* [size_t{1} << length_bits_] {}) {}
40
+ occupancy_(0),
41
+ array_(new LRUHandle[size_t{1} << length_bits_]) {
42
+ assert(hash_bits <= 32);
43
+ }
32
44
 
33
45
  LRUHandleTable::~LRUHandleTable() {
46
+ // TODO(Guido) If users still hold references to handles,
47
+ // those will become invalidated. And if we choose not to
48
+ // delete the data, it will become leaked.
34
49
  ApplyToEntriesRange(
35
50
  [](LRUHandle* h) {
51
+ // TODO(Guido) Remove the HasRefs() check?
36
52
  if (!h->HasRefs()) {
37
- h->Free();
53
+ h->FreeData();
38
54
  }
39
55
  },
40
56
  0, uint32_t{1} << length_bits_);
41
57
  }
42
58
 
43
59
  LRUHandle* LRUHandleTable::Lookup(const Slice& key, uint32_t hash) {
44
- return *FindPointer(key, hash);
45
- }
46
-
47
- inline LRUHandle** LRUHandleTable::Head(uint32_t hash) {
48
- return &list_[hash >> (32 - length_bits_)];
49
- }
50
-
51
- LRUHandle* LRUHandleTable::Insert(LRUHandle* h) {
52
- LRUHandle** ptr = FindPointer(h->key(), h->hash);
53
- LRUHandle* old = *ptr;
54
- h->next_hash = (old == nullptr ? nullptr : old->next_hash);
55
- *ptr = h;
56
- return old;
57
- }
60
+ int probe = 0;
61
+ int slot = FindVisibleElement(key, hash, probe, 0);
62
+ return (slot == -1) ? nullptr : &array_[slot];
63
+ }
64
+
65
+ LRUHandle* LRUHandleTable::Insert(LRUHandle* h, LRUHandle** old) {
66
+ int probe = 0;
67
+ int slot = FindVisibleElementOrAvailableSlot(h->key(), h->hash, probe,
68
+ 1 /*displacement*/);
69
+ *old = nullptr;
70
+ if (slot == -1) {
71
+ return nullptr;
72
+ }
58
73
 
59
- LRUHandle* LRUHandleTable::Remove(const Slice& key, uint32_t hash) {
60
- LRUHandle** ptr = FindPointer(key, hash);
61
- LRUHandle* result = *ptr;
62
- if (result != nullptr) {
63
- *ptr = result->next_hash;
74
+ if (array_[slot].IsEmpty() || array_[slot].IsTombstone()) {
75
+ bool empty = array_[slot].IsEmpty();
76
+ Assign(slot, h);
77
+ LRUHandle* new_entry = &array_[slot];
78
+ if (empty) {
79
+ // This used to be an empty slot.
80
+ return new_entry;
81
+ }
82
+ // It used to be a tombstone, so there may already be a copy of the
83
+ // key in the table.
84
+ slot = FindVisibleElement(h->key(), h->hash, probe, 0 /*displacement*/);
85
+ if (slot == -1) {
86
+ // No existing copy of the key.
87
+ return new_entry;
88
+ }
89
+ *old = &array_[slot];
90
+ return new_entry;
91
+ } else {
92
+ // There is an existing copy of the key.
93
+ *old = &array_[slot];
94
+ // Find an available slot for the new element.
95
+ array_[slot].displacements++;
96
+ slot = FindAvailableSlot(h->key(), probe, 1 /*displacement*/);
97
+ if (slot == -1) {
98
+ // No available slots. Roll back displacements.
99
+ probe = 0;
100
+ slot = FindVisibleElement(h->key(), h->hash, probe, -1);
101
+ array_[slot].displacements--;
102
+ FindAvailableSlot(h->key(), probe, -1);
103
+ return nullptr;
104
+ }
105
+ Assign(slot, h);
106
+ return &array_[slot];
64
107
  }
65
- return result;
66
108
  }
67
109
 
68
- LRUHandle** LRUHandleTable::FindPointer(const Slice& key, uint32_t hash) {
69
- LRUHandle** ptr = &list_[hash >> (32 - length_bits_)];
70
- while (*ptr != nullptr && ((*ptr)->hash != hash || key != (*ptr)->key())) {
71
- ptr = &(*ptr)->next_hash;
110
+ void LRUHandleTable::Remove(LRUHandle* h) {
111
+ assert(h->next == nullptr &&
112
+ h->prev == nullptr); // Already off the LRU list.
113
+ int probe = 0;
114
+ FindSlot(
115
+ h->key(), [&h](LRUHandle* e) { return e == h; }, probe,
116
+ -1 /*displacement*/);
117
+ h->SetIsVisible(false);
118
+ h->SetIsElement(false);
119
+ occupancy_--;
120
+ }
121
+
122
+ void LRUHandleTable::Assign(int slot, LRUHandle* h) {
123
+ LRUHandle* dst = &array_[slot];
124
+ uint32_t disp = dst->displacements;
125
+ *dst = *h;
126
+ dst->displacements = disp;
127
+ dst->SetIsVisible(true);
128
+ dst->SetIsElement(true);
129
+ occupancy_++;
130
+ }
131
+
132
+ void LRUHandleTable::Exclude(LRUHandle* h) { h->SetIsVisible(false); }
133
+
134
+ int LRUHandleTable::FindVisibleElement(const Slice& key, uint32_t hash,
135
+ int& probe, int displacement) {
136
+ return FindSlot(
137
+ key,
138
+ [&](LRUHandle* h) { return h->Matches(key, hash) && h->IsVisible(); },
139
+ probe, displacement);
140
+ }
141
+
142
+ int LRUHandleTable::FindAvailableSlot(const Slice& key, int& probe,
143
+ int displacement) {
144
+ return FindSlot(
145
+ key, [](LRUHandle* h) { return h->IsEmpty() || h->IsTombstone(); }, probe,
146
+ displacement);
147
+ }
148
+
149
+ int LRUHandleTable::FindVisibleElementOrAvailableSlot(const Slice& key,
150
+ uint32_t hash, int& probe,
151
+ int displacement) {
152
+ return FindSlot(
153
+ key,
154
+ [&](LRUHandle* h) {
155
+ return h->IsEmpty() || h->IsTombstone() ||
156
+ (h->Matches(key, hash) && h->IsVisible());
157
+ },
158
+ probe, displacement);
159
+ }
160
+
161
+ inline int LRUHandleTable::FindSlot(const Slice& key,
162
+ std::function<bool(LRUHandle*)> cond,
163
+ int& probe, int displacement) {
164
+ uint32_t base =
165
+ BinaryMod(Hash(key.data(), key.size(), kProbingSeed1), length_bits_);
166
+ uint32_t increment = BinaryMod(
167
+ (Hash(key.data(), key.size(), kProbingSeed2) << 1) | 1, length_bits_);
168
+ uint32_t current = BinaryMod(base + probe * increment, length_bits_);
169
+ while (true) {
170
+ LRUHandle* h = &array_[current];
171
+ probe++;
172
+ if (current == base && probe > 1) {
173
+ // We looped back.
174
+ return -1;
175
+ }
176
+ if (cond(h)) {
177
+ return current;
178
+ }
179
+ if (h->IsEmpty()) {
180
+ // We check emptyness after the condition, because
181
+ // the condition may be emptyness.
182
+ return -1;
183
+ }
184
+ h->displacements += displacement;
185
+ current = BinaryMod(current + increment, length_bits_);
72
186
  }
73
- return ptr;
74
187
  }
75
188
 
76
189
  LRUCacheShard::LRUCacheShard(size_t capacity, size_t estimated_value_size,
77
190
  bool strict_capacity_limit,
78
191
  CacheMetadataChargePolicy metadata_charge_policy)
79
- : capacity_(0),
192
+ : capacity_(capacity),
80
193
  strict_capacity_limit_(strict_capacity_limit),
81
194
  table_(
82
- GetHashBits(capacity, estimated_value_size, metadata_charge_policy)),
195
+ CalcHashBits(capacity, estimated_value_size, metadata_charge_policy) +
196
+ static_cast<uint8_t>(ceil(log2(1.0 / kLoadFactor)))),
83
197
  usage_(0),
84
198
  lru_usage_(0) {
85
199
  set_metadata_charge_policy(metadata_charge_policy);
@@ -87,29 +201,27 @@ LRUCacheShard::LRUCacheShard(size_t capacity, size_t estimated_value_size,
87
201
  lru_.next = &lru_;
88
202
  lru_.prev = &lru_;
89
203
  lru_low_pri_ = &lru_;
90
- SetCapacity(capacity);
91
204
  }
92
205
 
93
206
  void LRUCacheShard::EraseUnRefEntries() {
94
- autovector<LRUHandle*> last_reference_list;
207
+ autovector<LRUHandle> last_reference_list;
95
208
  {
96
- MutexLock l(&mutex_);
209
+ DMutexLock l(mutex_);
97
210
  while (lru_.next != &lru_) {
98
211
  LRUHandle* old = lru_.next;
99
212
  // LRU list contains only elements which can be evicted.
100
- assert(old->InCache() && !old->HasRefs());
213
+ assert(old->IsVisible() && !old->HasRefs());
101
214
  LRU_Remove(old);
102
- table_.Remove(old->key(), old->hash);
103
- old->SetInCache(false);
215
+ table_.Remove(old);
104
216
  assert(usage_ >= old->total_charge);
105
217
  usage_ -= old->total_charge;
106
- last_reference_list.push_back(old);
218
+ last_reference_list.push_back(*old);
107
219
  }
108
220
  }
109
221
 
110
222
  // Free the entries here outside of mutex for performance reasons.
111
- for (auto entry : last_reference_list) {
112
- entry->Free();
223
+ for (auto& h : last_reference_list) {
224
+ h.FreeData();
113
225
  }
114
226
  }
115
227
 
@@ -120,7 +232,7 @@ void LRUCacheShard::ApplyToSomeEntries(
120
232
  // The state is essentially going to be the starting hash, which works
121
233
  // nicely even if we resize between calls because we use upper-most
122
234
  // hash bits for table indexes.
123
- MutexLock l(&mutex_);
235
+ DMutexLock l(mutex_);
124
236
  uint32_t length_bits = table_.GetLengthBits();
125
237
  uint32_t length = uint32_t{1} << length_bits;
126
238
 
@@ -148,57 +260,48 @@ void LRUCacheShard::ApplyToSomeEntries(
148
260
  index_begin, index_end);
149
261
  }
150
262
 
151
- void LRUCacheShard::LRU_Remove(LRUHandle* e) {
152
- assert(e->next != nullptr);
153
- assert(e->prev != nullptr);
154
- e->next->prev = e->prev;
155
- e->prev->next = e->next;
156
- e->prev = e->next = nullptr;
157
- assert(lru_usage_ >= e->total_charge);
158
- lru_usage_ -= e->total_charge;
263
+ void LRUCacheShard::LRU_Remove(LRUHandle* h) {
264
+ assert(h->next != nullptr);
265
+ assert(h->prev != nullptr);
266
+ h->next->prev = h->prev;
267
+ h->prev->next = h->next;
268
+ h->prev = h->next = nullptr;
269
+ assert(lru_usage_ >= h->total_charge);
270
+ lru_usage_ -= h->total_charge;
159
271
  }
160
272
 
161
- void LRUCacheShard::LRU_Insert(LRUHandle* e) {
162
- assert(e->next == nullptr);
163
- assert(e->prev == nullptr);
164
- // Inset "e" to head of LRU list.
165
- e->next = &lru_;
166
- e->prev = lru_.prev;
167
- e->prev->next = e;
168
- e->next->prev = e;
169
- lru_usage_ += e->total_charge;
273
+ void LRUCacheShard::LRU_Insert(LRUHandle* h) {
274
+ assert(h->next == nullptr);
275
+ assert(h->prev == nullptr);
276
+ // Insert h to head of LRU list.
277
+ h->next = &lru_;
278
+ h->prev = lru_.prev;
279
+ h->prev->next = h;
280
+ h->next->prev = h;
281
+ lru_usage_ += h->total_charge;
170
282
  }
171
283
 
172
284
  void LRUCacheShard::EvictFromLRU(size_t charge,
173
- autovector<LRUHandle*>* deleted) {
285
+ autovector<LRUHandle>* deleted) {
174
286
  while ((usage_ + charge) > capacity_ && lru_.next != &lru_) {
175
287
  LRUHandle* old = lru_.next;
176
288
  // LRU list contains only elements which can be evicted.
177
- assert(old->InCache() && !old->HasRefs());
289
+ assert(old->IsVisible() && !old->HasRefs());
178
290
  LRU_Remove(old);
179
- table_.Remove(old->key(), old->hash);
180
- old->SetInCache(false);
291
+ table_.Remove(old);
181
292
  assert(usage_ >= old->total_charge);
182
293
  usage_ -= old->total_charge;
183
- deleted->push_back(old);
294
+ deleted->push_back(*old);
184
295
  }
185
296
  }
186
297
 
187
- int LRUCacheShard::GetHashBits(
298
+ uint8_t LRUCacheShard::CalcHashBits(
188
299
  size_t capacity, size_t estimated_value_size,
189
300
  CacheMetadataChargePolicy metadata_charge_policy) {
190
- LRUHandle* e = reinterpret_cast<LRUHandle*>(
191
- new char[sizeof(LRUHandle) - 1 + KEY_LENGTH]);
192
- e->key_length = KEY_LENGTH;
193
- e->deleter = nullptr;
194
- e->refs = 0;
195
- e->flags = 0;
196
- e->refs = 0;
197
-
198
- e->CalcTotalCharge(estimated_value_size, metadata_charge_policy);
199
- size_t num_entries = capacity / e->total_charge;
200
- e->Free();
201
- int num_hash_bits = 0;
301
+ LRUHandle h;
302
+ h.CalcTotalCharge(estimated_value_size, metadata_charge_policy);
303
+ size_t num_entries = capacity / h.total_charge;
304
+ uint8_t num_hash_bits = 0;
202
305
  while (num_entries >>= 1) {
203
306
  ++num_hash_bits;
204
307
  }
@@ -206,106 +309,128 @@ int LRUCacheShard::GetHashBits(
206
309
  }
207
310
 
208
311
  void LRUCacheShard::SetCapacity(size_t capacity) {
209
- autovector<LRUHandle*> last_reference_list;
312
+ assert(false); // Not supported. TODO(Guido) Support it?
313
+ autovector<LRUHandle> last_reference_list;
210
314
  {
211
- MutexLock l(&mutex_);
315
+ DMutexLock l(mutex_);
212
316
  capacity_ = capacity;
213
317
  EvictFromLRU(0, &last_reference_list);
214
318
  }
215
319
 
216
320
  // Free the entries here outside of mutex for performance reasons.
217
- for (auto entry : last_reference_list) {
218
- entry->Free();
321
+ for (auto& h : last_reference_list) {
322
+ h.FreeData();
219
323
  }
220
324
  }
221
325
 
222
326
  void LRUCacheShard::SetStrictCapacityLimit(bool strict_capacity_limit) {
223
- MutexLock l(&mutex_);
327
+ DMutexLock l(mutex_);
224
328
  strict_capacity_limit_ = strict_capacity_limit;
225
329
  }
226
330
 
227
- Status LRUCacheShard::InsertItem(LRUHandle* e, Cache::Handle** handle,
228
- bool free_handle_on_fail) {
331
+ Status LRUCacheShard::Insert(const Slice& key, uint32_t hash, void* value,
332
+ size_t charge, Cache::DeleterFn deleter,
333
+ Cache::Handle** handle,
334
+ Cache::Priority /*priority*/) {
335
+ if (key.size() != kCacheKeySize) {
336
+ return Status::NotSupported("FastLRUCache only supports key size " +
337
+ std::to_string(kCacheKeySize) + "B");
338
+ }
339
+
340
+ LRUHandle tmp;
341
+ tmp.value = value;
342
+ tmp.deleter = deleter;
343
+ tmp.hash = hash;
344
+ tmp.CalcTotalCharge(charge, metadata_charge_policy_);
345
+ for (int i = 0; i < kCacheKeySize; i++) {
346
+ tmp.key_data[i] = key.data()[i];
347
+ }
348
+
229
349
  Status s = Status::OK();
230
- autovector<LRUHandle*> last_reference_list;
350
+ autovector<LRUHandle> last_reference_list;
231
351
  {
232
- MutexLock l(&mutex_);
352
+ DMutexLock l(mutex_);
233
353
 
234
354
  // Free the space following strict LRU policy until enough space
235
355
  // is freed or the lru list is empty.
236
- EvictFromLRU(e->total_charge, &last_reference_list);
237
-
238
- if ((usage_ + e->total_charge) > capacity_ &&
239
- (strict_capacity_limit_ || handle == nullptr)) {
240
- e->SetInCache(false);
356
+ EvictFromLRU(tmp.total_charge, &last_reference_list);
357
+ if ((usage_ + tmp.total_charge > capacity_ &&
358
+ (strict_capacity_limit_ || handle == nullptr)) ||
359
+ table_.GetOccupancy() == size_t{1} << table_.GetLengthBits()) {
360
+ // Originally, when strict_capacity_limit_ == false and handle != nullptr
361
+ // (i.e., the user wants to immediately get a reference to the new
362
+ // handle), the insertion would proceed even if the total charge already
363
+ // exceeds capacity. We can't do this now, because we can't physically
364
+ // insert a new handle when the table is at maximum occupancy.
365
+ // TODO(Guido) Some tests (at least two from cache_test, as well as the
366
+ // stress tests) currently assume the old behavior.
241
367
  if (handle == nullptr) {
242
368
  // Don't insert the entry but still return ok, as if the entry inserted
243
369
  // into cache and get evicted immediately.
244
- last_reference_list.push_back(e);
370
+ last_reference_list.push_back(tmp);
245
371
  } else {
246
- if (free_handle_on_fail) {
247
- delete[] reinterpret_cast<char*>(e);
248
- *handle = nullptr;
249
- }
250
372
  s = Status::Incomplete("Insert failed due to LRU cache being full.");
251
373
  }
252
374
  } else {
253
375
  // Insert into the cache. Note that the cache might get larger than its
254
376
  // capacity if not enough space was freed up.
255
- LRUHandle* old = table_.Insert(e);
256
- usage_ += e->total_charge;
377
+ LRUHandle* old;
378
+ LRUHandle* h = table_.Insert(&tmp, &old);
379
+ assert(h != nullptr); // Insertions should never fail.
380
+ usage_ += h->total_charge;
257
381
  if (old != nullptr) {
258
382
  s = Status::OkOverwritten();
259
- assert(old->InCache());
260
- old->SetInCache(false);
383
+ assert(old->IsVisible());
384
+ table_.Exclude(old);
261
385
  if (!old->HasRefs()) {
262
386
  // old is on LRU because it's in cache and its reference count is 0.
263
387
  LRU_Remove(old);
388
+ table_.Remove(old);
264
389
  assert(usage_ >= old->total_charge);
265
390
  usage_ -= old->total_charge;
266
- last_reference_list.push_back(old);
391
+ last_reference_list.push_back(*old);
267
392
  }
268
393
  }
269
394
  if (handle == nullptr) {
270
- LRU_Insert(e);
395
+ LRU_Insert(h);
271
396
  } else {
272
397
  // If caller already holds a ref, no need to take one here.
273
- if (!e->HasRefs()) {
274
- e->Ref();
398
+ if (!h->HasRefs()) {
399
+ h->Ref();
275
400
  }
276
- *handle = reinterpret_cast<Cache::Handle*>(e);
401
+ *handle = reinterpret_cast<Cache::Handle*>(h);
277
402
  }
278
403
  }
279
404
  }
280
405
 
281
406
  // Free the entries here outside of mutex for performance reasons.
282
- for (auto entry : last_reference_list) {
283
- entry->Free();
407
+ for (auto& h : last_reference_list) {
408
+ h.FreeData();
284
409
  }
285
410
 
286
411
  return s;
287
412
  }
288
413
 
289
414
  Cache::Handle* LRUCacheShard::Lookup(const Slice& key, uint32_t hash) {
290
- LRUHandle* e = nullptr;
415
+ LRUHandle* h = nullptr;
291
416
  {
292
- MutexLock l(&mutex_);
293
- e = table_.Lookup(key, hash);
294
- if (e != nullptr) {
295
- assert(e->InCache());
296
- if (!e->HasRefs()) {
417
+ DMutexLock l(mutex_);
418
+ h = table_.Lookup(key, hash);
419
+ if (h != nullptr) {
420
+ assert(h->IsVisible());
421
+ if (!h->HasRefs()) {
297
422
  // The entry is in LRU since it's in hash and has no external references
298
- LRU_Remove(e);
423
+ LRU_Remove(h);
299
424
  }
300
- e->Ref();
425
+ h->Ref();
301
426
  }
302
427
  }
303
- return reinterpret_cast<Cache::Handle*>(e);
428
+ return reinterpret_cast<Cache::Handle*>(h);
304
429
  }
305
430
 
306
431
  bool LRUCacheShard::Ref(Cache::Handle* h) {
307
432
  LRUHandle* e = reinterpret_cast<LRUHandle*>(h);
308
- MutexLock l(&mutex_);
433
+ DMutexLock l(mutex_);
309
434
  // To create another reference - entry must be already externally referenced.
310
435
  assert(e->HasRefs());
311
436
  e->Ref();
@@ -316,101 +441,74 @@ bool LRUCacheShard::Release(Cache::Handle* handle, bool erase_if_last_ref) {
316
441
  if (handle == nullptr) {
317
442
  return false;
318
443
  }
319
- LRUHandle* e = reinterpret_cast<LRUHandle*>(handle);
444
+ LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);
445
+ LRUHandle copy;
320
446
  bool last_reference = false;
321
447
  {
322
- MutexLock l(&mutex_);
323
- last_reference = e->Unref();
324
- if (last_reference && e->InCache()) {
448
+ DMutexLock l(mutex_);
449
+ last_reference = h->Unref();
450
+ if (last_reference && h->IsVisible()) {
325
451
  // The item is still in cache, and nobody else holds a reference to it.
326
452
  if (usage_ > capacity_ || erase_if_last_ref) {
327
453
  // The LRU list must be empty since the cache is full.
328
454
  assert(lru_.next == &lru_ || erase_if_last_ref);
329
455
  // Take this opportunity and remove the item.
330
- table_.Remove(e->key(), e->hash);
331
- e->SetInCache(false);
456
+ table_.Remove(h);
332
457
  } else {
333
458
  // Put the item back on the LRU list, and don't free it.
334
- LRU_Insert(e);
459
+ LRU_Insert(h);
335
460
  last_reference = false;
336
461
  }
337
462
  }
338
463
  // If it was the last reference, then decrement the cache usage.
339
464
  if (last_reference) {
340
- assert(usage_ >= e->total_charge);
341
- usage_ -= e->total_charge;
465
+ assert(usage_ >= h->total_charge);
466
+ usage_ -= h->total_charge;
467
+ copy = *h;
342
468
  }
343
469
  }
344
470
 
345
471
  // Free the entry here outside of mutex for performance reasons.
346
472
  if (last_reference) {
347
- e->Free();
473
+ copy.FreeData();
348
474
  }
349
475
  return last_reference;
350
476
  }
351
477
 
352
- Status LRUCacheShard::Insert(const Slice& key, uint32_t hash, void* value,
353
- size_t charge, Cache::DeleterFn deleter,
354
- Cache::Handle** handle,
355
- Cache::Priority /*priority*/) {
356
- if (key.size() != KEY_LENGTH) {
357
- return Status::NotSupported("FastLRUCache only supports key size " +
358
- std::to_string(KEY_LENGTH) + "B");
359
- }
360
-
361
- // Allocate the memory here outside of the mutex.
362
- // If the cache is full, we'll have to release it.
363
- // It shouldn't happen very often though.
364
- LRUHandle* e = reinterpret_cast<LRUHandle*>(
365
- new char[sizeof(LRUHandle) - 1 + key.size()]);
366
-
367
- e->value = value;
368
- e->flags = 0;
369
- e->deleter = deleter;
370
- e->key_length = key.size();
371
- e->hash = hash;
372
- e->refs = 0;
373
- e->next = e->prev = nullptr;
374
- e->SetInCache(true);
375
- e->CalcTotalCharge(charge, metadata_charge_policy_);
376
- memcpy(e->key_data, key.data(), key.size());
377
-
378
- return InsertItem(e, handle, /* free_handle_on_fail */ true);
379
- }
380
-
381
478
  void LRUCacheShard::Erase(const Slice& key, uint32_t hash) {
382
- LRUHandle* e;
479
+ LRUHandle copy;
383
480
  bool last_reference = false;
384
481
  {
385
- MutexLock l(&mutex_);
386
- e = table_.Remove(key, hash);
387
- if (e != nullptr) {
388
- assert(e->InCache());
389
- e->SetInCache(false);
390
- if (!e->HasRefs()) {
391
- // The entry is in LRU since it's in hash and has no external references
392
- LRU_Remove(e);
393
- assert(usage_ >= e->total_charge);
394
- usage_ -= e->total_charge;
482
+ DMutexLock l(mutex_);
483
+ LRUHandle* h = table_.Lookup(key, hash);
484
+ if (h != nullptr) {
485
+ table_.Exclude(h);
486
+ if (!h->HasRefs()) {
487
+ // The entry is in LRU since it's in cache and has no external
488
+ // references
489
+ LRU_Remove(h);
490
+ table_.Remove(h);
491
+ assert(usage_ >= h->total_charge);
492
+ usage_ -= h->total_charge;
395
493
  last_reference = true;
494
+ copy = *h;
396
495
  }
397
496
  }
398
497
  }
399
-
400
498
  // Free the entry here outside of mutex for performance reasons.
401
499
  // last_reference will only be true if e != nullptr.
402
500
  if (last_reference) {
403
- e->Free();
501
+ copy.FreeData();
404
502
  }
405
503
  }
406
504
 
407
505
  size_t LRUCacheShard::GetUsage() const {
408
- MutexLock l(&mutex_);
506
+ DMutexLock l(mutex_);
409
507
  return usage_;
410
508
  }
411
509
 
412
510
  size_t LRUCacheShard::GetPinnedUsage() const {
413
- MutexLock l(&mutex_);
511
+ DMutexLock l(mutex_);
414
512
  assert(usage_ >= lru_usage_);
415
513
  return usage_ - lru_usage_;
416
514
  }