passenger 4.0.30 → 4.0.31

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (409) hide show
  1. data.tar.gz.asc +7 -7
  2. data/NEWS +31 -0
  3. data/bin/passenger +5 -5
  4. data/bin/passenger-config +6 -126
  5. data/bin/passenger-install-apache2-module +108 -26
  6. data/bin/passenger-install-nginx-module +81 -27
  7. data/bin/passenger-memory-stats +7 -6
  8. data/bin/passenger-status +13 -10
  9. data/build/agents.rb +8 -12
  10. data/build/apache2.rb +12 -7
  11. data/build/basics.rb +28 -20
  12. data/build/common_library.rb +4 -4
  13. data/build/cplusplus_support.rb +4 -4
  14. data/build/cxx_tests.rb +5 -3
  15. data/build/debian.rb +1 -2
  16. data/build/integration_tests.rb +25 -9
  17. data/build/misc.rb +2 -2
  18. data/build/oxt_tests.rb +5 -6
  19. data/build/packaging.rb +72 -40
  20. data/build/ruby_tests.rb +5 -1
  21. data/build/test_basics.rb +1 -2
  22. data/debian.template/locations.ini.template +1 -0
  23. data/debian.template/rules.template +2 -1
  24. data/dev/install_scripts_bootstrap_code.rb +42 -0
  25. data/dev/run_travis.sh +1 -0
  26. data/dev/runner +27 -0
  27. data/doc/Packaging.txt.md +5 -10
  28. data/doc/Users guide Apache.idmap.txt +3 -1
  29. data/doc/Users guide Apache.txt +5 -3
  30. data/doc/Users guide Nginx.idmap.txt +9 -5
  31. data/doc/Users guide Nginx.txt +47 -17
  32. data/doc/users_guide_snippets/environment_variables.txt +2 -2
  33. data/doc/users_guide_snippets/installation.txt +6 -2
  34. data/doc/users_guide_snippets/tips.txt +4 -0
  35. data/ext/apache2/Hooks.cpp +16 -3
  36. data/ext/common/Account.h +6 -5
  37. data/ext/common/AgentsStarter.h +1 -1
  38. data/ext/common/ApplicationPool2/Common.h +72 -0
  39. data/ext/common/ApplicationPool2/Group.h +263 -148
  40. data/ext/common/ApplicationPool2/Implementation.cpp +66 -44
  41. data/ext/common/ApplicationPool2/Options.h +1 -7
  42. data/ext/common/ApplicationPool2/Pool.h +96 -72
  43. data/ext/common/ApplicationPool2/Process.h +12 -17
  44. data/ext/common/ApplicationPool2/Socket.h +4 -4
  45. data/ext/common/ApplicationPool2/SuperGroup.h +20 -17
  46. data/ext/common/Constants.h +15 -1
  47. data/ext/common/MessageServer.h +22 -0
  48. data/ext/common/Utils.cpp +4 -1
  49. data/ext/common/Utils.h +3 -1
  50. data/ext/common/Utils/StrIntUtils.h +1 -0
  51. data/ext/common/Utils/Timer.h +15 -1
  52. data/ext/common/Utils/utf8/checked.h +0 -0
  53. data/ext/common/Utils/utf8/core.h +0 -0
  54. data/ext/common/Utils/utf8/unchecked.h +0 -0
  55. data/ext/common/agents/Base.cpp +59 -35
  56. data/ext/common/agents/HelperAgent/Main.cpp +23 -12
  57. data/ext/common/agents/HelperAgent/RequestHandler.h +10 -1
  58. data/ext/common/agents/LoggingAgent/FilterSupport.h +9 -5
  59. data/ext/common/agents/TempDirToucher.c +12 -3
  60. data/ext/common/agents/Watchdog/Main.cpp +8 -2
  61. data/ext/nginx/ConfigurationCommands.c +10 -0
  62. data/ext/nginx/ConfigurationFields.h +2 -0
  63. data/ext/nginx/ContentHandler.c +32 -19
  64. data/ext/nginx/CreateLocationConfig.c +5 -0
  65. data/ext/nginx/MergeLocationConfig.c +6 -0
  66. data/ext/nginx/config +13 -6
  67. data/ext/ruby/passenger_native_support.c +61 -2
  68. data/helper-scripts/classic-rails-loader.rb +9 -10
  69. data/helper-scripts/classic-rails-preloader.rb +10 -11
  70. data/helper-scripts/node-loader.js +3 -2
  71. data/helper-scripts/rack-loader.rb +8 -9
  72. data/helper-scripts/rack-preloader.rb +9 -10
  73. data/lib/phusion_passenger.rb +36 -7
  74. data/lib/phusion_passenger/abstract_installer.rb +16 -15
  75. data/lib/phusion_passenger/active_support3_extensions/init.rb +1 -1
  76. data/lib/phusion_passenger/admin_tools/memory_stats.rb +2 -2
  77. data/lib/phusion_passenger/admin_tools/server_instance.rb +5 -5
  78. data/lib/phusion_passenger/analytics_logger.rb +3 -3
  79. data/lib/phusion_passenger/classic_rails/thread_handler_extension.rb +1 -1
  80. data/lib/phusion_passenger/config.rb +125 -0
  81. data/lib/phusion_passenger/config/about_command.rb +183 -0
  82. data/lib/phusion_passenger/config/command.rb +57 -0
  83. data/lib/phusion_passenger/config/restart_app_command.rb +146 -0
  84. data/lib/phusion_passenger/config/utils.rb +108 -0
  85. data/lib/phusion_passenger/console_text_template.rb +2 -1
  86. data/lib/phusion_passenger/constants.rb +7 -2
  87. data/lib/phusion_passenger/loader_shared_helpers.rb +12 -21
  88. data/lib/phusion_passenger/message_client.rb +15 -4
  89. data/lib/phusion_passenger/native_support.rb +116 -98
  90. data/lib/phusion_passenger/nginx/config_options.rb +5 -0
  91. data/lib/phusion_passenger/platform_info.rb +1 -1
  92. data/lib/phusion_passenger/platform_info/apache.rb +9 -5
  93. data/lib/phusion_passenger/platform_info/apache_detector.rb +5 -6
  94. data/lib/phusion_passenger/platform_info/binary_compatibility.rb +3 -3
  95. data/lib/phusion_passenger/platform_info/compiler.rb +29 -11
  96. data/lib/phusion_passenger/platform_info/curl.rb +1 -1
  97. data/lib/phusion_passenger/platform_info/cxx_portability.rb +30 -16
  98. data/lib/phusion_passenger/platform_info/depcheck.rb +6 -6
  99. data/lib/phusion_passenger/platform_info/linux.rb +2 -2
  100. data/lib/phusion_passenger/platform_info/operating_system.rb +25 -5
  101. data/lib/phusion_passenger/platform_info/ruby.rb +7 -4
  102. data/lib/phusion_passenger/platform_info/zlib.rb +1 -1
  103. data/lib/phusion_passenger/plugin.rb +0 -1
  104. data/lib/phusion_passenger/preloader_shared_helpers.rb +1 -1
  105. data/lib/phusion_passenger/public_api.rb +1 -1
  106. data/lib/phusion_passenger/rack/thread_handler_extension.rb +1 -1
  107. data/lib/phusion_passenger/request_handler.rb +8 -9
  108. data/lib/phusion_passenger/request_handler/thread_handler.rb +21 -9
  109. data/lib/phusion_passenger/ruby_core_enhancements.rb +1 -1
  110. data/lib/phusion_passenger/standalone/app_finder.rb +2 -2
  111. data/lib/phusion_passenger/standalone/command.rb +10 -8
  112. data/lib/phusion_passenger/standalone/help_command.rb +1 -1
  113. data/lib/phusion_passenger/standalone/main.rb +3 -3
  114. data/lib/phusion_passenger/standalone/package_runtime_command.rb +2 -2
  115. data/lib/phusion_passenger/standalone/runtime_installer.rb +55 -13
  116. data/lib/phusion_passenger/standalone/runtime_locator.rb +3 -3
  117. data/lib/phusion_passenger/standalone/start_command.rb +6 -7
  118. data/lib/phusion_passenger/standalone/status_command.rb +1 -1
  119. data/lib/phusion_passenger/standalone/stop_command.rb +1 -1
  120. data/lib/phusion_passenger/standalone/utils.rb +1 -1
  121. data/lib/phusion_passenger/standalone/version_command.rb +2 -3
  122. data/lib/phusion_passenger/utils.rb +1 -1
  123. data/lib/phusion_passenger/utils/download.rb +1 -2
  124. data/lib/phusion_passenger/utils/file_system_watcher.rb +1 -1
  125. data/lib/phusion_passenger/utils/hosts_file_parser.rb +1 -1
  126. data/lib/phusion_passenger/utils/tee_input.rb +1 -1
  127. data/lib/phusion_passenger/utils/terminal_choice_menu.rb +217 -0
  128. data/lib/phusion_passenger/utils/unseekable_socket.rb +1 -1
  129. data/resources/templates/apache2/config_snippets.txt.erb +2 -3
  130. data/resources/templates/apache2/deployment_example.txt.erb +2 -2
  131. data/resources/templates/apache2/notify_apache_module_installed.txt.erb +3 -0
  132. data/resources/templates/nginx/config_snippets.txt.erb +1 -1
  133. data/resources/templates/nginx/deployment_example.txt.erb +2 -2
  134. data/resources/templates/nginx/nginx_module_sources_not_available.txt.erb +11 -5
  135. data/rpm/Vagrantfile +1 -0
  136. data/test/cxx/ApplicationPool2/PoolTest.cpp +224 -35
  137. data/test/cxx/ApplicationPool2/ProcessTest.cpp +6 -6
  138. data/test/cxx/MessagePassingTest.cpp +1 -1
  139. data/test/cxx/RequestHandlerTest.cpp +26 -26
  140. data/test/integration_tests/apache2_tests.rb +162 -243
  141. data/test/integration_tests/native_packaging_spec.rb +10 -10
  142. data/test/integration_tests/nginx_tests.rb +87 -107
  143. data/test/integration_tests/shared/example_webapp_tests.rb +246 -0
  144. data/test/integration_tests/source_packaging_test.rb +2 -1
  145. data/test/integration_tests/standalone_tests.rb +34 -19
  146. data/test/ruby/admin_tools_spec.rb +4 -4
  147. data/test/ruby/analytics_logger_spec.rb +1 -1
  148. data/test/ruby/debug_logging_spec.rb +2 -2
  149. data/test/ruby/message_channel_spec.rb +1 -1
  150. data/test/ruby/request_handler_spec.rb +171 -64
  151. data/test/ruby/shared/loader_sharedspec.rb +5 -5
  152. data/test/ruby/shared/rails/analytics_logging_extensions_sharedspec.rb +2 -2
  153. data/test/ruby/spec_helper.rb +4 -4
  154. data/test/ruby/standalone/runtime_installer_spec.rb +1 -1
  155. data/test/ruby/standalone/runtime_locator_spec.rb +1 -1
  156. data/test/ruby/utils/file_system_watcher_spec.rb +1 -1
  157. data/test/ruby/utils/hosts_file_parser.rb +1 -1
  158. data/test/ruby/utils/unseekable_socket_spec.rb +1 -1
  159. data/test/ruby/utils_spec.rb +4 -4
  160. data/test/stub/apache2/httpd.conf.erb +5 -0
  161. data/test/stub/index.html +1 -0
  162. data/test/stub/rack/config.ru +80 -33
  163. data/test/stub/{rails_apps/1.2/empty/app/models → rack/public}/.gitignore +0 -0
  164. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/Rakefile +0 -0
  165. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/controllers/application_controller.rb +0 -0
  166. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/controllers/recipes_controller.rb +0 -0
  167. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/controllers/uploads_controller.rb +0 -0
  168. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/controllers/welcome_controller.rb +0 -0
  169. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/app/helpers/application_helper.rb +0 -0
  170. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/helpers/recipes_helper.rb +0 -0
  171. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/helpers/test_helper.rb +0 -0
  172. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/helpers/uploads_helper.rb +0 -0
  173. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/helpers/welcome_helper.rb +0 -0
  174. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/views/layouts/default.rhtml +0 -0
  175. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/views/recipes/create.rhtml +0 -0
  176. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/views/recipes/index.rhtml +0 -0
  177. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/views/recipes/new.rhtml +0 -0
  178. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/views/uploads/index.rhtml +0 -0
  179. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/views/uploads/new.html.erb +0 -0
  180. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/views/welcome/cached.rhtml +0 -0
  181. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/app/views/welcome/index.rhtml +0 -0
  182. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/config/boot.rb +0 -0
  183. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/config/database.yml +0 -0
  184. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/config/environment.rb +0 -0
  185. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/config/environments/development.rb +0 -0
  186. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/config/environments/production.rb +0 -0
  187. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/config/initializers/inflections.rb +0 -0
  188. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/config/initializers/mime_types.rb +0 -0
  189. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/config/routes.rb +0 -0
  190. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/log/useless.txt +0 -0
  191. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/.htaccess +0 -0
  192. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/public/404.html +0 -0
  193. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/public/422.html +0 -0
  194. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/public/500.html +0 -0
  195. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/dispatch.cgi +0 -0
  196. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/dispatch.fcgi +0 -0
  197. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/dispatch.rb +0 -0
  198. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/public/favicon.ico +0 -0
  199. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/images/angrywizard.gif +0 -0
  200. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/images/cookbook.gif +0 -0
  201. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/images/header.png +0 -0
  202. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/public/images/rails.png +0 -0
  203. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/public/robots.txt +0 -0
  204. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/uploads.html +0 -0
  205. data/test/stub/{rails_apps/1.2/empty/db → rails2.3-mycook/public/uploads}/.gitignore +0 -0
  206. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/public/welcome/cached.html +0 -0
  207. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/script/about +0 -0
  208. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/script/console +0 -0
  209. data/test/stub/{rails_apps/2.2/empty → rails2.3-mycook}/script/dbconsole +0 -0
  210. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/script/destroy +0 -0
  211. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/script/generate +0 -0
  212. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/script/performance/benchmarker +0 -0
  213. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/script/performance/profiler +0 -0
  214. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/script/performance/request +0 -0
  215. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/script/plugin +0 -0
  216. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/script/process/inspector +0 -0
  217. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/script/process/reaper +0 -0
  218. data/test/stub/{rails_apps/1.2/empty → rails2.3-mycook}/script/process/spawner +0 -0
  219. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/script/runner +0 -0
  220. data/test/stub/{rails_apps/2.0/empty → rails2.3-mycook}/script/server +0 -0
  221. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/sites/some.site/public/uploads.html +0 -0
  222. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/sites/some.site/public/welcome/cached.html +0 -0
  223. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/tmp/cache/useless.txt +0 -0
  224. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/tmp/pids/useless.txt +0 -0
  225. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/tmp/sessions/useless.txt +0 -0
  226. data/test/stub/{rails_apps/2.3/mycook → rails2.3-mycook}/tmp/sockets/useless.txt +0 -0
  227. data/test/stub/rails2.3/app/controllers/foo_controller.rb +1 -1
  228. data/test/stub/rails2.3/config/routes.rb +1 -2
  229. data/test/stub/wsgi/passenger_wsgi.py +47 -8
  230. data/test/stub/{rails_apps/1.2/empty/public/stylesheets → wsgi/public}/.gitignore +0 -0
  231. data/test/support/apache2_controller.rb +2 -2
  232. data/test/support/nginx_controller.rb +11 -5
  233. data/test/support/placebo-preloader.rb +2 -2
  234. data/test/support/test_helper.rb +26 -7
  235. metadata +78 -240
  236. metadata.gz.asc +7 -7
  237. data/debian.template/repack.sh +0 -42
  238. data/debian.template/watch +0 -3
  239. data/test/integration_tests/cgi_environment_spec.rb +0 -36
  240. data/test/integration_tests/hello_world_rack_spec.rb +0 -43
  241. data/test/integration_tests/hello_world_wsgi_spec.rb +0 -41
  242. data/test/integration_tests/mycook_spec.rb +0 -166
  243. data/test/stub/rack/public/rack.jpg +0 -0
  244. data/test/stub/rails_apps/1.2/empty/.gitignore +0 -3
  245. data/test/stub/rails_apps/1.2/empty/app/controllers/application.rb +0 -7
  246. data/test/stub/rails_apps/1.2/empty/config/boot.rb +0 -108
  247. data/test/stub/rails_apps/1.2/empty/config/database.yml +0 -31
  248. data/test/stub/rails_apps/1.2/empty/config/environment.rb +0 -66
  249. data/test/stub/rails_apps/1.2/empty/config/environments/development.rb +0 -21
  250. data/test/stub/rails_apps/1.2/empty/config/environments/production.rb +0 -18
  251. data/test/stub/rails_apps/1.2/empty/config/environments/staging.rb +0 -18
  252. data/test/stub/rails_apps/1.2/empty/config/environments/test.rb +0 -19
  253. data/test/stub/rails_apps/1.2/empty/config/routes.rb +0 -23
  254. data/test/stub/rails_apps/1.2/empty/doc/README_FOR_APP +0 -2
  255. data/test/stub/rails_apps/1.2/empty/public/.htaccess +0 -40
  256. data/test/stub/rails_apps/1.2/empty/public/500.html +0 -30
  257. data/test/stub/rails_apps/1.2/empty/public/dispatch.cgi +0 -10
  258. data/test/stub/rails_apps/1.2/empty/public/dispatch.fcgi +0 -24
  259. data/test/stub/rails_apps/1.2/empty/public/dispatch.rb +0 -10
  260. data/test/stub/rails_apps/1.2/empty/public/robots.txt +0 -1
  261. data/test/stub/rails_apps/1.2/empty/script/about +0 -3
  262. data/test/stub/rails_apps/1.2/empty/script/breakpointer +0 -3
  263. data/test/stub/rails_apps/1.2/empty/script/console +0 -3
  264. data/test/stub/rails_apps/1.2/empty/script/destroy +0 -3
  265. data/test/stub/rails_apps/1.2/empty/script/generate +0 -3
  266. data/test/stub/rails_apps/1.2/empty/script/plugin +0 -3
  267. data/test/stub/rails_apps/1.2/empty/script/runner +0 -3
  268. data/test/stub/rails_apps/1.2/empty/script/server +0 -3
  269. data/test/stub/rails_apps/1.2/empty/test/test_helper.rb +0 -28
  270. data/test/stub/rails_apps/2.0/empty/.gitignore +0 -3
  271. data/test/stub/rails_apps/2.0/empty/Rakefile +0 -10
  272. data/test/stub/rails_apps/2.0/empty/app/controllers/application.rb +0 -10
  273. data/test/stub/rails_apps/2.0/empty/app/helpers/application_helper.rb +0 -3
  274. data/test/stub/rails_apps/2.0/empty/app/models/.gitignore +0 -0
  275. data/test/stub/rails_apps/2.0/empty/config/boot.rb +0 -108
  276. data/test/stub/rails_apps/2.0/empty/config/database.yml +0 -31
  277. data/test/stub/rails_apps/2.0/empty/config/environment.rb +0 -59
  278. data/test/stub/rails_apps/2.0/empty/config/environments/production.rb +0 -18
  279. data/test/stub/rails_apps/2.0/empty/config/environments/staging.rb +0 -18
  280. data/test/stub/rails_apps/2.0/empty/config/environments/test.rb +0 -22
  281. data/test/stub/rails_apps/2.0/empty/config/routes.rb +0 -35
  282. data/test/stub/rails_apps/2.0/empty/db/.gitignore +0 -0
  283. data/test/stub/rails_apps/2.0/empty/doc/README_FOR_APP +0 -2
  284. data/test/stub/rails_apps/2.0/empty/public/.htaccess +0 -40
  285. data/test/stub/rails_apps/2.0/empty/public/404.html +0 -30
  286. data/test/stub/rails_apps/2.0/empty/public/dispatch.cgi +0 -10
  287. data/test/stub/rails_apps/2.0/empty/public/dispatch.fcgi +0 -24
  288. data/test/stub/rails_apps/2.0/empty/public/dispatch.rb +0 -10
  289. data/test/stub/rails_apps/2.0/empty/public/favicon.ico +0 -0
  290. data/test/stub/rails_apps/2.0/empty/public/images/rails.png +0 -0
  291. data/test/stub/rails_apps/2.0/empty/public/stylesheets/.gitignore +0 -0
  292. data/test/stub/rails_apps/2.0/empty/script/performance/benchmarker +0 -3
  293. data/test/stub/rails_apps/2.0/empty/script/performance/profiler +0 -3
  294. data/test/stub/rails_apps/2.0/empty/script/process/inspector +0 -3
  295. data/test/stub/rails_apps/2.0/empty/script/process/reaper +0 -3
  296. data/test/stub/rails_apps/2.0/empty/script/process/spawner +0 -3
  297. data/test/stub/rails_apps/2.0/empty/test/test_helper.rb +0 -38
  298. data/test/stub/rails_apps/2.2/empty/.gitignore +0 -3
  299. data/test/stub/rails_apps/2.2/empty/Rakefile +0 -10
  300. data/test/stub/rails_apps/2.2/empty/app/controllers/application.rb +0 -15
  301. data/test/stub/rails_apps/2.2/empty/app/helpers/application_helper.rb +0 -3
  302. data/test/stub/rails_apps/2.2/empty/app/models/.gitignore +0 -0
  303. data/test/stub/rails_apps/2.2/empty/config/boot.rb +0 -109
  304. data/test/stub/rails_apps/2.2/empty/config/database.yml +0 -31
  305. data/test/stub/rails_apps/2.2/empty/config/environment.rb +0 -75
  306. data/test/stub/rails_apps/2.2/empty/config/environments/development.rb +0 -17
  307. data/test/stub/rails_apps/2.2/empty/config/environments/production.rb +0 -24
  308. data/test/stub/rails_apps/2.2/empty/config/environments/staging.rb +0 -24
  309. data/test/stub/rails_apps/2.2/empty/config/environments/test.rb +0 -22
  310. data/test/stub/rails_apps/2.2/empty/config/initializers/inflections.rb +0 -10
  311. data/test/stub/rails_apps/2.2/empty/config/initializers/mime_types.rb +0 -5
  312. data/test/stub/rails_apps/2.2/empty/config/initializers/new_rails_defaults.rb +0 -17
  313. data/test/stub/rails_apps/2.2/empty/config/locales/en.yml +0 -5
  314. data/test/stub/rails_apps/2.2/empty/config/routes.rb +0 -43
  315. data/test/stub/rails_apps/2.2/empty/db/.gitignore +0 -0
  316. data/test/stub/rails_apps/2.2/empty/doc/README_FOR_APP +0 -5
  317. data/test/stub/rails_apps/2.2/empty/public/404.html +0 -30
  318. data/test/stub/rails_apps/2.2/empty/public/422.html +0 -30
  319. data/test/stub/rails_apps/2.2/empty/public/500.html +0 -33
  320. data/test/stub/rails_apps/2.2/empty/public/dispatch.cgi +0 -10
  321. data/test/stub/rails_apps/2.2/empty/public/dispatch.fcgi +0 -24
  322. data/test/stub/rails_apps/2.2/empty/public/dispatch.rb +0 -10
  323. data/test/stub/rails_apps/2.2/empty/public/favicon.ico +0 -0
  324. data/test/stub/rails_apps/2.2/empty/public/images/rails.png +0 -0
  325. data/test/stub/rails_apps/2.2/empty/public/robots.txt +0 -5
  326. data/test/stub/rails_apps/2.2/empty/public/stylesheets/.gitignore +0 -0
  327. data/test/stub/rails_apps/2.2/empty/script/about +0 -4
  328. data/test/stub/rails_apps/2.2/empty/script/console +0 -3
  329. data/test/stub/rails_apps/2.2/empty/script/destroy +0 -3
  330. data/test/stub/rails_apps/2.2/empty/script/generate +0 -3
  331. data/test/stub/rails_apps/2.2/empty/script/performance/benchmarker +0 -3
  332. data/test/stub/rails_apps/2.2/empty/script/performance/profiler +0 -3
  333. data/test/stub/rails_apps/2.2/empty/script/performance/request +0 -3
  334. data/test/stub/rails_apps/2.2/empty/script/plugin +0 -3
  335. data/test/stub/rails_apps/2.2/empty/script/process/inspector +0 -3
  336. data/test/stub/rails_apps/2.2/empty/script/process/reaper +0 -3
  337. data/test/stub/rails_apps/2.2/empty/script/process/spawner +0 -3
  338. data/test/stub/rails_apps/2.2/empty/script/runner +0 -3
  339. data/test/stub/rails_apps/2.2/empty/script/server +0 -3
  340. data/test/stub/rails_apps/2.2/empty/test/performance/browsing_test.rb +0 -9
  341. data/test/stub/rails_apps/2.2/empty/test/test_helper.rb +0 -38
  342. data/test/stub/rails_apps/2.3/empty/.gitignore +0 -3
  343. data/test/stub/rails_apps/2.3/empty/Rakefile +0 -10
  344. data/test/stub/rails_apps/2.3/empty/app/controllers/application_controller.rb +0 -10
  345. data/test/stub/rails_apps/2.3/empty/app/helpers/application_helper.rb +0 -3
  346. data/test/stub/rails_apps/2.3/empty/app/models/.gitignore +0 -0
  347. data/test/stub/rails_apps/2.3/empty/config/boot.rb +0 -110
  348. data/test/stub/rails_apps/2.3/empty/config/database.yml +0 -31
  349. data/test/stub/rails_apps/2.3/empty/config/environment.rb +0 -41
  350. data/test/stub/rails_apps/2.3/empty/config/environments/development.rb +0 -17
  351. data/test/stub/rails_apps/2.3/empty/config/environments/production.rb +0 -28
  352. data/test/stub/rails_apps/2.3/empty/config/environments/staging.rb +0 -28
  353. data/test/stub/rails_apps/2.3/empty/config/environments/test.rb +0 -28
  354. data/test/stub/rails_apps/2.3/empty/config/initializers/backtrace_silencers.rb +0 -7
  355. data/test/stub/rails_apps/2.3/empty/config/initializers/inflections.rb +0 -10
  356. data/test/stub/rails_apps/2.3/empty/config/initializers/mime_types.rb +0 -5
  357. data/test/stub/rails_apps/2.3/empty/config/initializers/new_rails_defaults.rb +0 -21
  358. data/test/stub/rails_apps/2.3/empty/config/initializers/session_store.rb +0 -15
  359. data/test/stub/rails_apps/2.3/empty/config/locales/en.yml +0 -5
  360. data/test/stub/rails_apps/2.3/empty/config/routes.rb +0 -43
  361. data/test/stub/rails_apps/2.3/empty/db/.gitignore +0 -0
  362. data/test/stub/rails_apps/2.3/empty/db/seeds.rb +0 -7
  363. data/test/stub/rails_apps/2.3/empty/doc/README_FOR_APP +0 -2
  364. data/test/stub/rails_apps/2.3/empty/public/404.html +0 -30
  365. data/test/stub/rails_apps/2.3/empty/public/422.html +0 -30
  366. data/test/stub/rails_apps/2.3/empty/public/500.html +0 -30
  367. data/test/stub/rails_apps/2.3/empty/public/favicon.ico +0 -0
  368. data/test/stub/rails_apps/2.3/empty/public/images/rails.png +0 -0
  369. data/test/stub/rails_apps/2.3/empty/public/robots.txt +0 -5
  370. data/test/stub/rails_apps/2.3/empty/public/stylesheets/.gitignore +0 -0
  371. data/test/stub/rails_apps/2.3/empty/script/about +0 -4
  372. data/test/stub/rails_apps/2.3/empty/script/console +0 -3
  373. data/test/stub/rails_apps/2.3/empty/script/dbconsole +0 -3
  374. data/test/stub/rails_apps/2.3/empty/script/destroy +0 -3
  375. data/test/stub/rails_apps/2.3/empty/script/generate +0 -3
  376. data/test/stub/rails_apps/2.3/empty/script/performance/benchmarker +0 -3
  377. data/test/stub/rails_apps/2.3/empty/script/performance/profiler +0 -3
  378. data/test/stub/rails_apps/2.3/empty/script/plugin +0 -3
  379. data/test/stub/rails_apps/2.3/empty/script/runner +0 -3
  380. data/test/stub/rails_apps/2.3/empty/script/server +0 -3
  381. data/test/stub/rails_apps/2.3/empty/test/performance/browsing_test.rb +0 -9
  382. data/test/stub/rails_apps/2.3/empty/test/test_helper.rb +0 -38
  383. data/test/stub/rails_apps/2.3/mycook/Rakefile +0 -10
  384. data/test/stub/rails_apps/2.3/mycook/app/helpers/application_helper.rb +0 -3
  385. data/test/stub/rails_apps/2.3/mycook/config/environments/development.rb +0 -18
  386. data/test/stub/rails_apps/2.3/mycook/config/initializers/inflections.rb +0 -10
  387. data/test/stub/rails_apps/2.3/mycook/config/initializers/mime_types.rb +0 -5
  388. data/test/stub/rails_apps/2.3/mycook/public/404.html +0 -30
  389. data/test/stub/rails_apps/2.3/mycook/public/422.html +0 -30
  390. data/test/stub/rails_apps/2.3/mycook/public/500.html +0 -30
  391. data/test/stub/rails_apps/2.3/mycook/public/favicon.ico +0 -0
  392. data/test/stub/rails_apps/2.3/mycook/public/images/rails.png +0 -0
  393. data/test/stub/rails_apps/2.3/mycook/public/robots.txt +0 -5
  394. data/test/stub/rails_apps/2.3/mycook/public/uploads/.gitignore +0 -0
  395. data/test/stub/rails_apps/2.3/mycook/script/about +0 -3
  396. data/test/stub/rails_apps/2.3/mycook/script/console +0 -3
  397. data/test/stub/rails_apps/2.3/mycook/script/dbconsole +0 -3
  398. data/test/stub/rails_apps/2.3/mycook/script/destroy +0 -3
  399. data/test/stub/rails_apps/2.3/mycook/script/generate +0 -3
  400. data/test/stub/rails_apps/2.3/mycook/script/performance/benchmarker +0 -3
  401. data/test/stub/rails_apps/2.3/mycook/script/performance/profiler +0 -3
  402. data/test/stub/rails_apps/2.3/mycook/script/performance/request +0 -3
  403. data/test/stub/rails_apps/2.3/mycook/script/plugin +0 -3
  404. data/test/stub/rails_apps/2.3/mycook/script/process/inspector +0 -3
  405. data/test/stub/rails_apps/2.3/mycook/script/process/reaper +0 -3
  406. data/test/stub/rails_apps/2.3/mycook/script/process/spawner +0 -3
  407. data/test/stub/rails_apps/2.3/mycook/script/runner +0 -3
  408. data/test/stub/rails_apps/2.3/mycook/script/server +0 -3
  409. data/test/stub/wsgi/public/wsgi-snake.jpg +0 -0
