Skip to content

Commit 442b6f4

Browse files
guptaskvinser52
authored andcommitted
Add support for shm opts serialization
After introducing file segment type, nameToKey_ does not provide enough information to recover/remove segments on restart. This commit fixes that by replacing nameToKey_ with nameToOpts_. Previously, the Key from nameToKey_ map was only used in a single DCHECK().
1 parent aed38aa commit 442b6f4

File tree

7 files changed

+106
-43
lines changed

7 files changed

+106
-43
lines changed

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3456,7 +3456,7 @@ bool CacheAllocator<CacheTrait>::stopReaper(std::chrono::seconds timeout) {
34563456

34573457
template <typename CacheTrait>
34583458
bool CacheAllocator<CacheTrait>::cleanupStrayShmSegments(
3459-
const std::string& cacheDir, bool posix /*TODO(SHM_FILE): const std::vector<CacheMemoryTierConfig>& config */) {
3459+
const std::string& cacheDir, bool posix /*TODO(SHM_FILE): const std::vector<CacheMemoryTierConfig>& config */) {
34603460
if (util::getStatIfExists(cacheDir, nullptr) && util::isDir(cacheDir)) {
34613461
try {
34623462
// cache dir exists. clean up only if there are no other processes

cachelib/shm/PosixShmSegment.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ class PosixShmSegment : public ShmBase {
9292
// @return true if the segment existed. false otherwise
9393
static bool removeByName(const std::string& name);
9494

95+
// returns the key type corresponding to the given name.
96+
static std::string createKeyForName(const std::string& name) noexcept;
97+
9598
private:
9699
static int createNewSegment(const std::string& name);
97100
static int getExisting(const std::string& name, const ShmSegmentOpts& opts);
98101

99-
// returns the key type corresponding to the given name.
100-
static std::string createKeyForName(const std::string& name) noexcept;
101-
102102
// resize the segment
103103
// @param size the new size
104104
// @return none

cachelib/shm/ShmManager.cpp

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include <fstream>
2424
#include <vector>
25+
#include <string>
2526

2627
#pragma GCC diagnostic push
2728
#pragma GCC diagnostic ignored "-Wconversion"
@@ -98,7 +99,7 @@ ShmManager::ShmManager(const std::string& dir, bool usePosix)
9899
// if file exists, init from it if needed.
99100
const bool reattach = dropSegments ? false : initFromFile();
100101
if (!reattach) {
101-
DCHECK(nameToKey_.empty());
102+
DCHECK(nameToOpts_.empty());
102103
}
103104
// Lock file for exclusive access
104105
lockMetadataFile(metaFile);
@@ -109,7 +110,7 @@ ShmManager::ShmManager(const std::string& dir, bool usePosix)
109110
}
110111

111112
bool ShmManager::initFromFile() {
112-
// restore the nameToKey_ map and destroy the contents of the file.
113+
// restore the nameToOpts_ map and destroy the contents of the file.
113114
const std::string fileName = pathName(controlDir_, kMetaDataFile);
114115
std::ifstream f(fileName);
115116
SCOPE_EXIT { f.close(); };
@@ -139,9 +140,16 @@ bool ShmManager::initFromFile() {
139140
}
140141

141142
for (const auto& kv : *object.nameToKeyMap_ref()) {
142-
nameToKey_.insert({kv.first, kv.second});
143+
if (kv.second.path == "") {
144+
PosixSysVSegmentOpts type;
145+
type.usePosix = kv.second.usePosix;
146+
nameToOpts_.insert({kv.first, type});
147+
} else {
148+
FileShmSegmentOpts type;
149+
type.path = kv.second.path;
150+
nameToOpts_.insert({kv.first, type});
151+
}
143152
}
144-
145153
return true;
146154
}
147155

@@ -157,17 +165,28 @@ typename ShmManager::ShutDownRes ShmManager::writeActiveSegmentsToFile() {
157165
return ShutDownRes::kFileDeleted;
158166
}
159167

160-
// write the shmtype, nameToKey_ map to the file.
168+
// write the shmtype, nameToOpts_ map to the file.
161169
DCHECK(metadataStream_);
162170

163171
serialization::ShmManagerObject object;
164172

165173
object.shmVal_ref() = usePosix_ ? static_cast<int8_t>(ShmVal::SHM_POSIX)
166174
: static_cast<int8_t>(ShmVal::SHM_SYS_V);
167175

168-
for (const auto& kv : nameToKey_) {
176+
for (const auto& kv : nameToOpts_) {
169177
const auto& name = kv.first;
170-
const auto& key = kv.second;
178+
serialization::ShmTypeObject key;
179+
if (const auto* opts = std::get_if<FileShmSegmentOpts>(&kv.second)) {
180+
key.path = opts->path;
181+
} else {
182+
try {
183+
const auto& v = std::get<PosixSysVSegmentOpts>(kv.second);
184+
key.usePosix = v.usePosix;
185+
key.path = "";
186+
} catch(std::bad_variant_access&) {
187+
throw std::invalid_argument(folly::sformat("Not a valid segment"));
188+
}
189+
}
171190
const auto it = segments_.find(name);
172191
// segment exists and is active.
173192
if (it != segments_.end() && it->second->isActive()) {
@@ -199,14 +218,14 @@ typename ShmManager::ShutDownRes ShmManager::shutDown() {
199218

200219
// clear our data.
201220
segments_.clear();
202-
nameToKey_.clear();
221+
nameToOpts_.clear();
203222
return ret;
204223
}
205224

206225
namespace {
207226

208227
bool removeSegByName(ShmTypeOpts typeOpts, const std::string& uniqueName) {
209-
if (auto *v = std::get_if<FileShmSegmentOpts>(&typeOpts)) {
228+
if (const auto* v = std::get_if<FileShmSegmentOpts>(&typeOpts)) {
210229
return FileShmSegment::removeByPath(v->path);
211230
}
212231

@@ -258,22 +277,20 @@ void ShmManager::cleanup(const std::string& dir, bool posix) {
258277
}
259278

260279
void ShmManager::removeAllSegments() {
261-
// TODO(SHM_FILE): extend this once we have opts stored in nameToKey_
262-
for (const auto& kv : nameToKey_) {
263-
removeSegByName(usePosix_, uniqueIdForName(kv.first));
280+
for (const auto& kv : nameToOpts_) {
281+
removeSegByName(kv.second, uniqueIdForName(kv.first));
264282
}
265-
nameToKey_.clear();
283+
nameToOpts_.clear();
266284
}
267285

268286
void ShmManager::removeUnAttachedSegments() {
269-
// TODO(SHM_FILE): extend this once we have opts stored in nameToKey_
270-
auto it = nameToKey_.begin();
271-
while (it != nameToKey_.end()) {
287+
auto it = nameToOpts_.begin();
288+
while (it != nameToOpts_.end()) {
272289
const auto name = it->first;
273290
// check if the segment is attached.
274291
if (segments_.find(name) == segments_.end()) { // not attached
275-
removeSegByName(usePosix_, uniqueIdForName(name));
276-
it = nameToKey_.erase(it);
292+
removeSegByName(it->second, uniqueIdForName(name));
293+
it = nameToOpts_.erase(it);
277294
} else {
278295
++it;
279296
}
@@ -292,13 +309,13 @@ ShmAddr ShmManager::createShm(const std::string& shmName,
292309
removeShm(shmName, opts.typeOpts);
293310

294311
DCHECK(segments_.find(shmName) == segments_.end());
295-
DCHECK(nameToKey_.find(shmName) == nameToKey_.end());
312+
DCHECK(nameToOpts_.find(shmName) == nameToOpts_.end());
296313

297-
if (auto *v = std::get_if<PosixSysVSegmentOpts>(&opts.typeOpts)) {
298-
if (usePosix_ != v->usePosix)
299-
throw std::invalid_argument(
300-
folly::sformat("Expected {} but got {} segment",
301-
usePosix_ ? "posix" : "SysV", usePosix_ ? "SysV" : "posix"));
314+
const auto* v = std::get_if<PosixSysVSegmentOpts>(&opts.typeOpts);
315+
if (v && usePosix_ != v->usePosix) {
316+
throw std::invalid_argument(
317+
folly::sformat("Expected {} but got {} segment",
318+
usePosix_ ? "posix" : "SysV", usePosix_ ? "SysV" : "posix"));
302319
}
303320

304321
std::unique_ptr<ShmSegment> newSeg;
@@ -326,24 +343,32 @@ ShmAddr ShmManager::createShm(const std::string& shmName,
326343
}
327344

328345
auto ret = newSeg->getCurrentMapping();
329-
nameToKey_.emplace(shmName, newSeg->getKeyStr());
346+
if (v) {
347+
PosixSysVSegmentOpts opts;
348+
opts.usePosix = v->usePosix;
349+
nameToOpts_.emplace(shmName, opts);
350+
} else {
351+
FileShmSegmentOpts opts;
352+
opts.path = newSeg->getKeyStr();
353+
nameToOpts_.emplace(shmName, opts);
354+
}
330355
segments_.emplace(shmName, std::move(newSeg));
331356
return ret;
332357
}
333358

334359
void ShmManager::attachNewShm(const std::string& shmName, ShmSegmentOpts opts) {
335-
const auto keyIt = nameToKey_.find(shmName);
360+
const auto keyIt = nameToOpts_.find(shmName);
336361
// if key is not known already, there is not much we can do to attach.
337-
if (keyIt == nameToKey_.end()) {
362+
if (keyIt == nameToOpts_.end()) {
338363
throw std::invalid_argument(
339364
folly::sformat("Unable to find any segment with name {}", shmName));
340365
}
341366

342-
if (auto *v = std::get_if<PosixSysVSegmentOpts>(&opts.typeOpts)) {
343-
if (usePosix_ != v->usePosix)
344-
throw std::invalid_argument(
345-
folly::sformat("Expected {} but got {} segment",
346-
usePosix_ ? "posix" : "SysV", usePosix_ ? "SysV" : "posix"));
367+
const auto* v = std::get_if<PosixSysVSegmentOpts>(&opts.typeOpts);
368+
if (v && usePosix_ != v->usePosix) {
369+
throw std::invalid_argument(
370+
folly::sformat("Expected {} but got {} segment",
371+
usePosix_ ? "posix" : "SysV", usePosix_ ? "SysV" : "posix"));
347372
}
348373

349374
// This means the segment exists and we can try to attach it.
@@ -360,7 +385,17 @@ void ShmManager::attachNewShm(const std::string& shmName, ShmSegmentOpts opts) {
360385
shmName, e.what()));
361386
}
362387
DCHECK(segments_.find(shmName) != segments_.end());
363-
DCHECK_EQ(segments_[shmName]->getKeyStr(), keyIt->second);
388+
if (v) { // If it is a posix shm segment
389+
// Comparison unnecessary since getKeyStr() retuns name_from ShmBase
390+
// createKeyForShm also returns the same variable.
391+
} else { // Else it is a file segment
392+
try {
393+
auto opts = std::get<FileShmSegmentOpts>(keyIt->second);
394+
DCHECK_EQ(segments_[shmName]->getKeyStr(), opts.path);
395+
} catch(std::bad_variant_access&) {
396+
throw std::invalid_argument(folly::sformat("Not a valid segment"));
397+
}
398+
}
364399
}
365400

366401
ShmAddr ShmManager::attachShm(const std::string& shmName,
@@ -403,13 +438,13 @@ bool ShmManager::removeShm(const std::string& shmName, ShmTypeOpts typeOpts) {
403438
removeSegByName(typeOpts, uniqueIdForName(shmName));
404439
if (!wasPresent) {
405440
DCHECK(segments_.end() == segments_.find(shmName));
406-
DCHECK(nameToKey_.end() == nameToKey_.find(shmName));
441+
DCHECK(nameToOpts_.end() == nameToOpts_.find(shmName));
407442
return false;
408443
}
409444
}
410445
// not mapped and already removed.
411446
segments_.erase(shmName);
412-
nameToKey_.erase(shmName);
447+
nameToOpts_.erase(shmName);
413448
return true;
414449
}
415450

@@ -424,5 +459,15 @@ ShmSegment& ShmManager::getShmByName(const std::string& shmName) {
424459
}
425460
}
426461

462+
ShmTypeOpts& ShmManager::getShmTypeByName(const std::string& shmName) {
463+
const auto it = nameToOpts_.find(shmName);
464+
if (it != nameToOpts_.end()) {
465+
return it->second;
466+
} else {
467+
throw std::invalid_argument(folly::sformat(
468+
"shared memory segment does not exist: name: {}", shmName));
469+
}
470+
}
471+
427472
} // namespace cachelib
428473
} // namespace facebook

cachelib/shm/ShmManager.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ class ShmManager {
109109
// it is returned. Otherwise, it throws std::invalid_argument
110110
ShmSegment& getShmByName(const std::string& shmName);
111111

112+
// gets a current segment type by the name that is managed by this
113+
// instance. The lifetime of the returned object is same as the
114+
// lifetime of this instance.
115+
// @param name Name of the segment
116+
// @return If a segment of that name, managed by this instance exists,
117+
// it is returned. Otherwise, it throws std::invalid_argument
118+
ShmTypeOpts& getShmTypeByName(const std::string& shmName);
119+
112120
enum class ShutDownRes { kSuccess = 0, kFileDeleted, kFailedWrite };
113121

114122
// persists the metadata information for the current segments managed
@@ -223,8 +231,9 @@ class ShmManager {
223231
std::unordered_map<std::string, std::unique_ptr<ShmSegment>> segments_{};
224232

225233
// name to key mapping used for reattaching. This is persisted to a
226-
// file and used for attaching to the segment.
227-
std::unordered_map<std::string, std::string> nameToKey_{};
234+
// file using serialization::ShmSegmentVariant and used for attaching
235+
// to the segment.
236+
std::unordered_map<std::string, ShmTypeOpts> nameToOpts_{};
228237

229238
// file handle for the metadata file. It remains open throughout the lifetime
230239
// of the object.

cachelib/shm/SysVShmSegment.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,11 @@ class SysVShmSegment : public ShmBase {
8888
// @return true if the segment existed. false otherwise
8989
static bool removeByName(const std::string& name);
9090

91-
private:
9291
// returns the key identifier for the given name.
9392
static KeyType createKeyForName(const std::string& name) noexcept;
9493

94+
private:
95+
9596
static int createNewSegment(key_t key,
9697
size_t size,
9798
const ShmSegmentOpts& opts);

cachelib/shm/shm.thrift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616

1717
namespace cpp2 facebook.cachelib.serialization
1818

19+
struct ShmTypeObject {
20+
1: required string path,
21+
2: required bool usePosix,
22+
}
23+
1924
struct ShmManagerObject {
2025
1: required byte shmVal,
21-
3: required map<string, string> nameToKeyMap,
26+
3: required map<string, ShmTypeObject> nameToKeyMap,
2227
}

cachelib/shm/tests/test_shm_manager.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,9 @@ void ShmManagerTest::testShutDown(bool posix) {
796796
// destroyed.
797797
ASSERT_NO_THROW(s.createShm(seg2, seg2Size, nullptr, seg2Opt));
798798
ASSERT_EQ(s.getShmByName(seg2).getSize(), seg2Size);
799+
auto *v = std::get_if<PosixSysVSegmentOpts>(&s.getShmTypeByName(seg2));
800+
ASSERT_TRUE(v);
801+
ASSERT_EQ(v->usePosix, posix);
799802

800803
ASSERT_TRUE(s.shutDown() == ShutDownRes::kSuccess);
801804
};

0 commit comments

Comments
 (0)