passenger 2.0.6 → 2.1.2

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 (497) hide show
  1. data/DEVELOPERS.TXT +10 -4
  2. data/LICENSE +1 -1
  3. data/NEWS +0 -0
  4. data/Rakefile +183 -117
  5. data/benchmark/dispatcher.rb +5 -9
  6. data/bin/passenger-install-apache2-module +52 -18
  7. data/bin/passenger-memory-stats +67 -13
  8. data/bin/passenger-spawn-server +8 -4
  9. data/bin/passenger-status +21 -46
  10. data/bin/passenger-stress-test +5 -5
  11. data/debian/postinst +1 -1
  12. data/doc/ApplicationPool algorithm.txt +180 -128
  13. data/doc/Architectural overview.html +1 -778
  14. data/doc/Security of user switching support.html +1 -643
  15. data/doc/Users guide Apache.html +3127 -0
  16. data/doc/Users guide Nginx.html +1458 -0
  17. data/doc/Users guide.html +1404 -467
  18. data/doc/Users guide.txt +843 -105
  19. data/doc/cxxapi/ApplicationPoolServer_8h-source.html +751 -641
  20. data/doc/cxxapi/ApplicationPool_8h-source.html +168 -171
  21. data/doc/cxxapi/Application_8h-source.html +494 -394
  22. data/doc/cxxapi/Bucket_8h-source.html +21 -15
  23. data/doc/cxxapi/CachedFileStat_8h-source.html +191 -0
  24. data/doc/cxxapi/Configuration_8h-source.html +311 -149
  25. data/doc/cxxapi/DirectoryMapper_8h-source.html +309 -0
  26. data/doc/cxxapi/DummySpawnManager_8h-source.html +3 -4
  27. data/doc/cxxapi/Exceptions_8h-source.html +182 -165
  28. data/doc/cxxapi/FileChecker_8h-source.html +130 -0
  29. data/doc/cxxapi/Hooks_8h-source.html +2 -3
  30. data/doc/cxxapi/Logging_8h-source.html +92 -89
  31. data/doc/cxxapi/MessageChannel_8h-source.html +585 -477
  32. data/doc/cxxapi/PoolOptions_8h-source.html +305 -0
  33. data/doc/cxxapi/SpawnManager_8h-source.html +515 -540
  34. data/doc/cxxapi/StandardApplicationPool_8h-source.html +779 -679
  35. data/doc/cxxapi/SystemTime_8h-source.html +104 -0
  36. data/doc/cxxapi/Utils_8h-source.html +331 -227
  37. data/doc/cxxapi/annotated.html +6 -7
  38. data/doc/cxxapi/classClient-members.html +1 -2
  39. data/doc/cxxapi/classClient.html +1 -2
  40. data/doc/cxxapi/classHooks-members.html +5 -2
  41. data/doc/cxxapi/classHooks.html +112 -2
  42. data/doc/cxxapi/classPassenger_1_1Application-members.html +2 -3
  43. data/doc/cxxapi/classPassenger_1_1Application.html +8 -9
  44. data/doc/cxxapi/classPassenger_1_1ApplicationPool-members.html +4 -4
  45. data/doc/cxxapi/classPassenger_1_1ApplicationPool.html +42 -81
  46. data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer-members.html +1 -2
  47. data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer.html +3 -4
  48. data/doc/cxxapi/classPassenger_1_1ApplicationPool__inherit__graph.png +0 -0
  49. data/doc/cxxapi/classPassenger_1_1Application_1_1Session-members.html +3 -2
  50. data/doc/cxxapi/classPassenger_1_1Application_1_1Session.html +74 -3
  51. data/doc/cxxapi/classPassenger_1_1BusyException-members.html +1 -2
  52. data/doc/cxxapi/classPassenger_1_1BusyException.html +2 -3
  53. data/doc/cxxapi/classPassenger_1_1ConfigurationException-members.html +1 -2
  54. data/doc/cxxapi/classPassenger_1_1ConfigurationException.html +2 -3
  55. data/doc/cxxapi/classPassenger_1_1DirectoryMapper-members.html +38 -0
  56. data/doc/cxxapi/classPassenger_1_1DirectoryMapper.html +256 -0
  57. data/doc/cxxapi/classPassenger_1_1DummySpawnManager-members.html +1 -2
  58. data/doc/cxxapi/classPassenger_1_1DummySpawnManager.html +2 -3
  59. data/doc/cxxapi/{classPassenger_1_1Thread-members.html → classPassenger_1_1FileChecker-members.html} +4 -5
  60. data/doc/cxxapi/classPassenger_1_1FileChecker.html +121 -0
  61. data/doc/cxxapi/classPassenger_1_1FileNotFoundException-members.html +1 -2
  62. data/doc/cxxapi/classPassenger_1_1FileNotFoundException.html +2 -3
  63. data/doc/cxxapi/classPassenger_1_1FileNotFoundException__inherit__graph.png +0 -0
  64. data/doc/cxxapi/classPassenger_1_1FileSystemException-members.html +2 -3
  65. data/doc/cxxapi/classPassenger_1_1FileSystemException.html +2 -3
  66. data/doc/cxxapi/classPassenger_1_1FileSystemException__inherit__graph.png +0 -0
  67. data/doc/cxxapi/classPassenger_1_1IOException-members.html +1 -2
  68. data/doc/cxxapi/classPassenger_1_1IOException.html +2 -3
  69. data/doc/cxxapi/classPassenger_1_1IOException__inherit__graph.png +0 -0
  70. data/doc/cxxapi/classPassenger_1_1MessageChannel-members.html +5 -2
  71. data/doc/cxxapi/classPassenger_1_1MessageChannel.html +155 -5
  72. data/doc/cxxapi/{classboost_1_1this__thread_1_1enable__syscall__interruption-members.html → classPassenger_1_1RuntimeException-members.html} +2 -3
  73. data/doc/cxxapi/{classboost_1_1this__thread_1_1enable__syscall__interruption.html → classPassenger_1_1RuntimeException.html} +10 -8
  74. data/doc/cxxapi/classPassenger_1_1SpawnException-members.html +1 -2
  75. data/doc/cxxapi/classPassenger_1_1SpawnException.html +2 -3
  76. data/doc/cxxapi/classPassenger_1_1SpawnManager-members.html +2 -3
  77. data/doc/cxxapi/classPassenger_1_1SpawnManager.html +15 -56
  78. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool-members.html +5 -4
  79. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool.html +20 -81
  80. data/doc/cxxapi/classPassenger_1_1StandardApplicationPool__inherit__graph.png +0 -0
  81. data/doc/cxxapi/classPassenger_1_1SystemException-members.html +2 -3
  82. data/doc/cxxapi/classPassenger_1_1SystemException.html +9 -10
  83. data/doc/cxxapi/classPassenger_1_1SystemException__inherit__graph.png +0 -0
  84. data/doc/cxxapi/{classboost_1_1this__thread_1_1disable__syscall__interruption-members.html → classPassenger_1_1SystemTime-members.html} +5 -3
  85. data/doc/cxxapi/classPassenger_1_1SystemTime.html +86 -0
  86. data/doc/cxxapi/classPassenger_1_1TempFile-members.html +2 -3
  87. data/doc/cxxapi/classPassenger_1_1TempFile.html +17 -9
  88. data/doc/cxxapi/definitions_8h-source.html +1 -2
  89. data/doc/cxxapi/files.html +6 -3
  90. data/doc/cxxapi/functions.html +98 -35
  91. data/doc/cxxapi/functions_func.html +60 -32
  92. data/doc/cxxapi/functions_type.html +1 -2
  93. data/doc/cxxapi/functions_vars.html +27 -2
  94. data/doc/cxxapi/graph_legend.html +1 -2
  95. data/doc/cxxapi/graph_legend.png +0 -0
  96. data/doc/cxxapi/group__Configuration.html +3 -4
  97. data/doc/cxxapi/group__Configuration.png +0 -0
  98. data/doc/cxxapi/group__Core.html +3 -4
  99. data/doc/cxxapi/group__Core.png +0 -0
  100. data/doc/cxxapi/group__Exceptions.html +4 -2
  101. data/doc/cxxapi/group__Hooks.html +1 -6
  102. data/doc/cxxapi/group__Hooks.png +0 -0
  103. data/doc/cxxapi/group__Support.html +259 -36
  104. data/doc/cxxapi/hierarchy.html +6 -7
  105. data/doc/cxxapi/inherit__graph__0.map +1 -1
  106. data/doc/cxxapi/inherit__graph__0.md5 +1 -1
  107. data/doc/cxxapi/inherit__graph__0.png +0 -0
  108. data/doc/cxxapi/inherit__graph__1.map +1 -1
  109. data/doc/cxxapi/inherit__graph__1.md5 +1 -1
  110. data/doc/cxxapi/inherit__graph__1.png +0 -0
  111. data/doc/cxxapi/inherit__graph__10.map +1 -1
  112. data/doc/cxxapi/inherit__graph__10.md5 +1 -1
  113. data/doc/cxxapi/inherit__graph__10.png +0 -0
  114. data/doc/cxxapi/inherit__graph__11.map +1 -1
  115. data/doc/cxxapi/inherit__graph__11.md5 +1 -1
  116. data/doc/cxxapi/inherit__graph__11.png +0 -0
  117. data/doc/cxxapi/inherit__graph__12.map +2 -1
  118. data/doc/cxxapi/inherit__graph__12.md5 +1 -1
  119. data/doc/cxxapi/inherit__graph__12.png +0 -0
  120. data/doc/cxxapi/inherit__graph__13.map +1 -1
  121. data/doc/cxxapi/inherit__graph__13.md5 +1 -1
  122. data/doc/cxxapi/inherit__graph__13.png +0 -0
  123. data/doc/cxxapi/inherit__graph__14.map +1 -2
  124. data/doc/cxxapi/inherit__graph__14.md5 +1 -1
  125. data/doc/cxxapi/inherit__graph__14.png +0 -0
  126. data/doc/cxxapi/inherit__graph__15.map +1 -1
  127. data/doc/cxxapi/inherit__graph__15.md5 +1 -1
  128. data/doc/cxxapi/inherit__graph__15.png +0 -0
  129. data/doc/cxxapi/inherit__graph__16.map +1 -1
  130. data/doc/cxxapi/inherit__graph__16.md5 +1 -1
  131. data/doc/cxxapi/inherit__graph__16.png +0 -0
  132. data/doc/cxxapi/inherit__graph__17.png +0 -0
  133. data/doc/cxxapi/inherit__graph__18.png +0 -0
  134. data/doc/cxxapi/inherit__graph__19.png +0 -0
  135. data/doc/cxxapi/inherit__graph__2.map +1 -1
  136. data/doc/cxxapi/inherit__graph__2.md5 +1 -1
  137. data/doc/cxxapi/inherit__graph__2.png +0 -0
  138. data/doc/cxxapi/inherit__graph__20.map +1 -1
  139. data/doc/cxxapi/inherit__graph__20.md5 +1 -1
  140. data/doc/cxxapi/inherit__graph__20.png +0 -0
  141. data/doc/cxxapi/inherit__graph__21.map +1 -1
  142. data/doc/cxxapi/inherit__graph__21.md5 +1 -1
  143. data/doc/cxxapi/inherit__graph__21.png +0 -0
  144. data/doc/cxxapi/inherit__graph__3.map +1 -1
  145. data/doc/cxxapi/inherit__graph__3.md5 +1 -1
  146. data/doc/cxxapi/inherit__graph__3.png +0 -0
  147. data/doc/cxxapi/inherit__graph__4.map +1 -1
  148. data/doc/cxxapi/inherit__graph__4.md5 +1 -1
  149. data/doc/cxxapi/inherit__graph__4.png +0 -0
  150. data/doc/cxxapi/inherit__graph__5.map +2 -1
  151. data/doc/cxxapi/inherit__graph__5.md5 +1 -1
  152. data/doc/cxxapi/inherit__graph__5.png +0 -0
  153. data/doc/cxxapi/inherit__graph__6.map +1 -1
  154. data/doc/cxxapi/inherit__graph__6.md5 +1 -1
  155. data/doc/cxxapi/inherit__graph__6.png +0 -0
  156. data/doc/cxxapi/inherit__graph__7.map +1 -1
  157. data/doc/cxxapi/inherit__graph__7.md5 +1 -1
  158. data/doc/cxxapi/inherit__graph__7.png +0 -0
  159. data/doc/cxxapi/inherit__graph__8.map +1 -1
  160. data/doc/cxxapi/inherit__graph__8.md5 +1 -1
  161. data/doc/cxxapi/inherit__graph__8.png +0 -0
  162. data/doc/cxxapi/inherit__graph__9.map +1 -2
  163. data/doc/cxxapi/inherit__graph__9.md5 +1 -1
  164. data/doc/cxxapi/inherit__graph__9.png +0 -0
  165. data/doc/cxxapi/inherits.html +30 -31
  166. data/doc/cxxapi/main.html +1 -2
  167. data/doc/cxxapi/modules.html +1 -2
  168. data/doc/cxxapi/structPassenger_1_1AnythingToString-members.html +1 -2
  169. data/doc/cxxapi/structPassenger_1_1AnythingToString.html +2 -3
  170. data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4-members.html +1 -2
  171. data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4.html +2 -3
  172. data/doc/cxxapi/structPassenger_1_1PoolOptions-members.html +49 -0
  173. data/doc/cxxapi/structPassenger_1_1PoolOptions.html +404 -0
  174. data/doc/cxxapi/tree.html +18 -20
  175. data/doc/images/conservative_spawning.png +0 -0
  176. data/doc/images/conservative_spawning.svg +248 -0
  177. data/doc/images/smart-lv2.png +0 -0
  178. data/doc/images/smart-lv2.svg +320 -0
  179. data/doc/rdoc/classes/ConditionVariable.html +68 -34
  180. data/doc/rdoc/classes/Exception.html +16 -16
  181. data/doc/rdoc/classes/GC.html +9 -9
  182. data/doc/rdoc/classes/IO.html +36 -17
  183. data/doc/rdoc/classes/PhusionPassenger.html +183 -0
  184. data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +511 -0
  185. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer.html +285 -242
  186. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerAlreadyStarted.html +3 -3
  187. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerError.html +3 -3
  188. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerNotStarted.html +3 -3
  189. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/UnknownMessage.html +3 -3
  190. data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +598 -0
  191. data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +140 -0
  192. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +247 -0
  193. data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +138 -0
  194. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AppInitError.html +36 -19
  195. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/Application.html +81 -96
  196. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/ConsoleTextTemplate.html +18 -18
  197. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/FrameworkInitError.html +20 -18
  198. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/HTMLTemplate.html +18 -18
  199. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/InitializationError.html +9 -9
  200. data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +92 -0
  201. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/MessageChannel.html +93 -92
  202. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/NativeSupport.html +55 -25
  203. data/doc/rdoc/classes/PhusionPassenger/Rack.html +91 -0
  204. data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +185 -0
  205. data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +182 -0
  206. data/doc/rdoc/classes/PhusionPassenger/Railz.html +95 -0
  207. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +424 -0
  208. data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +98 -0
  209. data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +200 -0
  210. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +444 -0
  211. data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +98 -0
  212. data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +154 -0
  213. data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +408 -0
  214. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/UnknownError.html +13 -13
  215. data/doc/rdoc/classes/PhusionPassenger/Utils.html +687 -0
  216. data/doc/rdoc/classes/{Passenger → PhusionPassenger}/VersionNotFound.html +8 -8
  217. data/doc/rdoc/classes/PhusionPassenger/WSGI.html +89 -0
  218. data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +188 -0
  219. data/doc/rdoc/classes/PlatformInfo.html +663 -159
  220. data/doc/rdoc/classes/RakeExtensions.html +4 -4
  221. data/doc/rdoc/classes/Signal.html +134 -0
  222. data/doc/rdoc/created.rid +1 -1
  223. data/doc/rdoc/files/DEVELOPERS_TXT.html +15 -10
  224. data/doc/rdoc/files/README.html +5 -7
  225. data/doc/rdoc/files/ext/{passenger → phusion_passenger}/native_support_c.html +2 -2
  226. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/abstract_request_handler_rb.html +7 -9
  227. data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +120 -0
  228. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/abstract_server_rb.html +7 -10
  229. data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +99 -0
  230. data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +92 -0
  231. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/application_rb.html +6 -8
  232. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/console_text_template_rb.html +5 -7
  233. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/constants_rb.html +4 -5
  234. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/dependencies_rb.html +6 -8
  235. data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +116 -0
  236. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/exceptions_rb.html +5 -7
  237. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/html_template_rb.html +5 -7
  238. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/message_channel_rb.html +5 -7
  239. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/platform_info_rb.html +6 -7
  240. data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +123 -0
  241. data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +117 -0
  242. data/doc/rdoc/files/lib/{passenger/utils_rb.html → phusion_passenger/railz/application_spawner_rb.html} +24 -17
  243. data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +126 -0
  244. data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +139 -0
  245. data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +118 -0
  246. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/simple_benchmarking_rb.html +5 -7
  247. data/doc/rdoc/files/lib/{passenger → phusion_passenger}/spawn_manager_rb.html +40 -24
  248. data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +169 -0
  249. data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +120 -0
  250. data/doc/rdoc/files/lib/rake/extensions_rb.html +3 -4
  251. data/doc/rdoc/fr_class_index.html +37 -19
  252. data/doc/rdoc/fr_file_index.html +25 -14
  253. data/doc/rdoc/fr_method_index.html +145 -74
  254. data/ext/apache2/Application.h +145 -44
  255. data/ext/apache2/ApplicationPool.h +27 -29
  256. data/ext/apache2/ApplicationPoolServer.h +183 -72
  257. data/ext/apache2/ApplicationPoolServerExecutable.cpp +249 -42
  258. data/ext/apache2/Bucket.cpp +61 -9
  259. data/ext/apache2/Bucket.h +15 -8
  260. data/ext/apache2/CachedFileStat.cpp +114 -0
  261. data/ext/apache2/CachedFileStat.h +169 -0
  262. data/ext/apache2/Configuration.cpp +213 -22
  263. data/ext/apache2/Configuration.h +176 -13
  264. data/ext/apache2/DirectoryMapper.h +287 -0
  265. data/ext/apache2/Exceptions.h +30 -12
  266. data/ext/apache2/FileChecker.h +108 -0
  267. data/ext/apache2/Hooks.cpp +709 -493
  268. data/ext/apache2/LICENSE-CNRI.TXT +15 -0
  269. data/ext/apache2/Logging.h +26 -22
  270. data/ext/apache2/MessageChannel.h +124 -15
  271. data/ext/apache2/PoolOptions.h +283 -0
  272. data/ext/apache2/SpawnManager.h +75 -99
  273. data/ext/apache2/StandardApplicationPool.h +296 -195
  274. data/ext/apache2/SystemTime.cpp +28 -0
  275. data/ext/apache2/SystemTime.h +82 -0
  276. data/ext/apache2/Utils.cpp +172 -18
  277. data/ext/apache2/Utils.h +124 -19
  278. data/ext/boost/cstdint.hpp +4 -2
  279. data/ext/boost/current_function.hpp +67 -0
  280. data/ext/boost/detail/sp_counted_base.hpp +4 -4
  281. data/ext/boost/thread/exceptions.hpp +2 -1
  282. data/ext/boost/thread/pthread/thread.hpp +11 -3
  283. data/ext/boost/thread/pthread/thread_data.hpp +2 -1
  284. data/ext/oxt/backtrace.cpp +172 -0
  285. data/ext/oxt/backtrace.hpp +135 -0
  286. data/ext/oxt/detail/backtrace_disabled.hpp +39 -0
  287. data/ext/oxt/detail/backtrace_enabled.hpp +155 -0
  288. data/ext/oxt/detail/spin_lock_gcc_x86.hpp +82 -0
  289. data/ext/oxt/detail/spin_lock_portable.hpp +38 -0
  290. data/ext/oxt/detail/spin_lock_pthreads.hpp +97 -0
  291. data/ext/oxt/detail/tracable_exception_disabled.hpp +46 -0
  292. data/ext/oxt/detail/tracable_exception_enabled.hpp +48 -0
  293. data/ext/oxt/macros.hpp +58 -0
  294. data/ext/oxt/spin_lock.hpp +55 -0
  295. data/ext/{apache2/System.cpp → oxt/system_calls.cpp} +87 -52
  296. data/ext/oxt/system_calls.hpp +234 -0
  297. data/ext/oxt/thread.cpp +32 -0
  298. data/ext/oxt/thread.hpp +223 -0
  299. data/ext/oxt/tracable_exception.cpp +87 -0
  300. data/ext/oxt/tracable_exception.hpp +35 -0
  301. data/{lib/passenger/constants.rb → ext/phusion_passenger/extconf.rb} +14 -9
  302. data/ext/{passenger → phusion_passenger}/native_support.c +33 -6
  303. data/lib/{passenger → phusion_passenger}/abstract_request_handler.rb +209 -93
  304. data/lib/{passenger → phusion_passenger}/abstract_server.rb +23 -8
  305. data/lib/phusion_passenger/abstract_server_collection.rb +301 -0
  306. data/lib/phusion_passenger/admin_tools.rb +25 -0
  307. data/lib/phusion_passenger/admin_tools/control_process.rb +107 -0
  308. data/lib/{passenger → phusion_passenger}/application.rb +13 -16
  309. data/lib/{passenger → phusion_passenger}/console_text_template.rb +2 -2
  310. data/{ext/passenger/extconf.rb → lib/phusion_passenger/constants.rb} +5 -5
  311. data/lib/{passenger → phusion_passenger}/dependencies.rb +38 -32
  312. data/lib/phusion_passenger/events.rb +45 -0
  313. data/lib/{passenger → phusion_passenger}/exceptions.rb +12 -5
  314. data/lib/{passenger → phusion_passenger}/html_template.rb +2 -2
  315. data/lib/{passenger → phusion_passenger}/message_channel.rb +3 -2
  316. data/lib/phusion_passenger/platform_info.rb +500 -0
  317. data/lib/{passenger → phusion_passenger}/rack/application_spawner.rb +29 -22
  318. data/lib/{passenger → phusion_passenger}/rack/request_handler.rb +14 -9
  319. data/lib/{passenger → phusion_passenger}/railz/application_spawner.rb +94 -74
  320. data/lib/{passenger → phusion_passenger}/railz/cgi_fixed.rb +2 -2
  321. data/lib/{passenger → phusion_passenger}/railz/framework_spawner.rb +86 -98
  322. data/lib/{passenger → phusion_passenger}/railz/request_handler.rb +6 -6
  323. data/lib/{passenger → phusion_passenger}/simple_benchmarking.rb +0 -0
  324. data/lib/{passenger → phusion_passenger}/spawn_manager.rb +136 -128
  325. data/lib/{passenger → phusion_passenger}/templates/apache2_config_snippets.txt.erb +0 -0
  326. data/lib/{passenger → phusion_passenger}/templates/apache_must_be_compiled_with_compatible_mpm.txt.erb +0 -0
  327. data/lib/phusion_passenger/templates/app_exited_during_initialization.html.erb +38 -0
  328. data/lib/{passenger → phusion_passenger}/templates/app_init_error.html.erb +0 -0
  329. data/lib/{passenger → phusion_passenger}/templates/database_error.html.erb +0 -0
  330. data/lib/{passenger → phusion_passenger}/templates/deployment_example.txt.erb +1 -1
  331. data/lib/{passenger → phusion_passenger}/templates/error_layout.css +0 -0
  332. data/lib/{passenger → phusion_passenger}/templates/error_layout.html.erb +0 -0
  333. data/lib/{passenger → phusion_passenger}/templates/framework_init_error.html.erb +0 -0
  334. data/lib/{passenger → phusion_passenger}/templates/general_error.html.erb +0 -0
  335. data/lib/{passenger → phusion_passenger}/templates/invalid_app_root.html.erb +1 -1
  336. data/lib/{passenger → phusion_passenger}/templates/load_error.html.erb +0 -0
  337. data/lib/{passenger → phusion_passenger}/templates/no_write_permission_to_passenger_root.txt.erb +0 -0
  338. data/lib/{passenger → phusion_passenger}/templates/possible_solutions_for_compilation_and_installation_problems.txt.erb +0 -0
  339. data/lib/{passenger → phusion_passenger}/templates/run_installer_as_root.txt.erb +0 -0
  340. data/lib/{passenger → phusion_passenger}/templates/version_not_found.html.erb +0 -0
  341. data/lib/{passenger → phusion_passenger}/templates/welcome.txt.erb +0 -0
  342. data/lib/{passenger → phusion_passenger}/utils.rb +210 -44
  343. data/lib/{passenger → phusion_passenger}/wsgi/application_spawner.rb +18 -15
  344. data/lib/{passenger → phusion_passenger}/wsgi/request_handler.py +7 -1
  345. data/man/passenger-memory-stats.8 +1 -1
  346. data/misc/render_error_pages.rb +1 -1
  347. data/test/ApplicationPoolServerTest.cpp +0 -28
  348. data/test/ApplicationPoolServer_ApplicationPoolTest.cpp +4 -0
  349. data/test/ApplicationPoolTest.cpp +307 -69
  350. data/test/CachedFileStatTest.cpp +262 -0
  351. data/test/FileCheckerTest.cpp +79 -0
  352. data/test/MessageChannelTest.cpp +3 -3
  353. data/test/PoolOptionsTest.cpp +37 -0
  354. data/test/SpawnManagerTest.cpp +4 -4
  355. data/test/StandardApplicationPoolTest.cpp +4 -0
  356. data/test/SystemTimeTest.cpp +37 -0
  357. data/test/UtilsTest.cpp +137 -0
  358. data/test/integration_tests.rb +270 -23
  359. data/test/oxt/backtrace_test.cpp +128 -0
  360. data/test/oxt/oxt_test_main.cpp +25 -0
  361. data/test/oxt/syscall_interruption_test.cpp +50 -0
  362. data/test/ruby/abstract_request_handler_spec.rb +83 -0
  363. data/test/ruby/abstract_server_collection_spec.rb +246 -0
  364. data/test/ruby/application_spec.rb +3 -3
  365. data/test/ruby/message_channel_spec.rb +2 -2
  366. data/test/ruby/rack/application_spawner_spec.rb +3 -5
  367. data/test/ruby/rails/application_spawner_spec.rb +54 -15
  368. data/test/ruby/rails/framework_spawner_spec.rb +6 -8
  369. data/test/ruby/rails/minimal_spawner_spec.rb +29 -0
  370. data/test/ruby/rails/spawner_error_handling_spec.rb +1 -1
  371. data/test/ruby/rails/spawner_privilege_lowering_spec.rb +3 -3
  372. data/test/ruby/spawn_manager_spec.rb +23 -12
  373. data/test/ruby/utils_spec.rb +36 -2
  374. data/test/ruby/wsgi/application_spawner_spec.rb +47 -0
  375. data/test/stub/apache2/httpd.conf.erb +3 -5
  376. data/test/stub/message_channel.rb +2 -2
  377. data/test/stub/message_channel_2.rb +2 -2
  378. data/test/stub/message_channel_3.rb +3 -3
  379. data/test/stub/minimal-railsapp/README +0 -0
  380. data/test/stub/minimal-railsapp/config/application.rb +0 -0
  381. data/test/stub/minimal-railsapp/config/environment.rb +0 -0
  382. data/test/stub/minimal-railsapp/vendor/rails/actionmailer/lib/action_mailer.rb +0 -0
  383. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +0 -0
  384. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_pack.rb +0 -0
  385. data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_view.rb +0 -0
  386. data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +0 -0
  387. data/test/stub/minimal-railsapp/vendor/rails/activeresource/lib/active_resource.rb +0 -0
  388. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support.rb +0 -0
  389. data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support/whiny_nil.rb +0 -0
  390. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/dispatcher.rb +0 -0
  391. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/initializer.rb +0 -0
  392. data/test/stub/minimal-railsapp/vendor/rails/railties/lib/ruby_version_check.rb +0 -0
  393. data/test/stub/rails_apps/foobar/app/controllers/foo_controller.rb +8 -0
  394. data/test/stub/rails_apps/foobar/config/environments/development.rb +1 -2
  395. data/test/stub/rails_apps/mycook/app/controllers/welcome_controller.rb +21 -1
  396. data/test/stub/rails_apps/mycook/sites/some.site/public/uploads.html +26 -0
  397. data/test/stub/rails_apps/mycook/sites/some.site/public/welcome/cached.html +26 -0
  398. data/test/stub/railsapp/app/controllers/application.rb +0 -0
  399. data/test/stub/railsapp/app/controllers/bar_controller_1.rb +0 -0
  400. data/test/stub/railsapp/app/controllers/bar_controller_2.rb +1 -1
  401. data/test/stub/railsapp/app/controllers/foo_controller.rb +4 -0
  402. data/test/stub/railsapp/app/helpers/application_helper.rb +0 -0
  403. data/test/stub/railsapp/config/boot.rb +0 -0
  404. data/test/stub/railsapp/config/database.yml +0 -0
  405. data/test/stub/railsapp/config/environment.rb +0 -0
  406. data/test/stub/railsapp/config/environments/development.rb +0 -0
  407. data/test/stub/railsapp/config/environments/production.rb +0 -0
  408. data/test/stub/railsapp/config/initializers/inflections.rb +0 -0
  409. data/test/stub/railsapp/config/initializers/mime_types.rb +0 -0
  410. data/test/stub/railsapp/config/routes.rb +0 -0
  411. data/test/stub/railsapp/public/useless.txt +0 -0
  412. data/test/stub/spawn_server.rb +3 -4
  413. data/test/stub/wsgi/passenger_wsgi.pyc +0 -0
  414. data/test/support/apache2_controller.rb +57 -7
  415. data/test/support/tut.h +15 -0
  416. data/vendor/README +12 -0
  417. data/vendor/README_FOR_PACKAGERS +1 -0
  418. data/vendor/rack-0.9.1/AUTHORS +8 -0
  419. data/vendor/rack-0.9.1/COPYING +18 -0
  420. data/vendor/rack-0.9.1/ChangeLog +1423 -0
  421. data/vendor/rack-0.9.1/KNOWN-ISSUES +18 -0
  422. data/vendor/rack-0.9.1/README +306 -0
  423. data/vendor/rack-0.9.1/Rakefile +188 -0
  424. data/vendor/rack-0.9.1/SPEC +129 -0
  425. data/vendor/rack-0.9.1/lib/rack.rb +86 -0
  426. data/vendor/rack-0.9.1/lib/rack/adapter/camping.rb +22 -0
  427. data/vendor/rack-0.9.1/lib/rack/auth/abstract/handler.rb +28 -0
  428. data/vendor/rack-0.9.1/lib/rack/auth/abstract/request.rb +37 -0
  429. data/vendor/rack-0.9.1/lib/rack/auth/basic.rb +58 -0
  430. data/vendor/rack-0.9.1/lib/rack/auth/digest/md5.rb +124 -0
  431. data/vendor/rack-0.9.1/lib/rack/auth/digest/nonce.rb +51 -0
  432. data/vendor/rack-0.9.1/lib/rack/auth/digest/params.rb +55 -0
  433. data/vendor/rack-0.9.1/lib/rack/auth/digest/request.rb +40 -0
  434. data/vendor/rack-0.9.1/lib/rack/auth/openid.rb +438 -0
  435. data/vendor/rack-0.9.1/lib/rack/builder.rb +67 -0
  436. data/vendor/rack-0.9.1/lib/rack/cascade.rb +36 -0
  437. data/vendor/rack-0.9.1/lib/rack/commonlogger.rb +61 -0
  438. data/vendor/rack-0.9.1/lib/rack/conditionalget.rb +43 -0
  439. data/vendor/rack-0.9.1/lib/rack/content_length.rb +25 -0
  440. data/vendor/rack-0.9.1/lib/rack/deflater.rb +87 -0
  441. data/vendor/rack-0.9.1/lib/rack/directory.rb +150 -0
  442. data/vendor/rack-0.9.1/lib/rack/file.rb +85 -0
  443. data/vendor/rack-0.9.1/lib/rack/handler.rb +48 -0
  444. data/vendor/rack-0.9.1/lib/rack/handler/cgi.rb +57 -0
  445. data/vendor/rack-0.9.1/lib/rack/handler/evented_mongrel.rb +8 -0
  446. data/vendor/rack-0.9.1/lib/rack/handler/fastcgi.rb +86 -0
  447. data/vendor/rack-0.9.1/lib/rack/handler/lsws.rb +52 -0
  448. data/vendor/rack-0.9.1/lib/rack/handler/mongrel.rb +82 -0
  449. data/vendor/rack-0.9.1/lib/rack/handler/scgi.rb +57 -0
  450. data/vendor/rack-0.9.1/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  451. data/vendor/rack-0.9.1/lib/rack/handler/thin.rb +15 -0
  452. data/vendor/rack-0.9.1/lib/rack/handler/webrick.rb +61 -0
  453. data/vendor/rack-0.9.1/lib/rack/head.rb +19 -0
  454. data/vendor/rack-0.9.1/lib/rack/lint.rb +465 -0
  455. data/vendor/rack-0.9.1/lib/rack/lobster.rb +65 -0
  456. data/vendor/rack-0.9.1/lib/rack/methodoverride.rb +27 -0
  457. data/vendor/rack-0.9.1/lib/rack/mime.rb +204 -0
  458. data/vendor/rack-0.9.1/lib/rack/mock.rb +160 -0
  459. data/vendor/rack-0.9.1/lib/rack/recursive.rb +57 -0
  460. data/vendor/rack-0.9.1/lib/rack/reloader.rb +64 -0
  461. data/vendor/rack-0.9.1/lib/rack/request.rb +218 -0
  462. data/vendor/rack-0.9.1/lib/rack/response.rb +171 -0
  463. data/vendor/rack-0.9.1/lib/rack/session/abstract/id.rb +153 -0
  464. data/vendor/rack-0.9.1/lib/rack/session/cookie.rb +89 -0
  465. data/vendor/rack-0.9.1/lib/rack/session/memcache.rb +97 -0
  466. data/vendor/rack-0.9.1/lib/rack/session/pool.rb +73 -0
  467. data/vendor/rack-0.9.1/lib/rack/showexceptions.rb +348 -0
  468. data/vendor/rack-0.9.1/lib/rack/showstatus.rb +106 -0
  469. data/vendor/rack-0.9.1/lib/rack/static.rb +38 -0
  470. data/vendor/rack-0.9.1/lib/rack/urlmap.rb +48 -0
  471. data/vendor/rack-0.9.1/lib/rack/utils.rb +347 -0
  472. metadata +1197 -1055
  473. data/doc/cxxapi/System_8h-source.html +0 -251
  474. data/doc/cxxapi/classDirectoryMapper-members.html +0 -38
  475. data/doc/cxxapi/classDirectoryMapper.html +0 -203
  476. data/doc/cxxapi/classPassenger_1_1Thread.html +0 -100
  477. data/doc/cxxapi/classboost_1_1this__thread_1_1disable__syscall__interruption.html +0 -46
  478. data/doc/cxxapi/classboost_1_1this__thread_1_1restore__syscall__interruption-members.html +0 -33
  479. data/doc/cxxapi/classboost_1_1this__thread_1_1restore__syscall__interruption.html +0 -44
  480. data/doc/cxxapi/namespacePassenger.html +0 -208
  481. data/doc/cxxapi/namespacePassenger_1_1InterruptableCalls.html +0 -43
  482. data/doc/cxxapi/namespacemembers.html +0 -70
  483. data/doc/cxxapi/namespacemembers_func.html +0 -66
  484. data/doc/cxxapi/namespacemembers_type.html +0 -46
  485. data/doc/cxxapi/namespaces.html +0 -35
  486. data/doc/rdoc/classes/Passenger.html +0 -136
  487. data/doc/rdoc/classes/Passenger/AbstractRequestHandler.html +0 -402
  488. data/doc/rdoc/classes/Passenger/SpawnManager.html +0 -379
  489. data/doc/rdoc/classes/Passenger/Utils.html +0 -578
  490. data/ext/apache2/System.h +0 -228
  491. data/lib/passenger/platform_info.rb +0 -302
  492. data/lib/passenger/templates/app_exited_during_initialization.html.erb +0 -19
  493. data/test/stub/apache2/httpd.conf +0 -75
  494. data/test/stub/rails_apps/foobar/config/environments/test.rb +0 -22
  495. data/test/stub/rails_apps/mycook/config/environments/test.rb +0 -22
  496. data/test/stub/railsapp/config/environments/test.rb +0 -22
  497. data/test/stub/railsapp2/config/environments/test.rb +0 -22