@@ -28,9 +28,9 @@
28
28
  #include <string>
29
29
  #include <vector>
30
30
  #include <boost/shared_ptr.hpp>
31
- #include "StaticString.h"
32
- #include "Exceptions.h"
33
- #include "Utils/StrIntUtils.h"
31
+ #include <StaticString.h>
32
+ #include <Exceptions.h>
33
+ #include <Utils/StrIntUtils.h>
34
34
 
35
35
  namespace Passenger {
36
36
 
@@ -66,8 +66,9 @@ public:
66
66
  CLEAR = 1 << 0,
67
67
  DETACH = 1 << 1,
68
68
  SET_PARAMETERS = 1 << 2,
69
- INSPECT_BASIC_INFO = 1 << 3,
70
- INSPECT_SENSITIVE_INFO = 1 << 4,
69
+ RESTART = 1 << 3,
70
+ INSPECT_BASIC_INFO = 1 << 4,
71
+ INSPECT_SENSITIVE_INFO = 1 << 5,
71
72
 
72
73
  // HelperAgent admin rights.
73
74
  INSPECT_REQUESTS = 1 << 8,
@@ -446,7 +446,7 @@ public:
446
446
  UPDATE_TRACE_POINT();
447
447
  FileDescriptor feedbackFd = fds[0];
448
448
  vector<string> args;
449
- bool result;
449
+ bool result = false;
450
450
 
451
451
  ScopeGuard guard(boost::bind(&AgentsStarter::killProcessGroupAndWait, &pid, 0));
452
452
  fds[1].close();
@@ -49,6 +49,63 @@ class Group;
49
49
  class Process;
50
50
  class Session;
51
51
 
52
+ /**
53
+ * The result of a Group::spawn() call.
54
+ */
55
+ enum SpawnResult {
56
+ // The spawn request has been honored. One or more processes are now being spawned.
57
+ SR_OK,
58
+
59
+ // A previous spawn request is still in progress, so this spawn request has been
60
+ // ignored. Having said that, the desired result (increasing the number of processes
61
+ // by one, within imposed constraints) will still be achieved.
62
+ SR_IN_PROGRESS,
63
+
64
+ // A non-rolling restart is currently in progress, so the spawn request cannot
65
+ // be honored.
66
+ SR_ERR_RESTARTING,
67
+
68
+ // Unable to spawn a new process: the upper bound of the group process limits have
69
+ // already been reached.
70
+ // The group limit is checked before checking whether the pool is at full capacity,
71
+ // so if you get this result then it is possible that the pool is also at full
72
+ // capacity at the same time.
73
+ SR_ERR_GROUP_UPPER_LIMITS_REACHED,
74
+
75
+ // Unable to spawn a new process: the pool is at full capacity. Pool capacity is
76
+ // checked after checking the group upper bound limits, so if you get this result
77
+ // then it is guaranteed that the group upper bound limits have not been reached.
78
+ SR_ERR_POOL_AT_FULL_CAPACITY
79
+ };
80
+
81
+ /**
82
+ * The result of a Group::attach() call.
83
+ */
84
+ enum AttachResult {
85
+ // Attaching succeeded.
86
+ AR_OK,
87
+
88
+ // Attaching failed: the upper bound of the group process limits have
89
+ // already been reached.
90
+ // The group limit is checked before checking whether the pool is at full capacity,
91
+ // so if you get this result then it is possible that the pool is also at full
92
+ // capacity at the same time.
93
+ AR_GROUP_UPPER_LIMITS_REACHED,
94
+
95
+ // Attaching failed: the pool is at full capacity. Pool capacity is
96
+ // checked after checking the group upper bound limits, so if you get this result
97
+ // then it is guaranteed that the group upper bound limits have not been reached.
98
+ AR_POOL_AT_FULL_CAPACITY,
99
+
100
+ // Attaching failed: another group is waiting for capacity, while this group is
101
+ // not waiting for capacity. You should throw away the current process and let the
102
+ // other group spawn, e.g. by calling `pool->possiblySpawnMoreProcessesForExistingGroups()`.
103
+ // This is checked after checking for the group upper bound limits and the pool
104
+ // capacity, so if you get this result then there is guaranteed to be capacity
105
+ // in the current group and in the pool.
106
+ AR_ANOTHER_GROUP_IS_WAITING_FOR_CAPACITY
107
+ };
108
+
52
109
  /**
53
110
  * The result of a Pool::disableProcess/Group::disable() call. Some values are only
54
111
  * returned by the functions, some values are only passed to the Group::disable()
@@ -79,6 +136,21 @@ enum DisableResult {
79
136
  DR_DEFERRED
80
137
  };
81
138
 
139
+ /**
140
+ * Determines the behavior of Pool::restartGroupsByName() and Group::restart().
141
+ * Specifically, determines whether to perform a rolling restart or not.
142
+ */
143
+ enum RestartMethod {
144
+ // Whether a rolling restart is performed, is determined by whether rolling restart
145
+ // was enabled in the web server configuration (i.e. whether group->options.rollingRestart
146
+ // is already true).
147
+ RM_DEFAULT,
148
+ // Perform a blocking restart. group->options.rollingRestart will not be changed.
149
+ RM_BLOCKING,
150
+ // Perform a rolling restart. group->options.rollingRestart will not be changed.
151
+ RM_ROLLING
152
+ };
153
+
82
154
  typedef boost::shared_ptr<Pool> PoolPtr;
83
155
  typedef boost::shared_ptr<SuperGroup> SuperGroupPtr;
84
156
  typedef boost::shared_ptr<Group> GroupPtr;
@@ -93,9 +93,38 @@ private:
93
93
  };
