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
@@ -345,6 +345,7 @@ Group::Group(const SuperGroupPtr &_superGroup, const Options &options, const Com
345
345
  disabledCount = 0;
346
346
  spawner = getPool()->spawnerFactory->create(options);
347
347
  restartsInitiated = 0;
348
+ processesBeingSpawned = 0;
348
349
  m_spawning = false;
349
350
  m_restarting = false;
350
351
  lifeStatus = ALIVE;
@@ -419,13 +420,13 @@ Group::onSessionClose(const ProcessPtr &process, Session *session) {
419
420
  || process->enabled == Process::DISABLING
420
421
  || process->enabled == Process::DETACHED);
421
422
  if (process->enabled == Process::ENABLED) {
422
- pqueue.decrease(process->pqHandle, process->utilization());
423
+ pqueue.decrease(process->pqHandle, process->busyness());
423
424
  }
424
425
 
425
- /* This group now has a process that's guaranteed to be not at
426
- * full utilization.
426
+ /* This group now has a process that's guaranteed to be not
427
+ * totally busy.
427
428
  */
428
- assert(!process->atFullUtilization());
429
+ assert(!process->isTotallyBusy());
429
430
 
430
431
  bool detachingBecauseOfMaxRequests = false;
431
432
  bool detachingBecauseCapacityNeeded = false;
@@ -459,8 +460,8 @@ Group::onSessionClose(const ProcessPtr &process, Session *session) {
459
460
  * checked conditions) then now's a good time to detach
460
461
  * this process or group in order to free capacity.
461
462
  */
462
- P_DEBUG("Process " << process->inspect() << " is no longer at "
463
- "full utilization; detaching it in order to make room in the pool");
463
+ P_DEBUG("Process " << process->inspect() << " is no longer totally "
464
+ "busy; detaching it in order to make room in the pool");
464
465
  } else {
465
466
  /* This process has processed its maximum number of requests,
466
467
  * so we detach it.
@@ -848,19 +849,31 @@ Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, un
848
849
 
849
850
  verifyInvariants();
850
851
  assert(m_spawning);
852
+ assert(processesBeingSpawned > 0);
853
+
854
+ processesBeingSpawned--;
855
+ assert(processesBeingSpawned == 0);
851
856
 
852
857
  UPDATE_TRACE_POINT();
853
858
  vector<Callback> actions;
854
859
  if (process != NULL) {
855
- attach(process, actions);
856
- guard.clear();
857
- if (getWaitlist.empty()) {
858
- pool->assignSessionsToGetWaiters(actions);
860
+ AttachResult result = attach(process, actions);
861
+ if (result == AR_OK) {
862
+ guard.clear();
863
+ if (getWaitlist.empty()) {
864
+ pool->assignSessionsToGetWaiters(actions);
865
+ } else {
866
+ assignSessionsToGetWaiters(actions);
867
+ }
868
+ P_DEBUG("New process count = " << enabledCount <<
869
+ ", remaining get waiters = " << getWaitlist.size());
859
870
  } else {
860
- assignSessionsToGetWaiters(actions);
871
+ done = true;
872
+ P_DEBUG("Unable to attach spawned process " << process->inspect());
873
+ if (result == AR_ANOTHER_GROUP_IS_WAITING_FOR_CAPACITY) {
874
+ pool->possiblySpawnMoreProcessesForExistingGroups();
875
+ }
861
876
  }
862
- P_DEBUG("New process count = " << enabledCount <<
863
- ", remaining get waiters = " << getWaitlist.size());
864
877
  } else {
865
878
  // TODO: sure this is the best thing? if there are
866
879
  // processes currently alive we should just use them.
@@ -875,22 +888,18 @@ Group::spawnThreadRealMain(const SpawnerPtr &spawner, const Options &options, un
875
888
  done = true;
876
889
  }
877
890
 
878
- // Temporarily mark this Group as 'not spawning' so
879
- // that pool->utilization() doesn't take this thread's spawning
880
- // state into account.
881
- m_spawning = false;
882
-
883
891
  done = done
884
- || (getProcessCount() >= options.minProcesses && getWaitlist.empty())
885
- || (options.maxProcesses != 0 && getProcessCount() >= options.maxProcesses)
892
+ || (processLowerLimitsSatisfied() && getWaitlist.empty())
893
+ || processUpperLimitsReached()
886
894
  || pool->atFullCapacity(false);
887
895
  m_spawning = !done;
888
896
  if (done) {
889
897
  P_DEBUG("Spawn loop done");
890
898
  } else {
899
+ processesBeingSpawned++;
891
900
  P_DEBUG("Continue spawning");
892
901
  }
893
-
902
+
894
903
  UPDATE_TRACE_POINT();
895
904
  pool->fullVerifyInvariants();
896
905
  lock.unlock();
@@ -908,8 +917,9 @@ bool
908
917
  Group::shouldSpawn() const {
909
918
  return allowSpawn()
910
919
  && (
911
- (unsigned long) getProcessCount() < options.minProcesses
912
- || (enabledCount > 0 && pqueue.top()->atFullCapacity())
920
+ !processLowerLimitsSatisfied()
921
+ || allEnabledProcessesAreTotallyBusy()
922
+ || !getWaitlist.empty()
913
923
  );
914
924
  }
915
925
 
@@ -918,15 +928,8 @@ Group::shouldSpawnForGetAction() const {
918
928
  return enabledCount == 0 || shouldSpawn();
919
929
  }
920
930
 
921
- bool
922
- Group::allowSpawn() const {
923
- return isAlive()
924
- && !poolAtFullCapacity()
925
- && (options.maxProcesses == 0 || getProcessCount() < options.maxProcesses);
926
- }
927
-
928
931
  void
929
- Group::restart(const Options &options) {
932
+ Group::restart(const Options &options, RestartMethod method) {
930
933
  vector<Callback> actions;
931
934
 
932
935
  assert(isAlive());
@@ -936,13 +939,14 @@ Group::restart(const Options &options) {
936
939
  // the following tells them to abort their current work as soon as possible.
937
940
  restartsInitiated++;
938
941
 
939
- m_spawning = false;
942
+ processesBeingSpawned = 0;
943
+ m_spawning = false;
940
944
  m_restarting = true;
941
945
  detachAll(actions);
942
946
  getPool()->interruptableThreads.create_thread(
943
947
  boost::bind(&Group::finalizeRestart, this, shared_from_this(),
944
948
  options.copyAndPersist().clearPerRequestFields(),
945
- getPool()->spawnerFactory, restartsInitiated, actions),
949
+ method, getPool()->spawnerFactory, restartsInitiated, actions),
946
950
  "Group restarter: " + name,
947
951
  POOL_HELPER_THREAD_STACK_SIZE
948
952
  );
@@ -950,8 +954,9 @@ Group::restart(const Options &options) {
950
954
 
951
955
  // The 'self' parameter is for keeping the current Group object alive while this thread is running.
952
956
  void
953
- Group::finalizeRestart(GroupPtr self, Options options, SpawnerFactoryPtr spawnerFactory,
954
- unsigned int restartsInitiated, vector<Callback> postLockActions)
957
+ Group::finalizeRestart(GroupPtr self, Options options, RestartMethod method,
958
+ SpawnerFactoryPtr spawnerFactory, unsigned int restartsInitiated,
959
+ vector<Callback> postLockActions)
955
960
  {
956
961
  TRACE_POINT();
957
962
 
@@ -1003,13 +1008,23 @@ Group::finalizeRestart(GroupPtr self, Options options, SpawnerFactoryPtr spawner
1003
1008
  spawner = newSpawner;
1004
1009
 
1005
1010
  m_restarting = false;
1006
- if (!getWaitlist.empty()) {
1011
+ if (shouldSpawn()) {
1007
1012
  spawn();
1013
+ } else if (isWaitingForCapacity()) {
1014
+ P_INFO("Group " << name << " is waiting for capacity to become available. "
1015
+ "Trying to shutdown another idle process to free capacity...");
1016
+ if (pool->forceFreeCapacity(this, postLockActions) != NULL) {
1017
+ spawn();
1018
+ } else {
1019
+ P_INFO("There are no processes right now that are eligible "
1020
+ "for shutdown. Will try again later.");
1021
+ }
1008
1022
  }
1009
1023
  verifyInvariants();
1010
1024
 
1011
1025
  l.unlock();
1012
1026
  oldSpawner.reset();
1027
+ Pool::runAllActions(postLockActions);
1013
1028
  P_DEBUG("Restart of group " << name << " done");
1014
1029
  if (debug != NULL && debug->restarting) {
1015
1030
  debug->debugger->send("Restarting done");
@@ -1143,21 +1158,28 @@ Group::poolAtFullCapacity() const {
1143
1158
 
1144
1159
  bool
1145
1160
  Group::anotherGroupIsWaitingForCapacity() const {
1161
+ return findOtherGroupWaitingForCapacity() != NULL;
1162
+ }
1163
+
1164
+ boost::shared_ptr<Group>
1165
+ Group::findOtherGroupWaitingForCapacity() const {
1146
1166
  PoolPtr pool = getPool();
1147
1167
  StringMap<SuperGroupPtr>::const_iterator sg_it, sg_end = pool->superGroups.end();
1148
1168
  for (sg_it = pool->superGroups.begin(); sg_it != sg_end; sg_it++) {
1149
1169
  pair<StaticString, SuperGroupPtr> p = *sg_it;
1150
- foreach (GroupPtr group, p.second->groups) {
1151
- if (group.get() != this
1152
- && group->enabledProcesses.empty()
1153
- && !group->spawning()
1154
- && !group->getWaitlist.empty())
1155
- {
1156
- return true;
1170
+ vector<GroupPtr>::const_iterator g_it, g_end = p.second->groups.end();
1171
+ for (g_it = p.second->groups.begin(); g_it != g_end; g_it++) {
1172
+ if (g_it->get() != this && (*g_it)->isWaitingForCapacity()) {
1173
+ return *g_it;
1157
1174
  }
1158
1175
  }
1159
1176
  }
1160
- return false;
1177
+ return GroupPtr();
1178
+ }
1179
+
1180
+ ProcessPtr
1181
+ Group::poolForceFreeCapacity(const Group *exclude, vector<Callback> &postLockActions) {
1182
+ return getPool()->forceFreeCapacity(exclude, postLockActions);
1161
1183
  }
1162
1184
 
1163
1185
  bool
@@ -391,11 +391,6 @@ public:
391
391
  */
392
392
  bool noop;
393
393
 
394
- /** Specifies whether, if the pool is already full, the pool is allowed to
395
- * trash a non-idle process in order to free capacity. True by default.
396
- */
397
- bool allowTrashingNonIdleProcesses;
398
-
399
394
  /*-----------------*/
400
395
  /*-----------------*/
401
396
 
@@ -441,8 +436,7 @@ public:
441
436
  statThrottleRate = 0;
442
437
  maxRequests = 0;
443
438
  noop = false;
444
- allowTrashingNonIdleProcesses = true;
445
-
439
+
446
440
  /*********************************/
447
441
  }