@@ -2,16 +2,15 @@
2
2
  # Benchmark raw speed of the Rails dispatcher.
3
3
  PASSENGER_ROOT = File.expand_path("#{File.dirname(__FILE__)}/..")
4
4
  $LOAD_PATH << "#{PASSENGER_ROOT}/lib"
5
+ $LOAD_PATH << "#{PASSENGER_ROOT}/ext"
5
6
  ENV["RAILS_ENV"] = "production"
6
7
 
7
8
  require 'yaml'
8
9
  require 'benchmark'
9
- require 'passenger/request_handler'
10
10
  require 'config/environment'
11
+ require 'passenger/railz/cgi_fixed'
11
12
  require 'dispatcher'
12
13
 
13
- include Passenger
14
-
15
14
  class OutputChannel
16
15
  def write(data)
17
16
  # Black hole
@@ -25,7 +24,7 @@ def start(iterations)
25
24
  milestone = 1 if milestone == 0
26
25
  result = Benchmark.measure do
27
26
  iterations.times do |i|
28
- cgi = CGIFixed.new(headers, output, STDOUT)
27
+ cgi = PhusionPassenger::Railz::CGIFixed.new(headers, output, output)
29
28
  ::Dispatcher.dispatch(cgi,
30
29
  ::ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS,
31
30
  cgi.stdoutput)