94
94
 
95
95
  /**
96
- * Protects `m_shuttingDown`.
96
+ * Protects `lifeStatus`.
97
97
  */
98
98
  mutable boost::mutex lifetimeSyncher;
99
+ /**
100
+ * A Group object progresses through a life.
101
+ *
102
+ * Do not access directly, always use `isAlive()`/`getLifeStatus()` or
103
+ * through `lifetimeSyncher`.
104
+ *
105
+ * Invariant:
106
+ * if lifeStatus != ALIVE:
107
+ * enabledCount == 0
108
+ * disablingCount == 0
109
+ * disabledCount == 0
110
+ */
111
+ enum LifeStatus {
112
+ /** Up and operational. */
113
+ ALIVE,
114
+ /** Being shut down. The containing SuperGroup has issued the shutdown()
115
+ * command, and this Group is now waiting for all detached processes to
116
+ * exit. You cannot call `get()`, `restart()` and other mutating methods
117
+ * anymore, and all threads created by this Group will exit as soon
118
+ * as possible.
119
+ */
120
+ SHUTTING_DOWN,
121
+ /**
122
+ * Shut down complete. Object no longer usable. No Processes are referenced
123
+ * from this Group anymore.
124
+ */
125
+ SHUT_DOWN
126
+ } lifeStatus;
127
+
99
128
  /**
100
129
  * A back reference to the containing SuperGroup. Should never
101
130
  * be NULL because a SuperGroup should outlive all its containing
@@ -114,7 +143,19 @@ private:
114
143
  */
