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 |