@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.
- package/binding.cc +320 -324
- package/chained-batch.js +6 -1
- package/deps/rocksdb/rocksdb/CMakeLists.txt +8 -3
- package/deps/rocksdb/rocksdb/Makefile +10 -4
- package/deps/rocksdb/rocksdb/TARGETS +6 -4
- package/deps/rocksdb/rocksdb/cache/cache_bench_tool.cc +9 -0
- package/deps/rocksdb/rocksdb/cache/cache_test.cc +14 -0
- package/deps/rocksdb/rocksdb/cache/clock_cache.cc +8 -8
- package/deps/rocksdb/rocksdb/cache/fast_lru_cache.cc +272 -174
- package/deps/rocksdb/rocksdb/cache/fast_lru_cache.h +201 -57
- package/deps/rocksdb/rocksdb/cache/lru_cache.cc +19 -19
- package/deps/rocksdb/rocksdb/cache/lru_cache.h +2 -1
- package/deps/rocksdb/rocksdb/db/blob/blob_source.cc +170 -0
- package/deps/rocksdb/rocksdb/db/blob/blob_source.h +95 -0
- package/deps/rocksdb/rocksdb/db/blob/blob_source_test.cc +298 -0
- package/deps/rocksdb/rocksdb/db/blob/db_blob_basic_test.cc +172 -0
- package/deps/rocksdb/rocksdb/db/column_family.cc +8 -3
- package/deps/rocksdb/rocksdb/db/column_family.h +6 -3
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +10 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job_test.cc +6 -6
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_level.cc +22 -2
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +38 -0
- package/deps/rocksdb/rocksdb/db/db_basic_test.cc +17 -5
- package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +4 -7
- package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +74 -71
- package/deps/rocksdb/rocksdb/db/db_compaction_test.cc +70 -1
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +13 -12
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +36 -0
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +11 -4
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +1 -1
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +139 -91
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +48 -14
- package/deps/rocksdb/rocksdb/db/db_kv_checksum_test.cc +90 -55
- package/deps/rocksdb/rocksdb/db/db_rate_limiter_test.cc +9 -4
- package/deps/rocksdb/rocksdb/db/db_test.cc +3 -1
- package/deps/rocksdb/rocksdb/db/db_wal_test.cc +12 -7
- package/deps/rocksdb/rocksdb/db/db_write_test.cc +35 -0
- package/deps/rocksdb/rocksdb/db/dbformat.cc +3 -1
- package/deps/rocksdb/rocksdb/db/dbformat.h +5 -3
- package/deps/rocksdb/rocksdb/db/flush_job_test.cc +1 -1
- package/deps/rocksdb/rocksdb/db/memtable.cc +1 -0
- package/deps/rocksdb/rocksdb/db/memtable_list_test.cc +4 -2
- package/deps/rocksdb/rocksdb/db/repair.cc +1 -1
- package/deps/rocksdb/rocksdb/db/version_builder.cc +43 -1
- package/deps/rocksdb/rocksdb/db/version_edit.cc +13 -5
- package/deps/rocksdb/rocksdb/db/version_edit.h +22 -1
- package/deps/rocksdb/rocksdb/db/version_edit_handler.cc +4 -5
- package/deps/rocksdb/rocksdb/db/version_set.cc +109 -41
- package/deps/rocksdb/rocksdb/db/version_set.h +36 -3
- package/deps/rocksdb/rocksdb/db/version_set_sync_and_async.h +1 -4
- package/deps/rocksdb/rocksdb/db/version_set_test.cc +10 -10
- package/deps/rocksdb/rocksdb/db/version_util.h +1 -1
- package/deps/rocksdb/rocksdb/db/wal_manager_test.cc +1 -1
- package/deps/rocksdb/rocksdb/db/write_batch.cc +34 -10
- package/deps/rocksdb/rocksdb/db/write_batch_internal.h +2 -0
- package/deps/rocksdb/rocksdb/db/write_callback_test.cc +4 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/batched_ops_stress.cc +2 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/cf_consistency_stress.cc +4 -1
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +1 -1
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +7 -5
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +5 -10
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +0 -7
- package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +2 -0
- package/deps/rocksdb/rocksdb/file/random_access_file_reader.cc +24 -3
- package/deps/rocksdb/rocksdb/file/writable_file_writer.cc +8 -0
- package/deps/rocksdb/rocksdb/file/writable_file_writer.h +10 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +5 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/cache.h +4 -4
- package/deps/rocksdb/rocksdb/include/rocksdb/options.h +9 -5
- package/deps/rocksdb/rocksdb/include/rocksdb/statistics.h +5 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/types.h +1 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/write_batch_with_index.h +1 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/version.h +1 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/write_batch.h +0 -3
- package/deps/rocksdb/rocksdb/microbench/ribbon_bench.cc +8 -6
- package/deps/rocksdb/rocksdb/monitoring/statistics.cc +3 -1
- package/deps/rocksdb/rocksdb/options/options_helper.cc +4 -2
- package/deps/rocksdb/rocksdb/options/options_test.cc +1 -11
- package/deps/rocksdb/rocksdb/port/port_posix.h +7 -0
- package/deps/rocksdb/rocksdb/port/win/port_win.h +11 -3
- package/deps/rocksdb/rocksdb/src.mk +6 -2
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +4 -33
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.h +3 -3
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +38 -118
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +6 -8
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +10 -13
- package/deps/rocksdb/rocksdb/table/block_based/block_like_traits.h +4 -9
- package/deps/rocksdb/rocksdb/table/block_based/block_type.h +0 -1
- package/deps/rocksdb/rocksdb/table/block_based/filter_block.h +10 -28
- package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.cc +2 -3
- package/deps/rocksdb/rocksdb/table/block_based/filter_policy.cc +0 -91
- package/deps/rocksdb/rocksdb/table/block_based/filter_policy_internal.h +2 -30
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.cc +6 -27
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.h +11 -13
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block_test.cc +28 -40
- package/deps/rocksdb/rocksdb/table/block_based/mock_block_based_table.h +0 -1
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +22 -43
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.h +11 -22
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block_test.cc +24 -25
- package/deps/rocksdb/rocksdb/table/block_fetcher.cc +0 -1
- package/deps/rocksdb/rocksdb/table/get_context.h +0 -1
- package/deps/rocksdb/rocksdb/table/table_test.cc +3 -18
- package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +3 -16
- package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +3 -3
- package/deps/rocksdb/rocksdb/tools/ldb_cmd_test.cc +1 -1
- package/deps/rocksdb/rocksdb/util/bloom_test.cc +0 -201
- package/deps/rocksdb/rocksdb/util/distributed_mutex.h +48 -0
- package/deps/rocksdb/rocksdb/util/filter_bench.cc +5 -11
- package/deps/rocksdb/rocksdb/utilities/backup/backup_engine.cc +3 -0
- package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.cc +7 -21
- package/deps/rocksdb/rocksdb/utilities/cache_dump_load_impl.h +1 -1
- package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_test.cc +45 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction_db.h +21 -14
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.cc +10 -1
- package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn.cc +3 -1
- package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn_db.cc +9 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn.cc +3 -2
- package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn_db.cc +3 -1
- package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index.cc +5 -4
- package/deps/rocksdb/rocksdb.gyp +1 -1
- package/index.js +36 -14
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.node +0 -0
- package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block.cc +0 -358
- package/deps/rocksdb/rocksdb/table/block_based/block_based_filter_block.h +0 -127
- 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/
|
|
20
|
-
|
|
21
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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->
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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_(
|
|
192
|
+
: capacity_(capacity),
|
|
80
193
|
strict_capacity_limit_(strict_capacity_limit),
|
|
81
194
|
table_(
|
|
82
|
-
|
|
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
|
|
207
|
+
autovector<LRUHandle> last_reference_list;
|
|
95
208
|
{
|
|
96
|
-
|
|
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->
|
|
213
|
+
assert(old->IsVisible() && !old->HasRefs());
|
|
101
214
|
LRU_Remove(old);
|
|
102
|
-
table_.Remove(old
|
|
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
|
|
112
|
-
|
|
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
|
-
|
|
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*
|
|
152
|
-
assert(
|
|
153
|
-
assert(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
assert(lru_usage_ >=
|
|
158
|
-
lru_usage_ -=
|
|
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*
|
|
162
|
-
assert(
|
|
163
|
-
assert(
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
lru_usage_ +=
|
|
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
|
|
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->
|
|
289
|
+
assert(old->IsVisible() && !old->HasRefs());
|
|
178
290
|
LRU_Remove(old);
|
|
179
|
-
table_.Remove(old
|
|
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
|
-
|
|
298
|
+
uint8_t LRUCacheShard::CalcHashBits(
|
|
188
299
|
size_t capacity, size_t estimated_value_size,
|
|
189
300
|
CacheMetadataChargePolicy metadata_charge_policy) {
|
|
190
|
-
LRUHandle
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
312
|
+
assert(false); // Not supported. TODO(Guido) Support it?
|
|
313
|
+
autovector<LRUHandle> last_reference_list;
|
|
210
314
|
{
|
|
211
|
-
|
|
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
|
|
218
|
-
|
|
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
|
-
|
|
327
|
+
DMutexLock l(mutex_);
|
|
224
328
|
strict_capacity_limit_ = strict_capacity_limit;
|
|
225
329
|
}
|
|
226
330
|
|
|
227
|
-
Status LRUCacheShard::
|
|
228
|
-
|
|
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
|
|
350
|
+
autovector<LRUHandle> last_reference_list;
|
|
231
351
|
{
|
|
232
|
-
|
|
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(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
(
|
|
240
|
-
|
|
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(
|
|
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
|
|
256
|
-
|
|
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->
|
|
260
|
-
old
|
|
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(
|
|
395
|
+
LRU_Insert(h);
|
|
271
396
|
} else {
|
|
272
397
|
// If caller already holds a ref, no need to take one here.
|
|
273
|
-
if (!
|
|
274
|
-
|
|
398
|
+
if (!h->HasRefs()) {
|
|
399
|
+
h->Ref();
|
|
275
400
|
}
|
|
276
|
-
*handle = reinterpret_cast<Cache::Handle*>(
|
|
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
|
|
283
|
-
|
|
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*
|
|
415
|
+
LRUHandle* h = nullptr;
|
|
291
416
|
{
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (
|
|
295
|
-
assert(
|
|
296
|
-
if (!
|
|
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(
|
|
423
|
+
LRU_Remove(h);
|
|
299
424
|
}
|
|
300
|
-
|
|
425
|
+
h->Ref();
|
|
301
426
|
}
|
|
302
427
|
}
|
|
303
|
-
return reinterpret_cast<Cache::Handle*>(
|
|
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
|
-
|
|
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*
|
|
444
|
+
LRUHandle* h = reinterpret_cast<LRUHandle*>(handle);
|
|
445
|
+
LRUHandle copy;
|
|
320
446
|
bool last_reference = false;
|
|
321
447
|
{
|
|
322
|
-
|
|
323
|
-
last_reference =
|
|
324
|
-
if (last_reference &&
|
|
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(
|
|
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(
|
|
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_ >=
|
|
341
|
-
usage_ -=
|
|
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
|
-
|
|
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
|
|
479
|
+
LRUHandle copy;
|
|
383
480
|
bool last_reference = false;
|
|
384
481
|
{
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if (
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
//
|
|
392
|
-
LRU_Remove(
|
|
393
|
-
|
|
394
|
-
usage_
|
|
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
|
-
|
|
501
|
+
copy.FreeData();
|
|
404
502
|
}
|
|
405
503
|
}
|
|
406
504
|
|
|
407
505
|
size_t LRUCacheShard::GetUsage() const {
|
|
408
|
-
|
|
506
|
+
DMutexLock l(mutex_);
|
|
409
507
|
return usage_;
|
|
410
508
|
}
|
|
411
509
|
|
|
412
510
|
size_t LRUCacheShard::GetPinnedUsage() const {
|
|
413
|
-
|
|
511
|
+
DMutexLock l(mutex_);
|
|
414
512
|
assert(usage_ >= lru_usage_);
|
|
415
513
|
return usage_ - lru_usage_;
|
|
416
514
|
}
|