115
144
  unsigned int restartsInitiated;
116
145
  /**
117
- * Whether process(es) are being spawned right now.
146
+ * The number of processes that are being spawned right now.
147
+ *
148
+ * Invariant:
149
+ * if processesBeingSpawned > 0: m_spawning
150
+ */
151
+ short processesBeingSpawned;
152
+ /**
153
+ * Whether the spawner thread is currently working. Note that even
154
+ * if it's working, it doesn't necessarily mean that processes are
155
+ * being spawned (i.e. that processesBeingSpawned > 0). After the
156
+ * thread is done spawning a process, it will attempt to attach
157
+ * the newly-spawned process to the group. During that time it's not
158
+ * technically spawning anything.
118
159
  */
119
160
  bool m_spawning;
120
161
  /** Whether a non-rolling restart is in progress (i.e. whether spawnThreadRealMain()
@@ -125,35 +166,9 @@ private:
125
166
  * When rolling restarting is in progress, this flag is false.
126
167
  *
127
168
  * Invariant:
128
- * if m_restarting: !m_spawning
169
+ * if m_restarting: processesBeingSpawned == 0
129
170
  */
130
171
  bool m_restarting;
131
- /**
132
- * Do not access directly, always use `isAlive()`/`getLifeStatus()` or
133
- * through `lifetimeSyncher`.
134
- *
135
- * Invariant:
136
- * if lifeStatus != ALIVE:
137
- * enabledCount == 0
138
- * disablingCount == 0
139
- * disabledCount == 0
140
- */
141
- enum LifeStatus {
142
- /** Up and operational. */
143
- ALIVE,
144
- /** Being shut down. The containing SuperGroup has issued the shutdown()
145
- * command, and this Group is now waiting for all detached processes to
146
- * exit. You cannot call `get()`, `restart()` and other mutating methods
147
- * anymore, and all threads created by this Group will exit as soon
148
- * as possible.
149
- */
150
- SHUTTING_DOWN,
151
- /**
152
- * Shut down. Object no longer usable. No Processes are referenced from
153
- * this Group anymore.
154
- */
155
- SHUT_DOWN
156
- } lifeStatus;
157
172
 
