Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add the ability to checkpoint an existing server, and spawn a read-only server on that view. #2548

Open
wants to merge 25 commits into
base: unstable
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e8fd991
Add checkpoints
Sep 20, 2024
b2ce62b
Move global variables to Config
nathanlo-hrt Sep 24, 2024
770ce93
Merge branch 'unstable' into unstable
nathanlo99 Sep 24, 2024
b3e93fe
Fix lint error, rename checkpoint -> snapshot, deduplicate error mess…
nathanlo99 Sep 30, 2024
60b0860
Merge branch 'unstable' into unstable
nathanlo99 Sep 30, 2024
810a86c
Trigger tests
nathanlo-hrt Oct 3, 2024
b866c5f
Merge branch 'unstable' into unstable
git-hulk Oct 5, 2024
5a43069
Merge branch 'unstable' into unstable
nathanlo99 Oct 14, 2024
916ce73
Merge branch 'unstable' into unstable
aleksraiden Oct 15, 2024
2edb82b
Merge branch 'unstable' into unstable
nathanlo99 Oct 18, 2024
50a32d1
Merge branch 'unstable' into unstable
nathanlo99 Oct 21, 2024
d27c1bc
Move functionality out of main.cc
nathanlo-hrt Oct 21, 2024
e46818a
Format
nathanlo-hrt Oct 24, 2024
e86e115
Merge branch 'unstable' into unstable
nathanlo99 Oct 24, 2024
6f76141
Merge branch 'unstable' into unstable
nathanlo99 Nov 5, 2024
53b0ed7
Move creating snapshot from constructor to Open()
nathanlo-hrt Nov 5, 2024
7f6d0a2
Make snapshot-dir read-only
nathanlo-hrt Nov 5, 2024
694f839
Remove trailing whitespace
nathanlo-hrt Nov 6, 2024
19f25b9
Fix 'const prevents move' issue
nathanlo-hrt Nov 6, 2024
786908f
Revert changes in main.cc
nathanlo-hrt Nov 7, 2024
838a4ab
Merge branch 'unstable' into unstable
nathanlo99 Nov 7, 2024
9e6865b
Merge branch 'unstable' into unstable
nathanlo99 Nov 11, 2024
15776e5
Merge branch 'unstable' into unstable
nathanlo99 Nov 13, 2024
79309ff
Merge branch 'unstable' into unstable
nathanlo99 Nov 14, 2024
6a6ca87
Merge branch 'unstable' into unstable
nathanlo99 Nov 18, 2024
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
55 changes: 54 additions & 1 deletion src/cli/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
#include <event2/thread.h>
#include <glog/logging.h>

#include <filesystem>
#include <iomanip>
#include <ostream>

#include "config.h"
#include "daemon_util.h"
#include "io_util.h"
#include "pid_util.h"
#include "rocksdb/utilities/checkpoint.h"
#include "scope_exit.h"
#include "server/server.h"
#include "signal_util.h"
Expand All @@ -46,6 +48,8 @@
#include "version_util.h"

Server *srv = nullptr;
std::optional<std::string> checkpoint_location = std::nullopt;
bool keep_checkpoint = false;
git-hulk marked this conversation as resolved.
Show resolved Hide resolved

extern "C" void SignalHandler([[maybe_unused]] int sig) {
if (srv && !srv->IsStopped()) {
Expand All @@ -67,6 +71,10 @@ static void PrintUsage(const char *program) {
<< "print version information" << std::endl
<< new_opt << "-h, --help"
<< "print this help message" << std::endl
<< new_opt << "--use-checkpoint <dir>"
<< "create a checkpoint of the supplied database in <dir> and start a read-only server using that checkpoint" << std::endl
<< new_opt << "--keep-checkpoint"
<< "keep the checkpoint after the server is stopped" << std::endl
<< new_opt << "--<config-key> <config-value>"
<< "overwrite specific config option <config-key> to <config-value>" << std::endl;
}
Expand All @@ -84,6 +92,10 @@ static CLIOptions ParseCommandLineOptions(int argc, char **argv) {
} else if (argv[i] == "-h"sv || argv[i] == "--help"sv) {
PrintUsage(*argv);
std::exit(0);
} else if (argv[i] == "--use-checkpoint"sv && i + 1 < argc) {
checkpoint_location = argv[++i];
} else if (argv[i] == "--keep-checkpoint"sv) {
keep_checkpoint = true;
} else if (std::string_view(argv[i], 2) == "--" && std::string_view(argv[i]).size() > 2 && i + 1 < argc) {
auto key = std::string_view(argv[i] + 2);
opts.cli_options.emplace_back(key, argv[++i]);
Expand Down Expand Up @@ -116,6 +128,32 @@ static void InitGoogleLog(const Config *config) {
}
}

static void CreateCheckpoint(Config &config, const std::string &checkpoint_location) {
// The Storage destructor deletes anything at the checkpoint_dir, so we need to make sure it's empty in case the user
// happens to use a checkpoint folder name which matches the default (checkpoint/)
const std::string old_checkpoint_dir = std::exchange(config.checkpoint_dir, "");
const auto checkpoint_dir_guard =
MakeScopeExit([&config, &old_checkpoint_dir] { config.checkpoint_dir = old_checkpoint_dir; });

engine::Storage storage(&config);
if (const auto s = storage.Open(kDBOpenModeForReadOnly); !s.IsOK()) {
nathanlo99 marked this conversation as resolved.
Show resolved Hide resolved
LOG(ERROR) << "Failed to open: " << s.Msg();
throw std::runtime_error("Failed to open DB in read-only mode");
}

rocksdb::Checkpoint *checkpoint = nullptr;
if (const auto s = rocksdb::Checkpoint::Create(storage.GetDB(), &checkpoint); !s.ok()) {
LOG(ERROR) << "Failed to create checkpoint: " << s.ToString();
throw std::runtime_error("Failed to create checkpoint");
}

std::unique_ptr<rocksdb::Checkpoint> checkpoint_guard(checkpoint);
if (const auto s = checkpoint->CreateCheckpoint(checkpoint_location); !s.ok()) {
LOG(ERROR) << "Failed to create checkpoint: " << s.ToString();
throw std::runtime_error("Failed to create checkpoint");
}
}

int main(int argc, char *argv[]) {
srand(static_cast<unsigned>(util::GetTimeStamp()));

Expand Down Expand Up @@ -168,8 +206,23 @@ int main(int argc, char *argv[]) {
}
#endif

const bool read_only = checkpoint_location.has_value();
if (read_only) {
CreateCheckpoint(config, checkpoint_location.value());
LOG(INFO) << "Starting server in read-only mode with checkpoint dir: " << checkpoint_location.value();
config.db_dir = checkpoint_location.value();
}
const auto checkpoint_exit = MakeScopeExit([]() {
if (!keep_checkpoint && checkpoint_location.has_value()) {
LOG(INFO) << "Removing checkpoint dir: " << checkpoint_location.value();
std::filesystem::remove_all(checkpoint_location.value());
}
});

engine::Storage storage(&config);
s = storage.Open();
const DBOpenMode open_mode = read_only ? kDBOpenModeForReadOnly : kDBOpenModeDefault;
s = storage.Open(open_mode);

if (!s.IsOK()) {
LOG(ERROR) << "Failed to open: " << s.Msg();
return 1;
Expand Down