Skip to content
2 changes: 1 addition & 1 deletion mooncake-store/include/client_metric.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <ylt/metric/summary.hpp>
#include "environ.h"
#include "hybrid_metric.h"
#include "utils.h"
#include "common/byte_size.h"

namespace mooncake {

Expand Down
101 changes: 101 additions & 0 deletions mooncake-store/include/common/byte_size.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#pragma once

#include <algorithm>
#include <cctype>
#include <cstdint>
#include <exception>
#include <iomanip>
#include <limits>
#include <optional>
#include <sstream>
#include <string>

namespace mooncake {

[[nodiscard]] inline std::string byte_size_to_string(uint64_t bytes) {
constexpr double kKiB = 1024.0;
constexpr double kMiB = kKiB * 1024.0;
constexpr double kGiB = kMiB * 1024.0;
constexpr double kTiB = kGiB * 1024.0;

std::ostringstream oss;
oss << std::fixed << std::setprecision(2);
if (static_cast<int64_t>(bytes) == std::numeric_limits<int64_t>::max()) {
oss << "infinite";
} else if (bytes >= static_cast<uint64_t>(kTiB)) {
oss << bytes / kTiB << " TB";
} else if (bytes >= static_cast<uint64_t>(kGiB)) {
oss << bytes / kGiB << " GB";
} else if (bytes >= static_cast<uint64_t>(kMiB)) {
oss << bytes / kMiB << " MB";
} else if (bytes >= static_cast<uint64_t>(kKiB)) {
oss << bytes / kKiB << " KB";
} else {
oss.unsetf(std::ios::fixed);
oss << bytes << " B";
}
return oss.str();
}

[[nodiscard]] inline std::optional<uint64_t> try_string_to_byte_size(
const std::string& str) {
if (str.empty()) {
return std::nullopt;
}

std::string value_string = str;
value_string.erase(0, value_string.find_first_not_of(" \t\r\n"));
value_string.erase(value_string.find_last_not_of(" \t\r\n") + 1);
if (value_string.empty()) {
return std::nullopt;
}
if (value_string == "infinite") {
return std::numeric_limits<uint64_t>::max();
}

size_t unit_offset = 0;
double value = 0;
try {
value = std::stod(value_string, &unit_offset);
} catch (const std::exception&) {
return std::nullopt;
}
if (value < 0) {
return std::nullopt;
}
if (unit_offset >= value_string.length()) {
return static_cast<uint64_t>(value);
}

std::string unit = value_string.substr(unit_offset);
unit.erase(0, unit.find_first_not_of(" \t\r\n"));
std::transform(unit.begin(), unit.end(), unit.begin(),
[](unsigned char c) -> char { return std::toupper(c); });

constexpr double kKiB = 1024.0;
constexpr double kMiB = kKiB * 1024.0;
constexpr double kGiB = kMiB * 1024.0;
constexpr double kTiB = kGiB * 1024.0;
if (unit == "KB" || unit == "K") {
return static_cast<uint64_t>(value * kKiB);
}
if (unit == "MB" || unit == "M") {
return static_cast<uint64_t>(value * kMiB);
}
if (unit == "GB" || unit == "G") {
return static_cast<uint64_t>(value * kGiB);
}
if (unit == "TB" || unit == "T") {
return static_cast<uint64_t>(value * kTiB);
}
if (unit == "B" || unit.empty()) {
return static_cast<uint64_t>(value);
}
return std::nullopt;
}

[[nodiscard]] inline uint64_t string_to_byte_size(const std::string& str) {
return try_string_to_byte_size(str).value_or(0);
}

} // namespace mooncake
103 changes: 103 additions & 0 deletions mooncake-store/include/common/client_buffer_allocation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#pragma once

#include <cstddef>
#include <cstdlib>
#include <linux/memfd.h>
#include <linux/mman.h>
#include <string>
#include <vector>

#include <Slab.h>
#include <glog/logging.h>

#include "common/byte_size.h"

namespace mooncake {

constexpr size_t SZ_2MB = 2 * 1024 * 1024;
constexpr size_t SZ_512MB = 512 * 1024 * 1024;

// 512MiB hugepages on arm64 kernels with 64K base pages may not be
// defined by older glibc/kernel headers.
#ifndef MAP_HUGE_512MB
#define MAP_HUGE_512MB (29 << 26) // MAP_HUGE_SHIFT = 26
#endif
#ifndef MFD_HUGE_512MB
#define MFD_HUGE_512MB (29 << 26) // MFD_HUGE_SHIFT = 26
#endif
constexpr size_t SZ_1GB = 1024 * 1024 * 1024;
constexpr double BYTES_PER_GIB = static_cast<double>(SZ_1GB);

void* allocate_buffer_allocator_memory(
size_t total_size, const std::string& protocol = "",
size_t alignment = facebook::cachelib::Slab::kSize,
bool use_spdk_dma = false);

void free_memory(const std::string& protocol, void* ptr,
bool use_spdk_dma = false);

inline size_t align_up(size_t size, size_t alignment) {
if (alignment == 0) {
return size;
}
return ((size + alignment - 1) / alignment) * alignment;
}

[[nodiscard]] inline size_t get_hugepage_size_from_env(
unsigned int* out_flags = nullptr, bool use_memfd = false) {
if (std::getenv("MC_STORE_USE_HUGEPAGE") == nullptr) {
return 0;
}

size_t size = SZ_2MB;
if (const char* size_env = std::getenv("MC_STORE_HUGEPAGE_SIZE")) {
const size_t parsed_size = string_to_byte_size(size_env);
if (parsed_size == SZ_2MB || parsed_size == SZ_512MB ||
parsed_size == SZ_1GB) {
size = parsed_size;
} else {
LOG(WARNING) << "Invalid MC_STORE_HUGEPAGE_SIZE='" << size_env
<< "'. Supported: 2MB, 512MB, 1GB. Fallback to 2MB.";
}
}

if (out_flags == nullptr) {
return size;
}
if (use_memfd) {
*out_flags |= MFD_HUGETLB;
*out_flags |= size == SZ_2MB ? MFD_HUGE_2MB
: size == SZ_512MB ? MFD_HUGE_512MB
: MFD_HUGE_1GB;
} else {
*out_flags |= MAP_HUGETLB;
*out_flags |= size == SZ_2MB ? MAP_HUGE_2MB
: size == SZ_512MB ? MAP_HUGE_512MB
: MAP_HUGE_1GB;
}
LOG(INFO) << "Using hugepage size: "
<< (size == SZ_2MB ? "2MB"
: size == SZ_512MB ? "512MB"
: "1GB");
return size;
}

void populate_hugetlb_mapping(void* ptr, size_t total_size);

void populate_hugetlb_numa_mapping(void* ptr, size_t total_size,
const std::vector<int>& numa_nodes);

void* allocate_buffer_mmap_memory(size_t total_size, size_t alignment);

void* allocate_buffer_mmap_memory(size_t total_size, size_t alignment,
bool defer_hugetlb_population);

[[nodiscard]] bool is_mmap_arena_allocation(const void* ptr);

void free_buffer_mmap_memory(void* ptr, size_t total_size);

void* allocate_buffer_numa_segments(size_t total_size,
const std::vector<int>& numa_nodes,
size_t page_size = 0);

} // namespace mooncake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ namespace fs = std::filesystem;

class FileUtil {
public:
static std::string ResolvePathFromKey(const std::string& key,
const std::string& root_dir,
const std::string& fsdir);

/**
* @brief Save string content to file
* @param content Content to save
Expand Down
40 changes: 40 additions & 0 deletions mooncake-store/include/common/network.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <string>
#include <vector>

#include <ylt/util/tl/expected.hpp>

namespace mooncake {

bool isPortAvailable(int port);

class AutoPortBinder {
public:
AutoPortBinder(int min_port = 12300, int max_port = 14300);
~AutoPortBinder();

AutoPortBinder(const AutoPortBinder&) = delete;
AutoPortBinder& operator=(const AutoPortBinder&) = delete;
AutoPortBinder(AutoPortBinder&&) = delete;
AutoPortBinder& operator=(AutoPortBinder&&) = delete;

int getPort() const { return port_; }

private:
int socket_fd_;
int port_;
};

tl::expected<std::string, int> httpGet(const std::string& url);

tl::expected<std::string, std::string> GetInterfaceIPv4Address(
const std::string& interface_name);

int getFreeTcpPort();

std::vector<int> getFreeTcpPorts(int count);

std::string ResolveMooncakeHostId(const std::string& local_hostname);

} // namespace mooncake
131 changes: 131 additions & 0 deletions mooncake-store/include/common/result.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#pragma once

#include <cstdint>
#include <functional>
#include <optional>
#include <ostream>
#include <sstream>
#include <string>
#include <string_view>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>

#include <ylt/util/tl/expected.hpp>

#include "rpc_types.h"
#include "types.h"

namespace mooncake {

template <class T>
constexpr bool is_supported_return_type_v =
std::is_void_v<T> || std::is_integral_v<T>;

template <class T>
requires is_supported_return_type_v<T>
int64_t to_py_ret(const tl::expected<T, ErrorCode>& exp) noexcept {
if (!exp) {
return static_cast<int64_t>(toInt(exp.error()));
}
if constexpr (std::is_void_v<T>) {
return 0;
} else {
return static_cast<int64_t>(exp.value());
}
}

template <typename T>
void to_stream(std::ostream& os, const T& value);

template <typename T>
void to_stream(std::ostream& os, const std::vector<T>& vec);

template <typename T1, typename T2>
void to_stream(std::ostream& os, const std::pair<T1, T2>& p);

template <typename T>
void to_stream(std::ostream& os, const T& value) {
if constexpr (std::is_same_v<T, bool>) {
os << (value ? "true" : "false");
} else if constexpr (std::is_arithmetic_v<T>) {
os << value;
} else if constexpr (std::is_convertible_v<T, std::string_view>) {
os << "\"" << value << "\"";
} else if constexpr (ylt::reflection::is_ylt_refl_v<T>) {
std::string str;
struct_json::to_json(value, str);
os << str;
} else {
os << value;
}
}

template <typename T>
void to_stream(std::ostream& os, const std::vector<T>& vec) {
os << "[";
for (size_t i = 0; i < vec.size(); ++i) {
to_stream(os, vec[i]);
if (i + 1 < vec.size()) {
os << ",";
}
}
os << "]";
}

template <typename K, typename V, typename H>
void to_stream(std::ostream& os, const std::unordered_map<K, V, H>& map) {
os << "{";
auto it = map.begin();
while (it != map.end()) {
to_stream(os, it->first);
os << ": ";
to_stream(os, it->second);
if (++it != map.end()) {
os << ", ";
}
}
os << "}";
}

template <typename K, typename V>
void to_stream(std::ostream& os, const std::unordered_map<K, V>& map) {
to_stream<K, V, std::hash<K>>(os, map);
}

template <typename T1, typename T2>
void to_stream(std::ostream& os, const std::pair<T1, T2>& p) {
os << "{\"first\":";
to_stream(os, p.first);
os << ",\"second\":";
to_stream(os, p.second);
os << "}";
}

template <typename T>
void to_stream(std::ostream& os, const std::optional<T>& opt) {
if (opt.has_value()) {
to_stream(os, opt.value());
} else {
os << "nullopt";
}
}

template <typename T>
std::string expected_to_str(const tl::expected<T, ErrorCode>& expected) {
std::ostringstream oss;
if (expected.has_value()) {
oss << "status=success, value=";
if constexpr (std::is_same_v<T, void>) {
oss << "void";
} else {
to_stream(oss, expected.value());
}
} else {
oss << "status=failed, error=" << toString(expected.error());
}
return oss.str();
}

} // namespace mooncake
Loading
Loading