158
173
  /** Contains the spawn loop thread and the restarter thread. */
159
174
  dynamic_thread_group interruptableThreads;
@@ -197,13 +212,16 @@ private:
197
212
  unsigned int restartsInitiated);
198
213
  void spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options,
199
214
  unsigned int restartsInitiated);
200
- void finalizeRestart(GroupPtr self, Options options, SpawnerFactoryPtr spawnerFactory,
201
- unsigned int restartsInitiated, vector<Callback> postLockActions);
215
+ void finalizeRestart(GroupPtr self, Options options, RestartMethod method,
216
+ SpawnerFactoryPtr spawnerFactory, unsigned int restartsInitiated,
217
+ vector<Callback> postLockActions);
202
218
  void startCheckingDetachedProcesses(bool immediately);
203
219
  void detachedProcessesCheckerMain(GroupPtr self);
204
220
  void wakeUpGarbageCollector();
205
221
  bool poolAtFullCapacity() const;
206
222
  bool anotherGroupIsWaitingForCapacity() const;
223
+ boost::shared_ptr<Group> findOtherGroupWaitingForCapacity() const;
224
+ ProcessPtr poolForceFreeCapacity(const Group *exclude, vector<Callback> &postLockActions);
207
225
  bool testOverflowRequestQueue() const;
