Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions cachelib/allocator/CacheAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -1499,7 +1499,8 @@ class CacheAllocator : public CacheBase {
// and the cache was actually attached.
static bool cleanupStrayShmSegments(const std::string& cacheDir,
bool posix,
const std::string& hugePageMountDir = "");
const std::string& hugePageMountDir = "",
const std::string& posixShmDir = "");

// gives a relative offset to a pointer within the cache.
uint64_t getItemPtrAsOffset(const void* ptr);
Expand Down Expand Up @@ -2949,7 +2950,8 @@ CacheAllocator<CacheTrait>::CacheAllocator(
shmManager_(type != InitMemType::kNone
? std::make_unique<ShmManager>(config_.cacheDir,
config_.isUsingPosixShm(),
config_.hugePageMountDir)
config_.hugePageMountDir,
config_.posixShmDirectory)
: nullptr),
deserializer_(type == InitMemType::kMemAttach ? createDeserializer()
: nullptr),
Expand Down Expand Up @@ -7048,12 +7050,13 @@ template <typename CacheTrait>
bool CacheAllocator<CacheTrait>::cleanupStrayShmSegments(
const std::string& cacheDir,
bool posix,
const std::string& hugePageMountDir) {
const std::string& hugePageMountDir,
const std::string& posixShmDir) {
if (util::getStatIfExists(cacheDir, nullptr) && util::isDir(cacheDir)) {
try {
// cache dir exists. clean up only if there are no other processes
// attached. if another process was attached, the following would fail.
ShmManager::cleanup(cacheDir, posix, hugePageMountDir);
ShmManager::cleanup(cacheDir, posix, hugePageMountDir, posixShmDir);
} catch (const std::exception& e) {
XLOGF(ERR, "Error cleaning up {}. Exception: ", cacheDir, e.what());
return false;
Expand All @@ -7063,13 +7066,13 @@ bool CacheAllocator<CacheTrait>::cleanupStrayShmSegments(
// Any other concurrent process can not be attached to the segments or
// even if it does, we want to mark it for destruction.
ShmManager::removeByName(cacheDir, detail::kShmInfoName, posix,
hugePageMountDir);
hugePageMountDir, posixShmDir);
ShmManager::removeByName(cacheDir, detail::kShmCacheName, posix,
hugePageMountDir);
hugePageMountDir, posixShmDir);
ShmManager::removeByName(cacheDir, detail::kShmHashTableName, posix,
hugePageMountDir);
hugePageMountDir, posixShmDir);
ShmManager::removeByName(cacheDir, detail::kShmChainedItemHashTableName,
posix, hugePageMountDir);
posix, hugePageMountDir, posixShmDir);
}
return true;
}
Expand Down
22 changes: 22 additions & 0 deletions cachelib/allocator/CacheAllocatorConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,13 @@ class CacheAllocatorConfig {
// cachePersistence()
CacheAllocatorConfig& usePosixForShm();

// Like usePosixForShm(), but normal-page segments are files in the given
// directory instead of /dev/shm. Use an existing tmpfs directory. It is not
// saved with the cache: SharedMemAttach with another directory throws.
// @throw std::invalid_argument if the directory is empty or called without
// enabling cachePersistence()
CacheAllocatorConfig& usePosixShmDirectory(std::string directory);

// Requests HugeTLB-backed pages for slab (main cache) memory and access
// container hash tables; persistence metadata stays on normal pages.
// Shorthand for enableSlabHugePages + enableAccessHugePages with the same
Expand Down Expand Up @@ -571,6 +578,9 @@ class CacheAllocatorConfig {
// if true, uses posix shm; if not, uses sys-v (default)
bool usePosixShm{false};

// Directory for normal-page POSIX shm segments; empty means /dev/shm.
std::string posixShmDirectory;

// Huge-page size backing the slab memory segment; default => normal pages.
PageSize slabHugePageSize{};

Expand Down Expand Up @@ -1143,6 +1153,17 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::usePosixForShm() {
return *this;
}

template <typename T>
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::usePosixShmDirectory(
std::string directory) {
if (directory.empty()) {
throw std::invalid_argument("usePosixShmDirectory() needs a directory");
}
usePosixForShm();
posixShmDirectory = std::move(directory);
return *this;
}

template <typename T>
void CacheAllocatorConfig<T>::validateHugePageSize(const PageSize& pageSize) {
if (!pageSize.isHugePage()) {
Expand Down Expand Up @@ -1543,6 +1564,7 @@ std::map<std::string, std::string> CacheAllocatorConfig<T>::serialize() const {
configMap["slabHugePageSize"] = pageSizeStr(slabHugePageSize);
configMap["accessHugePageSize"] = pageSizeStr(accessHugePageSize);
configMap["hugePageMountDir"] = hugePageMountDir;
configMap["posixShmDirectory"] = posixShmDirectory;

configMap["defaultAllocSizes"] = "";
// Stringify std::set
Expand Down
7 changes: 5 additions & 2 deletions cachelib/allocator/ReadOnlySharedCacheView.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,20 @@ class ReadOnlySharedCacheView {
// address chosen by the kernel
// @param pageSize page size backing the cache's main segment
// @param hugePageMountDir hugetlbfs mount containing a POSIX huge-page cache
// @param posixShmDir the cache's usePosixShmDirectory(), if any
explicit ReadOnlySharedCacheView(const std::string& cacheDir,
bool usePosixShm,
void* addr = nullptr,
const PageSize& pageSize = PageSize(),
const std::string& hugePageMountDir = "")
const std::string& hugePageMountDir = "",
const std::string& posixShmDir = "")
: shm_(ShmManager::attachShmReadOnly(cacheDir,
detail::kShmCacheName,
usePosixShm,
addr,
pageSize,
hugePageMountDir)) {}
hugePageMountDir,
posixShmDir)) {}

// returns the absolute address at which the shared memory mapping is mounted.
// The caller can add a relative offset obtained from
Expand Down
62 changes: 62 additions & 0 deletions cachelib/allocator/tests/CacheAllocatorConfigTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@
* limitations under the License.
*/

#include <folly/testing/TestUtil.h>

#include <cstring>
#include <filesystem>

#include "cachelib/allocator/CacheAllocatorConfig.h"
#include "cachelib/allocator/MemoryTierCacheConfig.h"
#include "cachelib/allocator/ReadOnlySharedCacheView.h"
#include "cachelib/allocator/memory/Slab.h"
#include "cachelib/allocator/tests/TestBase.h"
#include "cachelib/common/EventSink.h"
Expand Down Expand Up @@ -122,6 +128,62 @@ TEST_F(CacheAllocatorConfigTest, ConflictingHugePageMountDirsThrow) {
EXPECT_EQ("/mnt/hugetlbfs-a", config.hugePageMountDir);
}

TEST_F(CacheAllocatorConfigTest, PosixShmDirectory) {
AllocatorT::Config config;
// Needs cache persistence, as usePosixForShm() does.
EXPECT_THROW(config.usePosixShmDirectory("/segments"), std::invalid_argument);
config.enableCachePersistence("/cache");
EXPECT_THROW(config.usePosixShmDirectory(""), std::invalid_argument);

config.usePosixShmDirectory("/segments");
EXPECT_TRUE(config.isUsingPosixShm());
EXPECT_EQ("/segments", config.posixShmDirectory);
EXPECT_EQ("/segments", config.serialize()["posixShmDirectory"]);
}

TEST_F(CacheAllocatorConfigTest, PosixShmDirectoryWarmRoll) {
folly::test::TemporaryDirectory cacheDir;
folly::test::TemporaryDirectory segmentDir("", "/dev/shm");
const std::string segments = segmentDir.path().string();
const auto makeConfig = [&](const std::string& directory) {
AllocatorT::Config config;
config.setCacheSize(64 * Slab::kSize)
.enableCachePersistence(cacheDir.path().string())
.usePosixShmDirectory(directory);
return config;
};
{
AllocatorT cache(AllocatorT::SharedMemNew, makeConfig(segments));
const auto pool =
cache.addPool("default", cache.getCacheMemoryStats().ramCacheSize);
auto handle = cache.allocate(pool, "key", 100);
ASSERT_NE(nullptr, handle);
std::memset(handle->getMemory(), 'v', 100);
cache.insertOrReplace(handle);
handle.reset();
ASSERT_EQ(AllocatorT::ShutDownStatus::kSuccess, cache.shutDown());
}
ASSERT_FALSE(std::filesystem::is_empty(segments));
{
ReadOnlySharedCacheView view(cacheDir.path().string(), true /* posix */,
nullptr, PageSize(), "", segments);
EXPECT_NE(0u, view.getShmMappingAddress());
}

{
AllocatorT cache(AllocatorT::SharedMemAttach, makeConfig(segments));
auto handle = cache.find("key");
ASSERT_NE(nullptr, handle);
EXPECT_EQ('v', *reinterpret_cast<const char*>(handle->getMemory()));
handle.reset();
ASSERT_EQ(AllocatorT::ShutDownStatus::kSuccess, cache.shutDown());
}

EXPECT_TRUE(AllocatorT::cleanupStrayShmSegments(
cacheDir.path().string(), true /* posix */, "", segments));
EXPECT_TRUE(std::filesystem::is_empty(segments));
}

TEST_F(CacheAllocatorConfigTest, SerializeEvictionPolicyLru) {
LruAllocator::Config config;
auto serialized = config.serialize();
Expand Down
2 changes: 2 additions & 0 deletions cachelib/persistence/PersistenceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ class PersistenceManager {
CACHELIB_CHECK_THROW(!config.slabHugePageSize.isHugePage() &&
!config.accessHugePageSize.isHugePage(),
"Huge pages are not supported to persist");
CACHELIB_CHECK_THROW(config.posixShmDirectory.empty(),
"usePosixShmDirectory() is not supported to persist");

if (config.nvmConfig.has_value()) {
const auto& navyConfig = config.nvmConfig->navyConfig;
Expand Down
5 changes: 3 additions & 2 deletions cachelib/shm/PosixShmSegment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,12 @@ int shmOpenForPageSize(const std::string& name,
int flags,
const PageSize& pageSize,
const std::string& hugePageMountDir) {
if (!pageSize.isHugePage()) {
if (!pageSize.isHugePage() && hugePageMountDir.empty()) {
return detail::shmOpenImpl(name.c_str(), flags);
}
// HugeTLB segments must use a different mount from /dev/shm (which is
// hardcoded by shm_open)
// hardcoded by shm_open). Normal-page segments get a directory only from
// usePosixShmDirectory().
if (hugePageMountDir.empty()) {
util::throwSystemError(
EINVAL,
Expand Down
16 changes: 8 additions & 8 deletions cachelib/shm/PosixShmSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class PosixShmSegment : public ShmBase {
//
// @param name Name of the segment
// @param opts the options for attaching to the segment.
// @param hugePageMountDir hugetlbfs mount backing the segment when it uses
// huge pages; empty for normal (tmpfs) segments.
// @param hugePageMountDir directory of the segment: the hugetlbfs mount for
// huge pages; for normal pages "" means /dev/shm.
PosixShmSegment(ShmAttachT,
const std::string& name,
ShmSegmentOpts opts = {},
Expand All @@ -60,8 +60,8 @@ class PosixShmSegment : public ShmBase {
// @param name The name of the segment
// @param size The size of the segment. This will be rounded up to the
// nearest page size.
// @param hugePageMountDir hugetlbfs mount to back the segment on when it
// uses huge pages; empty for normal (tmpfs) segments.
// @param hugePageMountDir directory of the segment: the hugetlbfs mount for
// huge pages; for normal pages "" means /dev/shm.
PosixShmSegment(ShmNewT,
const std::string& name,
size_t size,
Expand Down Expand Up @@ -98,8 +98,8 @@ class PosixShmSegment : public ShmBase {

// useful for removing without attaching
// @param name Name of the segment
// @param hugePageMountDir hugetlbfs mount backing the segment if it uses
// huge pages; empty for normal (tmpfs) segments.
// @param hugePageMountDir directory to remove the segment from in addition
// to /dev/shm, if not empty.
// @return true if the segment existed. false otherwise
static bool removeByName(const std::string& name,
const std::string& hugePageMountDir = "");
Expand All @@ -126,8 +126,8 @@ class PosixShmSegment : public ShmBase {

void memBind(void* addr) const;

// hugetlbfs mount backing this segment when it uses huge pages ("" for
// normal/tmpfs segments). Needed to locate the file for removal.
// Directory of the segment file ("" for /dev/shm). Needed to locate the
// file for removal.
const std::string hugePageMountDir_;

// file descriptor associated with the shm. This has FD_CLOEXEC set
Expand Down
8 changes: 4 additions & 4 deletions cachelib/shm/Shm.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ class ShmSegment {
// @param name name of the segment
// @param size size of the segment.
// @param opts the options for the segment.
// @param hugePageMountDir hugetlbfs mount for a huge-page POSIX segment;
// ignored for SysV and normal-page segments.
// @param hugePageMountDir directory of a POSIX segment: the hugetlbfs mount
// for huge pages; for normal pages "" means /dev/shm. Unused by SysV.
ShmSegment(ShmNewT,
std::string name,
size_t size,
Expand All @@ -67,8 +67,8 @@ class ShmSegment {
// attach to an existing segment with the given key
// @param name name of the segment
// @param opts the options for the segment.
// @param hugePageMountDir hugetlbfs mount for a huge-page POSIX segment;
// ignored for SysV and normal-page segments.
// @param hugePageMountDir directory of a POSIX segment: the hugetlbfs mount
// for huge pages; for normal pages "" means /dev/shm. Unused by SysV.
ShmSegment(ShmAttachT,
std::string name,
bool usePosix,
Expand Down
Loading
Loading