@@ -39,8 +38,5 @@ def start(iterations)
39
38
  end
40
39
 
41
40
  puts "Benchmark started."
42
- t = Thread.new do
43
- #start(ARGV[0] ? ARGV[0].to_i : 1000)
44
- end
45
- start(ARGV[0] ? ARGV[0].to_i : 1000)
46
- t.join
41
+ start(ARGV[0] ? ARGV[0].to_i : 2000)
42
+
@@ -27,13 +27,14 @@ $LOAD_PATH.unshift("#{PASSENGER_ROOT}/ext")
27
27
  # the start (i.e. not via 'su' or 'sudo').
28
28
  ENV["PATH"] += ":/usr/sbin:/sbin:/usr/local/sbin"
29
29
 
30
- require 'passenger/platform_info'
31
- require 'passenger/dependencies'
32
- require 'passenger/console_text_template'
30
+ require 'optparse'
31
+ require 'phusion_passenger/platform_info'
32
+ require 'phusion_passenger/dependencies'
33
+ require 'phusion_passenger/console_text_template'
33
34
  include PlatformInfo
34
35
 
35
36
  class Installer
36
- include Passenger
37
+ include PhusionPassenger
37
38
 
38
39
  PASSENGER_WEBSITE = "http://www.modrails.com/"