208
226
  const ResourceLocator &getResourceLocator() const;
209
227
  void runAttachHooks(const ProcessPtr process) const;
@@ -217,21 +235,22 @@ private:
217
235
  assert(disablingCount >= 0);
218
236
  assert(disabledCount >= 0);
219
237
  assert(enabledProcesses.empty() == (pqueue.top() == NULL));
220
- assert(!( enabledCount == 0 && disablingCount > 0 ) || spawning());
221
- assert(!( !spawning() ) || ( enabledCount > 0 || disablingCount == 0 ));
238
+ assert(!( enabledCount == 0 && disablingCount > 0 ) || ( processesBeingSpawned > 0) );
239
+ assert(!( !m_spawning ) || ( enabledCount > 0 || disablingCount == 0 ));
222
240
 
223
241
  assert((lifeStatus == ALIVE) == (spawner != NULL));
224
242
 
225
243
  // Verify getWaitlist invariants.
226
244
  assert(!( !getWaitlist.empty() ) || ( enabledProcesses.empty() || verifyNoRequestsOnGetWaitlistAreRoutable() ));
227
- assert(!( enabledProcesses.empty() && !spawning() && !restarting() && !poolAtFullCapacity() ) || ( getWaitlist.empty() ));
228
- assert(!( !getWaitlist.empty() ) || ( !enabledProcesses.empty() || spawning() || restarting() || poolAtFullCapacity() ));
245
+ assert(!( enabledProcesses.empty() && !m_spawning && !restarting() && !poolAtFullCapacity() ) || ( getWaitlist.empty() ));
246
+ assert(!( !getWaitlist.empty() ) || ( !enabledProcesses.empty() || m_spawning || restarting() || poolAtFullCapacity() ));
229
247
 
230
248
  // Verify disableWaitlist invariants.
231
249
  assert((int) disableWaitlist.size() >= disablingCount);
232
250
 
233
- // Verify m_spawning and m_restarting.
234
- assert(!( m_restarting ) || !m_spawning);
251
+ // Verify processesBeingSpawned, m_spawning and m_restarting.
252
+ assert(!( processesBeingSpawned > 0 ) || ( m_spawning ));
253
+ assert(!( m_restarting ) || ( processesBeingSpawned == 0 ));
235
254
 
236
255
  // Verify lifeStatus.
237
256
  LifeStatus lifeStatus = getLifeStatus();
@@ -345,7 +364,7 @@ private:
345
364
  }
346
365
 
347
366
  /* Determines which process to route a get() action to. The returned process
348
- * is guaranteed to be `canBeRoutedTo()`, i.e. not at full utilization.
367
+ * is guaranteed to be `canBeRoutedTo()`, i.e. not totally busy.
349
368
  *
350
369
  * A request is routed to an enabled processes, or if there are none,
351
370
  * from a disabling process. The rationale is as follows:
@@ -376,7 +395,7 @@ private:
376
395
  }
377
396
  }
378
397
  } else {
379
- Process *process = findProcessWithLowestUtilization(disablingProcesses);
398
+ Process *process = findProcessWithLowestBusyness(disablingProcesses);
380
399
  if (process->canBeRoutedTo()) {
381
400
  return RouteResult(process);
382
401
  } else {
@@ -395,7 +414,7 @@ private:
395
414
  } else {
396
415
  pqueue.erase(process->pqHandle);
397
416
  }
398
- process->pqHandle = pqueue.push(process, process->utilization());
417
+ process->pqHandle = pqueue.push(process, process->busyness());
399
418
  }
400
419
  return session;
401
420
  }
@@ -425,12 +444,12 @@ private:
425
444
  return NULL;
426
445
  }
427
446
 
428
- Process *findProcessWithLowestUtilization(const ProcessList &processes) const {
447
+ Process *findProcessWithLowestBusyness(const ProcessList &processes) const {
429
448
  Process *result = NULL;
430
449
  ProcessList::const_iterator it, end = processes.end();
431
450
  for (it = processes.begin(); it != end; it++) {
432
451
  Process *process = it->get();
433
- if (result == NULL || process->utilization() < result->utilization()) {
452
+ if (result == NULL || process->busyness() < result->busyness()) {
434
453
  result = process;
435
454
  }
436
455
  }
@@ -478,7 +497,7 @@ private:
478
497
  process->it = destination.last_iterator();
479
498
  if (&destination == &enabledProcesses) {
480
499
  process->enabled = Process::ENABLED;
481
- process->pqHandle = pqueue.push(process.get(), process->utilization());
500
+ process->pqHandle = pqueue.push(process.get(), process->busyness());
482
501
  enabledCount++;
483
502
  } else if (&destination == &disablingProcesses) {
484
503
  process->enabled = Process::DISABLING;
@@ -664,7 +683,7 @@ public:
664
683
  * their numbers.
665
684
  * These lists do not intersect. A process is in exactly 1 list.
666
685
  *
667
- * 'pqueue' orders all enabled processes according to utilization() values,
686
+ * 'pqueue' orders all enabled processes according to busyness() values,
668
687
  * from small to large.
669
688
  *
670
689
  * Invariants:
@@ -678,14 +697,14 @@ public:
678
697
  * enabledProcesses.empty() == (pqueue.top() == NULL)
679
698
  *
680
699
  * if (enabledCount == 0):
681
- * spawning() || restarting() || poolAtFullCapacity()
700
+ * processesBeingSpawned > 0 || restarting() || poolAtFullCapacity()
682
701
  * if (enabledCount == 0) and (disablingCount > 0):
683
- * spawning()
684
- * if !spawning():
685
- * (enabledCount > 0) or (disablingCount == 0)
702
+ * processesBeingSpawned > 0
703
+ * if !m_spawning:
704
+ * (enabledCount > 0) || (disablingCount == 0)
686
705
  *
687
- * if pqueue.top().atFullUtilization():
688
- * All enabled processes are at full utilization.
706
+ * if pqueue.top().isTotallyBusy():
707
+ * All enabled processes are totally busy.
689
708
  *
690
709
  * for all process in enabledProcesses:
691
710
  * process.enabled == Process::ENABLED
@@ -741,7 +760,7 @@ public:
741
760
  * The only reason why there are no enabled processes, while at the same time we're
742
761
  * not spawning or waiting for pool capacity, is because there is nothing to do.
743
762
  *
744
- * if enabledProcesses.empty() && !spawning() && !restarting() && !poolAtFullCapacity():
763
+ * if enabledProcesses.empty() && !m_spawning && !restarting() && !poolAtFullCapacity():
745
764
  * getWaitlist is empty
746
765
  *
747
766
  * Equivalently:
@@ -750,7 +769,7 @@ public:
750
769
  * unable to do that because of resource limits.
751
770
  *
752
771
  * if getWaitlist is non-empty:
753
- * !enabledProcesses.empty() || spawning() || restarting() || poolAtFullCapacity()
772
+ * !enabledProcesses.empty() || m_spawning || restarting() || poolAtFullCapacity()
754
773
  */
755
774
  deque<GetWaiter> getWaitlist;
756
775
  /**
@@ -768,7 +787,12 @@ public:
768
787
  * (lifeStatus == ALIVE) == (spawner != NULL)
769
788
  */
