Merge branch 'nghttpx-reload'

This commit is contained in:
Tatsuhiro Tsujikawa 2016-07-31 21:03:13 +09:00
commit fb3d6f68a8
9 changed files with 569 additions and 193 deletions

View File

@ -49,6 +49,9 @@ SIGQUIT
accepting connection. After all connections are handled, nghttpx accepting connection. After all connections are handled, nghttpx
exits. exits.
SIGHUP
Reload configuration file given in :option:`--conf`.
SIGUSR1 SIGUSR1
Reopen log files. Reopen log files.
@ -56,7 +59,11 @@ SIGUSR2
Fork and execute nghttpx. It will execute the binary in the same Fork and execute nghttpx. It will execute the binary in the same
path with same command-line arguments and environment variables. path with same command-line arguments and environment variables.
After new process comes up, sending SIGQUIT to the original process After new process comes up, sending SIGQUIT to the original process
to perform hot swapping. to perform hot swapping. The difference between SIGUSR2 + SIGQUIT
and SIGHUP is that former is usually used to execute new binary, and
the master process is newly spawned. On the other hand, the latter
just reloads configuration file, and the same master process
continues to exist.
.. note:: .. note::

View File

@ -236,6 +236,9 @@ all existing frontend connections are done, the current process will
exit. At this point, only new nghttpx process exists and serves exit. At this point, only new nghttpx process exists and serves
incoming requests. incoming requests.
If you want to just reload configuration file without executing new
binary, send SIGHUP to nghttpx master process.
Re-opening log files Re-opening log files
-------------------- --------------------

File diff suppressed because it is too large Load Diff

View File

