diff --git a/CHANGELOG b/CHANGELOG index 92628582d9..f8c51c336c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,10 @@ Release 6.0.25 (Not yet released) * [Standalone] Adds a config option to specify the stop timeout for Passenger: `--stop-timeout 120` or `PASSENGER_STOP_TIMEOUT=120`. * [Standalone] Changes Passenger's (not apps') start timeout to 25s (from 15s), stop timeouts default to 60s. * [Ruby] Fixes an issue where Bundler would try to re-exec the process name instead of the script. Closes GH-2567 and GH-2577. + * [Enterprise] Adds a temporary flag to allow reverting to previous routing behaviour, in order to mitigate possible performance regressions, this flag will become a no-op and eventually removed once the routing issues have been fixed. Closes GH-2579. + - Apache: PassengerOldRouting on + - Nginx: passenger_old_routing on; + - Standalone: --old-routing * Updated various library versions used in precompiled binaries (used for e.g. gem installs): - cmake: 3.31.2 -> 3.31.3 - curl: 8.11.0 -> 8.11.1 diff --git a/dev/configkit-schemas/index.json b/dev/configkit-schemas/index.json index a8d971f27d..946de35f10 100644 --- a/dev/configkit-schemas/index.json +++ b/dev/configkit-schemas/index.json @@ -302,6 +302,12 @@ "read_only" : true, "type" : "boolean" }, + "old_routing" : { + "default_value" : false, + "has_default_value" : "static", + "read_only" : true, + "type" : "boolean" + }, "request_freelist_limit" : { "default_value" : 1024, "has_default_value" : "static", @@ -806,6 +812,12 @@ "read_only" : true, "type" : "boolean" }, + "old_routing" : { + "default_value" : false, + "has_default_value" : "static", + "read_only" : true, + "type" : "boolean" + }, "oom_score" : { "read_only" : true, "type" : "string" @@ -1690,6 +1702,12 @@ "read_only" : true, "type" : "boolean" }, + "old_routing" : { + "default_value" : false, + "has_default_value" : "static", + "read_only" : true, + "type" : "boolean" + }, "passenger_root" : { "read_only" : true, "required" : true, diff --git a/resources/templates/standalone/http.erb b/resources/templates/standalone/http.erb index 7511c9013c..844c3d0a6d 100644 --- a/resources/templates/standalone/http.erb +++ b/resources/templates/standalone/http.erb @@ -32,6 +32,7 @@ passenger_user_switching off; <%= nginx_http_option(:pool_idle_time) %> <%= nginx_http_option(:max_preloader_idle_time) %> <%= nginx_http_option(:turbocaching) %> +<%= nginx_http_option(:old_routing) %> <%= nginx_http_option(:instance_registry_dir) %> <%= nginx_http_option(:spawn_dir) %> <%= nginx_http_option(:disable_security_update_check) %> diff --git a/src/agent/Core/ApplicationPool/Context.h b/src/agent/Core/ApplicationPool/Context.h index 0d761ca664..658fa5fc80 100644 --- a/src/agent/Core/ApplicationPool/Context.h +++ b/src/agent/Core/ApplicationPool/Context.h @@ -61,6 +61,8 @@ struct Context { boost::object_pool processObjectPool; mutable boost::mutex agentConfigSyncher; + // Whether to use the old routing algorithm + bool oldRouting; /****** Dependencies ******/ @@ -68,9 +70,10 @@ struct Context { Json::Value agentConfig; - Context() + Context(bool _oldRouting) : sessionObjectPool(64, 1024), - processObjectPool(4, 64) + processObjectPool(4, 64), + oldRouting(_oldRouting) { } void finalize() { diff --git a/src/agent/Core/ApplicationPool/Group.h b/src/agent/Core/ApplicationPool/Group.h index 34b556782f..f7b5ac16ba 100644 --- a/src/agent/Core/ApplicationPool/Group.h +++ b/src/agent/Core/ApplicationPool/Group.h @@ -27,8 +27,6 @@ #define _PASSENGER_APPLICATION_POOL2_GROUP_H_ #include -#include -#include #include #include #include @@ -202,7 +200,6 @@ class Group: public boost::enable_shared_from_this { Callback shutdownCallback; GroupPtr selfPointer; - /****** Initialization and shutdown ******/ static ApiKey generateApiKey(const Pool *pool); @@ -233,9 +230,13 @@ class Group: public boost::enable_shared_from_this { /****** Process list management ******/ Process *findProcessWithStickySessionId(unsigned int id) const; + Process *findProcessWithStickySessionIdOrLowestBusyness(unsigned int id) const; + Process *findProcessWithLowestBusyness(const ProcessList &processes) const; + Process *findEnabledProcessWithLowestBusyness() const; Process *findBestProcessPreferringStickySessionId(unsigned int id) const; Process *findBestProcess(const ProcessList &processes) const; Process *findBestEnabledProcess() const; + bool useNewRouting() const; void addProcessToList(const ProcessPtr &process, ProcessList &destination); void removeProcessFromList(const ProcessPtr &process, ProcessList &source); diff --git a/src/agent/Core/ApplicationPool/Group/ProcessListManagement.cpp b/src/agent/Core/ApplicationPool/Group/ProcessListManagement.cpp index fdded156a1..21ac00fa94 100644 --- a/src/agent/Core/ApplicationPool/Group/ProcessListManagement.cpp +++ b/src/agent/Core/ApplicationPool/Group/ProcessListManagement.cpp @@ -63,6 +63,73 @@ Group::findProcessWithStickySessionId(unsigned int id) const { return NULL; } +Process * +Group::findProcessWithStickySessionIdOrLowestBusyness(unsigned int id) const { + int leastBusyProcessIndex = -1; + int lowestBusyness = 0; + unsigned int i, size = enabledProcessBusynessLevels.size(); + const int *enabledProcessBusynessLevels = &this->enabledProcessBusynessLevels[0]; + for (i = 0; i < size; i++) { + Process *process = enabledProcesses[i].get(); + if (process->getStickySessionId() == id) { + return process; + } else if (leastBusyProcessIndex == -1 || enabledProcessBusynessLevels[i] < lowestBusyness) { + leastBusyProcessIndex = i; + lowestBusyness = enabledProcessBusynessLevels[i]; + } + } + + if (leastBusyProcessIndex == -1) { + return NULL; + } else { + return enabledProcesses[leastBusyProcessIndex].get(); + } +} + +Process * +Group::findProcessWithLowestBusyness(const ProcessList &processes) const { + if (processes.empty()) { + return NULL; + } + + int lowestBusyness = -1; + Process *leastBusyProcess = NULL; + ProcessList::const_iterator it; + ProcessList::const_iterator end = processes.end(); + for (it = processes.begin(); it != end; it++) { + Process *process = (*it).get(); + int busyness = process->busyness(); + if (lowestBusyness == -1 || lowestBusyness > busyness) { + lowestBusyness = busyness; + leastBusyProcess = process; + } + } + return leastBusyProcess; +} + +/** + * Cache-optimized version of findProcessWithLowestBusyness() for the common case. + */ +Process * +Group::findEnabledProcessWithLowestBusyness() const { + if (enabledProcesses.empty()) { + return NULL; + } + + int leastBusyProcessIndex = -1; + int lowestBusyness = 0; + unsigned int i, size = enabledProcessBusynessLevels.size(); + const int *enabledProcessBusynessLevels = &this->enabledProcessBusynessLevels[0]; + + for (i = 0; i < size; i++) { + if (leastBusyProcessIndex == -1 || enabledProcessBusynessLevels[i] < lowestBusyness) { + leastBusyProcessIndex = i; + lowestBusyness = enabledProcessBusynessLevels[i]; + } + } + return enabledProcesses[leastBusyProcessIndex].get(); +} + /** * Return the process with the given sticky session ID if it exists. * If not, then find the "best" enabled process to route a request to, diff --git a/src/agent/Core/ApplicationPool/Group/SessionManagement.cpp b/src/agent/Core/ApplicationPool/Group/SessionManagement.cpp index 41dd73e874..56c50b3514 100644 --- a/src/agent/Core/ApplicationPool/Group/SessionManagement.cpp +++ b/src/agent/Core/ApplicationPool/Group/SessionManagement.cpp @@ -30,7 +30,6 @@ #include #endif #include -#include /************************************************************************* * @@ -63,9 +62,14 @@ using namespace boost; */ Group::RouteResult Group::route(const Options &options) const { + Process *process = nullptr; if (OXT_LIKELY(enabledCount > 0)) { if (options.stickySessionId == 0) { - Process *process = findBestProcess(enabledProcesses); + if (OXT_LIKELY(useNewRouting())) { + process = findBestProcess(enabledProcesses); + } else { + process = findEnabledProcessWithLowestBusyness(); + } if (process != nullptr) { assert(process->canBeRoutedTo()); return RouteResult(process); @@ -73,8 +77,11 @@ Group::route(const Options &options) const { return RouteResult(NULL, true); } } else { - Process *process = findBestProcessPreferringStickySessionId( - options.stickySessionId); + if (OXT_LIKELY(useNewRouting())) { + process = findBestProcessPreferringStickySessionId(options.stickySessionId); + }else{ + process = findProcessWithStickySessionIdOrLowestBusyness(options.stickySessionId); + } if (process != nullptr) { if (process->canBeRoutedTo()) { return RouteResult(process); @@ -86,7 +93,11 @@ Group::route(const Options &options) const { } } } else { - Process *process = findBestProcess(disablingProcesses); + if (OXT_LIKELY(useNewRouting())) { + process = findBestProcess(disablingProcesses); + } else { + process = findProcessWithLowestBusyness(disablingProcesses); + } if (process != nullptr) { assert(process->canBeRoutedTo()); return RouteResult(process); @@ -313,7 +324,12 @@ Group::get(const Options &newOptions, const GetCallback &callback, assert(m_spawning || restarting() || poolAtFullCapacity()); if (disablingCount > 0 && !restarting()) { - Process *process = findBestProcess(disablingProcesses); + Process *process = nullptr; + if (OXT_LIKELY(useNewRouting())) { + process = findBestProcess(disablingProcesses); + } else { + process = findProcessWithLowestBusyness(disablingProcesses); + } if (process != nullptr && !process->isTotallyBusy()) { return newSession(process, newOptions.currentTime); } @@ -341,6 +357,10 @@ Group::get(const Options &newOptions, const GetCallback &callback, } } +bool +Group::useNewRouting() const { + return !pool->context->oldRouting; +} } // namespace ApplicationPool2 } // namespace Passenger diff --git a/src/agent/Core/ApplicationPool/Options.h b/src/agent/Core/ApplicationPool/Options.h index c3f82a877b..c14333ac00 100644 --- a/src/agent/Core/ApplicationPool/Options.h +++ b/src/agent/Core/ApplicationPool/Options.h @@ -28,7 +28,6 @@ #include #include -#include #include #include #include @@ -79,7 +78,7 @@ class Options { template static vector getStringFields(OptionsClass &options) { vector result; - result.reserve(20); + result.reserve(30); result.push_back(&options.appRoot); result.push_back(&options.appGroupName); diff --git a/src/agent/Core/Config.h b/src/agent/Core/Config.h index 36f750c2f6..3bec70d7cc 100644 --- a/src/agent/Core/Config.h +++ b/src/agent/Core/Config.h @@ -155,6 +155,7 @@ using namespace std; * max_instances_per_app unsigned integer - read_only * max_pool_size unsigned integer - default(6) * multi_app boolean - default(false),read_only + * old_routing boolean - default(false),read_only * oom_score string - read_only * passenger_root string required read_only * pid_file string - read_only diff --git a/src/agent/Core/Controller/Config.h b/src/agent/Core/Controller/Config.h index bc61ba2f21..0af64e6129 100644 --- a/src/agent/Core/Controller/Config.h +++ b/src/agent/Core/Controller/Config.h @@ -115,6 +115,7 @@ parseControllerBenchmarkMode(const StaticString &mode) { * max_instances_per_app unsigned integer - read_only * min_spare_clients unsigned integer - default(0) * multi_app boolean - default(true),read_only + * old_routing boolean - default(false),read_only * request_freelist_limit unsigned integer - default(1024) * response_buffer_high_watermark unsigned integer - default(134217728) * server_software string - default("Phusion_Passenger/6.0.25") @@ -138,6 +139,7 @@ class ControllerSchema: public ServerKit::HttpServerSchema { add("thread_number", UINT_TYPE, REQUIRED | READ_ONLY); add("multi_app", BOOL_TYPE, OPTIONAL | READ_ONLY, true); add("turbocaching", BOOL_TYPE, OPTIONAL | READ_ONLY, true); + add("old_routing", BOOL_TYPE, OPTIONAL | READ_ONLY, false); add("integration_mode", STRING_TYPE, OPTIONAL | READ_ONLY, DEFAULT_INTEGRATION_MODE); add("user_switching", BOOL_TYPE, OPTIONAL, true); @@ -349,6 +351,7 @@ class ControllerMainConfig { bool userSwitching: 1; bool defaultStickySessions: 1; bool gracefulExit: 1; + bool oldRouting: 1; /*******************/ /*******************/ @@ -366,7 +369,8 @@ class ControllerMainConfig { singleAppMode(!config["multi_app"].asBool()), userSwitching(config["user_switching"].asBool()), defaultStickySessions(config["default_sticky_sessions"].asBool()), - gracefulExit(config["graceful_exit"].asBool()) + gracefulExit(config["graceful_exit"].asBool()), + oldRouting(config["old_routing"].asBool()) /*******************/ { @@ -396,6 +400,7 @@ class ControllerMainConfig { SWAP_BITFIELD(bool, userSwitching); SWAP_BITFIELD(bool, defaultStickySessions); SWAP_BITFIELD(bool, gracefulExit); + SWAP_BITFIELD(bool, oldRouting); /*******************/ diff --git a/src/agent/Core/Controller/InitRequest.cpp b/src/agent/Core/Controller/InitRequest.cpp index e6e3b859f4..002fd0f1c5 100644 --- a/src/agent/Core/Controller/InitRequest.cpp +++ b/src/agent/Core/Controller/InitRequest.cpp @@ -206,7 +206,6 @@ Controller::fillPoolOptionsFromConfigCaches(Options &options, options.statThrottleRate = mainConfig.statThrottleRate; options.maxRequests = requestConfig->defaultMaxRequests; options.stickySessionsCookieAttributes = requestConfig->defaultStickySessionsCookieAttributes; - /******************************/ } diff --git a/src/agent/Core/CoreMain.cpp b/src/agent/Core/CoreMain.cpp index 7743b837f3..9594201e74 100644 --- a/src/agent/Core/CoreMain.cpp +++ b/src/agent/Core/CoreMain.cpp @@ -719,7 +719,7 @@ initializeNonPrivilegedWorkingObjects() { wo->spawningKitContext->finalize(); UPDATE_TRACE_POINT(); - wo->appPoolContext = boost::make_shared(); + wo->appPoolContext = boost::make_shared(coreConfig->get("old_routing").asBool()); wo->appPoolContext->spawningKitFactory = boost::make_shared( wo->spawningKitContext.get()); wo->appPoolContext->agentConfig = coreConfig->inspectEffectiveValues(); diff --git a/src/agent/Core/OptionParser.h b/src/agent/Core/OptionParser.h index 772bfbc43f..d8d02453fd 100644 --- a/src/agent/Core/OptionParser.h +++ b/src/agent/Core/OptionParser.h @@ -181,6 +181,8 @@ coreUsage() { printf(" Vary the turbocache by the cookie of the given name\n"); printf(" --disable-turbocaching\n"); printf(" Disable turbocaching\n"); + printf(" --old-routing\n"); + printf(" Revert to old routing algorithm\n"); printf(" --no-abort-websockets-on-process-shutdown\n"); printf(" Do not abort WebSocket connections on process\n"); printf(" shutdown or restart\n"); @@ -366,6 +368,9 @@ parseCoreOption(int argc, const char *argv[], int &i, Json::Value &updates) { } else if (p.isFlag(argv[i], '\0', "--disable-turbocaching")) { updates["turbocaching"] = false; i++; + } else if (p.isFlag(argv[i], '\0', "--old-routing")) { + updates["old_routing"] = true; + i++; } else if (p.isFlag(argv[i], '\0', "--no-abort-websockets-on-process-shutdown")) { updates["default_abort_websockets_on_process_shutdown"] = false; i++; diff --git a/src/agent/Watchdog/Config.h b/src/agent/Watchdog/Config.h index 1e0d36f0fa..ad6cd17b75 100644 --- a/src/agent/Watchdog/Config.h +++ b/src/agent/Watchdog/Config.h @@ -144,6 +144,7 @@ using namespace std; * max_instances_per_app unsigned integer - read_only * max_pool_size unsigned integer - default(6) * multi_app boolean - default(false),read_only + * old_routing boolean - default(false),read_only * passenger_root string required read_only * pidfiles_to_delete_on_exit array of strings - default([]) * pool_idle_time unsigned integer - default(300) diff --git a/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp b/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp index 81b3299054..09aa03f0e7 100644 --- a/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +++ b/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp @@ -332,6 +332,11 @@ extern "C" const command_rec passenger_commands[] = { NULL, RSRC_CONF | ACCESS_CONF, "The Node.js command to use."), + AP_INIT_FLAG("PassengerOldRouting", + (FlagFunc) cmd_passenger_old_routing, + NULL, + RSRC_CONF, + "Whether to revert to old routing behaviour in Phusion Passenger(R)."), AP_INIT_TAKE1("PassengerPoolIdleTime", (Take1Func) cmd_passenger_pool_idle_time, NULL, diff --git a/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp b/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp index b1a5bb7db2..9e3c5e259e 100644 --- a/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +++ b/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp @@ -108,6 +108,11 @@ ConfigManifestGenerator::autoGenerated_setGlobalConfigDefaults() { "PassengerMaxPoolSize", DEFAULT_MAX_POOL_SIZE); + addOptionsContainerStaticDefaultBool( + globalConfigContainer, + "PassengerOldRouting", + false); + addOptionsContainerStaticDefaultInt( globalConfigContainer, "PassengerPoolIdleTime", diff --git a/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp b/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp index d3df9e70c1..5ceba174c7 100644 --- a/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp +++ b/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp @@ -715,6 +715,21 @@ cmd_passenger_nodejs(cmd_parms *cmd, void *pcfg, const char *arg) { return NULL; } +static const char * +cmd_passenger_old_routing(cmd_parms *cmd, void *pcfg, const char *arg) { + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); + if (err != NULL) { + ap_log_perror(APLOG_MARK, APLOG_STARTUP, 0, cmd->temp_pool, + "WARNING: %s", err); + } + + serverConfig.oldRoutingSourceFile = cmd->directive->filename; + serverConfig.oldRoutingSourceLine = cmd->directive->line_num; + serverConfig.oldRoutingExplicitlySet = true; + serverConfig.oldRouting = arg != NULL; + return NULL; +} + static const char * cmd_passenger_pool_idle_time(cmd_parms *cmd, void *pcfg, const char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); diff --git a/src/apache2_module/Hooks.cpp b/src/apache2_module/Hooks.cpp index b5a6555e1e..d578de8572 100644 --- a/src/apache2_module/Hooks.cpp +++ b/src/apache2_module/Hooks.cpp @@ -1380,6 +1380,7 @@ class Hooks { config["response_buffer_high_watermark"] = serverConfig.responseBufferHighWatermark; config["stat_throttle_rate"] = serverConfig.statThrottleRate; config["turbocaching"] = serverConfig.turbocaching; + config["old_routing"] = serverConfig.oldRouting; config["prestart_urls"] = strsetToJson(serverConfig.prestartURLs); config["admin_panel_url"] = nonEmptyString(serverConfig.adminPanelUrl); config["admin_panel_auth_type"] = nonEmptyString(serverConfig.adminPanelAuthType); diff --git a/src/apache2_module/ServerConfig/AutoGeneratedManifestGeneration.cpp b/src/apache2_module/ServerConfig/AutoGeneratedManifestGeneration.cpp index 37891b5737..02913d25f0 100644 --- a/src/apache2_module/ServerConfig/AutoGeneratedManifestGeneration.cpp +++ b/src/apache2_module/ServerConfig/AutoGeneratedManifestGeneration.cpp @@ -244,6 +244,15 @@ ConfigManifestGenerator::autoGenerated_generateConfigManifestForServerConfig() { serverConfig.maxPoolSizeSourceLine); hierarchyMember["value"] = serverConfig.maxPoolSize; } + if (serverConfig.oldRoutingExplicitlySet) { + Json::Value &optionContainer = findOrCreateOptionContainer(globalOptionsContainer, + "PassengerOldRouting", + sizeof("PassengerOldRouting") - 1); + Json::Value &hierarchyMember = addOptionContainerHierarchyMember(optionContainer, + serverConfig.oldRoutingSourceFile, + serverConfig.oldRoutingSourceLine); + hierarchyMember["value"] = serverConfig.oldRouting == Apache2Module::ENABLED; + } if (serverConfig.poolIdleTimeExplicitlySet) { Json::Value &optionContainer = findOrCreateOptionContainer(globalOptionsContainer, "PassengerPoolIdleTime", diff --git a/src/apache2_module/ServerConfig/AutoGeneratedStruct.h b/src/apache2_module/ServerConfig/AutoGeneratedStruct.h index a9c44f087f..b44efcc465 100644 --- a/src/apache2_module/ServerConfig/AutoGeneratedStruct.h +++ b/src/apache2_module/ServerConfig/AutoGeneratedStruct.h @@ -73,6 +73,11 @@ struct AutoGeneratedServerConfig { */ bool disableSecurityUpdateCheck; + /* + * Whether to revert to old routing behaviour in Phusion Passenger(R). + */ + bool oldRouting; + /* * Whether to show the Phusion Passenger(R) version number in the X-Powered-By header. */ @@ -212,6 +217,7 @@ struct AutoGeneratedServerConfig { StaticString disableAnonymousTelemetrySourceFile; StaticString disableLogPrefixSourceFile; StaticString disableSecurityUpdateCheckSourceFile; + StaticString oldRoutingSourceFile; StaticString showVersionInHeaderSourceFile; StaticString turbocachingSourceFile; StaticString userSwitchingSourceFile; @@ -243,6 +249,7 @@ struct AutoGeneratedServerConfig { unsigned int disableAnonymousTelemetrySourceLine; unsigned int disableLogPrefixSourceLine; unsigned int disableSecurityUpdateCheckSourceLine; + unsigned int oldRoutingSourceLine; unsigned int showVersionInHeaderSourceLine; unsigned int turbocachingSourceLine; unsigned int userSwitchingSourceLine; @@ -274,6 +281,7 @@ struct AutoGeneratedServerConfig { bool disableAnonymousTelemetryExplicitlySet: 1; bool disableLogPrefixExplicitlySet: 1; bool disableSecurityUpdateCheckExplicitlySet: 1; + bool oldRoutingExplicitlySet: 1; bool showVersionInHeaderExplicitlySet: 1; bool turbocachingExplicitlySet: 1; bool userSwitchingExplicitlySet: 1; @@ -307,6 +315,7 @@ struct AutoGeneratedServerConfig { disableAnonymousTelemetry = false; disableLogPrefix = false; disableSecurityUpdateCheck = false; + oldRouting = false; showVersionInHeader = true; turbocaching = true; userSwitching = true; @@ -368,6 +377,7 @@ struct AutoGeneratedServerConfig { disableAnonymousTelemetrySourceLine = 0; disableLogPrefixSourceLine = 0; disableSecurityUpdateCheckSourceLine = 0; + oldRoutingSourceLine = 0; showVersionInHeaderSourceLine = 0; turbocachingSourceLine = 0; userSwitchingSourceLine = 0; @@ -399,6 +409,7 @@ struct AutoGeneratedServerConfig { disableAnonymousTelemetryExplicitlySet = false; disableLogPrefixExplicitlySet = false; disableSecurityUpdateCheckExplicitlySet = false; + oldRoutingExplicitlySet = false; showVersionInHeaderExplicitlySet = false; turbocachingExplicitlySet = false; userSwitchingExplicitlySet = false; diff --git a/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c b/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c index a60844f808..dc257af264 100644 --- a/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +++ b/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c @@ -190,6 +190,14 @@ offsetof(passenger_main_conf_t, autogenerated.turbocaching), NULL }, +{ + ngx_string("passenger_old_routing"), + NGX_HTTP_MAIN_CONF | NGX_CONF_FLAG, + passenger_conf_set_old_routing, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(passenger_main_conf_t, autogenerated.old_routing), + NULL +}, { ngx_string("passenger_user_switching"), NGX_HTTP_MAIN_CONF | NGX_CONF_FLAG, diff --git a/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c b/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c index 24206e5362..e39823fb8a 100644 --- a/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +++ b/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c @@ -119,6 +119,12 @@ set_manifest_autogenerated_global_conf_defaults(manifest_gen_ctx_t *ctx) { sizeof("passenger_turbocaching") - 1, 1); + add_manifest_options_container_static_default_bool(ctx, + ctx->global_config_container, + "passenger_old_routing", + sizeof("passenger_old_routing") - 1, + 0); + add_manifest_options_container_static_default_bool(ctx, ctx->global_config_container, "passenger_user_switching", diff --git a/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c b/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c index 8762c6a63b..e99e5a6711 100644 --- a/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +++ b/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c @@ -301,6 +301,18 @@ passenger_conf_set_turbocaching(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return ngx_conf_set_flag_slot(cf, cmd, conf); } +static char * +passenger_conf_set_old_routing(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + passenger_main_conf_t *passenger_conf = conf; + + passenger_conf->autogenerated.old_routing_explicitly_set = 1; + record_main_conf_source_location(cf, + &passenger_conf->autogenerated.old_routing_source_file, + &passenger_conf->autogenerated.old_routing_source_line); + + return ngx_conf_set_flag_slot(cf, cmd, conf); +} + static char * passenger_conf_set_user_switching(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { passenger_main_conf_t *passenger_conf = conf; diff --git a/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c b/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c index 87c2f7ae4a..4afbad8e87 100644 --- a/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c +++ b/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c @@ -68,6 +68,7 @@ passenger_create_autogenerated_main_conf(passenger_autogenerated_main_conf_t *co conf->spawn_dir.data = NULL; conf->spawn_dir.len = 0; conf->turbocaching = NGX_CONF_UNSET; + conf->old_routing = NGX_CONF_UNSET; conf->user_switching = NGX_CONF_UNSET; conf->default_user.data = NULL; conf->default_user.len = 0; @@ -165,6 +166,10 @@ passenger_create_autogenerated_main_conf(passenger_autogenerated_main_conf_t *co conf->turbocaching_source_file.len = 0; conf->turbocaching_source_line = 0; conf->turbocaching_explicitly_set = 0; + conf->old_routing_source_file.data = NULL; + conf->old_routing_source_file.len = 0; + conf->old_routing_source_line = 0; + conf->old_routing_explicitly_set = 0; conf->user_switching_source_file.data = NULL; conf->user_switching_source_file.len = 0; conf->user_switching_source_line = 0; diff --git a/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c b/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c index a6684df456..3a5cc3e243 100644 --- a/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c +++ b/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c @@ -262,6 +262,17 @@ generate_config_manifest_for_autogenerated_main_conf(manifest_gen_ctx_t *ctx, pa psg_json_value_set_bool(hierarchy_member, "value", conf->autogenerated.turbocaching); } + if (conf->autogenerated.old_routing_explicitly_set) { + option_container = find_or_create_manifest_option_container(ctx, + ctx->global_config_container, + "passenger_old_routing", + sizeof("passenger_old_routing") - 1); + hierarchy_member = add_manifest_option_container_hierarchy_member(option_container, + &conf->autogenerated.old_routing_source_file, + conf->autogenerated.old_routing_source_line); + psg_json_value_set_bool(hierarchy_member, "value", + conf->autogenerated.old_routing); + } if (conf->autogenerated.user_switching_explicitly_set) { option_container = find_or_create_manifest_option_container(ctx, ctx->global_config_container, diff --git a/src/nginx_module/MainConfig/AutoGeneratedStruct.h b/src/nginx_module/MainConfig/AutoGeneratedStruct.h index e1b08df593..ca53839760 100644 --- a/src/nginx_module/MainConfig/AutoGeneratedStruct.h +++ b/src/nginx_module/MainConfig/AutoGeneratedStruct.h @@ -49,6 +49,7 @@ typedef struct { ngx_uint_t log_level; ngx_uint_t max_instances_per_app; ngx_uint_t max_pool_size; + ngx_flag_t old_routing; ngx_uint_t pool_idle_time; ngx_array_t *prestart_uris; ngx_uint_t response_buffer_high_watermark; @@ -95,6 +96,7 @@ typedef struct { ngx_str_t log_level_source_file; ngx_str_t max_instances_per_app_source_file; ngx_str_t max_pool_size_source_file; + ngx_str_t old_routing_source_file; ngx_str_t pool_idle_time_source_file; ngx_str_t prestart_uris_source_file; ngx_str_t response_buffer_high_watermark_source_file; @@ -129,6 +131,7 @@ typedef struct { ngx_uint_t log_level_source_line; ngx_uint_t max_instances_per_app_source_line; ngx_uint_t max_pool_size_source_line; + ngx_uint_t old_routing_source_line; ngx_uint_t pool_idle_time_source_line; ngx_uint_t prestart_uris_source_line; ngx_uint_t response_buffer_high_watermark_source_line; @@ -163,6 +166,7 @@ typedef struct { ngx_int_t log_level_explicitly_set; ngx_int_t max_instances_per_app_explicitly_set; ngx_int_t max_pool_size_explicitly_set; + ngx_int_t old_routing_explicitly_set; ngx_int_t pool_idle_time_explicitly_set; ngx_int_t prestart_uris_explicitly_set; ngx_int_t response_buffer_high_watermark_explicitly_set; diff --git a/src/nginx_module/ngx_http_passenger_module.c b/src/nginx_module/ngx_http_passenger_module.c index ce014458cc..9f4d238363 100644 --- a/src/nginx_module/ngx_http_passenger_module.c +++ b/src/nginx_module/ngx_http_passenger_module.c @@ -375,6 +375,7 @@ start_watchdog(ngx_cycle_t *cycle) { psg_json_value_set_ngx_flag (w_config, "user_switching", autogenerated_main_conf->user_switching); psg_json_value_set_ngx_flag (w_config, "show_version_in_header", autogenerated_main_conf->show_version_in_header); psg_json_value_set_ngx_flag (w_config, "turbocaching", autogenerated_main_conf->turbocaching); + psg_json_value_set_ngx_flag (w_config, "old_routing", autogenerated_main_conf->old_routing); psg_json_value_set_ngx_str_ne(w_config, "default_user", &autogenerated_main_conf->default_user); psg_json_value_set_ngx_str_ne(w_config, "default_group", &autogenerated_main_conf->default_group); psg_json_value_set_ngx_str_ne(w_config, "default_ruby", &passenger_main_conf.default_ruby); diff --git a/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb b/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb index 687d367573..5a98c1fc34 100644 --- a/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +++ b/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb @@ -277,6 +277,13 @@ :default => true, :desc => "Whether to enable turbocaching in #{PROGRAM_NAME}." }, + { + :name => 'PassengerOldRouting', + :type => :flag, + :context => :global, + :default => false, + :desc => "Whether to revert to old routing behaviour in #{PROGRAM_NAME}." + }, { :name => 'PassengerShowVersionInHeader', :type => :flag, diff --git a/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb b/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb index 9eb4165468..3c496d8d71 100644 --- a/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +++ b/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb @@ -255,6 +255,14 @@ :context => [:main], :struct => 'NGX_HTTP_MAIN_CONF_OFFSET' }, + { + :name => 'passenger_old_routing', + :scope => :global, + :type => :flag, + :default => false, + :context => [:main], + :struct => 'NGX_HTTP_MAIN_CONF_OFFSET' + }, { :name => 'passenger_user_switching', :scope => :global, diff --git a/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb b/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb index e614cfe88c..ede42dd960 100644 --- a/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +++ b/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb @@ -485,6 +485,11 @@ module Standalone options[:turbocaching] = false end }, + { + :name => :old_routing, + :type => :boolean, + :desc => 'Revert to old routing algorithm' + }, { :name => :unlimited_concurrency_paths, :type => :array, diff --git a/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb b/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb index e8e0769cc3..764e72ea2b 100644 --- a/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +++ b/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb @@ -155,6 +155,7 @@ def build_daemon_controller_options if @options[:turbocaching] == false command << " --disable-turbocaching" end + add_flag_param(command, :old_routing, "--old-routing") if @options[:abort_websockets_on_process_shutdown] == false command << " --no-abort-websockets-on-process-shutdown" end diff --git a/test/cxx/Core/ApplicationPool/PoolTest.cpp b/test/cxx/Core/ApplicationPool/PoolTest.cpp index 6a39853c46..43deea261f 100644 --- a/test/cxx/Core/ApplicationPool/PoolTest.cpp +++ b/test/cxx/Core/ApplicationPool/PoolTest.cpp @@ -34,7 +34,8 @@ namespace tut { bool retainSessions; Core_ApplicationPool_PoolTest() - : skContext(skContextSchema) + : skContext(skContextSchema), + context(false) { retainSessions = false; wrapperRegistry.finalize(); diff --git a/test/cxx/Core/ApplicationPool/ProcessTest.cpp b/test/cxx/Core/ApplicationPool/ProcessTest.cpp index a3d508cd06..9f87479e8f 100644 --- a/test/cxx/Core/ApplicationPool/ProcessTest.cpp +++ b/test/cxx/Core/ApplicationPool/ProcessTest.cpp @@ -19,7 +19,8 @@ namespace tut { FileDescriptor server1, server2, server3; Core_ApplicationPool_ProcessTest() - : skContext(skContextSchema) + : skContext(skContextSchema), + context(false) { wrapperRegistry.finalize(); skContext.resourceLocator = resourceLocator; diff --git a/test/cxx/Core/ControllerTest.cpp b/test/cxx/Core/ControllerTest.cpp index 67fcf46b32..034eeb2685 100644 --- a/test/cxx/Core/ControllerTest.cpp +++ b/test/cxx/Core/ControllerTest.cpp @@ -60,7 +60,8 @@ namespace tut { : bg(false, true), context(skSchema), singleAppModeSchema(&wrapperRegistry), - skContext(skContextSchema) + skContext(skContextSchema), + apContext(false) { config["thread_number"] = 1; config["multi_app"] = false;