Skip to content

Commit

Permalink
Support Hibernate options 'dest' and 'compress'
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianM27 committed Jan 15, 2025
1 parent 7052492 commit 2e9a682
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 22 deletions.
12 changes: 7 additions & 5 deletions client/tool/source/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,15 +510,17 @@ static void hibernateCommand(const std::shared_ptr<IDobbyProxy>& dobbyProxy,
size_t i = 0;
std::string options;

// Find options from arguments (start with a '-')
while (args[i].c_str()[0] == '-')
// Find options from arguments (start with a '--')
while (args[i].length() > 1 && args[i].c_str()[0] == '-' && args[i].c_str()[1] == '-')
{
// Add space between options
// strip off the '--'
std::string arg(args[i].c_str() + 2);
// Add comma between options
if (!options.empty())
{
options.append(" ");
options.append(",");
}
options.append(args[i]);
options.append(arg);
i++;
}

Expand Down
5 changes: 5 additions & 0 deletions daemon/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# limitations under the License.

option(DOBBY_HIBERNATE_MEMCR_IMPL "Hibernate containers using Memcr tool" OFF)
option(DOBBY_HIBERNATE_MEMCR_PARAMS_ENABLE "Enable optional parameters in Memcr protocol" OFF)

if (LEGACY_COMPONENTS)
list(APPEND ADDITIONAL_SOURCES
Expand Down Expand Up @@ -100,6 +101,10 @@ endif()

if(DOBBY_HIBERNATE_MEMCR_IMPL)
add_definitions( -DDOBBY_HIBERNATE_MEMCR_IMPL=1 )

if (DOBBY_HIBERNATE_MEMCR_PARAMS_ENABLED)
add_definitions( -DDOBBY_HIBERNATE_MEMCR_PARAMS_ENABLED=1 )
endif()
endif()

# Install public headers for external use
Expand Down
88 changes: 76 additions & 12 deletions daemon/lib/source/DobbyHibernate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,20 @@

typedef enum {
MEMCR_CHECKPOINT = 100,
MEMCR_RESTORE
MEMCR_RESTORE,
MEMCR_CMDS_V2
} ServerRequestCode;

typedef enum {
MEMCR_CHECKPOINT_DUMPDIR = 200,
MEMCR_CHECKPOINT_COMPRESS_ALG,
} ServerRequestCodeOptions;

typedef struct {
std::string dumpDir;
DobbyHibernate::CompressionAlg compressAlg;
} ServerRequestOptions;

typedef enum {
MEMCR_OK = 0,
MEMCR_ERROR = -1,
Expand All @@ -56,9 +67,12 @@ typedef struct {
ServerResponseCode respCode;
} __attribute__((packed)) ServerResponse;

const char* DobbyHibernate::DFL_LOCATOR = "/tmp/memcrcom";
const std::string DobbyHibernate::DFL_LOCATOR = "/tmp/memcrcom";
const uint32_t DobbyHibernate::DFL_TIMEOUTE_MS = 20000;

#define MEMCR_DUMPDIR_LEN_MAX 1024
#define CMD_LEN_MAX (sizeof(ServerRequest) + (2*sizeof(ServerRequestCodeOptions)) + MEMCR_DUMPDIR_LEN_MAX + 1)


static int Connect(const char* serverLocator, uint32_t timeoutMs)
{
Expand Down Expand Up @@ -138,11 +152,12 @@ static int Connect(const char* serverLocator, uint32_t timeoutMs)
return cd;
}

static bool SendRcvCmd(const ServerRequest* cmd, ServerResponse* resp, uint32_t timeoutMs, const char* serverLocator)
static bool SendRcvCmd(const ServerRequest* cmd, ServerResponse* resp, uint32_t timeoutMs, const char* serverLocator, const ServerRequestOptions *opt)
{
AI_LOG_FN_ENTRY();
int cd;
int ret;

resp->respCode = MEMCR_ERROR;

cd = Connect(serverLocator, timeoutMs);
Expand All @@ -152,13 +167,58 @@ static bool SendRcvCmd(const ServerRequest* cmd, ServerResponse* resp, uint32_t
return false;
}

#ifdef DOBBY_HIBERNATE_MEMCR_PARAMS_ENABLED
int cmdSize = 0;
unsigned char cmdBuf[CMD_LEN_MAX];

memcpy(cmdBuf, cmd, sizeof(ServerRequest));
cmdSize += sizeof(ServerRequest);

if (opt) {
if (opt->dumpDir.length() > 0) {
ServerRequestCodeOptions optId = MEMCR_CHECKPOINT_DUMPDIR;
memcpy(cmdBuf + cmdSize, &optId, sizeof(ServerRequestCodeOptions));
cmdSize += sizeof(ServerRequestCodeOptions);
strncpy((char *)cmdBuf + cmdSize, opt->dumpDir.c_str(), MEMCR_DUMPDIR_LEN_MAX);
cmdSize += opt->dumpDir.length() + 1;
}

if (opt->compressAlg != DobbyHibernate::CompressionAlg::AlgDefault) {
ServerRequestCodeOptions optId = MEMCR_CHECKPOINT_COMPRESS_ALG;
memcpy(cmdBuf + cmdSize, &optId, sizeof(ServerRequestCodeOptions));
cmdSize += sizeof(ServerRequestCodeOptions);
memcpy(cmdBuf + cmdSize, &opt->compressAlg, sizeof(DobbyHibernate::CompressionAlg));
cmdSize += sizeof(DobbyHibernate::CompressionAlg);
}
}

ServerRequest cmdV2 = {.reqCode = MEMCR_CMDS_V2, .pid = cmdSize};

ret = write(cd, &cmdV2, sizeof(ServerRequest));
if (ret != sizeof(ServerRequest)) {
AI_LOG_ERROR("Socket write failed: ret %d, %m", ret);
close(cd);
AI_LOG_FN_EXIT();
return false;
}

ret = write(cd, cmdBuf, cmdSize);
if (ret != cmdSize) {
AI_LOG_ERROR("Socket write failed: ret %d, %m", ret);
close(cd);
AI_LOG_FN_EXIT();
return false;
}

#else
ret = write(cd, cmd, sizeof(ServerRequest));
if (ret != sizeof(ServerRequest)) {
AI_LOG_ERROR("Socket write failed: ret %d, %m", ret);
close(cd);
AI_LOG_FN_EXIT();
return false;
}
#endif

ret = read(cd, resp, sizeof(ServerResponse));
if (ret != sizeof(ServerResponse)) {
Expand All @@ -175,17 +235,21 @@ static bool SendRcvCmd(const ServerRequest* cmd, ServerResponse* resp, uint32_t
return (resp->respCode == MEMCR_OK);
}

DobbyHibernate::Error DobbyHibernate::HibernateProcess(const pid_t pid, const uint32_t timeout, const char* locator,
const char* dumpDirPath, CompressionAlg compression)
DobbyHibernate::Error DobbyHibernate::HibernateProcess(const pid_t pid, const uint32_t timeout, const std::string &locator,
const std::string &dumpDirPath, CompressionAlg compression)
{
AI_LOG_FN_ENTRY();
ServerRequest req = {
.reqCode = MEMCR_CHECKPOINT,
.pid = pid
};
ServerRequestOptions opt = {
.dumpDir = dumpDirPath,
.compressAlg = compression
};
ServerResponse resp;

if (SendRcvCmd(&req, &resp, timeout, locator)) {
if (SendRcvCmd(&req, &resp, timeout, locator.c_str(), &opt)) {
AI_LOG_INFO("Hibernate process PID %d success", pid);
AI_LOG_FN_EXIT();
return DobbyHibernate::Error::ErrorNone;
Expand All @@ -200,7 +264,7 @@ DobbyHibernate::Error DobbyHibernate::HibernateProcess(const pid_t pid, const ui
}
}

DobbyHibernate::Error DobbyHibernate::WakeupProcess(const pid_t pid, const uint32_t timeout, const char* locator)
DobbyHibernate::Error DobbyHibernate::WakeupProcess(const pid_t pid, const uint32_t timeout, const std::string &locator)
{
AI_LOG_FN_ENTRY();
ServerRequest req = {
Expand All @@ -209,7 +273,7 @@ DobbyHibernate::Error DobbyHibernate::WakeupProcess(const pid_t pid, const uint3
};
ServerResponse resp;

if (SendRcvCmd(&req, &resp, timeout, locator)) {
if (SendRcvCmd(&req, &resp, timeout, locator.c_str(), nullptr)) {
AI_LOG_INFO("Wakeup process PID %d success", pid);
AI_LOG_FN_EXIT();
return DobbyHibernate::Error::ErrorNone;
Expand All @@ -226,17 +290,17 @@ DobbyHibernate::Error DobbyHibernate::WakeupProcess(const pid_t pid, const uint3

#else

const char* DobbyHibernate::DFL_LOCATOR = "";
const std::string DobbyHibernate::DFL_LOCATOR = "";
const uint32_t DobbyHibernate::DFL_TIMEOUTE_MS = 0;

DobbyHibernate::Error DobbyHibernate::HibernateProcess(const pid_t pid, const uint32_t timeout, const char* locator,
const char* dumpDirPath, CompressionAlg compression)
DobbyHibernate::Error DobbyHibernate::HibernateProcess(const pid_t pid, const uint32_t timeout, const std::string &locator,
const std::string &dumpDirPath, CompressionAlg compression)
{
AI_LOG_ERROR("DobbyHibernate Implementation not enabled");
return DobbyHibernate::Error::ErrorGeneral;
}

DobbyHibernate::Error DobbyHibernate::WakeupProcess(const pid_t pid, const uint32_t timeout, const char* locator)
DobbyHibernate::Error DobbyHibernate::WakeupProcess(const pid_t pid, const uint32_t timeout, const std::string &locator)
{
AI_LOG_ERROR("DobbyHibernate Implementation not enabled");
return DobbyHibernate::Error::ErrorGeneral;
Expand Down
10 changes: 6 additions & 4 deletions daemon/lib/source/DobbyHibernate.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <sys/types.h>
#include <stdint.h>
#include <string>

class DobbyHibernate
{
Expand All @@ -40,14 +41,15 @@ class DobbyHibernate
{
AlgNone = 0,
AlgLz4 = 1,
AlgZstd = 2
AlgZstd = 2,
AlgDefault = 3
};

static const char* DFL_LOCATOR;
static const std::string DFL_LOCATOR;
static const uint32_t DFL_TIMEOUTE_MS;

static Error HibernateProcess(const pid_t pid, const uint32_t timeout = DFL_TIMEOUTE_MS,
const char* locator = DFL_LOCATOR, const char* dumpDirPath = nullptr, CompressionAlg compression = AlgLz4);
const std::string &locator = DFL_LOCATOR, const std::string &dumpDirPath = std::string(), CompressionAlg compression = AlgDefault);

static Error WakeupProcess(const pid_t pid, const uint32_t timeout = DFL_TIMEOUTE_MS, const char* locator = DFL_LOCATOR);
static Error WakeupProcess(const pid_t pid, const uint32_t timeout = DFL_TIMEOUTE_MS, const std::string &locator = DFL_LOCATOR);
};
49 changes: 48 additions & 1 deletion daemon/lib/source/DobbyManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1573,6 +1573,52 @@ bool DobbyManager::hibernateContainer(int32_t cd, const std::string& options)
return false;
}

// parse options: dest, compress
// format: dest=/some/path/blah,compress=lz4
std::string dest;
DobbyHibernate::CompressionAlg compress = DobbyHibernate::CompressionAlg::AlgDefault;

// lambda to split a string by a delimiter
auto splitString = [](const std::string& str, char delimiter) -> std::vector<std::string>
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
}
return tokens;
};

std::vector<std::string> optionList = splitString(options, ',');
for (const std::string& option : optionList)
{
std::vector<std::string> keyValue = splitString(option, '=');
if (keyValue.size() == 2)
{
if (keyValue[0] == "dest")
{
dest = keyValue[1];
}
else if (keyValue[0] == "compress")
{
if (keyValue[1] == "lz4")
{
compress = DobbyHibernate::CompressionAlg::AlgLz4;
}
else if (keyValue[1] == "zstd")
{
compress = DobbyHibernate::CompressionAlg::AlgZstd;
}
else
{
AI_LOG_WARN("Unsupported compression algorithm: %s", keyValue[1].c_str());
}
}
}
}

std::thread hibernateThread =
std::thread([=]()
{
Expand All @@ -1597,7 +1643,8 @@ bool DobbyManager::hibernateContainer(int32_t cd, const std::string& options)
locker.unlock();

uint32_t pid = pidIt->asUInt();
ret = DobbyHibernate::HibernateProcess(pid);
ret = DobbyHibernate::HibernateProcess(pid, DobbyHibernate::DFL_TIMEOUTE_MS,
DobbyHibernate::DFL_LOCATOR, dest, compress);
if (ret != DobbyHibernate::Error::ErrorNone)
{
AI_LOG_WARN("Error hibernating pid: '%d'", pid);
Expand Down

0 comments on commit 2e9a682

Please sign in to comment.