GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 64.0% 73 / 0 / 114
Functions: 73.7% 14 / 0 / 19
Branches: 38.7% 48 / 0 / 124

storage/value_store/dram_value_store.h
Line Branch Exec Source
1 #pragma once
2
3 #include <cstring>
4 #include <memory>
5 #include <stdexcept>
6 #include <string>
7
8 #include <glog/logging.h>
9
10 #include "base/factory.h"
11 #include "memory/malloc.h"
12 #include "memory/memory_factory.h"
13 #include "storage/value_store/value_store.h"
14
15 class DramValueStore : public ValueStore {
16 public:
17 716 explicit DramValueStore(const BaseKVConfig& config) {
18 716 const auto& j = config.json_config_;
19
6/12
✓ Branch 1 taken 716 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 716 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 716 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 716 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 716 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 716 times.
716 if (!j.contains("value") || !j.at("value").contains("dram_allocator")) {
20 throw std::invalid_argument(
21 "DramValueStore requires value.dram_allocator");
22 }
23
1/2
✓ Branch 1 taken 716 times.
✗ Branch 2 not taken.
716 const auto& value = j.at("value");
24
4/6
✓ Branch 1 taken 716 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 716 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 714 times.
1432 if (!value.contains("path") ||
25
5/10
✓ Branch 1 taken 716 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 716 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 716 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 714 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
1432 value.at("path").get<std::string>().empty()) {
26
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 throw std::invalid_argument(
27 4 "DramValueStore requires non-empty value.path");
28 }
29
2/4
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 714 times.
✗ Branch 5 not taken.
714 const std::string path = value.at("path").get<std::string>();
30
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
714 const auto& dram = value.at("dram_allocator");
31
1/2
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
714 const std::string allocator_type = dram.value("type", "R2_SLAB");
32
2/4
✓ Branch 1 taken 714 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 714 times.
✗ Branch 5 not taken.
714 const uint64_t capacity_bytes = dram.at("capacity_bytes").get<uint64_t>();
33 using MF = base::
34 Factory<base::MallocApi, const std::string&, int64, const std::string&>;
35
2/4
✓ Branch 2 taken 714 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 714 times.
✗ Branch 6 not taken.
714 allocator_.reset(MF::NewInstance(
36 allocator_type, path, static_cast<int64>(capacity_bytes), "DRAM"));
37
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 714 times.
714 if (!allocator_) {
38 throw std::runtime_error("failed to create DramValueStore allocator");
39 }
40
1/2
✓ Branch 2 taken 714 times.
✗ Branch 3 not taken.
714 allocator_->Initialize();
41 714 recycler_ = std::make_unique<base::ThreadSafeDelayedRecycle>(
42
1/2
✓ Branch 2 taken 714 times.
✗ Branch 3 not taken.
714 allocator_.get(), kRecycleDelayUs);
43 720 }
44
45 256558 uint64_t Alloc(size_t size) override {
46 256558 char* data = allocator_->New(static_cast<int>(size));
47
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 256558 times.
256558 if (data == nullptr) {
48 return kValueHandleNone;
49 }
50 256558 return EncodeOffset(allocator_->GetMallocOffset(data));
51 }
52
53 256558 void Write(uint64_t handle, const void* data, size_t size) override {
54 256558 char* dst = Ptr(handle);
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 256558 times.
256558 if (dst == nullptr) {
56 return;
57 }
58 256558 std::memcpy(dst, data, size);
59 }
60
61 157950 uint64_t AllocAndWrite(const void* data, size_t size) override {
62 157950 const uint64_t handle = Alloc(size);
63
1/2
✓ Branch 0 taken 157950 times.
✗ Branch 1 not taken.
157950 if (handle != kValueHandleNone) {
64 157950 Write(handle, data, size);
65 }
66 157950 return handle;
67 }
68
69 size_t Read(uint64_t handle, void* out_buf, size_t buf_size) override {
70 char* src = Ptr(handle);
71 if (src == nullptr || out_buf == nullptr) {
72 return 0;
73 }
74 const size_t n = std::min(
75 buf_size,
76 static_cast<size_t>(allocator_->GetMallocSize(DecodeOffset(handle))));
77 std::memcpy(out_buf, src, n);
78 return n;
79 }
80
81 41788 void Free(uint64_t handle) override {
82 41788 char* data = Ptr(handle);
83
1/2
✓ Branch 0 taken 41788 times.
✗ Branch 1 not taken.
41788 if (data != nullptr) {
84 41788 allocator_->Free(data);
85 }
86 41788 }
87
88 73040 void Retire(uint64_t handle) override {
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73040 times.
73040 if (handle == kValueHandleNone) {
90 return;
91 }
92 73040 recycler_->Recycle(allocator_->GetMallocData(DecodeOffset(handle)));
93 }
94
95 188426 const char* DirectPtr(uint64_t handle) const override {
96 188426 return allocator_->GetMallocData(DecodeOffset(handle));
97 }
98
99 char* RDMABackingData() const override { return allocator_->BackingData(); }
100
101 size_t RDMABackingSize() const override {
102 return static_cast<size_t>(allocator_->BackingSize());
103 }
104
105 328822 size_t SlotCapacity(uint64_t handle) const override {
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 328822 times.
328822 if (handle == kValueHandleNone) {
107 return 0;
108 }
109 328822 return static_cast<size_t>(allocator_->GetMallocSize(DecodeOffset(handle)));
110 }
111
112 12 bool ReadFlatFixedRows(const uint64_t* handles,
113 size_t num_rows,
114 void* out_buf,
115 size_t row_bytes,
116 uint64_t* missing_rows) const override {
117
3/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
12 if (handles == nullptr || out_buf == nullptr || row_bytes == 0) {
118 return false;
119 }
120 12 uint64_t local_missing = 0;
121 12 char* dst = static_cast<char*>(out_buf);
122
2/10
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
12 DCHECK(IsPowerOfTwo(row_bytes))
123 << "DramValueStore flat row size must be a power of two";
124 12 const unsigned row_shift = Log2PowerOfTwo(row_bytes);
125
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 12 times.
34 for (size_t row = 0; row < num_rows; ++row) {
126 22 char* row_dst = dst + (row << row_shift);
127
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 20 times.
22 if (handles[row] == kValueHandleNone) {
128 2 std::memset(row_dst, 0, row_bytes);
129 2 ++local_missing;
130 2 continue;
131 }
132 20 const char* src = Ptr(handles[row]);
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (src == nullptr) {
134 return false;
135 }
136 20 std::memcpy(row_dst, src, row_bytes);
137 }
138
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (missing_rows != nullptr) {
139 12 *missing_rows = local_missing;
140 }
141 12 return true;
142 }
143
144 bool GetDirectFixedRows(const uint64_t* handles,
145 size_t num_rows,
146 size_t row_bytes,
147 DirectFixedRow* rows,
148 uint64_t* missing_rows) const override {
149 if (handles == nullptr || rows == nullptr || row_bytes == 0) {
150 return false;
151 }
152 uint64_t local_missing = 0;
153 for (size_t row = 0; row < num_rows; ++row) {
154 if (handles[row] == kValueHandleNone) {
155 rows[row] = DirectFixedRow{nullptr, row_bytes, true};
156 ++local_missing;
157 continue;
158 }
159 const char* src = Ptr(handles[row]);
160 if (src == nullptr) {
161 return false;
162 }
163 if (SlotCapacity(handles[row]) < row_bytes) {
164 return false;
165 }
166 rows[row] = DirectFixedRow{src, row_bytes, false};
167 }
168 if (missing_rows != nullptr) {
169 *missing_rows = local_missing;
170 }
171 return true;
172 }
173
174 std::string GetInfo() const override { return allocator_->GetInfo(); }
175 uint64_t TotalAllocCount() const { return allocator_->total_malloc(); }
176
177 private:
178 256558 static uint64_t EncodeOffset(int64 offset) {
179 256558 return static_cast<uint64_t>(offset) + 1;
180 }
181
182 888654 static int64 DecodeOffset(uint64_t handle) {
183 888654 return static_cast<int64>(handle - 1);
184 }
185
186 298366 char* Ptr(uint64_t handle) const {
187
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 298366 times.
298366 if (handle == kValueHandleNone) {
188 return nullptr;
189 }
190 298366 return allocator_->GetMallocData(DecodeOffset(handle));
191 }
192
193 12 static bool IsPowerOfTwo(size_t value) {
194
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 return value != 0 && (value & (value - 1)) == 0;
195 }
196
197 12 static unsigned Log2PowerOfTwo(size_t value) {
198 return static_cast<unsigned>(
199 12 __builtin_ctzll(static_cast<unsigned long long>(value)));
200 }
201
202 std::unique_ptr<base::MallocApi> allocator_;
203 std::unique_ptr<base::ThreadSafeDelayedRecycle> recycler_;
204 static constexpr int64 kRecycleDelayUs = 1000;
205 };
206
207 FACTORY_REGISTER(
208 ValueStore, DRAM_VALUE_STORE, DramValueStore, const BaseKVConfig&);
209