770
789
  SpawnerPtr spawner;
771
-
790
+
791
+
792
+ /********************************************
793
+ * Constructors and destructors
794
+ ********************************************/
795
+
772
796
  Group(const SuperGroupPtr &superGroup, const Options &options, const ComponentInfo &info);
773
797
  ~Group();
774
798
 
@@ -799,7 +823,52 @@ public:
799
823
  }
800
824
  }
801
825
 
802
- SessionPtr get(const Options &newOptions, const GetCallback &callback) {
826
+
827
+ /********************************************
828
+ * Life time and back-reference methods
829
+ ********************************************/
830
+
831
+ /**
832
+ * Thread-safe.
833
+ * @pre getLifeState() != SHUT_DOWN
834
+ * @post result != NULL
835
+ */
836
+ SuperGroupPtr getSuperGroup() const {
837
+ return superGroup.lock();
838
+ }
839
+
840
+ void setSuperGroup(const SuperGroupPtr &superGroup) {
841
+ assert(this->superGroup.lock() == NULL);
842
+ this->superGroup = superGroup;
843
+ }
844
+
845
+ /**
846
+ * Thread-safe.
847
+ * @pre getLifeState() != SHUT_DOWN
848
+ * @post result != NULL
849
+ */
850
+ PoolPtr getPool() const;
851
+
852
+ // Thread-safe.
853
+ bool isAlive() const {
854
+ boost::lock_guard<boost::mutex> lock(lifetimeSyncher);
855
+ return lifeStatus == ALIVE;
856
+ }
857
+
858
+ // Thread-safe.
859
+ LifeStatus getLifeStatus() const {
860
+ boost::lock_guard<boost::mutex> lock(lifetimeSyncher);
861
+ return lifeStatus;
862
+ }
863
+
864
+
865
+ /********************************************
866
+ * Core methods
867
+ ********************************************/
868
+
869
+ SessionPtr get(const Options &newOptions, const GetCallback &callback,
870
+ vector<Callback> &postLockActions)
871
+ {
803
872
  assert(isAlive());
804
873
 
805
874
  if (OXT_LIKELY(!restarting())) {
@@ -809,7 +878,22 @@ public:
809
878
  mergeOptions(newOptions);
810
879
  }
811
880
  if (OXT_UNLIKELY(!newOptions.noop && shouldSpawnForGetAction())) {
812
- spawn();
881
+ // If we're trying to spawn the first process for this group, and
882
+ // spawning failed because the pool is at full capacity, then we
883
+ // try to kill some random idle process in the pool and try again.
884
+ if (spawn() == SR_ERR_POOL_AT_FULL_CAPACITY && enabledCount == 0) {
885
+ P_INFO("Unable to spawn the the sole process for group " << name <<
886
+ " because the max pool size has been reached. Trying " <<
887
+ "to shutdown another idle process to free capacity...");
888
+ if (poolForceFreeCapacity(this, postLockActions) != NULL) {
889
+ SpawnResult result = spawn();
890
+ assert(result == SR_OK);
891
+ (void) result;
892
+ } else {
893
+ P_INFO("There are no processes right now that are eligible "
894
+ "for shutdown. Will try again later.");
895
+ }
896
+ }
813
897
  }
814
898
  }
815
899
 
@@ -831,19 +915,19 @@ public:
831
915
  * then we generally want to use them, except:
832
916
  * - When non-rolling restarting because those disabling processes
833
917
  * are from the old version.
834
- * - When all disabling processes are at full utilization.
918
+ * - When all disabling processes are totally busy.
835
919
  *
836
920
  * Whenever a disabling process cannot be used, call the callback
837
921
  * after a process has been spawned or has failed to spawn, or
838
922
  * when a disabling process becomes available.
839
923
  */
840
- assert(spawning() || restarting() || poolAtFullCapacity());
924
+ assert(m_spawning || restarting() || poolAtFullCapacity());
841
925
 
842
926
  if (disablingCount > 0 && !restarting()) {
843
- Process *process = findProcessWithLowestUtilization(
927
+ Process *process = findProcessWithLowestBusyness(
844
928
  disablingProcesses);
845
929
  assert(process != NULL);
846
- if (!process->atFullUtilization()) {
930
+ if (!process->isTotallyBusy()) {
847
931
  return newSession(process);
848
932
  }
849
933
  }
@@ -855,7 +939,7 @@ public:
855
939
  } else {
856
940
  RouteResult result = route(newOptions);
857
941
  if (result.process == NULL) {
858
- /* Looks like all processes are at full utilization.
942
+ /* Looks like all processes are totally busy.
859
943
  * Wait until a new one has been spawned or until
860
944
  * resources have become free.
861
945
  */
@@ -869,53 +953,33 @@ public:
869
953
  }
870
954
  }
871
955
  }
872
-
873
- /**
874
- * Thread-safe.
875
- * @pre getLifeState() != SHUT_DOWN
876
- * @post result != NULL
877
- */
878
- SuperGroupPtr getSuperGroup() const {
879
- return superGroup.lock();
880
- }
881
-
882
- void setSuperGroup(const SuperGroupPtr &superGroup) {
883
- assert(this->superGroup.lock() == NULL);
884
- this->superGroup = superGroup;
885
- }
886
-
887
- /**
888
- * Thread-safe.
889
- * @pre getLifeState() != SHUT_DOWN
890
- * @post result != NULL
891
- */
892
- PoolPtr getPool() const;
893
-
894
- // Thread-safe.
895
- bool isAlive() const {
896
- boost::lock_guard<boost::mutex> lock(lifetimeSyncher);
897
- return lifeStatus == ALIVE;
898
- }
899
956
 
900
- // Thread-safe.
901
- LifeStatus getLifeStatus() const {
902
- boost::lock_guard<boost::mutex> lock(lifetimeSyncher);
903
- return lifeStatus;
904
- }
905
-
957
+
958
+ /********************************************
959
+ * State mutation methods
960
+ ********************************************/
961
+
906
962
  // Thread-safe, but only call outside the pool lock!
907
963
  void requestOOBW(const ProcessPtr &process);
908
-
964
+
909
965
  /**
910
966
  * Attaches the given process to this Group and mark it as enabled. This
911
- * function doesn't touch getWaitlist so be sure to fix its invariants
912
- * afterwards if necessary.
967
+ * function doesn't touch `getWaitlist` so be sure to fix its invariants
968
+ * afterwards if necessary, e.g. by calling `assignSessionsToGetWaiters()`.
913
969
  */
914
- void attach(const ProcessPtr &process, vector<Callback> &postLockActions) {
970
+ AttachResult attach(const ProcessPtr &process, vector<Callback> &postLockActions) {
915
971
  assert(process->getGroup() == NULL || process->getGroup().get() == this);
916
972
  assert(process->isAlive());
917
973
  assert(isAlive());
918
974
 
975
+ if (processUpperLimitsReached()) {
976
+ return AR_GROUP_UPPER_LIMITS_REACHED;
977
+ } else if (poolAtFullCapacity()) {
978
+ return AR_POOL_AT_FULL_CAPACITY;
979
+ } else if (!isWaitingForCapacity() && anotherGroupIsWaitingForCapacity()) {
980
+ return AR_ANOTHER_GROUP_IS_WAITING_FOR_CAPACITY;
981
+ }
982
+
919
983
  process->setGroup(shared_from_this());
920
984
  process->stickySessionId = generateStickySessionId();
921
985
  P_DEBUG("Attaching process " << process->inspect());
@@ -953,6 +1017,8 @@ public:
953
1017
  wakeUpGarbageCollector();
954
1018
 
955
1019
  postLockActions.push_back(boost::bind(&Group::runAttachHooks, this, process));
1020
+
1021
+ return AR_OK;
956
1022
  }
957
1023
 
958
1024
  /**
@@ -1096,24 +1162,104 @@ public:
1096
1162
  }
1097
1163
  }
1098
1164
 
1165
+ /**
1166
+ * Attempts to increase the number of processes by one, while respecting the
1167
+ * resource limits. That is, this method will ensure that there are at least
1168
+ * `minProcesses` processes, but no more than `maxProcesses` processes, and no
1169
+ * more than `pool->max` processes in the entire pool.
1170
+ */
1171
+ SpawnResult spawn() {
1172
+ assert(isAlive());
1173
+ if (m_spawning) {
1174
+ return SR_IN_PROGRESS;
1175
+ } else if (restarting()) {
1176
+ return SR_ERR_RESTARTING;
1177
+ } else if (processUpperLimitsReached()) {
1178
+ return SR_ERR_GROUP_UPPER_LIMITS_REACHED;
1179
+ } else if (poolAtFullCapacity()) {
1180
+ return SR_ERR_POOL_AT_FULL_CAPACITY;
1181
+ } else {
1182
+ P_DEBUG("Requested spawning of new process for group " << name);
1183
+ interruptableThreads.create_thread(
1184
+ boost::bind(&Group::spawnThreadMain,
1185
+ this, shared_from_this(), spawner,
1186
+ options.copyAndPersist().clearPerRequestFields(),
1187
+ restartsInitiated),
1188
+ "Group process spawner: " + name,
1189
+ POOL_HELPER_THREAD_STACK_SIZE);
1190
+ m_spawning = true;
1191
+ processesBeingSpawned++;
1192
+ return SR_OK;
1193
+ }
1194
+ }
1195
+
1099
1196
  void cleanupSpawner(vector<Callback> &postLockActions) {
1100
1197
  assert(isAlive());
1101
1198
  postLockActions.push_back(boost::bind(doCleanupSpawner, spawner));
1102
1199
  }
1103
1200
 
1104
- unsigned int utilization() const {
1105
- int result = enabledCount;
1106
- if (spawning()) {
1107
- result++;
1108
- }
1109
- return result;
1201
+ void restart(const Options &options, RestartMethod method = RM_DEFAULT);
1202
+
1203
+
1204
+ /********************************************
1205
+ * Queries
1206
+ ********************************************/
1207
+
1208
+ unsigned int getProcessCount() const {
1209
+ return enabledCount + disablingCount + disabledCount;
1110
1210
  }
1111
-
1211
+
1212
+ /**
1213
+ * Returns the number of processes in this group that should be part of the
1214
+ * ApplicationPool process limits calculations.
1215
+ */
1216
+ unsigned int capacityUsed() const {
1217
+ return enabledCount + disablingCount + disabledCount + processesBeingSpawned;
1218
+ }
1219
+
1220
+ /**
1221
+ * Returns whether the lower bound of the group-specific process limits
1222
+ * have been satisfied. Note that even if the result is false, the pool limits
1223
+ * may not allow spawning, so you should check `pool->atFullCapacity()` too.
1224
+ */
1225
+ bool processLowerLimitsSatisfied() const {
1226
+ return capacityUsed() >= options.minProcesses;
1227
+ }
1228
+
1229
+ /**
1230
+ * Returns whether the upper bound of the group-specific process limits have
1231
+ * been reached, or surpassed. Does not check whether pool limits have been
1232
+ * reached. Use `pool->atFullCapacity()` to check for that.
1233
+ */
1234
+ bool processUpperLimitsReached() const {
1235
+ return options.maxProcesses != 0 && capacityUsed() >= options.maxProcesses;
1236
+ }
1237
+
1238
+ /**
1239
+ * Returns whether all enabled processes are totally busy. If so, another
1240
+ * process should be spawned, if allowed by the process limits.
1241
+ * Returns false if there are no enabled processes.
1242
+ */
1243
+ bool allEnabledProcessesAreTotallyBusy() const {
1244
+ return enabledCount > 0 && pqueue.top()->isTotallyBusy();
1245
+ }
1246
+
1247
+ /**
1248
+ * Checks whether this group is waiting for capacity on the pool to
1249
+ * become available before it can continue processing requests.
1250
+ */
1251
+ bool isWaitingForCapacity() const {
1252
+ return enabledProcesses.empty()
1253
+ && processesBeingSpawned == 0
1254
+ && !m_restarting
1255
+ && !getWaitlist.empty();
1256
+ }
1257
+
1112
1258
  bool garbageCollectable(unsigned long long now = 0) const {
1113
1259
  /* if (now == 0) {
1114
1260
  now = SystemTime::getUsec();
1115
1261
  }
1116
- return utilization() == 0
1262
+ return busyness() == 0
1117
1263
  && getWaitlist.empty()
1118
1264
  && disabledProcesses.empty()
1119
1265
  && options.getMaxPreloaderIdleTime() != 0
@@ -1128,26 +1274,15 @@ public:
1128
1274
  * specific case that another get action is to be performed.
1129
1275
  */
1130
1276
  bool shouldSpawnForGetAction() const;
1131
- /** Whether a new process is allowed to be spawned for this group. */
1132
- bool allowSpawn() const;
1133
-
1134
- /** Start spawning a new process in the background, in case this
1135
- * isn't already happening and the group isn't being restarted.
1136
- * Will ensure that at least options.minProcesses processes are spawned.
1277
+
1278
+ /**
1279
+ * Whether a new process is allowed to be spawned for this group,
1280
+ * i.e. whether the upper processes limits have not been reached.
1137
1281
  */
1138
- void spawn() {
1139
- assert(isAlive());
1140
- if (!spawning() && !restarting()) {
1141
- P_DEBUG("Requested spawning of new process for group " << name);
1142
- interruptableThreads.create_thread(
1143
- boost::bind(&Group::spawnThreadMain,
1144
- this, shared_from_this(), spawner,
1145
- options.copyAndPersist().clearPerRequestFields(),
1146
- restartsInitiated),
1147
- "Group process spawner: " + name,
1148
- POOL_HELPER_THREAD_STACK_SIZE);
1149
- m_spawning = true;
1150
- }
1282
+ bool allowSpawn() const {
1283
+ return isAlive()
1284
+ && !processUpperLimitsReached()
1285
+ && !poolAtFullCapacity();
1151
1286
  }
1152
1287
 
1153
1288
  bool needsRestart(const Options &options) {
@@ -1159,9 +1294,7 @@ public:
1159
1294
  fileChangeChecker.changed(restartFile, options.statThrottleRate);
1160
1295
  }
1161
1296
  }
1162
-
1163
- void restart(const Options &options);
1164
-
1297
+
1165
1298
  bool spawning() const {
1166
1299
  return m_spawning;
1167
1300
  }
@@ -1170,25 +1303,6 @@ public:
1170
1303
  return m_restarting;
1171
1304
  }
1172
1305
 
1173
- /**
1174
- * Returns the number of processes in this group that should be part for the
1175
- * MaxPoolSize constraint calculation.
1176
- */
1177
- unsigned int getProcessCount() const {
1178
- return enabledCount + disablingCount + disabledCount;
1179
- }
1180
-
1181
- /**
1182
- * Checks whether this group is waiting for capacity on the pool to
1183
- * become available before it can continue processing requests.
1184
- */
1185
- bool isWaitingForCapacity() const {
1186
- return enabledProcesses.empty()
1187
- && !m_spawning
1188
- && !m_restarting
1189
- && !getWaitlist.empty();
1190
- }
1191
-
1192
1306
  template<typename Stream>
1193
1307
  void inspectXml(Stream &stream, bool includeSecrets = true) const {
1194
1308
  ProcessList::const_iterator it;
@@ -1201,10 +1315,11 @@ public:
1201
1315
  stream << "<enabled_process_count>" << enabledCount << "</enabled_process_count>";
1202
1316
  stream << "<disabling_process_count>" << disablingCount << "</disabling_process_count>";
1203
1317
  stream << "<disabled_process_count>" << disabledCount << "</disabled_process_count>";
1204
- stream << "<utilization>" << utilization() << "</utilization>";
1318
+ stream << "<capacity_used>" << capacityUsed() << "</capacity_used>";
1205
1319
  stream << "<get_wait_list_size>" << getWaitlist.size() << "</get_wait_list_size>";
1206
1320
  stream << "<disable_wait_list_size>" << disableWaitlist.size() << "</disable_wait_list_size>";
1207
- if (spawning()) {
1321
+ stream << "<processes_being_spawned>" << processesBeingSpawned << "</processes_being_spawned>";
1322
+ if (m_spawning) {
1208
1323
  stream << "<spawning/>";
1209
1324
  }
1210
1325
  if (restarting()) {