448
442
 
@@ -27,6 +27,7 @@
27
27
 
28
28
  #include <string>
29
29
  #include <vector>
30
+ #include <algorithm>
30
31
  #include <utility>
31
32
  #include <sstream>
32
33
  #include <iomanip>
@@ -165,7 +166,7 @@ public:
165
166
  *
166
167
  * - A process has been spawned but its associated group has
167
168
  * no get waiters. This process can be killed and the resulting
168
- * free capacity will be used to use spawn a process for this
169
+ * free capacity will be used to spawn a process for this
169
170
  * get request.
170
171
  * - A process (that has apparently been spawned after getWaitlist
171
172
  * was populated) is done processing a request. This process can
@@ -268,7 +269,15 @@ public:
268
269
  }
269
270
  }
270
271
 
271
- ProcessPtr findOldestIdleProcess() const {
272
+ static const char *maybePluralize(unsigned int count, const char *singular, const char *plural) {
273
+ if (count == 1) {
274
+ return singular;
275
+ } else {
276
+ return plural;
277
+ }
278
+ }
279
+
280
+ ProcessPtr findOldestIdleProcess(const Group *exclude = NULL) const {
272
281
  ProcessPtr oldestIdleProcess;
273
282
 
274
283
  SuperGroupMap::const_iterator it, end = superGroups.end();
@@ -278,11 +287,14 @@ public:
278
287
  vector<GroupPtr>::const_iterator g_it, g_end = groups.end();
279
288
  for (g_it = groups.begin(); g_it != g_end; g_it++) {
280
289
  const GroupPtr &group = *g_it;
290
+ if (group.get() == exclude) {
291
+ continue;
292
+ }
281
293
  const ProcessList &processes = group->enabledProcesses;
282
294
  ProcessList::const_iterator p_it, p_end = processes.end();
283
295
  for (p_it = processes.begin(); p_it != p_end; p_it++) {
284
296
  const ProcessPtr process = *p_it;
285
- if (process->utilization() == 0
297
+ if (process->busyness() == 0
286
298
  && (oldestIdleProcess == NULL
287
299
  || process->lastUsed < oldestIdleProcess->lastUsed)
288
300
  ) {
@@ -328,13 +340,14 @@ public:
328
340
  bool done = false;
329
341
  vector<GetWaiter>::iterator it, end = getWaitlist.end();
330
342
  vector<GetWaiter> newWaitlist;
331
-
343
+
332
344
  for (it = getWaitlist.begin(); it != end && !done; it++) {
333
345
  GetWaiter &waiter = *it;
334
-
346
+
335
347
  SuperGroup *superGroup = findMatchingSuperGroup(waiter.options);
336
348
  if (superGroup != NULL) {
337
- SessionPtr session = superGroup->get(waiter.options, waiter.callback);
349
+ SessionPtr session = superGroup->get(waiter.options, waiter.callback,
350
+ postLockActions);
338
351
  if (session != NULL) {
339
352
  postLockActions.push_back(boost::bind(
340
353
  waiter.callback, session, ExceptionPtr()));
@@ -343,7 +356,8 @@ public:
343
356
  * the group's get wait list.
344
357
  */
345
358
  } else if (!atFullCapacity(false)) {
346
- createSuperGroupAndAsyncGetFromIt(waiter.options, waiter.callback);
359
+ createSuperGroupAndAsyncGetFromIt(waiter.options, waiter.callback,
360
+ postLockActions);
347
361
  } else {
348
362
  /* Still cannot satisfy this get request. Keep it on the get
349
363
  * wait list and try again later.
@@ -351,8 +365,8 @@ public:
351
365
  newWaitlist.push_back(waiter);
352
366
  }
353
367
  }
354
-
355
- getWaitlist = newWaitlist;
368
+
369
+ std::swap(getWaitlist, newWaitlist);
356
370
  }
357
371
 
358
372
  template<typename Queue>
@@ -409,6 +423,30 @@ public:
409
423
  superGroup->getWaitlist.pop_front();
410
424
  }
411
425
  }
426
+
427
+ /**
428
+ * Calls Group::detach() so be sure to fix up the invariants afterwards.
429
+ * See the comments for Group::detach() and the code for detachProcessUnlocked().
430
+ */
431
+ ProcessPtr forceFreeCapacity(const Group *exclude,
432
+ vector<Callback> &postLockActions)
433
+ {
434
+ ProcessPtr process = findOldestIdleProcess(exclude);
435
+ if (process != NULL) {
436
+ P_DEBUG("Forcefully detaching process " << process->inspect() <<
437
+ " in order to free capacity in the pool");
438
+
439
+ const GroupPtr group = process->getGroup();
440
+ assert(group != NULL);
441
+ assert(group->getWaitlist.empty());
442
+
443
+ const SuperGroupPtr superGroup = group->getSuperGroup();
444
+ assert(superGroup != NULL);
445
+
446
+ group->detach(process, postLockActions);
447
+ }
448
+ return process;
449
+ }
412
450
 
413
451
  /**
414
452
  * Forcefully destroys and detaches the given SuperGroup. After detaching
@@ -437,7 +475,7 @@ public:
437
475
  const SuperGroupPtr superGroup = group->getSuperGroup();
438
476
  assert(superGroup->state != SuperGroup::INITIALIZING);
439
477
  assert(superGroup->getWaitlist.empty());
440
-
478
+
441
479
  group->detach(process, postLockActions);
442
480
  // 'process' may now be a stale pointer so don't use it anymore.
443
481
  assignSessionsToGetWaiters(postLockActions);
@@ -866,10 +904,11 @@ public:
866
904
  }
867
905
 
868
906
  SuperGroupPtr createSuperGroupAndAsyncGetFromIt(const Options &options,
869
- const GetCallback &callback)
907
+ const GetCallback &callback, vector<Callback> &postLockActions)
870
908
  {
871
909
  SuperGroupPtr superGroup = createSuperGroup(options);
872
- SessionPtr session = superGroup->get(options, callback);
910
+ SessionPtr session = superGroup->get(options, callback,
911
+ postLockActions);
873
912
  /* Callback should now have been put on the wait list,
874
913
  * unless something has changed and we forgot to update
875
914
  * some code here...
@@ -964,17 +1003,18 @@ public:
964
1003
  // should never call the callback while holding the lock.
965
1004
  void asyncGet(const Options &options, const GetCallback &callback, bool lockNow = true) {
966
1005
  DynamicScopedLock lock(syncher, lockNow);
967
-
1006
+
968
1007
  assert(lifeStatus == ALIVE);
969
1008
  verifyInvariants();
970
- P_TRACE(2, "asyncGet(appRoot=" << options.appRoot << ")");
971
-
1009
+ P_TRACE(2, "asyncGet(appGroupName=" << options.getAppGroupName() << ")");
1010
+ vector<Callback> actions;
1011
+
972
1012
  SuperGroup *existingSuperGroup = findMatchingSuperGroup(options);
973
1013
  if (OXT_LIKELY(existingSuperGroup != NULL)) {
974
1014
  /* Best case: the app super group is already in the pool. Let's use it. */
975
1015
  P_TRACE(2, "Found existing SuperGroup");
976
1016
  existingSuperGroup->verifyInvariants();
977
- SessionPtr session = existingSuperGroup->get(options, callback);
1017
+ SessionPtr session = existingSuperGroup->get(options, callback, actions);
978
1018
  existingSuperGroup->verifyInvariants();
979
1019
  verifyInvariants();
980
1020
  P_TRACE(2, "asyncGet() finished");
@@ -990,36 +1030,21 @@ public:
990
1030
  * resources to make a new one.
991
1031
  */
992
1032
  P_DEBUG("Spawning new SuperGroup");
993
- SuperGroupPtr superGroup = createSuperGroupAndAsyncGetFromIt(options, callback);
1033
+ SuperGroupPtr superGroup = createSuperGroupAndAsyncGetFromIt(options,
1034
+ callback, actions);
994
1035
  superGroup->verifyInvariants();
995
1036
  verifyInvariants();
996
1037
  P_DEBUG("asyncGet() finished");
997
1038
 
998
1039
  } else {
999
- vector<Callback> actions;
1000
-
1001
1040
  /* Uh oh, the app super group isn't in the pool but we don't
1002
1041
  * have the resources to make a new one. The sysadmin should
1003
1042
  * configure the system to let something like this happen
1004
1043
  * as least as possible, but let's try to handle it as well
1005
1044
  * as we can.
1006
- *
1007
- * First, try to trash an idle process that's the oldest.
1008
1045
  */
1009
- P_DEBUG("Pool is at full capacity; trying to free a process...");
1010
- ProcessPtr process = findOldestIdleProcess();
1011
- if (process == NULL) {
1012
- /* All processes are doing something. We have no choice
1013
- * but to trash a non-idle process.
1014
- */
1015
- if (options.allowTrashingNonIdleProcesses) {
1016
- process = findBestProcessToTrash();
1017
- }
1018
- } else {
1019
- // Check invariant.
1020
- assert(process->getGroup()->getWaitlist.empty());
1021
- }
1022
- if (process == NULL) {
1046
+ ProcessPtr freedProcess = forceFreeCapacity(NULL, actions);
1047
+ if (freedProcess == NULL) {
1023
1048
  /* No process is eligible for killing. This could happen if, for example,
1024
1049
  * all (super)groups are currently initializing/restarting/spawning/etc.
1025
1050
  * We have no choice but to satisfy this get() action later when resources
@@ -1030,33 +1055,24 @@ public:
1030
1055
  options.copyAndPersist().clearLogger(),
1031
1056
  callback));
1032
1057
  } else {
1033
- GroupPtr group;
1034
- SuperGroupPtr superGroup;
1035
-
1036
- P_DEBUG("Freeing process " << process->inspect());
1037
- group = process->getGroup();
1038
- assert(group != NULL);
1039
- superGroup = group->getSuperGroup();
1040
- assert(superGroup != NULL);
1041
-
1042
- group->detach(process, actions);
1043
-
1044
1058
  /* Now that a process has been trashed we can create
1045
1059
  * the missing SuperGroup.
1046
1060
  */
1047
1061
  P_DEBUG("Creating new SuperGroup");
1062
+ SuperGroupPtr superGroup;
1048
1063
  superGroup = boost::make_shared<SuperGroup>(shared_from_this(), options);
1049
1064
  superGroup->initialize();
1050
1065
  superGroups.set(options.getAppGroupName(), superGroup);
1051
1066
  garbageCollectionCond.notify_all();
1052
- SessionPtr session = superGroup->get(options, callback);
1067
+ SessionPtr session = superGroup->get(options, callback,
1068
+ actions);
1053
1069
  /* The SuperGroup is still initializing so the callback
1054
1070
  * should now have been put on the wait list,
1055
1071
  * unless something has changed and we forgot to update
1056
1072
  * some code here...
1057
1073
  */
1058
1074
  assert(session == NULL);
1059
- group->verifyInvariants();
1075
+ freedProcess->getGroup()->verifyInvariants();
1060
1076
  superGroup->verifyInvariants();
1061
1077
  }
1062
1078
 
@@ -1064,17 +1080,19 @@ public:
1064
1080
  verifyInvariants();
1065
1081
  verifyExpensiveInvariants();
1066
1082
  P_TRACE(2, "asyncGet() finished");
1067
-
1068
- if (!actions.empty()) {
1069
- if (lockNow) {
1083
+ }
1084
+
1085
+ if (!actions.empty()) {
1086
+ if (lockNow) {
1087
+ if (lock.owns_lock()) {
1070
1088
  lock.unlock();
1071
- runAllActions(actions);
1072
- } else {
1073
- // This state is not allowed. If we reach
1074
- // here then it probably indicates a bug in
1075
- // the test suite.
1076
- abort();
1077
1089
  }
1090
+ runAllActions(actions);
1091
+ } else {
1092
+ // This state is not allowed. If we reach
1093
+ // here then it probably indicates a bug in
1094
+ // the test suite.
1095
+ abort();
1078
1096
  }
1079
1097
  }
1080
1098
  }
@@ -1152,20 +1170,20 @@ public:
1152
1170
  garbageCollectionCond.notify_all();
1153
1171
  }
1154
1172
 
1155
- unsigned int utilization(bool lock = true) const {
1173
+ unsigned int capacityUsed(bool lock = true) const {
1156
1174
  DynamicScopedLock l(syncher, lock);
1157
1175
  SuperGroupMap::const_iterator it, end = superGroups.end();
1158
1176
  int result = 0;
1159
1177
  for (it = superGroups.begin(); it != end; it++) {
1160
1178
  const SuperGroupPtr &superGroup = it->second;
1161
- result += superGroup->utilization();
1179
+ result += superGroup->capacityUsed();
1162
1180
  }
1163
1181
  return result;
1164
1182
  }
1165
1183
 
1166
1184
  bool atFullCapacity(bool lock = true) const {
1167
1185
  DynamicScopedLock l(syncher, lock);
1168
- return utilization(false) >= max;
1186
+ return capacityUsed(false) >= max;
1169
1187
  }
1170
1188
 
1171
1189
  vector<ProcessPtr> getProcesses(bool lock = true) const {
@@ -1196,7 +1214,8 @@ public:
1196
1214
 
1197
1215
  /**
1198
1216
  * Returns the total number of processes in the pool, including all disabling and
1199
- * disabled processes, but excluding processes that are shutting down.
1217
+ * disabled processes, but excluding processes that are shutting down and excluding
1218
+ * processes that are being spawned.
1200
1219
  */
1201
1220
  unsigned int getProcessCount(bool lock = true) const {
1202
1221
  DynamicScopedLock l(syncher, lock);
@@ -1385,34 +1404,33 @@ public:
1385
1404
  }
1386
1405
  }
1387
1406
 
1388
- unsigned int restartGroupsByAppRoot(const string &appRoot) {
1407
+ bool restartGroupByName(const StaticString &name, RestartMethod method = RM_DEFAULT) {
1389
1408
  ScopedLock l(syncher);
1390
1409
  SuperGroupMap::iterator sg_it, sg_end = superGroups.end();
1391
- unsigned int result = 0;
1392
1410
 
1393
1411
  for (sg_it = superGroups.begin(); sg_it != sg_end; sg_it++) {
1394
1412
  const SuperGroupPtr &superGroup = sg_it->second;
1395
1413
  foreach (const GroupPtr &group, superGroup->groups) {
1396
- if (group->options.appRoot == appRoot) {
1397
- result++;
1414
+ if (name == group->name) {
1398
1415
  if (!group->restarting()) {
1399
- group->restart(group->options);
1416
+ group->restart(group->options, method);
1400
1417
  }
1418
+ return true;
1401
1419
  }
1402
1420
  }
1403
1421
  }
1404
1422
 
1405
- return result;
1423
+ return false;
1406
1424
  }
1407
1425
 
1408
- unsigned int restartSuperGroupsByAppRoot(const string &appRoot) {
1426
+ unsigned int restartSuperGroupsByAppRoot(const StaticString &appRoot) {
1409
1427
  ScopedLock l(syncher);
1410
1428
  SuperGroupMap::iterator sg_it, sg_end = superGroups.end();
1411
1429
  unsigned int result = 0;
1412
1430
 
1413
1431
  for (sg_it = superGroups.begin(); sg_it != sg_end; sg_it++) {
1414
1432
  const SuperGroupPtr &superGroup = sg_it->second;
1415
- if (superGroup->options.appRoot == appRoot) {
1433
+ if (appRoot == superGroup->options.appRoot) {
1416
1434
  result++;
1417
1435
  superGroup->restart(superGroup->options);
1418
1436
  }
@@ -1470,7 +1488,13 @@ public:
1470
1488
  result << " (restarting...)" << endl;
1471
1489
  }
1472
1490
  if (group->spawning()) {
1473
- result << " (spawning new process...)" << endl;
1491
+ if (group->processesBeingSpawned == 0) {
1492
+ result << " (spawning...)" << endl;
1493
+ } else {
1494
+ result << " (spawning " << group->processesBeingSpawned << " new " <<
1495
+ maybePluralize(group->processesBeingSpawned, "process", "processes") <<
1496
+ "...)" << endl;
1497
+ }
1474
1498
  }
1475
1499
  result << " Requests in queue: " << group->getWaitlist.size() << endl;
1476
1500
  inspectProcessList(options, result, group, group->enabledProcesses);
@@ -1495,7 +1519,7 @@ public:
1495
1519
 
1496
1520
  result << "<process_count>" << getProcessCount(false) << "</process_count>";
1497
1521
  result << "<max>" << max << "</max>";
1498
- result << "<utilization>" << utilization(false) << "</utilization>";
1522
+ result << "<capacity_used>" << capacityUsed(false) << "</capacity_used>";
1499
1523
  result << "<get_wait_list_size>" << getWaitlist.size() << "</get_wait_list_size>";
1500
1524
 
1501
1525
  if (includeSecrets) {
@@ -1519,7 +1543,7 @@ public:
1519
1543
  result << "<name>" << escapeForXml(superGroup->name) << "</name>";
1520
1544
  result << "<state>" << superGroup->getStateName() << "</state>";
1521
1545
  result << "<get_wait_list_size>" << superGroup->getWaitlist.size() << "</get_wait_list_size>";
1522
- result << "<utilization>" << superGroup->utilization() << "</utilization>";
1546
+ result << "<capacity_used>" << superGroup->capacityUsed() << "</capacity_used>";
1523
1547
  if (includeSecrets) {
1524
1548
  result << "<secret>" << escapeForXml(superGroup->secret) << "</secret>";
1525
1549
  }