39
40
  PHUSION_WEBSITE = "www.phusion.nl"
@@ -45,14 +46,25 @@ class Installer
45
46
  Dependencies::RubyGems,
46
47
  Dependencies::Rake,
47
48
  Dependencies::Apache2,
48
- Dependencies::Apache2_DevHeaders,
49
- Dependencies::APR_DevHeaders,
50
- Dependencies::APU_DevHeaders,
51
- Dependencies::FastThread,
52
- Dependencies::Rack
49
+ Dependencies::Apache2_DevHeaders
53
50
  ]
51
+ if Dependencies.fastthread_required?
52
+ REQUIRED_DEPENDENCIES << Dependencies::FastThread
53
+ end
54
+ # Some broken servers don't have apr-config or apu-config installed.
55
+ # Nevertheless, it is possible to compile Apache modules if Apache
56
+ # was configured with --included-apr. So here we check whether
57
+ # apr-config and apu-config are available. If they're not available,
58
+ # then we only register them as required dependency if no Apache
59
+ # module can be compiled without their presence.
60
+ if (PlatformInfo.apr_config && PlatformInfo.apu_config) ||
61
+ PlatformInfo.apr_config_needed_for_building_apache_modules?
62
+ REQUIRED_DEPENDENCIES << Dependencies::APR_DevHeaders
63
+ REQUIRED_DEPENDENCIES << Dependencies::APU_DevHeaders
64
+ end
54
65
 
