This is an automated email from the ASF dual-hosted git repository.
twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new a9397f2b Split functions in main.cc to multiple headers (#1787)
a9397f2b is described below
commit a9397f2b857e5f228082df625413704fb0010249
Author: Twice <[email protected]>
AuthorDate: Thu Sep 28 17:03:57 2023 +0900
Split functions in main.cc to multiple headers (#1787)
---
CMakeLists.txt | 4 +-
src/cli/daemon_util.h | 127 +++++++++++++++
src/cli/main.cc | 186 ++++++++++++++++++++++
src/cli/pid_util.h | 44 +++++
src/cli/signal_util.h | 93 +++++++++++
src/cli/version_util.h | 39 +++++
src/main.cc | 379 --------------------------------------------
utils/kvrocks2redis/main.cc | 61 +------
8 files changed, 496 insertions(+), 437 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2112a61e..4aadc0d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -196,7 +196,7 @@ endif()
# kvrocks objects target
file(GLOB_RECURSE KVROCKS_SRCS src/*.cc)
-list(FILTER KVROCKS_SRCS EXCLUDE REGEX src/main.cc)
+list(FILTER KVROCKS_SRCS EXCLUDE REGEX src/cli/main.cc)
add_library(kvrocks_objs OBJECT ${KVROCKS_SRCS})
@@ -239,7 +239,7 @@ if(ENABLE_IPO)
endif()
# kvrocks main target
-add_executable(kvrocks src/main.cc)
+add_executable(kvrocks src/cli/main.cc)
target_link_libraries(kvrocks PRIVATE kvrocks_objs ${EXTERNAL_LIBS})
# kvrocks2redis sync tool
diff --git a/src/cli/daemon_util.h b/src/cli/daemon_util.h
new file mode 100644
index 00000000..9d22b708
--- /dev/null
+++ b/src/cli/daemon_util.h
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#pragma once
+
+#include <config/config.h>
+#include <glog/logging.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <cstdlib>
+
+#include "unique_fd.h"
+
+inline bool SupervisedUpstart() {
+ const char *upstart_job = getenv("UPSTART_JOB");
+ if (!upstart_job) {
+ LOG(WARNING) << "upstart supervision requested, but UPSTART_JOB not found";
+ return false;
+ }
+ LOG(INFO) << "supervised by upstart, will stop to signal readiness";
+ raise(SIGSTOP);
+ unsetenv("UPSTART_JOB");
+ return true;
+}
+
+inline bool SupervisedSystemd() {
+ const char *notify_socket = getenv("NOTIFY_SOCKET");
+ if (!notify_socket) {
+ LOG(WARNING) << "systemd supervision requested, but NOTIFY_SOCKET not
found";
+ return false;
+ }
+
+ auto fd = UniqueFD(socket(AF_UNIX, SOCK_DGRAM, 0));
+ if (!fd) {
+ LOG(WARNING) << "Cannot connect to systemd socket " << notify_socket;
+ return false;
+ }
+
+ sockaddr_un su;
+ memset(&su, 0, sizeof(su));
+ su.sun_family = AF_UNIX;
+ strncpy(su.sun_path, notify_socket, sizeof(su.sun_path) - 1);
+ su.sun_path[sizeof(su.sun_path) - 1] = '\0';
+ if (notify_socket[0] == '@') su.sun_path[0] = '\0';
+
+ iovec iov;
+ memset(&iov, 0, sizeof(iov));
+ std::string ready = "READY=1";
+ iov.iov_base = &ready[0];
+ iov.iov_len = ready.size();
+
+ msghdr hdr;
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.msg_name = &su;
+ hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
strlen(notify_socket);
+ hdr.msg_iov = &iov;
+ hdr.msg_iovlen = 1;
+
+ int sendto_flags = 0;
+ unsetenv("NOTIFY_SOCKET");
+#ifdef HAVE_MSG_NOSIGNAL
+ sendto_flags |= MSG_NOSIGNAL;
+#endif
+ if (sendmsg(*fd, &hdr, sendto_flags) < 0) {
+ LOG(WARNING) << "Cannot send notification to systemd";
+ return false;
+ }
+ return true;
+}
+
+inline bool IsSupervisedMode(SupervisedMode mode) {
+ if (mode == kSupervisedAutoDetect) {
+ const char *upstart_job = getenv("UPSTART_JOB");
+ const char *notify_socket = getenv("NOTIFY_SOCKET");
+ if (upstart_job) {
+ mode = kSupervisedUpStart;
+ } else if (notify_socket) {
+ mode = kSupervisedSystemd;
+ }
+ }
+ if (mode == kSupervisedUpStart) {
+ return SupervisedUpstart();
+ } else if (mode == kSupervisedSystemd) {
+ return SupervisedSystemd();
+ }
+ return false;
+}
+
+inline void Daemonize() {
+ pid_t pid = fork();
+ if (pid < 0) {
+ LOG(ERROR) << "Failed to fork the process, err: " << strerror(errno);
+ exit(1);
+ }
+
+ if (pid > 0) exit(EXIT_SUCCESS); // parent process
+ // change the file mode
+ umask(0);
+ if (setsid() < 0) {
+ LOG(ERROR) << "Failed to setsid, err: %s" << strerror(errno);
+ exit(1);
+ }
+
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+}
diff --git a/src/cli/main.cc b/src/cli/main.cc
new file mode 100644
index 00000000..a9661b7f
--- /dev/null
+++ b/src/cli/main.cc
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifdef __linux__
+#define _XOPEN_SOURCE 700 // NOLINT
+#else
+#define _XOPEN_SOURCE
+#endif
+
+#include <event2/thread.h>
+#include <glog/logging.h>
+
+#include <iomanip>
+#include <ostream>
+
+#include "config.h"
+#include "daemon_util.h"
+#include "io_util.h"
+#include "pid_util.h"
+#include "scope_exit.h"
+#include "server/server.h"
+#include "signal_util.h"
+#include "storage/storage.h"
+#include "string_util.h"
+#include "time_util.h"
+#include "unique_fd.h"
+#include "vendor/crc64.h"
+#include "version.h"
+#include "version_util.h"
+
+Server *srv = nullptr;
+
+extern "C" void SignalHandler(int sig) {
+ if (srv && !srv->IsStopped()) {
+ LOG(INFO) << "Bye Bye";
+ srv->Stop();
+ }
+}
+
+struct NewOpt {
+ friend auto &operator<<(std::ostream &os, NewOpt) { return os <<
std::string(4, ' ') << std::setw(32); }
+} new_opt;
+
+static void PrintUsage(const char *program) {
+ std::cout << program << " implements the Redis protocol based on rocksdb" <<
std::endl
+ << "Usage:" << std::endl
+ << std::left << new_opt << "-c, --config <filename>"
+ << "set config file to <filename>, or `-` for stdin" << std::endl
+ << new_opt << "-v, --version"
+ << "print version information" << std::endl
+ << new_opt << "-h, --help"
+ << "print this help message" << std::endl
+ << new_opt << "--<config-key> <config-value>"
+ << "overwrite specific config option <config-key> to
<config-value>" << std::endl;
+}
+
+static CLIOptions ParseCommandLineOptions(int argc, char **argv) {
+ using namespace std::string_view_literals;
+ CLIOptions opts;
+
+ for (int i = 1; i < argc; ++i) {
+ if ((argv[i] == "-c"sv || argv[i] == "--config"sv) && i + 1 < argc) {
+ opts.conf_file = argv[++i];
+ } else if (argv[i] == "-v"sv || argv[i] == "--version"sv) {
+ std::cout << "kvrocks " << PrintVersion << std::endl;
+ std::exit(0);
+ } else if (argv[i] == "-h"sv || argv[i] == "--help"sv) {
+ PrintUsage(*argv);
+ std::exit(0);
+ } 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]);
+ } else {
+ PrintUsage(*argv);
+ std::exit(1);
+ }
+ }
+
+ return opts;
+}
+
+static void InitGoogleLog(const Config *config) {
+ FLAGS_minloglevel = config->log_level;
+ FLAGS_max_log_size = 100;
+ FLAGS_logbufsecs = 0;
+
+ if (util::EqualICase(config->log_dir, "stdout")) {
+ for (int level = google::INFO; level <= google::FATAL; level++) {
+ google::SetLogDestination(level, "");
+ }
+ FLAGS_stderrthreshold = google::ERROR;
+ FLAGS_logtostdout = true;
+ } else {
+ FLAGS_log_dir = config->log_dir + "/";
+ if (config->log_retention_days != -1) {
+ google::EnableLogCleaner(config->log_retention_days);
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ srand(static_cast<unsigned>(util::GetTimeStamp()));
+
+ google::InitGoogleLogging("kvrocks");
+ auto glog_exit = MakeScopeExit(google::ShutdownGoogleLogging);
+
+ evthread_use_pthreads();
+ auto event_exit = MakeScopeExit(libevent_global_shutdown);
+
+ signal(SIGPIPE, SIG_IGN);
+ SetupSigSegvAction(SignalHandler);
+
+ auto opts = ParseCommandLineOptions(argc, argv);
+
+ Config config;
+ Status s = config.Load(opts);
+ if (!s.IsOK()) {
+ std::cout << "Failed to load config. Error: " << s.Msg() << std::endl;
+ return 1;
+ }
+
+ crc64_init();
+ InitGoogleLog(&config);
+ LOG(INFO) << "kvrocks " << PrintVersion;
+ // Tricky: We don't expect that different instances running on the same port,
+ // but the server use REUSE_PORT to support the multi listeners. So we
connect
+ // the listen port to check if the port has already listened or not.
+ if (!config.binds.empty()) {
+ uint32_t ports[] = {config.port, config.tls_port, 0};
+ for (uint32_t *port = ports; *port; ++port) {
+ if (util::IsPortInUse(*port)) {
+ LOG(ERROR) << "Could not create server TCP since the specified port["
<< *port << "] is already in use";
+ return 1;
+ }
+ }
+ }
+ bool is_supervised =
IsSupervisedMode(static_cast<SupervisedMode>(config.supervised_mode));
+ if (config.daemonize && !is_supervised) Daemonize();
+ s = CreatePidFile(config.pidfile);
+ if (!s.IsOK()) {
+ LOG(ERROR) << "Failed to create pidfile: " << s.Msg();
+ return 1;
+ }
+ auto pidfile_exit = MakeScopeExit([&config] { RemovePidFile(config.pidfile);
});
+
+#ifdef ENABLE_OPENSSL
+ // initialize OpenSSL
+ if (config.tls_port || config.tls_replication) {
+ InitSSL();
+ }
+#endif
+
+ engine::Storage storage(&config);
+ s = storage.Open();
+ if (!s.IsOK()) {
+ LOG(ERROR) << "Failed to open: " << s.Msg();
+ return 1;
+ }
+ Server server(&storage, &config);
+ srv = &server;
+ s = srv->Start();
+ if (!s.IsOK()) {
+ LOG(ERROR) << "Failed to start server: " << s.Msg();
+ return 1;
+ }
+ srv->Join();
+
+ return 0;
+}
diff --git a/src/cli/pid_util.h b/src/cli/pid_util.h
new file mode 100644
index 00000000..eb7c41b2
--- /dev/null
+++ b/src/cli/pid_util.h
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#pragma once
+
+#include <fcntl.h>
+
+#include "io_util.h"
+#include "status.h"
+#include "unique_fd.h"
+
+inline Status CreatePidFile(const std::string &path) {
+ auto fd = UniqueFD(open(path.data(), O_RDWR | O_CREAT, 0660));
+ if (!fd) {
+ return Status::FromErrno();
+ }
+
+ std::string pid_str = std::to_string(getpid());
+ auto s = util::Write(*fd, pid_str);
+ if (!s.IsOK()) {
+ return s.Prefixed("failed to write to PID-file");
+ }
+
+ return Status::OK();
+}
+
+inline void RemovePidFile(const std::string &path) { std::remove(path.data());
}
diff --git a/src/cli/signal_util.h b/src/cli/signal_util.h
new file mode 100644
index 00000000..cb5abc67
--- /dev/null
+++ b/src/cli/signal_util.h
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#pragma once
+
+#include <execinfo.h>
+#include <glog/logging.h>
+#include <signal.h>
+
+#include <cstddef>
+#include <iomanip>
+
+#include "version_util.h"
+
+namespace google {
+bool Symbolize(void *pc, char *out, size_t out_size);
+} // namespace google
+
+extern "C" inline void SegvHandler(int sig, siginfo_t *info, void *secret) {
+ void *trace[100];
+
+ LOG(ERROR) << "======= Ooops! kvrocks " << PrintVersion << " got signal: "
<< strsignal(sig) << " (" << sig
+ << ") =======";
+ int trace_size = backtrace(trace, sizeof(trace) / sizeof(void *));
+ char **messages = backtrace_symbols(trace, trace_size);
+
+ size_t max_msg_len = 0;
+ for (int i = 1; i < trace_size; ++i) {
+ auto msg_len = strlen(messages[i]);
+ if (msg_len > max_msg_len) {
+ max_msg_len = msg_len;
+ }
+ }
+
+ for (int i = 1; i < trace_size; ++i) {
+ char func_info[1024] = {};
+ if (google::Symbolize(trace[i], func_info, sizeof(func_info) - 1)) {
+ LOG(ERROR) << std::left << std::setw(static_cast<int>(max_msg_len)) <<
messages[i] << " " << func_info;
+ } else {
+ LOG(ERROR) << messages[i];
+ }
+ }
+
+ struct sigaction act;
+ /* Make sure we exit with the right signal at the end. So for instance
+ * the core will be dumped if enabled.
+ */
+ sigemptyset(&act.sa_mask);
+ /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
+ * is used. Otherwise, sa_handler is used
+ */
+ act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
+ act.sa_handler = SIG_DFL;
+ sigaction(sig, &act, nullptr);
+ kill(getpid(), sig);
+}
+
+inline void SetupSigSegvAction(void (*handler)(int)) {
+ struct sigaction act;
+
+ sigemptyset(&act.sa_mask);
+ /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
+ * is used. Otherwise, sa_handler is used */
+ act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
+ act.sa_sigaction = SegvHandler;
+ sigaction(SIGSEGV, &act, nullptr);
+ sigaction(SIGBUS, &act, nullptr);
+ sigaction(SIGFPE, &act, nullptr);
+ sigaction(SIGILL, &act, nullptr);
+ sigaction(SIGABRT, &act, nullptr);
+
+ act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
+ act.sa_handler = handler;
+ sigaction(SIGTERM, &act, nullptr);
+ sigaction(SIGINT, &act, nullptr);
+}
diff --git a/src/cli/version_util.h b/src/cli/version_util.h
new file mode 100644
index 00000000..38a8bcc2
--- /dev/null
+++ b/src/cli/version_util.h
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#pragma once
+
+#include <iostream>
+
+#include "version.h"
+
+inline std::ostream &PrintVersion(std::ostream &os) {
+ if (VERSION != "unstable") {
+ os << "version ";
+ }
+
+ os << VERSION;
+
+ if (!GIT_COMMIT.empty()) {
+ os << " (commit " << GIT_COMMIT << ")";
+ }
+
+ return os;
+}
diff --git a/src/main.cc b/src/main.cc
deleted file mode 100644
index a04f8aa8..00000000
--- a/src/main.cc
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#ifdef __linux__
-#define _XOPEN_SOURCE 700 // NOLINT
-#else
-#define _XOPEN_SOURCE
-#endif
-
-#include <dlfcn.h>
-#include <event2/thread.h>
-#include <execinfo.h>
-#include <fcntl.h>
-#include <glog/logging.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include <ucontext.h>
-
-#include <iomanip>
-#include <ostream>
-
-#include "config.h"
-#include "io_util.h"
-#include "scope_exit.h"
-#include "server/server.h"
-#include "storage/storage.h"
-#include "string_util.h"
-#include "time_util.h"
-#include "unique_fd.h"
-#include "vendor/crc64.h"
-#include "version.h"
-
-namespace google {
-bool Symbolize(void *pc, char *out, size_t out_size);
-} // namespace google
-
-Server *srv = nullptr;
-
-extern "C" void SignalHandler(int sig) {
- if (srv && !srv->IsStopped()) {
- LOG(INFO) << "Bye Bye";
- srv->Stop();
- }
-}
-
-std::ostream &PrintVersion(std::ostream &os) {
- os << "kvrocks ";
-
- if (VERSION != "unstable") {
- os << "version ";
- }
-
- os << VERSION;
-
- if (!GIT_COMMIT.empty()) {
- os << " (commit " << GIT_COMMIT << ")";
- }
-
- return os;
-}
-
-extern "C" void SegvHandler(int sig, siginfo_t *info, void *secret) {
- void *trace[100];
-
- LOG(ERROR) << "======= Ooops! " << PrintVersion << " got signal: " <<
strsignal(sig) << " (" << sig << ") =======";
- int trace_size = backtrace(trace, sizeof(trace) / sizeof(void *));
- char **messages = backtrace_symbols(trace, trace_size);
-
- size_t max_msg_len = 0;
- for (int i = 1; i < trace_size; ++i) {
- auto msg_len = strlen(messages[i]);
- if (msg_len > max_msg_len) {
- max_msg_len = msg_len;
- }
- }
-
- for (int i = 1; i < trace_size; ++i) {
- char func_info[1024] = {};
- if (google::Symbolize(trace[i], func_info, sizeof(func_info) - 1)) {
- LOG(ERROR) << std::left << std::setw(static_cast<int>(max_msg_len)) <<
messages[i] << " " << func_info;
- } else {
- LOG(ERROR) << messages[i];
- }
- }
-
- struct sigaction act;
- /* Make sure we exit with the right signal at the end. So for instance
- * the core will be dumped if enabled.
- */
- sigemptyset(&act.sa_mask);
- /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
- * is used. Otherwise, sa_handler is used
- */
- act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
- act.sa_handler = SIG_DFL;
- sigaction(sig, &act, nullptr);
- kill(getpid(), sig);
-}
-
-void SetupSigSegvAction() {
- struct sigaction act;
-
- sigemptyset(&act.sa_mask);
- /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
- * is used. Otherwise, sa_handler is used */
- act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
- act.sa_sigaction = SegvHandler;
- sigaction(SIGSEGV, &act, nullptr);
- sigaction(SIGBUS, &act, nullptr);
- sigaction(SIGFPE, &act, nullptr);
- sigaction(SIGILL, &act, nullptr);
- sigaction(SIGABRT, &act, nullptr);
-
- act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
- act.sa_handler = SignalHandler;
- sigaction(SIGTERM, &act, nullptr);
- sigaction(SIGINT, &act, nullptr);
-}
-
-struct NewOpt {
- friend auto &operator<<(std::ostream &os, NewOpt) { return os <<
std::string(4, ' ') << std::setw(32); }
-} new_opt;
-
-static void PrintUsage(const char *program) {
- std::cout << program << " implements the Redis protocol based on rocksdb" <<
std::endl
- << "Usage:" << std::endl
- << std::left << new_opt << "-c, --config <filename>"
- << "set config file to <filename>, or `-` for stdin" << std::endl
- << new_opt << "-v, --version"
- << "print version information" << std::endl
- << new_opt << "-h, --help"
- << "print this help message" << std::endl
- << new_opt << "--<config-key> <config-value>"
- << "overwrite specific config option <config-key> to
<config-value>" << std::endl;
-}
-
-static CLIOptions ParseCommandLineOptions(int argc, char **argv) {
- using namespace std::string_view_literals;
- CLIOptions opts;
-
- for (int i = 1; i < argc; ++i) {
- if ((argv[i] == "-c"sv || argv[i] == "--config"sv) && i + 1 < argc) {
- opts.conf_file = argv[++i];
- } else if (argv[i] == "-v"sv || argv[i] == "--version"sv) {
- std::cout << PrintVersion << std::endl;
- std::exit(0);
- } else if (argv[i] == "-h"sv || argv[i] == "--help"sv) {
- PrintUsage(*argv);
- std::exit(0);
- } 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]);
- } else {
- PrintUsage(*argv);
- std::exit(1);
- }
- }
-
- return opts;
-}
-
-static void InitGoogleLog(const Config *config) {
- FLAGS_minloglevel = config->log_level;
- FLAGS_max_log_size = 100;
- FLAGS_logbufsecs = 0;
-
- if (util::EqualICase(config->log_dir, "stdout")) {
- for (int level = google::INFO; level <= google::FATAL; level++) {
- google::SetLogDestination(level, "");
- }
- FLAGS_stderrthreshold = google::ERROR;
- FLAGS_logtostdout = true;
- } else {
- FLAGS_log_dir = config->log_dir + "/";
- if (config->log_retention_days != -1) {
- google::EnableLogCleaner(config->log_retention_days);
- }
- }
-}
-
-bool SupervisedUpstart() {
- const char *upstart_job = getenv("UPSTART_JOB");
- if (!upstart_job) {
- LOG(WARNING) << "upstart supervision requested, but UPSTART_JOB not found";
- return false;
- }
- LOG(INFO) << "supervised by upstart, will stop to signal readiness";
- raise(SIGSTOP);
- unsetenv("UPSTART_JOB");
- return true;
-}
-
-bool SupervisedSystemd() {
- const char *notify_socket = getenv("NOTIFY_SOCKET");
- if (!notify_socket) {
- LOG(WARNING) << "systemd supervision requested, but NOTIFY_SOCKET not
found";
- return false;
- }
-
- auto fd = UniqueFD(socket(AF_UNIX, SOCK_DGRAM, 0));
- if (!fd) {
- LOG(WARNING) << "Cannot connect to systemd socket " << notify_socket;
- return false;
- }
-
- sockaddr_un su;
- memset(&su, 0, sizeof(su));
- su.sun_family = AF_UNIX;
- strncpy(su.sun_path, notify_socket, sizeof(su.sun_path) - 1);
- su.sun_path[sizeof(su.sun_path) - 1] = '\0';
- if (notify_socket[0] == '@') su.sun_path[0] = '\0';
-
- iovec iov;
- memset(&iov, 0, sizeof(iov));
- std::string ready = "READY=1";
- iov.iov_base = &ready[0];
- iov.iov_len = ready.size();
-
- msghdr hdr;
- memset(&hdr, 0, sizeof(hdr));
- hdr.msg_name = &su;
- hdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
strlen(notify_socket);
- hdr.msg_iov = &iov;
- hdr.msg_iovlen = 1;
-
- int sendto_flags = 0;
- unsetenv("NOTIFY_SOCKET");
-#ifdef HAVE_MSG_NOSIGNAL
- sendto_flags |= MSG_NOSIGNAL;
-#endif
- if (sendmsg(*fd, &hdr, sendto_flags) < 0) {
- LOG(WARNING) << "Cannot send notification to systemd";
- return false;
- }
- return true;
-}
-
-bool IsSupervisedMode(int mode) {
- if (mode == kSupervisedAutoDetect) {
- const char *upstart_job = getenv("UPSTART_JOB");
- const char *notify_socket = getenv("NOTIFY_SOCKET");
- if (upstart_job) {
- mode = kSupervisedUpStart;
- } else if (notify_socket) {
- mode = kSupervisedSystemd;
- }
- }
- if (mode == kSupervisedUpStart) {
- return SupervisedUpstart();
- } else if (mode == kSupervisedSystemd) {
- return SupervisedSystemd();
- }
- return false;
-}
-
-static Status CreatePidFile(const std::string &path) {
- auto fd = UniqueFD(open(path.data(), O_RDWR | O_CREAT, 0660));
- if (!fd) {
- return Status::FromErrno();
- }
-
- std::string pid_str = std::to_string(getpid());
- auto s = util::Write(*fd, pid_str);
- if (!s.IsOK()) {
- return s.Prefixed("failed to write to PID-file");
- }
-
- return Status::OK();
-}
-
-static void RemovePidFile(const std::string &path) { std::remove(path.data());
}
-
-static void Daemonize() {
- pid_t pid = fork();
- if (pid < 0) {
- LOG(ERROR) << "Failed to fork the process, err: " << strerror(errno);
- exit(1);
- }
- if (pid > 0) exit(EXIT_SUCCESS); // parent process
- // change the file mode
- umask(0);
- if (setsid() < 0) {
- LOG(ERROR) << "Failed to setsid, err: %s" << strerror(errno);
- exit(1);
- }
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
-}
-
-int main(int argc, char *argv[]) {
- srand(static_cast<unsigned>(util::GetTimeStamp()));
-
- google::InitGoogleLogging("kvrocks");
- auto glog_exit = MakeScopeExit(google::ShutdownGoogleLogging);
-
- evthread_use_pthreads();
- auto event_exit = MakeScopeExit(libevent_global_shutdown);
-
- signal(SIGPIPE, SIG_IGN);
- SetupSigSegvAction();
-
- auto opts = ParseCommandLineOptions(argc, argv);
-
- Config config;
- Status s = config.Load(opts);
- if (!s.IsOK()) {
- std::cout << "Failed to load config. Error: " << s.Msg() << std::endl;
- return 1;
- }
-
- crc64_init();
- InitGoogleLog(&config);
- LOG(INFO) << PrintVersion;
- // Tricky: We don't expect that different instances running on the same port,
- // but the server use REUSE_PORT to support the multi listeners. So we
connect
- // the listen port to check if the port has already listened or not.
- if (!config.binds.empty()) {
- uint32_t ports[] = {config.port, config.tls_port, 0};
- for (uint32_t *port = ports; *port; ++port) {
- if (util::IsPortInUse(*port)) {
- LOG(ERROR) << "Could not create server TCP since the specified port["
<< *port << "] is already in use";
- return 1;
- }
- }
- }
- bool is_supervised = IsSupervisedMode(config.supervised_mode);
- if (config.daemonize && !is_supervised) Daemonize();
- s = CreatePidFile(config.pidfile);
- if (!s.IsOK()) {
- LOG(ERROR) << "Failed to create pidfile: " << s.Msg();
- return 1;
- }
- auto pidfile_exit = MakeScopeExit([&config] { RemovePidFile(config.pidfile);
});
-
-#ifdef ENABLE_OPENSSL
- // initialize OpenSSL
- if (config.tls_port || config.tls_replication) {
- InitSSL();
- }
-#endif
-
- engine::Storage storage(&config);
- s = storage.Open();
- if (!s.IsOK()) {
- LOG(ERROR) << "Failed to open: " << s.Msg();
- return 1;
- }
- Server server(&storage, &config);
- srv = &server;
- s = srv->Start();
- if (!s.IsOK()) {
- LOG(ERROR) << "Failed to start server: " << s.Msg();
- return 1;
- }
- srv->Join();
-
- return 0;
-}
diff --git a/utils/kvrocks2redis/main.cc b/utils/kvrocks2redis/main.cc
index 76b0d7bc..767c2f19 100644
--- a/utils/kvrocks2redis/main.cc
+++ b/utils/kvrocks2redis/main.cc
@@ -26,6 +26,9 @@
#include <csignal>
+#include "cli/daemon_util.h"
+#include "cli/pid_util.h"
+#include "cli/version_util.h"
#include "config.h"
#include "config/config.h"
#include "io_util.h"
@@ -43,22 +46,6 @@ struct Options {
std::string conf_file = kDefaultConfPath;
};
-std::ostream &PrintVersion(std::ostream &os) {
- os << "kvrocks2redis ";
-
- if (VERSION != "unstable") {
- os << "version ";
- }
-
- os << VERSION;
-
- if (!GIT_COMMIT.empty()) {
- os << " (commit " << GIT_COMMIT << ")";
- }
-
- return os;
-}
-
extern "C" void SignalHandler(int sig) {
if (hup_handler) hup_handler();
}
@@ -81,7 +68,7 @@ static Options ParseCommandLineOptions(int argc, char **argv)
{
break;
}
case 'v':
- std::cout << PrintVersion << std::endl;
+ std::cout << "kvrocks2redis " << PrintVersion << std::endl;
exit(0);
case 'h':
default:
@@ -98,44 +85,6 @@ static void InitGoogleLog(const kvrocks2redis::Config
*config) {
FLAGS_log_dir = config->output_dir;
}
-static Status CreatePidFile(const std::string &path) {
- int fd = open(path.data(), O_RDWR | O_CREAT | O_EXCL, 0660);
- if (fd < 0) {
- return {Status::NotOK, strerror(errno)};
- }
-
- std::string pid_str = std::to_string(getpid());
- auto s = util::Write(fd, pid_str);
- if (!s.IsOK()) {
- return s.Prefixed("failed to write to PID-file");
- }
-
- close(fd);
- return Status::OK();
-}
-
-static void RemovePidFile(const std::string &path) { std::remove(path.data());
}
-
-static void Daemonize() {
- pid_t pid = fork();
- if (pid < 0) {
- LOG(ERROR) << "Failed to fork the process. Error: " << strerror(errno);
- exit(1);
- }
-
- if (pid > 0) exit(EXIT_SUCCESS); // parent process
- // change the file mode
- umask(0);
- if (setsid() < 0) {
- LOG(ERROR) << "Failed to setsid. Error: " << strerror(errno);
- exit(1);
- }
-
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
-}
-
Server *GetServer() { return nullptr; }
int main(int argc, char *argv[]) {
@@ -157,7 +106,7 @@ int main(int argc, char *argv[]) {
}
InitGoogleLog(&config);
- LOG(INFO) << PrintVersion;
+ LOG(INFO) << "kvrocks2redis " << PrintVersion;
if (config.daemonize) Daemonize();