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
Show file tree
Hide file tree
Changes from 19 commits
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
7 changes: 7 additions & 0 deletions kvrocks.conf
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ db-name change.me.db
# Note that you must specify a directory here, not a file name.
dir /tmp/kvrocks

# Optional: A snapshot directory
#
# If specified, Kvrocks will snapshot the DB at [dir] to the specified [snapshot-dir],
# and start a read-only server from the snapshot.
#
# snapshot-dir /tmp/kvrocks-snapshot-changeme

# You can configure where to store your server logs by the log-dir.
# If you don't specify one, we will use the above `dir` as our default log directory.
# We also can send logs to stdout/stderr is as simple as:
Expand Down
3 changes: 2 additions & 1 deletion src/cli/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ int main(int argc, char *argv[]) {
#endif

engine::Storage storage(&config);
s = storage.Open();
s = storage.Open(kDBOpenModeDefault);
nathanlo99 marked this conversation as resolved.
Show resolved Hide resolved

if (!s.IsOK()) {
LOG(ERROR) << "Failed to open: " << s.Msg();
return 1;
Expand Down
3 changes: 1 addition & 2 deletions src/config/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@
#include <rocksdb/env.h>
#include <strings.h>

#include <algorithm>
#include <cstdint>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <limits>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -190,6 +188,7 @@ Config::Config() {
new IntField(&force_compact_file_min_deleted_percentage, 10, 1, 100)},
{"db-name", true, new StringField(&db_name, "change.me.db")},
{"dir", true, new StringField(&dir, kDefaultDir)},
{"snapshot-dir", true, new StringField(&snapshot_dir, "")},
{"backup-dir", false, new StringField(&backup_dir, kDefaultBackupDir)},
{"log-dir", true, new StringField(&log_dir, "")},
{"log-level", false, new EnumField<int>(&log_level, log_levels, google::INFO)},
Expand Down
4 changes: 4 additions & 0 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ struct Config {
std::string replica_announce_ip;
uint32_t replica_announce_port = 0;

// The following option exists so users can spawn a read-only server from a snapshot
// of a running server.
std::string snapshot_dir;

bool persist_cluster_nodes_enabled = true;
bool slot_id_encoded = false;
bool cluster_enabled = false;
Expand Down
44 changes: 44 additions & 0 deletions src/storage/storage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "redis_metadata.h"
#include "rocksdb/cache.h"
#include "rocksdb_crc32c.h"
#include "scope_exit.h"
#include "server/server.h"
#include "storage/batch_indexer.h"
#include "table_properties_collector.h"
Expand Down Expand Up @@ -75,6 +76,37 @@ const int64_t kIORateLimitMaxMb = 1024000;

using rocksdb::Slice;

static Status CreateSnapshot(Config &config) {
// 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 snapshot 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; });

// Since .Open() will call `CreateSnapshot` if `snapshot_dir` is set, we need to
// clear it, and reset it after the snapshot is created to preserve symmetry.
const std::string snapshot_dir = std::exchange(config.snapshot_dir, "");
const auto snapshot_dir_guard = MakeScopeExit([&config, &snapshot_dir] { config.snapshot_dir = snapshot_dir; });

engine::Storage storage(&config);
if (const auto s = storage.Open(kDBOpenModeForReadOnly); !s.IsOK()) {
return {Status::NotOK, fmt::format("failed to open DB in read-only mode: {}", s.Msg())};
}

rocksdb::Checkpoint *snapshot = nullptr;
if (const auto s = rocksdb::Checkpoint::Create(storage.GetDB(), &snapshot); !s.ok()) {
return {Status::NotOK, s.ToString()};
}

std::unique_ptr<rocksdb::Checkpoint> snapshot_guard(snapshot);
if (const auto s = snapshot->CreateCheckpoint(snapshot_dir + "/db"); !s.ok()) {
return {Status::NotOK, s.ToString()};
}

return Status::OK();
}

Storage::Storage(Config *config)
: backup_creating_time_secs_(util::GetTimeStamp<std::chrono::seconds>()),
env_(rocksdb::Env::Default()),
Expand Down Expand Up @@ -267,6 +299,18 @@ Status Storage::CreateColumnFamilies(const rocksdb::Options &options) {
}

Status Storage::Open(DBOpenMode mode) {
// If a snapshot directory was specified, create a snapshot and open the database
// there in read-only mode.
if (config_->snapshot_dir != "") {
if (auto s = CreateSnapshot(*config_); !s.IsOK()) {
return s;
}
LOG(INFO) << "Starting server in read-only mode with snapshot dir: " << config_->snapshot_dir;
config_->dir = config_->snapshot_dir;
config_->db_dir = config_->snapshot_dir + "/db";
mode = DBOpenMode::kDBOpenModeForReadOnly;
}

auto guard = WriteLockGuard();
db_closing_ = false;

Expand Down
1 change: 0 additions & 1 deletion src/storage/storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#include <rocksdb/utilities/write_batch_with_index.h>

#include <atomic>
#include <cinttypes>
#include <cstddef>
#include <memory>
#include <shared_mutex>
Expand Down
Loading