55
- def start
66
+ def start(automatic = false)
67
+ @auto = automatic
56
68
  if natively_packaged?
57
69
  check_dependencies || exit(1)
58
70
  show_apache2_config_snippets
@@ -147,7 +159,7 @@ private
147
159
  # ...
148
160
  # Server compiled with....
149
161
  # -D APACHE_MPM_DIR="server/mpm/prefork"
150
- output = `#{HTTPD} -V`
162
+ output = `#{PlatformInfo.httpd} -V`
151
163
  output =~ /^Server MPM: +(.*)$/
152
164
  if $1
153
165
  mpm = $1.downcase
@@ -188,11 +200,11 @@ private
188
200
  color_puts '<banner>Compiling and installing Apache 2 module...</banner>'
189
201
  puts "cd #{PASSENGER_ROOT}"
190
202
  if ENV['TRACE']
191
- puts "#{RUBY} -S rake --trace clean apache2"
192
- return system(RUBY, "-S", "rake", "--trace", "clean", "apache2")
203
+ puts "#{RUBY} -S #{PlatformInfo.rake} --trace clean apache2"
204
+ return system(RUBY, "-S", PlatformInfo.rake, "--trace", "clean", "apache2")
193
205
  else
194
- puts "#{RUBY} -S rake clean apache2"
195
- return system(RUBY, "-S", "rake", "clean", "apache2")
206
+ puts "#{RUBY} -S #{PlatformInfo.rake} clean apache2"
207
+ return system(RUBY, "-S", PlatformInfo.rake, "clean", "apache2")
196
208
  end
197
209
  end
198
210
 
@@ -200,7 +212,7 @@ private
200
212
  puts
201
213
  line
202
214
  if natively_packaged?
203
- module_location = "#{PASSENGER_ROOT}/lib/passenger/mod_passenger.so"
215
+ module_location = "#{PASSENGER_ROOT}/lib/phusion_passenger/mod_passenger.so"
204
216
  else
205
217
  module_location = "#{PASSENGER_ROOT}/ext/apache2/mod_passenger.so"
206
218
  end
@@ -251,6 +263,7 @@ private
251
263
  end
252
264
 
253
265
  def wait(timeout = nil)
266
+ return if @auto
254
267
  begin
255
268
  if timeout
256
269
  require 'timeout' unless defined?(Timeout)
@@ -305,7 +318,7 @@ private
305
318
 
306
319
  def self.determine_users_guide
307
320
  if natively_packaged?
308
- return "/usr/share/doc/passenger/Users guide.html"
321
+ return "/usr/share/doc/phusion_passenger/Users guide.html"
309
322
  else
310
323
  return "#{PASSENGER_ROOT}/doc/Users guide.html"
311
324
  end
@@ -315,4 +328,25 @@ private
315
328
  USERS_GUIDE = determine_users_guide
316
329
  end
317
330
 
318
- Installer.new.start
331
+ options = {}
332
+ parser = OptionParser.new do |opts|
333
+ opts.banner = "Usage: passenger-install-apache2-module [options]"
334
+ opts.separator ""
335
+
336
+ opts.separator "Options:"
337
+ opts.on("-a", "--auto", String, "Automatically build the Apache module,\n" <<
338
+ "#{' ' * 37}without interactively asking for user\n" <<
339
+ "#{' ' * 37}input.") do
340
+ options[:auto] = true
341
+ end
342
+ end
343
+ begin
344
+ parser.parse!
345
+ rescue OptionParser::ParseError => e
346
+ puts e
347
+ puts
348
+ puts "Please see '--help' for valid options."
349
+ exit 1
350
+ end
351
+
352
+ Installer.new.start(options[:auto])
@@ -18,7 +18,14 @@
18
18
  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
19
 
20
20
  $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib")
21
- require 'passenger/platform_info'
21
+ require 'phusion_passenger/platform_info'
22
+
23
+ # ANSI color codes
24
+ RESET = "\e[0m"
25
+ BOLD = "\e[1m"
26
+ WHITE = "\e[37m"
27
+ YELLOW = "\e[33m"
28
+ BLUE_BG = "\e[44m"
22
29
 
23
30
  # Container for tabular data.
24
31
  class Table
@@ -64,14 +71,22 @@ class Table
64
71
  left_bar_size = free_space / 2
65
72
  right_bar_size = free_space - left_bar_size
66
73
  end
67
- result = "#{"-" * left_bar_size} #{title} #{"-" * right_bar_size}\n"
68
- result << header
74
+ result = "#{BLUE_BG}#{BOLD}#{YELLOW}"
75
+ result << "#{"-" * left_bar_size} #{title} #{"-" * right_bar_size}\n"
76
+ if !@rows.empty?
77
+ result << WHITE
78
+ result << header
79
+ end
69
80
  else
70
81
  result = header.dup
71
82
  end
72
- result << ("-" * header.size) << "\n"
73
- @rows.each do |row|
74
- result << sprintf(format_string, *row).rstrip << "\n"
83
+ if @rows.empty?
84
+ result << RESET
85
+ else
86
+ result << ("-" * header.size) << "#{RESET}\n"
87
+ @rows.each do |row|
88
+ result << sprintf(format_string, *row).rstrip << "\n"
89
+ end
75
90
  end
76
91
  result
77
92
  end
@@ -109,12 +124,25 @@ class MemoryStats
109
124
  end
110
125
 
111
126
  def start
112
- apache_processes = list_processes(:exe => PlatformInfo::HTTPD)
127
+ if PlatformInfo.httpd.nil?
128
+ STDERR.puts "*** ERROR: The Apache executable cannot be found."
129
+ STDERR.puts "Please set the APXS2 environment variable to your 'apxs2' " <<
130
+ "executable's filename, or set the HTTPD environment variable " <<
131
+ "to your 'httpd' or 'apache2' executable's filename."
132
+ exit 1
133
+ end
134
+
135
+ apache_processes = list_processes(:exe => PlatformInfo.httpd)
136
+ if apache_processes.empty?
137
+ # On some Linux distros, the Apache worker processes
138
+ # are called "httpd.worker"
139
+ apache_processes = list_processes(:exe => "#{PlatformInfo.httpd}.worker")
140
+ end
113
141
  print_process_list("Apache processes", apache_processes)
