GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 75.8% 94 / 0 / 124
Functions: 80.0% 12 / 0 / 15
Branches: 44.4% 79 / 0 / 178

storage/external/fasterkv/fasterkv_engine.cc
Line Branch Exec Source
1 #include <algorithm>
2 #include <cstring>
3 #include <stdexcept>
4 #include <string>
5 #include <string_view>
6 #include <vector>
7
8 #include "base/factory.h"
9 #include "storage/external/fasterkv/fasterkv_backend.h"
10 #include "storage/kv_engine/base_kv.h"
11
12 namespace {
13
14 22 size_t ConfigValueSize(const BaseKVConfig& config) {
15 22 const auto& j = config.json_config_;
16
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 if (j.contains("value_size")) {
17 22 return j.at("value_size").get<size_t>();
18 }
19 if (j.contains("value")) {
20 return j.at("value").value("default_value_size_hint", 0);
21 }
22 return 0;
23 }
24
25 recstore::storage::fasterkv::FasterKVBackendOptions
26 22 ConfigBackendOptions(const BaseKVConfig& config) {
27 22 recstore::storage::fasterkv::FasterKVBackendOptions options;
28 22 const auto& j = config.json_config_;
29
3/4
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 4 times.
22 if (!j.contains("fasterkv")) {
30 18 return options;
31 }
32
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 const auto& fkv = j.at("fasterkv");
33
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 const std::string storage = fkv.value("storage", "memory");
34
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (storage == "memory") {
35 options.storage = recstore::storage::fasterkv::FasterKVStorage::kMemory;
36
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 } else if (storage == "ssd") {
37 4 options.storage = recstore::storage::fasterkv::FasterKVStorage::kSsd;
38 } else {
39 throw std::invalid_argument(
40 "KVEngineFasterKV fasterkv.storage must be memory or ssd");
41 }
42
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
4 if (fkv.contains("log_path")) {
43
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 options.log_path = fkv.at("log_path").get<std::string>();
44 4 } else if (options.storage ==
45 2 recstore::storage::fasterkv::FasterKVStorage::kSsd &&
46
8/18
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 2 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
2 j.contains("path") && !j.at("path").get<std::string>().empty()) {
47 options.log_path = j.at("path").get<std::string>() + "/fasterkv-log";
48 }
49
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
4 if (fkv.contains("hlog_memory_bytes")) {
50
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 options.hlog_memory_bytes = fkv.at("hlog_memory_bytes").get<uint64_t>();
51 }
52
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
4 if (fkv.contains("mutable_fraction")) {
53
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 options.mutable_fraction = fkv.at("mutable_fraction").get<double>();
54 }
55
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 if (fkv.contains("read_cache_bytes")) {
56 options.read_cache_bytes = fkv.at("read_cache_bytes").get<uint64_t>();
57 }
58
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (options.mutable_fraction < 0.0 || options.mutable_fraction > 1.0) {
59 throw std::invalid_argument(
60 "KVEngineFasterKV fasterkv.mutable_fraction must be in [0, 1]");
61 }
62 4 return options;
63 4 }
64
65 12 void ValidateFloatAligned(size_t value_size, const char* operation) {
66
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 if (value_size == 0 || value_size % sizeof(float) != 0) {
67 throw std::invalid_argument(
68 std::string(operation) +
69 " requires a non-zero float-aligned value_size");
70 }
71 12 }
72
73 14 std::vector<long long> ConvertKeys(base::ConstArray<uint64_t> keys) {
74
1/2
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
14 std::vector<long long> out(keys.Size());
75
2/2
✓ Branch 1 taken 244 times.
✓ Branch 2 taken 14 times.
258 for (int i = 0; i < keys.Size(); ++i) {
76 244 out[i] = static_cast<long long>(keys[i]);
77 }
78 14 return out;
79 }
80
81 } // namespace
82
83 class KVEngineFasterKV : public BaseKV {
84 public:
85 22 explicit KVEngineFasterKV(const BaseKVConfig& config)
86 22 : BaseKV(config),
87 44 value_size_(ConfigValueSize(config)),
88
4/6
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✓ Branch 8 taken 2 times.
22 backend_(config.json_config_.at("capacity").get<uint64_t>(),
89 value_size_,
90
2/4
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 22 times.
✗ Branch 6 not taken.
46 ConfigBackendOptions(config)) {
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (value_size_ == 0) {
92 throw std::invalid_argument("KVEngineFasterKV requires value_size");
93 }
94 22 }
95
96 318 void Get(const uint64_t key, std::string& value, unsigned tid) override {
97 (void)tid;
98 318 const long long hps_key = static_cast<long long>(key);
99
1/2
✓ Branch 1 taken 318 times.
✗ Branch 2 not taken.
318 value.assign(value_size_, '\0');
100 318 bool missed = false;
101
1/2
✓ Branch 3 taken 318 times.
✗ Branch 4 not taken.
318 backend_.Fetch(1, &hps_key, value.data(), [&](size_t) { missed = true; });
102
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 310 times.
318 if (missed) {
103 8 value.clear();
104 }
105 318 }
106
107 bool Exists(const uint64_t key, unsigned tid) override {
108 (void)tid;
109 const long long hps_key = static_cast<long long>(key);
110 std::string value(value_size_, '\0');
111 bool missed = false;
112 backend_.Fetch(1, &hps_key, value.data(), [&](size_t) { missed = true; });
113 return !missed;
114 }
115
116 236 void Put(const uint64_t key,
117 const std::string_view& value,
118 unsigned tid) override {
119 (void)tid;
120
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 236 times.
236 if (value.size() != value_size_) {
121 throw std::invalid_argument("KVEngineFasterKV requires fixed-size Put");
122 }
123 236 const long long hps_key = static_cast<long long>(key);
124
1/2
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
236 backend_.Insert(1, &hps_key, value.data());
125 236 }
126
127 4 void BatchPut(base::ConstArray<uint64_t> keys,
128 std::vector<base::ConstArray<float>>* values,
129 unsigned tid) override {
130 (void)tid;
131
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 ValidateFloatAligned(value_size_, "KVEngineFasterKV::BatchPut");
132
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
4 if (values == nullptr || keys.Size() != static_cast<int>(values->size())) {
133 throw std::invalid_argument("KVEngineFasterKV::BatchPut size mismatch");
134 }
135
136 4 const int floats_per_row = static_cast<int>(value_size_ / sizeof(float));
137
1/2
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
4 std::vector<char> flat(static_cast<size_t>(keys.Size()) * value_size_);
138
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
16 for (int i = 0; i < keys.Size(); ++i) {
139 12 const auto& row = (*values)[i];
140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if (row.Size() != floats_per_row) {
141 throw std::invalid_argument(
142 "KVEngineFasterKV::BatchPut row size mismatch");
143 }
144 12 std::memcpy(flat.data() + static_cast<size_t>(i) * value_size_,
145 12 row.Data(),
146 value_size_);
147 }
148
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 std::vector<long long> hps_keys = ConvertKeys(keys);
149
1/2
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 backend_.Insert(hps_keys.size(), hps_keys.data(), flat.data());
150 4 }
151
152 8 void BatchGet(base::ConstArray<uint64_t> keys,
153 std::vector<base::ConstArray<float>>* values,
154 unsigned tid) override {
155 (void)tid;
156
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ValidateFloatAligned(value_size_, "KVEngineFasterKV::BatchGet");
157
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 values->resize(keys.Size());
158
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 thread_local std::vector<std::vector<float>> buffers;
159
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 buffers.assign(keys.Size(), {});
160
161
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 std::vector<long long> hps_keys = ConvertKeys(keys);
162
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 std::vector<char> flat(static_cast<size_t>(keys.Size()) * value_size_);
163
1/2
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
8 std::vector<uint8_t> misses(keys.Size(), 0);
164
1/2
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
16 backend_.Fetch(
165 8 hps_keys.size(), hps_keys.data(), flat.data(), [&](size_t index) {
166 misses[index] = 1;
167 });
168
169 8 const int floats_per_row = static_cast<int>(value_size_ / sizeof(float));
170
2/2
✓ Branch 1 taken 132 times.
✓ Branch 2 taken 8 times.
140 for (int i = 0; i < keys.Size(); ++i) {
171
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 132 times.
132 if (misses[i]) {
172 (*values)[i] = base::ConstArray<float>();
173 continue;
174 }
175
1/2
✓ Branch 2 taken 132 times.
✗ Branch 3 not taken.
132 buffers[i].resize(floats_per_row);
176 132 std::memcpy(buffers[i].data(),
177 132 flat.data() + static_cast<size_t>(i) * value_size_,
178 value_size_);
179 132 (*values)[i] =
180 264 base::ConstArray<float>(buffers[i].data(), buffers[i].size());
181 }
182 8 }
183
184 2 void BulkLoad(base::ConstArray<uint64_t> keys, const void* value) override {
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (value == nullptr) {
186 throw std::invalid_argument("KVEngineFasterKV::BulkLoad value is null");
187 }
188
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 std::vector<long long> hps_keys = ConvertKeys(keys);
189
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 backend_.Insert(
190 2 hps_keys.size(), hps_keys.data(), reinterpret_cast<const char*>(value));
191 2 }
192
193 private:
194 size_t value_size_;
195 recstore::storage::fasterkv::FasterKVBackend backend_;
196 };
197
198 10 extern "C" void RecStoreForceLinkFasterKVEngine() {}
199
200 FACTORY_REGISTER(
201 BaseKV, KVEngineFasterKV, KVEngineFasterKV, const BaseKVConfig&);
202