2017-10-31 16:49:33 +08:00
|
|
|
#include <csignal>
|
2017-05-30 22:26:16 +08:00
|
|
|
#include <experimental/filesystem>
|
2017-01-23 19:02:11 +08:00
|
|
|
#include <iostream>
|
2016-08-10 16:39:02 +08:00
|
|
|
|
2017-07-06 19:53:39 +08:00
|
|
|
#include <gflags/gflags.h>
|
|
|
|
#include <glog/logging.h>
|
2017-05-22 18:31:04 +08:00
|
|
|
|
2017-03-06 20:37:51 +08:00
|
|
|
#include "communication/bolt/v1/session.hpp"
|
|
|
|
#include "communication/server.hpp"
|
2017-10-25 21:28:10 +08:00
|
|
|
#include "config.hpp"
|
2018-01-12 22:17:04 +08:00
|
|
|
#include "database/graph_db.hpp"
|
2017-12-19 19:40:30 +08:00
|
|
|
#include "distributed/coordination_master.hpp"
|
|
|
|
#include "distributed/coordination_worker.hpp"
|
2018-01-15 21:03:07 +08:00
|
|
|
#include "io/network/endpoint.hpp"
|
2017-03-06 20:37:51 +08:00
|
|
|
#include "io/network/network_error.hpp"
|
2016-08-10 16:39:02 +08:00
|
|
|
#include "io/network/socket.hpp"
|
2018-02-02 18:11:06 +08:00
|
|
|
#include "stats/stats.hpp"
|
2017-06-09 21:48:40 +08:00
|
|
|
#include "utils/flag_validation.hpp"
|
2018-02-02 18:11:06 +08:00
|
|
|
#include "utils/on_scope_exit.hpp"
|
2017-09-22 20:24:53 +08:00
|
|
|
#include "utils/scheduler.hpp"
|
2016-12-16 20:56:36 +08:00
|
|
|
#include "utils/signals/handler.hpp"
|
2017-06-13 21:43:00 +08:00
|
|
|
#include "utils/stacktrace.hpp"
|
2017-09-22 20:24:53 +08:00
|
|
|
#include "utils/sysinfo/memory.hpp"
|
2017-01-13 17:47:17 +08:00
|
|
|
#include "utils/terminate_handler.hpp"
|
2017-09-26 15:43:43 +08:00
|
|
|
#include "version.hpp"
|
|
|
|
|
2017-05-30 22:26:16 +08:00
|
|
|
namespace fs = std::experimental::filesystem;
|
2018-01-12 22:17:04 +08:00
|
|
|
using communication::bolt::SessionData;
|
2018-01-15 21:03:07 +08:00
|
|
|
using io::network::Endpoint;
|
|
|
|
using io::network::Socket;
|
2017-10-17 20:05:08 +08:00
|
|
|
using SessionT = communication::bolt::Session<Socket>;
|
|
|
|
using ServerT = communication::Server<SessionT, SessionData>;
|
2017-03-06 20:37:51 +08:00
|
|
|
|
2017-12-19 19:40:30 +08:00
|
|
|
// General purpose flags.
|
2017-09-25 21:56:14 +08:00
|
|
|
DEFINE_string(interface, "0.0.0.0",
|
|
|
|
"Communication interface on which to listen.");
|
2018-01-15 21:03:07 +08:00
|
|
|
DEFINE_VALIDATED_int32(port, 7687, "Communication port on which to listen.",
|
|
|
|
FLAG_IN_RANGE(0, std::numeric_limits<uint16_t>::max()));
|
2017-06-09 21:48:40 +08:00
|
|
|
DEFINE_VALIDATED_int32(num_workers,
|
|
|
|
std::max(std::thread::hardware_concurrency(), 1U),
|
2018-02-23 17:56:56 +08:00
|
|
|
"Number of workers (Bolt)", FLAG_IN_RANGE(1, INT32_MAX));
|
2017-10-17 20:05:08 +08:00
|
|
|
DEFINE_string(log_file, "", "Path to where the log should be stored.");
|
2017-11-22 23:40:39 +08:00
|
|
|
DEFINE_HIDDEN_string(
|
|
|
|
log_link_basename, "",
|
|
|
|
"Basename used for symlink creation to the last log file.");
|
2017-09-25 21:56:14 +08:00
|
|
|
DEFINE_uint64(memory_warning_threshold, 1024,
|
2018-02-02 18:11:06 +08:00
|
|
|
"Memory warning threshold, in MB. If Memgraph detects there is "
|
|
|
|
"less available RAM it will log a warning. Set to 0 to "
|
2017-09-25 21:56:14 +08:00
|
|
|
"disable.");
|
2016-08-01 01:58:12 +08:00
|
|
|
|
2017-12-19 19:40:30 +08:00
|
|
|
// Distributed flags.
|
|
|
|
DEFINE_HIDDEN_bool(
|
|
|
|
master, false,
|
|
|
|
"If this Memgraph server is the master in a distributed deployment.");
|
|
|
|
DEFINE_HIDDEN_bool(
|
|
|
|
worker, false,
|
|
|
|
"If this Memgraph server is a worker in a distributed deployment.");
|
2018-02-16 22:35:39 +08:00
|
|
|
DECLARE_int32(worker_id);
|
2017-12-19 19:40:30 +08:00
|
|
|
|
2017-10-31 16:49:33 +08:00
|
|
|
// Needed to correctly handle memgraph destruction from a signal handler.
|
|
|
|
// Without having some sort of a flag, it is possible that a signal is handled
|
2018-01-12 22:17:04 +08:00
|
|
|
// when we are exiting main, inside destructors of database::GraphDb and
|
|
|
|
// similar. The signal handler may then initiate another shutdown on memgraph
|
|
|
|
// which is in half destructed state, causing invalid memory access and crash.
|
2017-10-31 16:49:33 +08:00
|
|
|
volatile sig_atomic_t is_shutting_down = 0;
|
|
|
|
|
2017-12-19 19:40:30 +08:00
|
|
|
// Registers the given shutdown function with the appropriate signal handlers.
|
|
|
|
// See implementation for details.
|
|
|
|
void InitSignalHandlers(const std::function<void()> &shutdown) {
|
2017-10-31 16:49:33 +08:00
|
|
|
// Prevent handling shutdown inside a shutdown. For example, SIGINT handler
|
|
|
|
// being interrupted by SIGTERM before is_shutting_down is set, thus causing
|
|
|
|
// double shutdown.
|
|
|
|
sigset_t block_shutdown_signals;
|
|
|
|
sigemptyset(&block_shutdown_signals);
|
|
|
|
sigaddset(&block_shutdown_signals, SIGTERM);
|
|
|
|
sigaddset(&block_shutdown_signals, SIGINT);
|
|
|
|
|
|
|
|
CHECK(SignalHandler::RegisterHandler(Signal::Terminate, shutdown,
|
|
|
|
block_shutdown_signals))
|
|
|
|
<< "Unable to register SIGTERM handler!";
|
|
|
|
CHECK(SignalHandler::RegisterHandler(Signal::Interupt, shutdown,
|
|
|
|
block_shutdown_signals))
|
|
|
|
<< "Unable to register SIGINT handler!";
|
2017-06-08 19:30:59 +08:00
|
|
|
|
2017-11-22 23:40:39 +08:00
|
|
|
// Setup SIGUSR1 to be used for reopening log files, when e.g. logrotate
|
|
|
|
// rotates our logs.
|
|
|
|
CHECK(SignalHandler::RegisterHandler(Signal::User1, []() {
|
|
|
|
google::CloseLogDestination(google::INFO);
|
|
|
|
})) << "Unable to register SIGUSR1 handler!";
|
2017-12-19 19:40:30 +08:00
|
|
|
}
|
2017-11-22 23:40:39 +08:00
|
|
|
|
2017-12-19 19:40:30 +08:00
|
|
|
void MasterMain() {
|
|
|
|
google::SetUsageMessage("Memgraph distributed master");
|
|
|
|
|
2018-01-12 22:17:04 +08:00
|
|
|
database::Master db;
|
|
|
|
SessionData session_data{db};
|
2018-01-15 21:03:07 +08:00
|
|
|
ServerT server({FLAGS_interface, static_cast<uint16_t>(FLAGS_port)},
|
2018-02-23 21:35:16 +08:00
|
|
|
session_data, false, "Bolt", FLAGS_num_workers);
|
2017-12-19 19:40:30 +08:00
|
|
|
|
|
|
|
// Handler for regular termination signals
|
2018-01-12 22:17:04 +08:00
|
|
|
auto shutdown = [&server] {
|
2017-12-19 19:40:30 +08:00
|
|
|
if (is_shutting_down) return;
|
|
|
|
is_shutting_down = 1;
|
|
|
|
// Server needs to be shutdown first and then the database. This prevents a
|
|
|
|
// race condition when a transaction is accepted during server shutdown.
|
|
|
|
server.Shutdown();
|
|
|
|
};
|
2018-01-10 20:56:12 +08:00
|
|
|
|
2017-12-19 19:40:30 +08:00
|
|
|
InitSignalHandlers(shutdown);
|
2018-01-10 20:56:12 +08:00
|
|
|
server.AwaitShutdown();
|
2017-12-19 19:40:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WorkerMain() {
|
|
|
|
google::SetUsageMessage("Memgraph distributed worker");
|
2018-01-12 22:17:04 +08:00
|
|
|
database::Worker db;
|
|
|
|
db.WaitForShutdown();
|
2017-12-19 19:40:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void SingleNodeMain() {
|
|
|
|
google::SetUsageMessage("Memgraph single-node database server");
|
2018-01-12 22:17:04 +08:00
|
|
|
database::SingleNode db;
|
|
|
|
SessionData session_data{db};
|
2018-01-15 21:03:07 +08:00
|
|
|
ServerT server({FLAGS_interface, static_cast<uint16_t>(FLAGS_port)},
|
2018-02-23 21:35:16 +08:00
|
|
|
session_data, false, "Bolt", FLAGS_num_workers);
|
2017-12-19 19:40:30 +08:00
|
|
|
|
|
|
|
// Handler for regular termination signals
|
2018-01-12 22:17:04 +08:00
|
|
|
auto shutdown = [&server] {
|
2017-12-19 19:40:30 +08:00
|
|
|
if (is_shutting_down) return;
|
|
|
|
is_shutting_down = 1;
|
|
|
|
// Server needs to be shutdown first and then the database. This prevents a
|
|
|
|
// race condition when a transaction is accepted during server shutdown.
|
|
|
|
server.Shutdown();
|
|
|
|
};
|
|
|
|
InitSignalHandlers(shutdown);
|
|
|
|
|
2018-01-10 20:56:12 +08:00
|
|
|
server.AwaitShutdown();
|
2017-12-19 19:40:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
gflags::SetVersionString(version_string);
|
|
|
|
|
|
|
|
// Load config before parsing arguments, so that flags from the command line
|
|
|
|
// overwrite the config.
|
|
|
|
LoadConfig();
|
|
|
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
|
|
|
|
|
|
|
google::InitGoogleLogging(argv[0]);
|
|
|
|
google::SetLogDestination(google::INFO, FLAGS_log_file.c_str());
|
|
|
|
google::SetLogSymlink(google::INFO, FLAGS_log_link_basename.c_str());
|
|
|
|
|
|
|
|
// Unhandled exception handler init.
|
|
|
|
std::set_terminate(&terminate_handler);
|
2017-01-23 19:02:11 +08:00
|
|
|
|
2018-02-16 22:35:39 +08:00
|
|
|
std::string stats_prefix;
|
|
|
|
if (FLAGS_master) {
|
|
|
|
stats_prefix = "master";
|
|
|
|
} else if (FLAGS_worker) {
|
|
|
|
stats_prefix = fmt::format("worker-{}", FLAGS_worker_id);
|
|
|
|
} else {
|
|
|
|
stats_prefix = "memgraph";
|
|
|
|
}
|
|
|
|
stats::InitStatsLogging(stats_prefix);
|
2018-02-15 23:28:38 +08:00
|
|
|
utils::OnScopeExit stop_stats([] { stats::StopStatsLogging(); });
|
2018-02-02 18:11:06 +08:00
|
|
|
|
2018-02-23 21:35:16 +08:00
|
|
|
// Start memory warning logger.
|
|
|
|
Scheduler mem_log_scheduler;
|
|
|
|
if (FLAGS_memory_warning_threshold > 0) {
|
|
|
|
mem_log_scheduler.Run("Memory warning", std::chrono::seconds(3), [] {
|
|
|
|
auto free_ram_mb = utils::AvailableMem() / 1024;
|
|
|
|
if (free_ram_mb < FLAGS_memory_warning_threshold)
|
|
|
|
LOG(WARNING) << "Running out of available RAM, only " << free_ram_mb
|
|
|
|
<< " MB left.";
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-19 19:40:30 +08:00
|
|
|
CHECK(!(FLAGS_master && FLAGS_worker))
|
|
|
|
<< "Can't run Memgraph as worker and master at the same time";
|
|
|
|
if (FLAGS_master)
|
|
|
|
MasterMain();
|
|
|
|
else if (FLAGS_worker)
|
|
|
|
WorkerMain();
|
|
|
|
else
|
|
|
|
SingleNodeMain();
|
2017-10-09 16:53:03 +08:00
|
|
|
return 0;
|
2016-08-01 01:58:12 +08:00
|
|
|
}
|