GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 9.3% 11 / 0 / 118
Functions: 45.5% 10 / 0 / 22
Branches: 0.0% 0 / 0 / 206

memory/shm_file.h
Line Branch Exec Source
1 #pragma once
2
3 #include <fcntl.h>
4 #include <sys/mman.h>
5 #include <atomic>
6 #include <deque>
7 #include <fstream>
8 #include <memory>
9 #include <queue>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "base/base.h"
15 #include "base/factory.h"
16 #include "base/json.h"
17 #include "base/string.h"
18 #include "storage/nvm/pet_kv/persistence.h"
19
20 namespace base {
21
22 class PMMmapRegisterCenter {
23 struct MetaBlock {
24 static const int MM_META_NR = 1000;
25
26 MetaBlock() {
27 mmMetaNr_ = 0;
28 magic_ = 0xdeadbeef;
29 for (int i = 0; i < MetaBlock::MM_META_NR; i++)
30 mmMeta_[i].magic_ = 0x66666666;
31 }
32 struct MmMeta {
33 MmMeta() {}
34 char file_name_[64];
35 uint64_t offset_;
36 uint64_t size_;
37 int magic_ = 0x66666666;
38 };
39 union {
40 struct {
41 int magic_ = 0xdeadbeef;
42 int mmMetaNr_ = 0;
43 MmMeta mmMeta_[MM_META_NR];
44 };
45 char _[2 * 4096 * 4096LL];
46 };
47 };
48
49 public:
50 static PMMmapRegisterCenter* GetInstance() {
51 static PMMmapRegisterCenter instance;
52 return &instance;
53 }
54 static constexpr int64_t align = 2 * 1024 * 1024LL;
55 // static constexpr int64_t align = 4 * 1024LL;
56
57 void* Register(const std::string& name, uint64_t size) {
58 std::lock_guard<std::mutex> _(mutex_);
59 auto* item = FindIfExists(name);
60 if (item == nullptr) {
61 return append_register(name, size);
62 } else if (item->size_ != size) {
63 // reinit MMAP
64 LOG(INFO) << base::SFormat(
65 "PM mmap {} registered size{} != existing{}",
66 name,
67 size,
68 item->size_);
69 ReInitialize();
70 return append_register(name, size);
71 } else {
72 LOG(INFO) << base::SFormat("PM mmap {} use existing map", name);
73
74 shmfile_mmap_addr_ =
75 std::max(shmfile_mmap_addr_.load(),
76 shmfile_mmap_data_addr_start_ + item->offset_ + item->size_);
77 return (void*)(shmfile_mmap_data_addr_start_ + item->offset_);
78 }
79 }
80
81 std::pair<uint64_t, uint64_t> ForRDMAMemoryRegion() const {
82 return std::make_pair(
83 shmfile_mmap_data_addr_start_,
84 shmfile_mmap_addr_.load() - shmfile_mmap_data_addr_start_);
85 }
86 // this function is non-reentrant
87 void ReInitialize() {
88 LOG(WARNING) << "reinitialize the whole PM space";
89 static std::atomic_int flag{false};
90 if (!flag.fetch_or(true)) {
91 LOG(WARNING) << "memset whole meta block";
92 memset((void*)metaBlock_, 0, sizeof(MetaBlock));
93 new (metaBlock_) MetaBlock();
94 } else {
95 LOG(FATAL) << "ReInitialize is non-reentrant";
96 }
97 CHECK(Valid());
98 }
99
100 enum class Backend {
101 kAnonymousDram,
102 kDevDax,
103 };
104
105 struct Config {
106 Backend backend = Backend::kAnonymousDram;
107 int numa_id = 0;
108 };
109
110 1992 static Config& GetConfig() {
111 static Config config;
112 1992 return config;
113 }
114
115 static Backend BackendFromUseDram(bool use_dram) {
116 return use_dram ? Backend::kAnonymousDram : Backend::kDevDax;
117 }
118
119 private:
120 bool Valid() const {
121 if (metaBlock_->magic_ != 0xdeadbeef)
122 return false;
123 for (int i = 0; i < MetaBlock::MM_META_NR; i++)
124 if (metaBlock_->mmMeta_[i].magic_ != 0x66666666)
125 return false;
126 return true;
127 }
128
129 void* append_register(const std::string& name, uint64_t size) {
130 CHECK_NE(size, 0);
131 // LOG(INFO) << fmt::format("PM mmap register {}, size={}", name, size);
132 auto new_size = (size + align - 1) / align * align;
133 auto ret = shmfile_mmap_addr_.fetch_add(new_size);
134 LOG(ERROR) << "xmh "
135 << (shmfile_mmap_addr_ - shmfile_mmap_addr_start_) /
136 (1024 * 1024 * 1024LL);
137 CHECK_GE((uint64_t)ret, shmfile_mmap_data_addr_start_);
138 CHECK_LT((uint64_t)ret + size,
139 shmfile_mmap_data_addr_start_ + dax_mm_size_);
140 memset((void*)ret, 0, size);
141
142 // persist meta data
143 auto& item = metaBlock_->mmMeta_[metaBlock_->mmMetaNr_];
144 std::strncpy(item.file_name_, name.c_str(), 50);
145 item.offset_ = ret - shmfile_mmap_data_addr_start_;
146 item.size_ = size;
147 metaBlock_->mmMetaNr_++;
148 CHECK_LE(metaBlock_->mmMetaNr_, MetaBlock::MM_META_NR);
149 base::clflushopt_range(metaBlock_, sizeof(MetaBlock));
150 return (char*)ret;
151 }
152
153 MetaBlock::MmMeta* FindIfExists(const std::string& name) {
154 for (int i = 0; i < metaBlock_->mmMetaNr_; i++) {
155 auto& item = metaBlock_->mmMeta_[i];
156 if (std::strncmp(item.file_name_, name.c_str(), 64) == 0) {
157 CHECK_EQ(item.magic_, 0x66666666);
158 return &item;
159 }
160 }
161 return nullptr;
162 }
163
164 PMMmapRegisterCenter() {
165 CHECK_NE(GetConfig().numa_id, -1);
166
167 char* data;
168 if (GetConfig().backend == Backend::kAnonymousDram) {
169 // filename_ = folly::sformat("/dev/shm/big_file{}", GetConfig().numa_id);
170 fd_ = 0;
171 LOG(WARNING) << "use dram mmap for PMMmapRegisterCenter";
172 data = reinterpret_cast<char*>(mmap(
173 nullptr,
174 dax_mm_size_,
175 PROT_READ | PROT_WRITE,
176 MAP_PRIVATE | MAP_POPULATE | MAP_ANONYMOUS,
177 -1,
178 0));
179 metaBlock_ = (MetaBlock*)data;
180 CHECK_NE(data, MAP_FAILED) << "map failed";
181 mlock(data, dax_mm_size_);
182 ReInitialize();
183 } else {
184 filename_ = base::SFormat("/dev/dax{}.0", GetConfig().numa_id);
185 fd_ = open(filename_.c_str(), 0666);
186 if (fd_ < 0) {
187 LOG(FATAL) << "Failed to open file " << filename_ << ": "
188 << strerror(errno);
189 }
190 data = reinterpret_cast<char*>(mmap(
191 nullptr,
192 dax_mm_size_,
193 PROT_READ | PROT_WRITE,
194 MAP_SHARED | MAP_POPULATE,
195 fd_,
196 0));
197 }
198
199 LOG(INFO) << "mmap " << filename_ << " ; size = " << dax_mm_size_;
200 CHECK_NE(data, MAP_FAILED) << "map failed";
201 // read meta file
202 metaBlock_ = (MetaBlock*)data;
203 if (!Valid()) {
204 // first use this device
205 LOG(ERROR)
206 << "metadata of dax is not valid, maybe you first use this device;"
207 << " Please use pm_command to reinit";
208 // ReInitialize();
209 }
210
211 *(uint64_t*)&shmfile_mmap_addr_start_ = (uint64_t)data;
212 *(uint64_t*)&shmfile_mmap_data_addr_start_ =
213 (uint64_t)data + sizeof(MetaBlock);
214 shmfile_mmap_addr_.store(shmfile_mmap_data_addr_start_);
215 }
216 ~PMMmapRegisterCenter() {
217 if (fd_ >= 0) {
218 LOG(INFO) << "ummap shm file: " << filename_ << ", size: " << dax_mm_size_
219 << ", fd: " << fd_;
220 munmap((void*)shmfile_mmap_addr_start_, dax_mm_size_);
221 close(fd_);
222 fd_ = -1;
223 }
224 }
225
226 std::string filename_;
227 // const int64_t dax_mm_size_ = 300 * 1024 * 1024 * 1024LL;
228 const int64_t dax_mm_size_ = 140 * 1024 * 1024 * 1024LL;
229 // const int64_t dax_mm_size_ = 500 * 1024 * 1024 * 1024LL;
230 // const int64_t dax_mm_size_ = 75 * 1024 * 1024 * 1024LL;
231 int fd_;
232 const uint64_t shmfile_mmap_addr_start_ = 0;
233 const uint64_t shmfile_mmap_data_addr_start_ = 0;
234 // const uint64_t shmfile_mmap_addr_start_ = 0xeff4200000ull;
235 std::atomic<uint64_t> shmfile_mmap_addr_;
236
237 std::mutex mutex_;
238
239 MetaBlock* metaBlock_ = nullptr;
240 };
241
242 class ShmFile {
243 public:
244 736 ShmFile() : data_(NULL), size_(0) {}
245 736 virtual ~ShmFile() = default;
246
247 static std::unique_ptr<ShmFile> New(const json& config);
248 static json ConfigForMedium(
249 const std::string& medium, const std::string& filename, int64 size);
250
251 virtual bool Initialize(const json& config) = 0;
252 virtual void Clear() = 0;
253 656442 char* Data() const { return data_; }
254 4 int64 Size() const { return size_; }
255 2 const std::string& filename() const { return filename_; }
256
257 protected:
258 static std::string ConfigFilename(const json& config);
259 static int64 ConfigSize(const json& config);
260
261 std::string filename_;
262 char* data_;
263 int64 size_;
264
265 private:
266 DISALLOW_COPY_AND_ASSIGN(ShmFile);
267 };
268
269 class FsDaxShmFile : public ShmFile {
270 public:
271 6 explicit FsDaxShmFile(const json& config) : fd_(-1) {}
272 12 ~FsDaxShmFile() override { Clear(); }
273 bool Initialize(const json& config) override;
274 void Clear() override;
275
276 private:
277 int fd_;
278 DISALLOW_COPY_AND_ASSIGN(FsDaxShmFile);
279 };
280
281 class AnonyDramShmFile : public ShmFile {
282 public:
283 730 explicit AnonyDramShmFile(const json& config) {}
284 1460 ~AnonyDramShmFile() override { Clear(); }
285 bool Initialize(const json& config) override;
286 void Clear() override;
287
288 private:
289 DISALLOW_COPY_AND_ASSIGN(AnonyDramShmFile);
290 };
291
292 class DevDaxShmFile : public ShmFile {
293 public:
294 explicit DevDaxShmFile(const json& config) {}
295 ~DevDaxShmFile() override { Clear(); }
296 bool Initialize(const json& config) override;
297 void Clear() override;
298
299 private:
300 DISALLOW_COPY_AND_ASSIGN(DevDaxShmFile);
301 };
302
303 } // namespace base
304