@ -60,16 +60,44 @@
namespace shrpx { namespace shrpx {
namespace { namespace {
Config *config = nullptr; std::unique_ptr<Config> config;
} // namespace } // namespace
constexpr auto SHRPX_UNIX_PATH_PREFIX = StringRef::from_lit("unix:"); constexpr auto SHRPX_UNIX_PATH_PREFIX = StringRef::from_lit("unix:");
const Config *get_config() { return config; } const Config *get_config() { return config.get(); }
Config *mod_config() { return config; } Config *mod_config() { return config.get(); }
void create_config() { config = new Config(); } std::unique_ptr<Config> replace_config(std::unique_ptr<Config> another) {
config.swap(another);
return another;
}
void create_config() { config = make_unique<Config>(); }
Config::~Config() {
auto &upstreamconf = http2.upstream;
nghttp2_option_del(upstreamconf.option);
nghttp2_option_del(upstreamconf.alt_mode_option);
nghttp2_session_callbacks_del(upstreamconf.callbacks);
auto &downstreamconf = http2.downstream;
nghttp2_option_del(downstreamconf.option);
nghttp2_session_callbacks_del(downstreamconf.callbacks);
auto &dumpconf = http2.upstream.debug.dump;
if (dumpconf.request_header) {
fclose(dumpconf.request_header);
}
if (dumpconf.response_header) {
fclose(dumpconf.response_header);
}
}
TicketKeys::~TicketKeys() { TicketKeys::~TicketKeys() {
/* Erase keys from memory */ /* Erase keys from memory */
@ -2398,7 +2426,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
} }
included_set.insert(optarg); included_set.insert(optarg);
auto rv = load_config(optarg.c_str(), included_set); auto rv = load_config(config, optarg.c_str(), included_set);
included_set.erase(optarg); included_set.erase(optarg);
if (rv != 0) { if (rv != 0) {
@ -2648,7 +2676,8 @@ int parse_config(Config *config, int optid, const StringRef &opt,
return -1; return -1;
} }
int load_config(const char *filename, std::set<StringRef> &include_set) { int load_config(Config *config, const char *filename,
std::set<StringRef> &include_set) {
std::ifstream in(filename, std::ios::binary); std::ifstream in(filename, std::ios::binary);
if (!in) { if (!in) {
LOG(ERROR) << "Could not open config file " << filename; LOG(ERROR) << "Could not open config file " << filename;
@ -2669,7 +2698,7 @@ int load_config(const char *filename, std::set<StringRef> &include_set) {
} }
*eq = '\0'; *eq = '\0';
if (parse_config(mod_config(), StringRef{std::begin(line), eq}, if (parse_config(config, StringRef{std::begin(line), eq},
StringRef{eq + 1, std::end(line)}, include_set) != 0) { StringRef{eq + 1, std::end(line)}, include_set) != 0) {
return -1; return -1;
} }

View File

@ -706,6 +706,8 @@ struct APIConfig {
}; };
struct Config { struct Config {
~Config();
HttpProxy downstream_http_proxy; HttpProxy downstream_http_proxy;
HttpConfig http; HttpConfig http;
Http2Config http2; Http2Config http2;
@ -717,13 +719,9 @@ struct Config {
ImmutableString conf_path; ImmutableString conf_path;
ImmutableString user; ImmutableString user;
ImmutableString mruby_file; ImmutableString mruby_file;
char **original_argv;
char **argv;
char *cwd;
size_t num_worker; size_t num_worker;
size_t padding; size_t padding;
size_t rlimit_nofile; size_t rlimit_nofile;
int argc;
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
pid_t pid; pid_t pid;
@ -736,6 +734,9 @@ struct Config {
const Config *get_config(); const Config *get_config();
Config *mod_config(); Config *mod_config();
// Replaces the current config with given |new_config|. The old config is
// returned.
std::unique_ptr<Config> replace_config(std::unique_ptr<Config> new_config);
void create_config(); void create_config();
// generated by gennghttpxfun.py // generated by gennghttpxfun.py
@ -890,10 +891,11 @@ int parse_config(Config *config, const StringRef &opt, const StringRef &optarg,
int parse_config(Config *config, int optid, const StringRef &opt, int parse_config(Config *config, int optid, const StringRef &opt,
const StringRef &optarg, std::set<StringRef> &included_set); const StringRef &optarg, std::set<StringRef> &included_set);
// Loads configurations from |filename| and stores them in statically // Loads configurations from |filename| and stores them in |config|.
// allocated Config object. This function returns 0 if it succeeds, or // This function returns 0 if it succeeds, or -1. See parse_config()
// -1. See parse_config() for |include_set|. // for |include_set|.
int load_config(const char *filename, std::set<StringRef> &include_set); int load_config(Config *config, const char *filename,
std::set<StringRef> &include_set);
// Parses header field in |optarg|. We expect header field is formed // Parses header field in |optarg|. We expect header field is formed
// like "NAME: VALUE". We require that NAME is non empty string. ":" // like "NAME: VALUE". We require that NAME is non empty string. ":"

View File

@ -114,8 +114,9 @@ constexpr auto master_proc_ign_signals = std::array<int, 1>{{SIGPIPE}};
} // namespace } // namespace
namespace { namespace {
constexpr auto worker_proc_ign_signals = std::array<int, 4>{ constexpr auto worker_proc_ign_signals =
{REOPEN_LOG_SIGNAL, EXEC_BINARY_SIGNAL, GRACEFUL_SHUTDOWN_SIGNAL, SIGPIPE}}; std::array<int, 5>{{REOPEN_LOG_SIGNAL, EXEC_BINARY_SIGNAL,
GRACEFUL_SHUTDOWN_SIGNAL, RELOAD_SIGNAL, SIGPIPE}};
} // namespace } // namespace
void shrpx_signal_set_master_proc_ign_handler() { void shrpx_signal_set_master_proc_ign_handler() {

View File

@ -34,6 +34,7 @@ namespace shrpx {
constexpr int REOPEN_LOG_SIGNAL = SIGUSR1; constexpr int REOPEN_LOG_SIGNAL = SIGUSR1;
constexpr int EXEC_BINARY_SIGNAL = SIGUSR2; constexpr int EXEC_BINARY_SIGNAL = SIGUSR2;
constexpr int GRACEFUL_SHUTDOWN_SIGNAL = SIGQUIT; constexpr int GRACEFUL_SHUTDOWN_SIGNAL = SIGQUIT;
constexpr int RELOAD_SIGNAL = SIGHUP;
// Blocks all signals. The previous signal mask is stored into // Blocks all signals. The previous signal mask is stored into
// |oldset| if it is not nullptr. This function returns 0 if it // |oldset| if it is not nullptr. This function returns 0 if it

View File

@ -94,16 +94,14 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
} }
} // namespace } // namespace
// This function is meant be called from master process, hence the int set_alpn_prefs(std::vector<unsigned char> &out,
// call exit(3). const std::vector<std::string> &protos) {
std::vector<unsigned char>
set_alpn_prefs(const std::vector<std::string> &protos) {
size_t len = 0; size_t len = 0;
for (const auto &proto : protos) { for (const auto &proto : protos) {
if (proto.size() > 255) { if (proto.size() > 255) {
LOG(FATAL) << "Too long ALPN identifier: " << proto.size(); LOG(FATAL) << "Too long ALPN identifier: " << proto.size();
exit(EXIT_FAILURE); return -1;
} }
len += 1 + proto.size(); len += 1 + proto.size();
@ -111,10 +109,10 @@ set_alpn_prefs(const std::vector<std::string> &protos) {
if (len > (1 << 16) - 1) { if (len > (1 << 16) - 1) {
LOG(FATAL) << "Too long ALPN identifier list: " << len; LOG(FATAL) << "Too long ALPN identifier list: " << len;
exit(EXIT_FAILURE); return -1;
} }
auto out = std::vector<unsigned char>(len); out.resize(len);
auto ptr = out.data(); auto ptr = out.data();
for (const auto &proto : protos) { for (const auto &proto : protos) {
@ -123,7 +121,7 @@ set_alpn_prefs(const std::vector<std::string> &protos) {
ptr += proto.size(); ptr += proto.size();
} }
return out; return 0;
} }
namespace { namespace {

View File

@ -181,8 +181,8 @@ bool check_http2_requirement(SSL *ssl);
// passed to SSL_CTX_set_options(). // passed to SSL_CTX_set_options().
long int create_tls_proto_mask(const std::vector<std::string> &tls_proto_list); long int create_tls_proto_mask(const std::vector<std::string> &tls_proto_list);
std::vector<unsigned char> int set_alpn_prefs(std::vector<unsigned char> &out,
set_alpn_prefs(const std::vector<std::string> &protos); const std::vector<std::string> &protos);
// Setups server side SSL_CTX. This function inspects get_config() // Setups server side SSL_CTX. This function inspects get_config()
// and if upstream_no_tls is true, returns nullptr. Otherwise // and if upstream_no_tls is true, returns nullptr. Otherwise