114
142
 
115
143
  puts
116
144
  passenger_processes = list_processes(:match =>
117
- /(^Passenger |^Rails:|^Rack:|ApplicationPoolServerExecutable)/)
145
+ /((^| )Passenger |(^| )Rails:|(^| )Rack:|ApplicationPoolServerExecutable)/)
118
146
  print_process_list("Passenger processes", passenger_processes, :show_ppid => false)
119
147
 
120
148
  if RUBY_PLATFORM !~ /linux/
@@ -141,9 +169,19 @@ class MemoryStats
141
169
  def list_processes(options)
142
170
  if options[:exe]
143
171
  name = options[:exe].sub(/.*\/(.*)/, '\1')
144
- ps = "ps -C '#{name}'"
172
+ if RUBY_PLATFORM =~ /linux/
173
+ ps = "ps -C '#{name}'"
174
+ else
175
+ ps = "ps -A"
176
+ options[:match] = Regexp.new(Regexp.escape(name))
177
+ end
145
178
  elsif options[:name]
146
- ps = "ps -C '#{options[:name]}'"
179
+ if RUBY_PLATFORM =~ /linux/
180
+ ps = "ps -C '#{options[:name]}'"
181
+ else
182
+ ps = "ps -A"
183
+ options[:match] = Regexp.new(" #{Regexp.escape(options[:name])}")
184
+ end
147
185
  elsif options[:match]
148
186
  ps = "ps -A"
149
187
  else
@@ -151,21 +189,37 @@ class MemoryStats
151
189
  end
152
190
 
153
191
  processes = []
154
- list = `#{ps} -w -o pid,ppid,nlwp,vsz,rss,command`.split("\n")
192
+ case RUBY_PLATFORM
193
+ when /solaris/
194
+ list = `#{ps} -o pid,ppid,nlwp,vsz,rss,comm`.split("\n")
195
+ threads_known = true
196
+ when /darwin/
197
+ list = `#{ps} -w -o pid,ppid,vsz,rss,command`.split("\n")
198
+ threads_known = false
199
+ else
200
+ list = `#{ps} -w -o pid,ppid,nlwp,vsz,rss,command`.split("\n")
201
+ threads_known = true
202
+ end
155
203
  list.shift
156
204
  list.each do |line|
157
205
  line.gsub!(/^ */, '')
158
206
  line.gsub!(/ *$/, '')
159
207
 
160
208
  p = Process.new
161
- p.pid, p.ppid, p.threads, p.vm_size, p.rss, p.name = line.split(/ +/, 6)
209
+ if threads_known
210
+ p.pid, p.ppid, p.threads, p.vm_size, p.rss, p.name = line.split(/ +/, 6)
211
+ else
212
+ p.pid, p.ppid, p.vm_size, p.rss, p.name = line.split(/ +/, 6)
213
+ p.threads = "?"
214
+ end
162
215
  p.name.sub!(/\Aruby: /, '')
163
216
  p.name.sub!(/ \(ruby\)\Z/, '')
164
217
  if p.name !~ /^ps/ && (!options[:match] || p.name.match(options[:match]))
165
218
  # Convert some values to integer.
166
- [:pid, :ppid, :threads, :vm_size, :rss].each do |attr|
219
+ [:pid, :ppid, :vm_size, :rss].each do |attr|
167
220
  p.send("#{attr}=", p.send(attr).to_i)
168
221
  end
222
+ p.threads = p.threads.to_i if threads_known
169
223
 
170
224
  if platform_provides_private_dirty_rss_information?
171
225
  p.private_dirty_rss = determine_private_dirty_rss(p.pid)
@@ -41,13 +41,17 @@ begin
41
41
  exit
42
42
  end
43
43
 
44
- require 'passenger/spawn_manager'
45
- spawn_manager = Passenger::SpawnManager.new
44
+ require 'phusion_passenger/spawn_manager'
45
+ require 'phusion_passenger/utils'
46
+ if defined?(PhusionPassenger::NativeSupport)
47
+ PhusionPassenger::NativeSupport.disable_stdio_buffering
48
+ end
49
+ spawn_manager = PhusionPassenger::SpawnManager.new
46
50
  spawn_manager.start_synchronously(input)
47
51
  spawn_manager.cleanup
48
52
  rescue => e
49
- require 'passenger/utils'
50
- include Passenger::Utils
53
+ require 'phusion_passenger/utils'
54
+ include PhusionPassenger::Utils
51
55
  print_exception("spawn manager", e)
52
56
  exit 10
53
57
  end
data/bin/passenger-status CHANGED
@@ -19,63 +19,38 @@
19
19
 
20
20
  $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../lib")
21
21
  $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../ext")
22
+ require 'phusion_passenger/admin_tools/control_process'
22
23
 
23
- class StatusFifo
24
- attr_accessor :filename
25
- attr_accessor :pid
26
-
27
- def initialize(filename, pid)
28
- @filename = filename
29
- @pid = pid
30
- end
31
- end
24
+ include PhusionPassenger::AdminTools
32
25
 
33
- # Returns an array of all status FIFO files that are alive,
34
- # and attempt to remove stale status FIFO files.
35
- def list_and_clean_status_fifos
36
- result = []
37
- Dir["/tmp/passenger_status.*.fifo"].each do |filename|
38
- filename =~ /(\d+).fifo$/
39
- pid = $1.to_i
40
- if process_is_alive?(pid)
41
- result << StatusFifo.new(filename, pid)
42
- else
43
- puts "*** NOTICE: Removing stale status FIFO file #{filename}"
44
- File.unlink(filename) rescue nil
45
- end
46
- end
47
- return result
48
- end
26
+ # ANSI color codes
27
+ RESET = "\e[0m"
28
+ BOLD = "\e[1m"
29
+ YELLOW = "\e[33m"
30
+ BLUE_BG = "\e[44m"
49
31
 
50
- def process_is_alive?(pid)
32
+ def show_status(control_process, format = :text)
51
33
  begin
52
- Process.kill(0, pid)
53
- return true
54
- rescue Errno::ESRCH
55
- return false
34
+ text = control_process.status
56
35
  rescue SystemCallError => e
57
- return true
58
- end
59
- end
60
-
61
- def show_status(status_fifo)
62
- begin
63
- puts File.read(status_fifo.filename)
64
- rescue => e
65
- STDERR.puts "*** ERROR: Cannot query status for Passenger instance #{status_fifo.pid}:"
36
+ STDERR.puts "*** ERROR: Cannot query status for Passenger instance #{control_process.pid}:"
66
37
  STDERR.puts e.to_s
67
38
  exit 2
68
39
  end
40
+ # Colorize output
41
+ text.gsub!(/^(----)(.*)$/, YELLOW + BLUE_BG + BOLD + '\1\2' + RESET)
42
+ text.gsub!(/^( +in '.*? )(.*?)\(/, '\1' + BOLD + '\2' + RESET + '(')
43
+ puts text
69
44
  end
70
45
 
71
46
  def start
72
47
  if ARGV.empty?
73
- status_fifos = list_and_clean_status_fifos
74
- if status_fifos.size == 0
48
+ control_processes = ControlProcess.list
49
+ if control_processes.empty?
75
50
  STDERR.puts("ERROR: Phusion Passenger doesn't seem to be running.")
76
51
  exit 2
77
- elsif status_fifos.size == 1
78
- show_status(status_fifos[0])
52
+ elsif control_processes.size == 1
53
+ show_status(control_processes.first)
79
54
  else
80
55
  puts "It appears that multiple Passenger instances are running. Please select a"
81
56
  puts "specific one by running:"
@@ -83,13 +58,13 @@ def start
83
58
  puts " passenger-status <PID>"
84
59
  puts
85
60
  puts "The following Passenger instances are running:"
86
- status_fifos.each do |status_fifo|
87
- puts " PID: #{status_fifo.pid}"
61
+ control_processes.each do |control|
62
+ puts " PID: #{control.pid}"
88
63
  end
89
64
  exit 1
90
65
  end
91
66
  else
92
- show_status(StatusFifo.new("/tmp/passenger_status.#{ARGV[0]}.fifo", ARGV[0].to_i))
67
+ show_status(ControlProcess.new(ARGV[0].to_i))
93
68
  end
94
69
  end
95
70
 
@@ -23,12 +23,12 @@ require 'rubygems'
23
23
  require 'optparse'
24
24
  require 'socket'
25
25
  require 'thread'
26
- require 'passenger/platform_info'
27
- require 'passenger/message_channel'
28
- require 'passenger/utils'
26
+ require 'phusion_passenger/platform_info'
27
+ require 'phusion_passenger/message_channel'
28
+ require 'phusion_passenger/utils'
29
29
 
30
- include Passenger
31
- include Passenger::Utils
30
+ include PhusionPassenger
31
+ include PhusionPassenger::Utils
32
32
  include PlatformInfo
33
33
 
34
34
  # A thread or a process, depending on the Ruby VM implementation.
data/debian/postinst CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/bin/sh
2
2
  if ruby -e ''; then
3
- if ! ruby -rpassenger/native_support -e '' 2>/dev/null; then
3
+ if ! ruby -rphusion_passenger/native_support -e '' 2>/dev/null; then
4
4
  export RUBYLIB=/usr/lib/ruby/1.8
5
5
  fi
6
6
  passenger-install-apache2-module
@@ -3,17 +3,27 @@
3
3
 
4
4
  == Introduction
5
5
 
6
- For efficiency reasons, Passenger keeps a pool spawned Rails applications.
6
+ For efficiency reasons, Passenger keeps a pool spawned Rails/Ruby applications.
7
7
  Please read the C++ API documentation for the ApplicationPool class for a full
8
- introduction. This document describes an algorithm for managing the pool.
8
+ introduction. This document describes an algorithm for managing the pool, in a
9
+ high-level way.
9
10
 
10
11
  The algorithm should strive to keep spawning to a minimum.
11
12
 
12
- TODO: check whether the algorithm has thrashing behavior.
13
-
14
13
 
15
14
  == Definitions
16
15
 
16
+ === Vocabulary
17
+
18
+ - "Application root":
19
+ The toplevel directory in which an application is contained. For Rails
20
+ application, this is the same as RAILS_ROOT, i.e. the directory that contains
21
+ "app/", "public/", etc. For a Rack application, this is the directory that
22
+ contains "config.ru".
23
+
24
+ - "Active application instance":
25
+ An application instance that has more than 0 active sessions.
26
+
17
27
  === Types
18
28
 
19
29
  Most of the types that we use in this document are pretty standard. But we
@@ -35,13 +45,44 @@ explicitly define some special types:
35
45
  Moves the specified element to the front of the list. _iterator_ is an
36
46
  iterator, as described earlier.
37
47
 
48
+ - Domain
49
+ A compound type (class) which contains information about an application root,
50
+ such as the application instances that have been spawned for this application
51
+ root.
52
+
53
+ A Domain has the following members:
54
+ * instances (list<AppContainer>) - a list of AppContainer objects.
55
+
56
+ Invariant:
57
+ containers is non-empty.
58
+ for all 0 <= i < containers.size() - 1:
59
+ if containers[i].app is active:
60
+ containers[i + 1].app is active
61
+
62
+ * size (unsigned integer): The number of items in _instances_.
63
+
64
+ * max_requests (unsigned integer): The maximum number of requests that each
65
+ application instance in this domain may process. After having processed this
66
+ many requests, the application instance will be shut down.
67
+ A value of 0 indicates that there is no maximum.
68
+
69
+ * restart_file_checker
70
+ An object which monitors the restart.txt file, which belongs to this
71
+ application root, for changes. This object has the method changed(),
72
+ which rteurns whether restart.txt's timestamp has changed since the last
73
+ check.
74
+
38
75
  - AppContainer
39
- A compound type which contains an application instance, as well as iterators
40
- for various linked lists. These iterators make it possible to perform actions
41
- on the linked list in O(1) time.
76
+ A compound type (class) which contains an application instance, as well as
77
+ iterators for various linked lists. These iterators make it possible to
78
+ perform actions on the linked list in O(1) time.
42
79
 
43
80
  An AppContainer has the following members:
44
81
  * app - An Application object, representing an application instance.
82
+ * start_time (time) - The time at which this application instance was
83
+ started. It's set to the current time by AppContainer's constructor.
84
+ * processed_requests (integer) - The number of requests processed by this
85
+ application instance so far.
45
86
  * last_used (time) - The last time a session for this application instance
46
87
  was opened or closed.
47
88
  * sessions (integer) - The number of open sessions for this application
@@ -49,11 +90,24 @@ explicitly define some special types:
49
90
  Invariant:
50
91
  (sessions == 0) == (This AppContainer is in inactive_apps.)
51
92
  * iterator - The iterator for this AppContainer in the linked list
52
- apps[app.app_root]
93
+ domains[app.app_root].instances
53
94
  * ia_iterator - The iterator for this AppContainer in the linked list
54
95
  inactive_apps. This iterator is only valid if this AppContainer really is
55
96
  in that list.
56
97
 
98
+ - PoolOptions
99
+ A structure containing additional information used by the spawn manager's
100
+ spawning process, as well as by the get() function.
101
+
102
+ A PoolOptions has the following members:
103
+ * max_requests (unsigned integer) - The maximum number of requests that the
104
+ application instance may process. After having processed this many requests,
105
+ the application instance will be shut down. A value of 0 indicates that there
106
+ is no maximum.
107
+ * use_global_queue (boolean) - Whether to use a global queue for all
108
+ application instances, or a queue that's private to the application instance.
109
+ The users guide explains this feature in more detail.
110
+
57
111
  === Special functions
58
112
 
59
113
  - spawn(app_root)
@@ -71,33 +125,29 @@ information:
71
125
  is non-recursive, i.e. if a thread locks a mutex that it has already locked,
72
126
  then it will result in a deadlock.
73
127
 
74
- - apps: map[string => list<AppContainer>]
75
- Maps an application root to a list of AppContainers. Thus, this map contains
76
- all application instances that are in the pool.
128
+ - domains: map[string => Domain]
129
+ Maps an application root to its Domain object. This map contains all
130
+ application instances in the pool.
77
131
 
78
132
  Invariant:
79
- for all values v in app:
80
- v is nonempty.
81
- for all 0 <= i < v.size() - 1:
82
- if v[i].app is active:
83
- v[i + 1].app is active
133
+ for all values d in domains:
134
+ d.size <= count
135
+ (sum of all d.size in domains) == count
84
136
 
85
- An active application is one that has more than 0 active sessions.
86
-
87
137
  - max: integer
88
- The maximum number of AppContainer objects that may exist in 'apps'.
138
+ The maximum number of AppContainer objects that may exist in the pool.
89
139
 
90
140
  - max_per_app: integer
91
- The maximum number of concurrent AppContainer objects a single
92
- application may spawn.
141
+ The maximum number of AppContainer objects that may be simultaneously alive
142
+ for a single Domain.
93
143
 
94
144
  - count: integer
95
- The current number of AppContainer objects in 'apps'.
145
+ The current number of AppContainer objects in the pool.
96
146
  Since 'max' can be set dynamically during the life time of an application
97
147
  pool, 'count > max' is possible.
98
148
 
99
149
  - active: integer
100
- The number of application instances in 'apps' that are active.
150
+ The number of application instances in the pool that are active.
101
151
  Invariant:
102
152
  active <= count
103
153
 
@@ -108,31 +158,29 @@ information:
108
158
  Invariant:
109
159
  inactive_apps.size() == count - active
110
160
  for all c in inactive_apps:
111
- c is in apps.
161
+ c can be found in _domains_.
112
162
  c.sessions == 0
113
163
 
114
- - restart_file_times: map[string => time]
115
- Maps an application root to the last known modification time of
116
- 'restart.txt'.
117
-
118
- Invariant:
119
- for all keys app_root in restart_times:
120
- apps.has_key(app_root)
121
-
122
164
  - waiting_on_global_queue: integer
123
165
  If global queuing mode is enabled, then when get() is waiting for a backend
124
166
  process to become idle, this variable will be incremented. When get() is done
125
167
  waiting, this variable will be decremented.
126
168
 
127
- - app_instance_count: map[string => unsigned int]
128
- Maps an application root to the number of spawned applications.
129
169
 
130
- Invariant:
131
- app_instance_count.keys == apps.keys
132
- for all (app_root, app_count) in app_instance_count:
133
- app_instance_count[app_root] < count
134
- app_count == apps[app_root].size()
135
- (sum of all values in app_instance_count) == count.
170
+ == Class relations
171
+
172
+ Here's an UML diagram in ASCII art:
173
+
174
+ [AppContainer] 1..* -------+
175
+ |
176
+ |
177
+
178
+ 1
179
+ [ApplicationPool] [Domain]
180
+ 1 0..*
181
+
182
+ | |
183
+ +-------------------+
136
184
 
137
185
 
138
186
  == Algorithm in pseudo code
@@ -140,64 +188,68 @@ information:
140
188
  # Thread-safetiness notes:
141
189
  # - All wait commands are to unlock the lock during waiting.
142
190
 
143
- function get(app_root):
191
+ # Connect to an existing application instance or to a newly spawned application instance.
192
+ # 'app_root' specifies the application root folder of the application. 'options' is an
193
+ # object of type 'PoolOptions', which contains additional information which may be
194
+ # relevant for spawning.
195
+ function get(app_root, options):
144
196
  MAX_ATTEMPTS = 10
145
197
  attempt = 0
146
198
  time_limit = now() + 5 seconds
147
199
  lock.synchronize:
148
200
  while (true):
149
201
  attempt++
150
- container, list = spawn_or_use_existing(app_root)
202
+ container, domain = spawn_or_use_existing(app_root, options)
151
203
  container.last_used = current_time()
152
204
  container.sessions++
153
205
  try:
154
206
  return container.app.connect()
155
207
  on exception:
208
+ # The app instance seems to have crashed.
209
+ # So we remove this instance from our data
210
+ # structures.
156
211
  container.sessions--
212
+ instances = domain.instances
213
+ instances.remove(container.iterator)
214
+ domain.size--
215
+ if instances.empty():
216
+ domains.remove(app_root)
217
+ count--
218
+ active--
157
219
  if (attempt == MAX_ATTEMPTS):
158
220
  propagate exception
159
- else:
160
- # The app instance seems to have crashed.
161
- # So we remove this instance from our data
162
- # structures.
163
- list.remove(container.iterator)
164
- if list.empty():
165
- apps.remove(app_root)
166
- app_instance_count.remove(app_root)
167
- count--
168
- active--
169
221
 
170
222
 
171
- # Returns a pair of [AppContainer, list<AppContainer>] that matches the
172
- # given application root. If no such AppContainer exists, then it is created
173
- # and a new application instance is spawned. All exceptions that occur are
174
- # propagated.
175
- function spawn_or_use_existing(app_root):
176
- list = apps[app_root]
223
+ # Returns a pair of [AppContainer, Domain] that matches the given application
224
+ # root. If no such AppContainer exists, then it is created and a new
225
+ # application instance is spawned. All exceptions that occur are propagated.
226
+ function spawn_or_use_existing(app_root, options):
227
+ domain = domains[app_root]
177
228
 
178
- if (list != nil) and (needs_restart(app_root)):
179
- for all container in list:
229
+ if (domain != nil) and (needs_restart(app_root, domain)):
230
+ for all container in domain.instances:
180
231
  if container.sessions == 0:
181
232
  inactive_apps.remove(container.ia_iterator)
182
233
  else:
183
234
  active--
184
- list.remove(container.iterator)
235
+ domain.instances.remove(container.iterator)
185
236
  count--
186
- apps.remove(app_root)
187
- app_instance_count.remove(app_root)
237
+ domains.remove(app_root)
188
238
  list = nil
189
239
  Tell spawn server to reload code for app_root.
190
240
 
191
- if list != nil:
241
+ if domain != nil:
192
242
  # There are apps for this app root.
193
- if (list.front.sessions == 0):
243
+ instances = domain.instances
244
+
245
+ if (instances.front.sessions == 0):
194
246
  # There is an inactive app, so we use it.
195
- container = list.front
196
- list.move_to_back(container.iterator)
247
+ container = instances.front
248
+ instances.move_to_back(container.iterator)
197
249
  inactive_apps.remove(container.ia_iterator)
198
250
  active++
199
251
  else if (count >= max) or (
200
- (max_per_app != 0) and (app_instance_count[app_root] >= max_per_app)
252
+ (max_per_app != 0) and (domain.size >= max_per_app)
201
253
  ):
202
254
  # All apps are active, and the pool is full.
203
255
  # -OR-
@@ -205,7 +257,7 @@ function spawn_or_use_existing(app_root):
205
257
  # spawned for this application domain has been reached.
206
258
  #
207
259
  # We're not allowed to spawn a new application instance.
208
- if use_global_queue:
260
+ if options.use_global_queue:
209
261
  # So we wait until _active_ has changed, then
210
262
  # we restart this function and try again.
211
263
  waiting_on_global_queue++
@@ -216,8 +268,8 @@ function spawn_or_use_existing(app_root):
216
268
  # So we connect to an already active application.
217
269
  # This connection will be put into that
218
270
  # application's private queue.
219
- container = a container in _list_ with the smallest _session_ value
220
- list.move_to_back(container.iterator)
271
+ container = a container in _instances_ with the smallest _session_ value
272
+ instances.move_to_back(container.iterator)
221
273
  else:
222
274
  # All apps are active, but the pool hasn't reached its
223
275
  # maximum yet. So we spawn a new app.
@@ -225,9 +277,9 @@ function spawn_or_use_existing(app_root):
225
277
  # TODO: we should add some kind of timeout check for spawning.
226
278
  container.app = spawn(app_root)
227
279
  container.sessions = 0
228
- iterator = list.add_to_back(container)
280
+ iterator = instances.add_to_back(container)
229
281
  container.iterator = iterator
230
- app_instance_count[app_root]++
282
+ domain.size++
231
283
  count++
232
284
  active++
233
285
  else:
@@ -239,11 +291,7 @@ function spawn_or_use_existing(app_root):
239
291
  if (active >= max):
240
292
  wait until _active_ has changed
241
293
  goto beginning of function
242
- # FIXME: there's a possible concurrency issue here. After
243
- # waiting and having reacquired the lock, the state might have
244
- # been completely changed, and there may now exist an instance
245
- # of this application domain.
246
- if count == max:
294
+ elsif count == max:
247
295
  # Here we are in a though situation. There are several
248
296
  # apps which are inactive, and none of them have
249
297
  # application root _app_root_, so we must kill one of
@@ -256,31 +304,33 @@ function spawn_or_use_existing(app_root):
256
304
  # killed. But for now, we kill a random application
257
305
  # instance.
258
306
  container = inactive_apps.pop_front
259
- list = apps[container.app.app_root]
260
- list.remove(container.iterator)
261
- if list.empty():
262
- apps.remove(container.app.app_root)
263
- restart_file_times.remove(container.app.app_root)
264
- app_instance_count.remove(container.app.app_root)
307
+ domain = domains[container.app.app_root]
308
+ instances = domain.instances
309
+ instances.remove(container.iterator)
310
+ if instances.empty():
311
+ domains.remove(container.app.app_root)
265
312
  else:
266
- app_instance_count[container.app.app_root]--
313
+ domain.size--
267
314
  count--
268
315
  container = new AppContainer
269
316
  # TODO: we should add some kind of timeout check for spawning.
270
317
  container.app = spawn(app_root)
271
318
  container.sessions = 0
272
- list = apps[app_root]
273
- if list == nil:
274
- list = new list
275
- apps[app_root] = list
276
- app_instance_count[app_root] = 1
319
+ domain = domains[app_root]
320
+ if domain == nil:
321
+ domain = new Domain
322
+ initialize domain.instances
323
+ initialize domain.restart_file_checker with "$app_root/tmp/restart.txt"
324
+ domain.size = 1
325
+ domain.max_requests = options.max_requests
326
+ domains[app_root] = domain
277
327
  else:
278
- app_instance_count[app_root]++
279
- iterator = list.add_to_back(container)
328
+ domain.size++
329
+ iterator = domain.instances.add_to_back(container)
280
330
  container.iterator = iterator
281
331
  count++
282
332
  active++
283
- return [container, list]
333
+ return [container, domain]
284
334
 
285
335
 
286
336
  # The following function is to be called when a session has been closed.
@@ -288,39 +338,39 @@ function spawn_or_use_existing(app_root):
288
338
  # session has been closed.
289
339
  function session_has_been_closed(container):
290
340
  lock.synchronize:
291
- list = apps[container.app.app_root]
292
- if list != nil:
293
- container.last_used = current_time()
294
- container.sessions--
295
- if container.sessions == 0:
296
- list.move_to_front(container.iterator)
297
- container.ia_iterator = inactive_apps.add_to_back(container.app)
341
+ domain = domains[container.app.app_root]
342
+ if domain != nil:
343
+ instances = domain.instances
344
+ container.processed++
345
+
346
+ if (domain.max_requests) > 0 and (container.processed >= domain.max_requests):
347
+ # The application instance has processed its maximum allowed
348
+ # number of requests, so we shut it down.
349
+ instances.remove(container.iterator)
350
+ domain.size--
351
+ if instances.empty():
352
+ domains.remove(app_root)
353
+ count--
298
354
  active--
355
+ else:
356
+ container.last_used = current_time()
357
+ container.sessions--
358
+ container.processed++
359
+ if container.sessions == 0:
360
+ instances.move_to_front(container.iterator)
361
+ container.ia_iterator = inactive_apps.add_to_back(container.app)
362
+ active--
299
363
 
300
364
 
301
- function needs_restart(app_root):
302
- restart_file = "$app_root/tmp/restart.txt"
303
- s = stat(restart_file)
304
- if s != null:
305
- delete_file(restart_file)
306
- if (deletion was successful) or (file was already deleted):
307
- restart_file_times.remove(app_root)
308
- result = true
309
- else:
310
- last_restart_file_time = restart_file_times[app_root]
311
- if last_restart_time == null:
312
- result = true
313
- else:
314
- result = s.mtime != last_restart_file_time
315
- restart_file_times[app_root] = s.mtime
316
- else:
317
- restart_file_times.remove(app_root)
318
- result = false
319
- return result
365
+ function needs_restart(app_root, domain):
366
+ always_restart_file = "$app_root/tmp/always_restart.txt"
367
+ return (file_exists(always_restart_file)) or
368
+ (domain.restart_file_checker.changed())
320
369
 
321
370
 
322
371
  # The following thread will be responsible for cleaning up idle application
323
372
  # instances, i.e. instances that haven't been used for a while.
373
+ # This can be disabled per app when setting it's maxIdleTime to 0.
324
374
  thread cleaner:
325
375
  lock.synchronize:
326
376
  done = false
@@ -333,14 +383,16 @@ thread cleaner:
333
383
  now = current_time()
334
384
  for all container in inactive_apps:
335
385
  app = container.app
336
- app_list = apps[app.app_root]
337
- if now - container.last_used > MAX_IDLE_TIME:
338
- app_list.remove(container.iterator)
339
- inactive_apps.remove(iterator for container)
340
- app_instance_count[app.app_root]--
386
+ domain = domains[app.app_root]
387
+ instances = domain.instances
388
+ # If MAX_IDLE_TIME is 0 we don't clean up the instance,
389
+ # giving us the option to persist the app container
390
+ # forever unless it's killed by another app.
391
+ if (MAX_IDLE_TIME > 0) and (now - container.last_used > MAX_IDLE_TIME):
392
+ instances.remove(container.iterator)
393
+ inactive_apps.remove(container.iterator)
394
+ domain.size--
341
395
  count--
342
- if app_list.empty():
343
- apps.remove(app.app_root)
344
- app_instance_count.remove(app.app_root)
345
- restart_file_times.remove(app.app_root)
396
+ if instances.empty():
397
+ domains.remove(app.app_root)
346
398