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.
- data/DEVELOPERS.TXT +10 -4
- data/LICENSE +1 -1
- data/NEWS +0 -0
- data/Rakefile +183 -117
- data/benchmark/dispatcher.rb +5 -9
- data/bin/passenger-install-apache2-module +52 -18
- data/bin/passenger-memory-stats +67 -13
- data/bin/passenger-spawn-server +8 -4
- data/bin/passenger-status +21 -46
- data/bin/passenger-stress-test +5 -5
- data/debian/postinst +1 -1
- data/doc/ApplicationPool algorithm.txt +180 -128
- data/doc/Architectural overview.html +1 -778
- data/doc/Security of user switching support.html +1 -643
- data/doc/Users guide Apache.html +3127 -0
- data/doc/Users guide Nginx.html +1458 -0
- data/doc/Users guide.html +1404 -467
- data/doc/Users guide.txt +843 -105
- data/doc/cxxapi/ApplicationPoolServer_8h-source.html +751 -641
- data/doc/cxxapi/ApplicationPool_8h-source.html +168 -171
- data/doc/cxxapi/Application_8h-source.html +494 -394
- data/doc/cxxapi/Bucket_8h-source.html +21 -15
- data/doc/cxxapi/CachedFileStat_8h-source.html +191 -0
- data/doc/cxxapi/Configuration_8h-source.html +311 -149
- data/doc/cxxapi/DirectoryMapper_8h-source.html +309 -0
- data/doc/cxxapi/DummySpawnManager_8h-source.html +3 -4
- data/doc/cxxapi/Exceptions_8h-source.html +182 -165
- data/doc/cxxapi/FileChecker_8h-source.html +130 -0
- data/doc/cxxapi/Hooks_8h-source.html +2 -3
- data/doc/cxxapi/Logging_8h-source.html +92 -89
- data/doc/cxxapi/MessageChannel_8h-source.html +585 -477
- data/doc/cxxapi/PoolOptions_8h-source.html +305 -0
- data/doc/cxxapi/SpawnManager_8h-source.html +515 -540
- data/doc/cxxapi/StandardApplicationPool_8h-source.html +779 -679
- data/doc/cxxapi/SystemTime_8h-source.html +104 -0
- data/doc/cxxapi/Utils_8h-source.html +331 -227
- data/doc/cxxapi/annotated.html +6 -7
- data/doc/cxxapi/classClient-members.html +1 -2
- data/doc/cxxapi/classClient.html +1 -2
- data/doc/cxxapi/classHooks-members.html +5 -2
- data/doc/cxxapi/classHooks.html +112 -2
- data/doc/cxxapi/classPassenger_1_1Application-members.html +2 -3
- data/doc/cxxapi/classPassenger_1_1Application.html +8 -9
- data/doc/cxxapi/classPassenger_1_1ApplicationPool-members.html +4 -4
- data/doc/cxxapi/classPassenger_1_1ApplicationPool.html +42 -81
- data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer-members.html +1 -2
- data/doc/cxxapi/classPassenger_1_1ApplicationPoolServer.html +3 -4
- data/doc/cxxapi/classPassenger_1_1ApplicationPool__inherit__graph.png +0 -0
- data/doc/cxxapi/classPassenger_1_1Application_1_1Session-members.html +3 -2
- data/doc/cxxapi/classPassenger_1_1Application_1_1Session.html +74 -3
- data/doc/cxxapi/classPassenger_1_1BusyException-members.html +1 -2
- data/doc/cxxapi/classPassenger_1_1BusyException.html +2 -3
- data/doc/cxxapi/classPassenger_1_1ConfigurationException-members.html +1 -2
- data/doc/cxxapi/classPassenger_1_1ConfigurationException.html +2 -3
- data/doc/cxxapi/classPassenger_1_1DirectoryMapper-members.html +38 -0
- data/doc/cxxapi/classPassenger_1_1DirectoryMapper.html +256 -0
- data/doc/cxxapi/classPassenger_1_1DummySpawnManager-members.html +1 -2
- data/doc/cxxapi/classPassenger_1_1DummySpawnManager.html +2 -3
- data/doc/cxxapi/{classPassenger_1_1Thread-members.html → classPassenger_1_1FileChecker-members.html} +4 -5
- data/doc/cxxapi/classPassenger_1_1FileChecker.html +121 -0
- data/doc/cxxapi/classPassenger_1_1FileNotFoundException-members.html +1 -2
- data/doc/cxxapi/classPassenger_1_1FileNotFoundException.html +2 -3
- data/doc/cxxapi/classPassenger_1_1FileNotFoundException__inherit__graph.png +0 -0
- data/doc/cxxapi/classPassenger_1_1FileSystemException-members.html +2 -3
- data/doc/cxxapi/classPassenger_1_1FileSystemException.html +2 -3
- data/doc/cxxapi/classPassenger_1_1FileSystemException__inherit__graph.png +0 -0
- data/doc/cxxapi/classPassenger_1_1IOException-members.html +1 -2
- data/doc/cxxapi/classPassenger_1_1IOException.html +2 -3
- data/doc/cxxapi/classPassenger_1_1IOException__inherit__graph.png +0 -0
- data/doc/cxxapi/classPassenger_1_1MessageChannel-members.html +5 -2
- data/doc/cxxapi/classPassenger_1_1MessageChannel.html +155 -5
- data/doc/cxxapi/{classboost_1_1this__thread_1_1enable__syscall__interruption-members.html → classPassenger_1_1RuntimeException-members.html} +2 -3
- data/doc/cxxapi/{classboost_1_1this__thread_1_1enable__syscall__interruption.html → classPassenger_1_1RuntimeException.html} +10 -8
- data/doc/cxxapi/classPassenger_1_1SpawnException-members.html +1 -2
- data/doc/cxxapi/classPassenger_1_1SpawnException.html +2 -3
- data/doc/cxxapi/classPassenger_1_1SpawnManager-members.html +2 -3
- data/doc/cxxapi/classPassenger_1_1SpawnManager.html +15 -56
- data/doc/cxxapi/classPassenger_1_1StandardApplicationPool-members.html +5 -4
- data/doc/cxxapi/classPassenger_1_1StandardApplicationPool.html +20 -81
- data/doc/cxxapi/classPassenger_1_1StandardApplicationPool__inherit__graph.png +0 -0
- data/doc/cxxapi/classPassenger_1_1SystemException-members.html +2 -3
- data/doc/cxxapi/classPassenger_1_1SystemException.html +9 -10
- data/doc/cxxapi/classPassenger_1_1SystemException__inherit__graph.png +0 -0
- data/doc/cxxapi/{classboost_1_1this__thread_1_1disable__syscall__interruption-members.html → classPassenger_1_1SystemTime-members.html} +5 -3
- data/doc/cxxapi/classPassenger_1_1SystemTime.html +86 -0
- data/doc/cxxapi/classPassenger_1_1TempFile-members.html +2 -3
- data/doc/cxxapi/classPassenger_1_1TempFile.html +17 -9
- data/doc/cxxapi/definitions_8h-source.html +1 -2
- data/doc/cxxapi/files.html +6 -3
- data/doc/cxxapi/functions.html +98 -35
- data/doc/cxxapi/functions_func.html +60 -32
- data/doc/cxxapi/functions_type.html +1 -2
- data/doc/cxxapi/functions_vars.html +27 -2
- data/doc/cxxapi/graph_legend.html +1 -2
- data/doc/cxxapi/graph_legend.png +0 -0
- data/doc/cxxapi/group__Configuration.html +3 -4
- data/doc/cxxapi/group__Configuration.png +0 -0
- data/doc/cxxapi/group__Core.html +3 -4
- data/doc/cxxapi/group__Core.png +0 -0
- data/doc/cxxapi/group__Exceptions.html +4 -2
- data/doc/cxxapi/group__Hooks.html +1 -6
- data/doc/cxxapi/group__Hooks.png +0 -0
- data/doc/cxxapi/group__Support.html +259 -36
- data/doc/cxxapi/hierarchy.html +6 -7
- data/doc/cxxapi/inherit__graph__0.map +1 -1
- data/doc/cxxapi/inherit__graph__0.md5 +1 -1
- data/doc/cxxapi/inherit__graph__0.png +0 -0
- data/doc/cxxapi/inherit__graph__1.map +1 -1
- data/doc/cxxapi/inherit__graph__1.md5 +1 -1
- data/doc/cxxapi/inherit__graph__1.png +0 -0
- data/doc/cxxapi/inherit__graph__10.map +1 -1
- data/doc/cxxapi/inherit__graph__10.md5 +1 -1
- data/doc/cxxapi/inherit__graph__10.png +0 -0
- data/doc/cxxapi/inherit__graph__11.map +1 -1
- data/doc/cxxapi/inherit__graph__11.md5 +1 -1
- data/doc/cxxapi/inherit__graph__11.png +0 -0
- data/doc/cxxapi/inherit__graph__12.map +2 -1
- data/doc/cxxapi/inherit__graph__12.md5 +1 -1
- data/doc/cxxapi/inherit__graph__12.png +0 -0
- data/doc/cxxapi/inherit__graph__13.map +1 -1
- data/doc/cxxapi/inherit__graph__13.md5 +1 -1
- data/doc/cxxapi/inherit__graph__13.png +0 -0
- data/doc/cxxapi/inherit__graph__14.map +1 -2
- data/doc/cxxapi/inherit__graph__14.md5 +1 -1
- data/doc/cxxapi/inherit__graph__14.png +0 -0
- data/doc/cxxapi/inherit__graph__15.map +1 -1
- data/doc/cxxapi/inherit__graph__15.md5 +1 -1
- data/doc/cxxapi/inherit__graph__15.png +0 -0
- data/doc/cxxapi/inherit__graph__16.map +1 -1
- data/doc/cxxapi/inherit__graph__16.md5 +1 -1
- data/doc/cxxapi/inherit__graph__16.png +0 -0
- data/doc/cxxapi/inherit__graph__17.png +0 -0
- data/doc/cxxapi/inherit__graph__18.png +0 -0
- data/doc/cxxapi/inherit__graph__19.png +0 -0
- data/doc/cxxapi/inherit__graph__2.map +1 -1
- data/doc/cxxapi/inherit__graph__2.md5 +1 -1
- data/doc/cxxapi/inherit__graph__2.png +0 -0
- data/doc/cxxapi/inherit__graph__20.map +1 -1
- data/doc/cxxapi/inherit__graph__20.md5 +1 -1
- data/doc/cxxapi/inherit__graph__20.png +0 -0
- data/doc/cxxapi/inherit__graph__21.map +1 -1
- data/doc/cxxapi/inherit__graph__21.md5 +1 -1
- data/doc/cxxapi/inherit__graph__21.png +0 -0
- data/doc/cxxapi/inherit__graph__3.map +1 -1
- data/doc/cxxapi/inherit__graph__3.md5 +1 -1
- data/doc/cxxapi/inherit__graph__3.png +0 -0
- data/doc/cxxapi/inherit__graph__4.map +1 -1
- data/doc/cxxapi/inherit__graph__4.md5 +1 -1
- data/doc/cxxapi/inherit__graph__4.png +0 -0
- data/doc/cxxapi/inherit__graph__5.map +2 -1
- data/doc/cxxapi/inherit__graph__5.md5 +1 -1
- data/doc/cxxapi/inherit__graph__5.png +0 -0
- data/doc/cxxapi/inherit__graph__6.map +1 -1
- data/doc/cxxapi/inherit__graph__6.md5 +1 -1
- data/doc/cxxapi/inherit__graph__6.png +0 -0
- data/doc/cxxapi/inherit__graph__7.map +1 -1
- data/doc/cxxapi/inherit__graph__7.md5 +1 -1
- data/doc/cxxapi/inherit__graph__7.png +0 -0
- data/doc/cxxapi/inherit__graph__8.map +1 -1
- data/doc/cxxapi/inherit__graph__8.md5 +1 -1
- data/doc/cxxapi/inherit__graph__8.png +0 -0
- data/doc/cxxapi/inherit__graph__9.map +1 -2
- data/doc/cxxapi/inherit__graph__9.md5 +1 -1
- data/doc/cxxapi/inherit__graph__9.png +0 -0
- data/doc/cxxapi/inherits.html +30 -31
- data/doc/cxxapi/main.html +1 -2
- data/doc/cxxapi/modules.html +1 -2
- data/doc/cxxapi/structPassenger_1_1AnythingToString-members.html +1 -2
- data/doc/cxxapi/structPassenger_1_1AnythingToString.html +2 -3
- data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4-members.html +1 -2
- data/doc/cxxapi/structPassenger_1_1AnythingToString_3_01vector_3_01string_01_4_01_4.html +2 -3
- data/doc/cxxapi/structPassenger_1_1PoolOptions-members.html +49 -0
- data/doc/cxxapi/structPassenger_1_1PoolOptions.html +404 -0
- data/doc/cxxapi/tree.html +18 -20
- data/doc/images/conservative_spawning.png +0 -0
- data/doc/images/conservative_spawning.svg +248 -0
- data/doc/images/smart-lv2.png +0 -0
- data/doc/images/smart-lv2.svg +320 -0
- data/doc/rdoc/classes/ConditionVariable.html +68 -34
- data/doc/rdoc/classes/Exception.html +16 -16
- data/doc/rdoc/classes/GC.html +9 -9
- data/doc/rdoc/classes/IO.html +36 -17
- data/doc/rdoc/classes/PhusionPassenger.html +183 -0
- data/doc/rdoc/classes/PhusionPassenger/AbstractRequestHandler.html +511 -0
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer.html +285 -242
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerAlreadyStarted.html +3 -3
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerError.html +3 -3
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/ServerNotStarted.html +3 -3
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AbstractServer/UnknownMessage.html +3 -3
- data/doc/rdoc/classes/PhusionPassenger/AbstractServerCollection.html +598 -0
- data/doc/rdoc/classes/PhusionPassenger/AdminTools.html +140 -0
- data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess.html +247 -0
- data/doc/rdoc/classes/PhusionPassenger/AdminTools/ControlProcess/Instance.html +138 -0
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/AppInitError.html +36 -19
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/Application.html +81 -96
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/ConsoleTextTemplate.html +18 -18
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/FrameworkInitError.html +20 -18
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/HTMLTemplate.html +18 -18
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/InitializationError.html +9 -9
- data/doc/rdoc/classes/PhusionPassenger/InvalidPath.html +92 -0
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/MessageChannel.html +93 -92
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/NativeSupport.html +55 -25
- data/doc/rdoc/classes/PhusionPassenger/Rack.html +91 -0
- data/doc/rdoc/classes/PhusionPassenger/Rack/ApplicationSpawner.html +185 -0
- data/doc/rdoc/classes/PhusionPassenger/Rack/RequestHandler.html +182 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz.html +95 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner.html +424 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/ApplicationSpawner/Error.html +98 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/CGIFixed.html +200 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner.html +444 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/FrameworkSpawner/Error.html +98 -0
- data/doc/rdoc/classes/PhusionPassenger/Railz/RequestHandler.html +154 -0
- data/doc/rdoc/classes/PhusionPassenger/SpawnManager.html +408 -0
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/UnknownError.html +13 -13
- data/doc/rdoc/classes/PhusionPassenger/Utils.html +687 -0
- data/doc/rdoc/classes/{Passenger → PhusionPassenger}/VersionNotFound.html +8 -8
- data/doc/rdoc/classes/PhusionPassenger/WSGI.html +89 -0
- data/doc/rdoc/classes/PhusionPassenger/WSGI/ApplicationSpawner.html +188 -0
- data/doc/rdoc/classes/PlatformInfo.html +663 -159
- data/doc/rdoc/classes/RakeExtensions.html +4 -4
- data/doc/rdoc/classes/Signal.html +134 -0
- data/doc/rdoc/created.rid +1 -1
- data/doc/rdoc/files/DEVELOPERS_TXT.html +15 -10
- data/doc/rdoc/files/README.html +5 -7
- data/doc/rdoc/files/ext/{passenger → phusion_passenger}/native_support_c.html +2 -2
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/abstract_request_handler_rb.html +7 -9
- data/doc/rdoc/files/lib/phusion_passenger/abstract_server_collection_rb.html +120 -0
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/abstract_server_rb.html +7 -10
- data/doc/rdoc/files/lib/phusion_passenger/admin_tools/control_process_rb.html +99 -0
- data/doc/rdoc/files/lib/phusion_passenger/admin_tools_rb.html +92 -0
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/application_rb.html +6 -8
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/console_text_template_rb.html +5 -7
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/constants_rb.html +4 -5
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/dependencies_rb.html +6 -8
- data/doc/rdoc/files/lib/phusion_passenger/events_rb.html +116 -0
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/exceptions_rb.html +5 -7
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/html_template_rb.html +5 -7
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/message_channel_rb.html +5 -7
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/platform_info_rb.html +6 -7
- data/doc/rdoc/files/lib/phusion_passenger/rack/application_spawner_rb.html +123 -0
- data/doc/rdoc/files/lib/phusion_passenger/rack/request_handler_rb.html +117 -0
- data/doc/rdoc/files/lib/{passenger/utils_rb.html → phusion_passenger/railz/application_spawner_rb.html} +24 -17
- data/doc/rdoc/files/lib/phusion_passenger/railz/cgi_fixed_rb.html +126 -0
- data/doc/rdoc/files/lib/phusion_passenger/railz/framework_spawner_rb.html +139 -0
- data/doc/rdoc/files/lib/phusion_passenger/railz/request_handler_rb.html +118 -0
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/simple_benchmarking_rb.html +5 -7
- data/doc/rdoc/files/lib/{passenger → phusion_passenger}/spawn_manager_rb.html +40 -24
- data/doc/rdoc/files/lib/phusion_passenger/utils_rb.html +169 -0
- data/doc/rdoc/files/lib/phusion_passenger/wsgi/application_spawner_rb.html +120 -0
- data/doc/rdoc/files/lib/rake/extensions_rb.html +3 -4
- data/doc/rdoc/fr_class_index.html +37 -19
- data/doc/rdoc/fr_file_index.html +25 -14
- data/doc/rdoc/fr_method_index.html +145 -74
- data/ext/apache2/Application.h +145 -44
- data/ext/apache2/ApplicationPool.h +27 -29
- data/ext/apache2/ApplicationPoolServer.h +183 -72
- data/ext/apache2/ApplicationPoolServerExecutable.cpp +249 -42
- data/ext/apache2/Bucket.cpp +61 -9
- data/ext/apache2/Bucket.h +15 -8
- data/ext/apache2/CachedFileStat.cpp +114 -0
- data/ext/apache2/CachedFileStat.h +169 -0
- data/ext/apache2/Configuration.cpp +213 -22
- data/ext/apache2/Configuration.h +176 -13
- data/ext/apache2/DirectoryMapper.h +287 -0
- data/ext/apache2/Exceptions.h +30 -12
- data/ext/apache2/FileChecker.h +108 -0
- data/ext/apache2/Hooks.cpp +709 -493
- data/ext/apache2/LICENSE-CNRI.TXT +15 -0
- data/ext/apache2/Logging.h +26 -22
- data/ext/apache2/MessageChannel.h +124 -15
- data/ext/apache2/PoolOptions.h +283 -0
- data/ext/apache2/SpawnManager.h +75 -99
- data/ext/apache2/StandardApplicationPool.h +296 -195
- data/ext/apache2/SystemTime.cpp +28 -0
- data/ext/apache2/SystemTime.h +82 -0
- data/ext/apache2/Utils.cpp +172 -18
- data/ext/apache2/Utils.h +124 -19
- data/ext/boost/cstdint.hpp +4 -2
- data/ext/boost/current_function.hpp +67 -0
- data/ext/boost/detail/sp_counted_base.hpp +4 -4
- data/ext/boost/thread/exceptions.hpp +2 -1
- data/ext/boost/thread/pthread/thread.hpp +11 -3
- data/ext/boost/thread/pthread/thread_data.hpp +2 -1
- data/ext/oxt/backtrace.cpp +172 -0
- data/ext/oxt/backtrace.hpp +135 -0
- data/ext/oxt/detail/backtrace_disabled.hpp +39 -0
- data/ext/oxt/detail/backtrace_enabled.hpp +155 -0
- data/ext/oxt/detail/spin_lock_gcc_x86.hpp +82 -0
- data/ext/oxt/detail/spin_lock_portable.hpp +38 -0
- data/ext/oxt/detail/spin_lock_pthreads.hpp +97 -0
- data/ext/oxt/detail/tracable_exception_disabled.hpp +46 -0
- data/ext/oxt/detail/tracable_exception_enabled.hpp +48 -0
- data/ext/oxt/macros.hpp +58 -0
- data/ext/oxt/spin_lock.hpp +55 -0
- data/ext/{apache2/System.cpp → oxt/system_calls.cpp} +87 -52
- data/ext/oxt/system_calls.hpp +234 -0
- data/ext/oxt/thread.cpp +32 -0
- data/ext/oxt/thread.hpp +223 -0
- data/ext/oxt/tracable_exception.cpp +87 -0
- data/ext/oxt/tracable_exception.hpp +35 -0
- data/{lib/passenger/constants.rb → ext/phusion_passenger/extconf.rb} +14 -9
- data/ext/{passenger → phusion_passenger}/native_support.c +33 -6
- data/lib/{passenger → phusion_passenger}/abstract_request_handler.rb +209 -93
- data/lib/{passenger → phusion_passenger}/abstract_server.rb +23 -8
- data/lib/phusion_passenger/abstract_server_collection.rb +301 -0
- data/lib/phusion_passenger/admin_tools.rb +25 -0
- data/lib/phusion_passenger/admin_tools/control_process.rb +107 -0
- data/lib/{passenger → phusion_passenger}/application.rb +13 -16
- data/lib/{passenger → phusion_passenger}/console_text_template.rb +2 -2
- data/{ext/passenger/extconf.rb → lib/phusion_passenger/constants.rb} +5 -5
- data/lib/{passenger → phusion_passenger}/dependencies.rb +38 -32
- data/lib/phusion_passenger/events.rb +45 -0
- data/lib/{passenger → phusion_passenger}/exceptions.rb +12 -5
- data/lib/{passenger → phusion_passenger}/html_template.rb +2 -2
- data/lib/{passenger → phusion_passenger}/message_channel.rb +3 -2
- data/lib/phusion_passenger/platform_info.rb +500 -0
- data/lib/{passenger → phusion_passenger}/rack/application_spawner.rb +29 -22
- data/lib/{passenger → phusion_passenger}/rack/request_handler.rb +14 -9
- data/lib/{passenger → phusion_passenger}/railz/application_spawner.rb +94 -74
- data/lib/{passenger → phusion_passenger}/railz/cgi_fixed.rb +2 -2
- data/lib/{passenger → phusion_passenger}/railz/framework_spawner.rb +86 -98
- data/lib/{passenger → phusion_passenger}/railz/request_handler.rb +6 -6
- data/lib/{passenger → phusion_passenger}/simple_benchmarking.rb +0 -0
- data/lib/{passenger → phusion_passenger}/spawn_manager.rb +136 -128
- data/lib/{passenger → phusion_passenger}/templates/apache2_config_snippets.txt.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/apache_must_be_compiled_with_compatible_mpm.txt.erb +0 -0
- data/lib/phusion_passenger/templates/app_exited_during_initialization.html.erb +38 -0
- data/lib/{passenger → phusion_passenger}/templates/app_init_error.html.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/database_error.html.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/deployment_example.txt.erb +1 -1
- data/lib/{passenger → phusion_passenger}/templates/error_layout.css +0 -0
- data/lib/{passenger → phusion_passenger}/templates/error_layout.html.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/framework_init_error.html.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/general_error.html.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/invalid_app_root.html.erb +1 -1
- data/lib/{passenger → phusion_passenger}/templates/load_error.html.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/no_write_permission_to_passenger_root.txt.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/possible_solutions_for_compilation_and_installation_problems.txt.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/run_installer_as_root.txt.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/version_not_found.html.erb +0 -0
- data/lib/{passenger → phusion_passenger}/templates/welcome.txt.erb +0 -0
- data/lib/{passenger → phusion_passenger}/utils.rb +210 -44
- data/lib/{passenger → phusion_passenger}/wsgi/application_spawner.rb +18 -15
- data/lib/{passenger → phusion_passenger}/wsgi/request_handler.py +7 -1
- data/man/passenger-memory-stats.8 +1 -1
- data/misc/render_error_pages.rb +1 -1
- data/test/ApplicationPoolServerTest.cpp +0 -28
- data/test/ApplicationPoolServer_ApplicationPoolTest.cpp +4 -0
- data/test/ApplicationPoolTest.cpp +307 -69
- data/test/CachedFileStatTest.cpp +262 -0
- data/test/FileCheckerTest.cpp +79 -0
- data/test/MessageChannelTest.cpp +3 -3
- data/test/PoolOptionsTest.cpp +37 -0
- data/test/SpawnManagerTest.cpp +4 -4
- data/test/StandardApplicationPoolTest.cpp +4 -0
- data/test/SystemTimeTest.cpp +37 -0
- data/test/UtilsTest.cpp +137 -0
- data/test/integration_tests.rb +270 -23
- data/test/oxt/backtrace_test.cpp +128 -0
- data/test/oxt/oxt_test_main.cpp +25 -0
- data/test/oxt/syscall_interruption_test.cpp +50 -0
- data/test/ruby/abstract_request_handler_spec.rb +83 -0
- data/test/ruby/abstract_server_collection_spec.rb +246 -0
- data/test/ruby/application_spec.rb +3 -3
- data/test/ruby/message_channel_spec.rb +2 -2
- data/test/ruby/rack/application_spawner_spec.rb +3 -5
- data/test/ruby/rails/application_spawner_spec.rb +54 -15
- data/test/ruby/rails/framework_spawner_spec.rb +6 -8
- data/test/ruby/rails/minimal_spawner_spec.rb +29 -0
- data/test/ruby/rails/spawner_error_handling_spec.rb +1 -1
- data/test/ruby/rails/spawner_privilege_lowering_spec.rb +3 -3
- data/test/ruby/spawn_manager_spec.rb +23 -12
- data/test/ruby/utils_spec.rb +36 -2
- data/test/ruby/wsgi/application_spawner_spec.rb +47 -0
- data/test/stub/apache2/httpd.conf.erb +3 -5
- data/test/stub/message_channel.rb +2 -2
- data/test/stub/message_channel_2.rb +2 -2
- data/test/stub/message_channel_3.rb +3 -3
- data/test/stub/minimal-railsapp/README +0 -0
- data/test/stub/minimal-railsapp/config/application.rb +0 -0
- data/test/stub/minimal-railsapp/config/environment.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/actionmailer/lib/action_mailer.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_controller.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_pack.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/actionpack/lib/action_view.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/activerecord/lib/active_record.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/activeresource/lib/active_resource.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/activesupport/lib/active_support/whiny_nil.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/railties/lib/dispatcher.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/railties/lib/initializer.rb +0 -0
- data/test/stub/minimal-railsapp/vendor/rails/railties/lib/ruby_version_check.rb +0 -0
- data/test/stub/rails_apps/foobar/app/controllers/foo_controller.rb +8 -0
- data/test/stub/rails_apps/foobar/config/environments/development.rb +1 -2
- data/test/stub/rails_apps/mycook/app/controllers/welcome_controller.rb +21 -1
- data/test/stub/rails_apps/mycook/sites/some.site/public/uploads.html +26 -0
- data/test/stub/rails_apps/mycook/sites/some.site/public/welcome/cached.html +26 -0
- data/test/stub/railsapp/app/controllers/application.rb +0 -0
- data/test/stub/railsapp/app/controllers/bar_controller_1.rb +0 -0
- data/test/stub/railsapp/app/controllers/bar_controller_2.rb +1 -1
- data/test/stub/railsapp/app/controllers/foo_controller.rb +4 -0
- data/test/stub/railsapp/app/helpers/application_helper.rb +0 -0
- data/test/stub/railsapp/config/boot.rb +0 -0
- data/test/stub/railsapp/config/database.yml +0 -0
- data/test/stub/railsapp/config/environment.rb +0 -0
- data/test/stub/railsapp/config/environments/development.rb +0 -0
- data/test/stub/railsapp/config/environments/production.rb +0 -0
- data/test/stub/railsapp/config/initializers/inflections.rb +0 -0
- data/test/stub/railsapp/config/initializers/mime_types.rb +0 -0
- data/test/stub/railsapp/config/routes.rb +0 -0
- data/test/stub/railsapp/public/useless.txt +0 -0
- data/test/stub/spawn_server.rb +3 -4
- data/test/stub/wsgi/passenger_wsgi.pyc +0 -0
- data/test/support/apache2_controller.rb +57 -7
- data/test/support/tut.h +15 -0
- data/vendor/README +12 -0
- data/vendor/README_FOR_PACKAGERS +1 -0
- data/vendor/rack-0.9.1/AUTHORS +8 -0
- data/vendor/rack-0.9.1/COPYING +18 -0
- data/vendor/rack-0.9.1/ChangeLog +1423 -0
- data/vendor/rack-0.9.1/KNOWN-ISSUES +18 -0
- data/vendor/rack-0.9.1/README +306 -0
- data/vendor/rack-0.9.1/Rakefile +188 -0
- data/vendor/rack-0.9.1/SPEC +129 -0
- data/vendor/rack-0.9.1/lib/rack.rb +86 -0
- data/vendor/rack-0.9.1/lib/rack/adapter/camping.rb +22 -0
- data/vendor/rack-0.9.1/lib/rack/auth/abstract/handler.rb +28 -0
- data/vendor/rack-0.9.1/lib/rack/auth/abstract/request.rb +37 -0
- data/vendor/rack-0.9.1/lib/rack/auth/basic.rb +58 -0
- data/vendor/rack-0.9.1/lib/rack/auth/digest/md5.rb +124 -0
- data/vendor/rack-0.9.1/lib/rack/auth/digest/nonce.rb +51 -0
- data/vendor/rack-0.9.1/lib/rack/auth/digest/params.rb +55 -0
- data/vendor/rack-0.9.1/lib/rack/auth/digest/request.rb +40 -0
- data/vendor/rack-0.9.1/lib/rack/auth/openid.rb +438 -0
- data/vendor/rack-0.9.1/lib/rack/builder.rb +67 -0
- data/vendor/rack-0.9.1/lib/rack/cascade.rb +36 -0
- data/vendor/rack-0.9.1/lib/rack/commonlogger.rb +61 -0
- data/vendor/rack-0.9.1/lib/rack/conditionalget.rb +43 -0
- data/vendor/rack-0.9.1/lib/rack/content_length.rb +25 -0
- data/vendor/rack-0.9.1/lib/rack/deflater.rb +87 -0
- data/vendor/rack-0.9.1/lib/rack/directory.rb +150 -0
- data/vendor/rack-0.9.1/lib/rack/file.rb +85 -0
- data/vendor/rack-0.9.1/lib/rack/handler.rb +48 -0
- data/vendor/rack-0.9.1/lib/rack/handler/cgi.rb +57 -0
- data/vendor/rack-0.9.1/lib/rack/handler/evented_mongrel.rb +8 -0
- data/vendor/rack-0.9.1/lib/rack/handler/fastcgi.rb +86 -0
- data/vendor/rack-0.9.1/lib/rack/handler/lsws.rb +52 -0
- data/vendor/rack-0.9.1/lib/rack/handler/mongrel.rb +82 -0
- data/vendor/rack-0.9.1/lib/rack/handler/scgi.rb +57 -0
- data/vendor/rack-0.9.1/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/vendor/rack-0.9.1/lib/rack/handler/thin.rb +15 -0
- data/vendor/rack-0.9.1/lib/rack/handler/webrick.rb +61 -0
- data/vendor/rack-0.9.1/lib/rack/head.rb +19 -0
- data/vendor/rack-0.9.1/lib/rack/lint.rb +465 -0
- data/vendor/rack-0.9.1/lib/rack/lobster.rb +65 -0
- data/vendor/rack-0.9.1/lib/rack/methodoverride.rb +27 -0
- data/vendor/rack-0.9.1/lib/rack/mime.rb +204 -0
- data/vendor/rack-0.9.1/lib/rack/mock.rb +160 -0
- data/vendor/rack-0.9.1/lib/rack/recursive.rb +57 -0
- data/vendor/rack-0.9.1/lib/rack/reloader.rb +64 -0
- data/vendor/rack-0.9.1/lib/rack/request.rb +218 -0
- data/vendor/rack-0.9.1/lib/rack/response.rb +171 -0
- data/vendor/rack-0.9.1/lib/rack/session/abstract/id.rb +153 -0
- data/vendor/rack-0.9.1/lib/rack/session/cookie.rb +89 -0
- data/vendor/rack-0.9.1/lib/rack/session/memcache.rb +97 -0
- data/vendor/rack-0.9.1/lib/rack/session/pool.rb +73 -0
- data/vendor/rack-0.9.1/lib/rack/showexceptions.rb +348 -0
- data/vendor/rack-0.9.1/lib/rack/showstatus.rb +106 -0
- data/vendor/rack-0.9.1/lib/rack/static.rb +38 -0
- data/vendor/rack-0.9.1/lib/rack/urlmap.rb +48 -0
- data/vendor/rack-0.9.1/lib/rack/utils.rb +347 -0
- metadata +1197 -1055
- data/doc/cxxapi/System_8h-source.html +0 -251
- data/doc/cxxapi/classDirectoryMapper-members.html +0 -38
- data/doc/cxxapi/classDirectoryMapper.html +0 -203
- data/doc/cxxapi/classPassenger_1_1Thread.html +0 -100
- data/doc/cxxapi/classboost_1_1this__thread_1_1disable__syscall__interruption.html +0 -46
- data/doc/cxxapi/classboost_1_1this__thread_1_1restore__syscall__interruption-members.html +0 -33
- data/doc/cxxapi/classboost_1_1this__thread_1_1restore__syscall__interruption.html +0 -44
- data/doc/cxxapi/namespacePassenger.html +0 -208
- data/doc/cxxapi/namespacePassenger_1_1InterruptableCalls.html +0 -43
- data/doc/cxxapi/namespacemembers.html +0 -70
- data/doc/cxxapi/namespacemembers_func.html +0 -66
- data/doc/cxxapi/namespacemembers_type.html +0 -46
- data/doc/cxxapi/namespaces.html +0 -35
- data/doc/rdoc/classes/Passenger.html +0 -136
- data/doc/rdoc/classes/Passenger/AbstractRequestHandler.html +0 -402
- data/doc/rdoc/classes/Passenger/SpawnManager.html +0 -379
- data/doc/rdoc/classes/Passenger/Utils.html +0 -578
- data/ext/apache2/System.h +0 -228
- data/lib/passenger/platform_info.rb +0 -302
- data/lib/passenger/templates/app_exited_during_initialization.html.erb +0 -19
- data/test/stub/apache2/httpd.conf +0 -75
- data/test/stub/rails_apps/foobar/config/environments/test.rb +0 -22
- data/test/stub/rails_apps/mycook/config/environments/test.rb +0 -22
- data/test/stub/railsapp/config/environments/test.rb +0 -22
- data/test/stub/railsapp2/config/environments/test.rb +0 -22
data/ext/apache2/SpawnManager.h
CHANGED
@@ -24,6 +24,8 @@
|
|
24
24
|
#include <list>
|
25
25
|
#include <boost/shared_ptr.hpp>
|
26
26
|
#include <boost/thread.hpp>
|
27
|
+
#include <oxt/system_calls.hpp>
|
28
|
+
#include <oxt/backtrace.hpp>
|
27
29
|
|
28
30
|
#include <sys/types.h>
|
29
31
|
#include <sys/wait.h>
|
@@ -33,19 +35,21 @@
|
|
33
35
|
#include <cstdarg>
|
34
36
|
#include <unistd.h>
|
35
37
|
#include <errno.h>
|
38
|
+
#include <grp.h>
|
36
39
|
#include <pwd.h>
|
37
40
|
#include <signal.h>
|
38
41
|
|
39
42
|
#include "Application.h"
|
43
|
+
#include "PoolOptions.h"
|
40
44
|
#include "MessageChannel.h"
|
41
45
|
#include "Exceptions.h"
|
42
46
|
#include "Logging.h"
|
43
|
-
#include "System.h"
|
44
47
|
|
45
48
|
namespace Passenger {
|
46
49
|
|
47
50
|
using namespace std;
|
48
51
|
using namespace boost;
|
52
|
+
using namespace oxt;
|
49
53
|
|
50
54
|
/**
|
51
55
|
* @brief Spawning of Ruby on Rails/Rack application instances.
|
@@ -89,7 +93,7 @@ private:
|
|
89
93
|
string rubyCommand;
|
90
94
|
string user;
|
91
95
|
|
92
|
-
mutex lock;
|
96
|
+
boost::mutex lock;
|
93
97
|
|
94
98
|
MessageChannel channel;
|
95
99
|
pid_t pid;
|
@@ -103,30 +107,34 @@ private:
|
|
103
107
|
* @throws IOException The specified log file could not be opened.
|
104
108
|
*/
|
105
109
|
void restartServer() {
|
110
|
+
TRACE_POINT();
|
106
111
|
if (pid != 0) {
|
112
|
+
UPDATE_TRACE_POINT();
|
107
113
|
channel.close();
|
108
114
|
|
109
115
|
// Wait at most 5 seconds for the spawn server to exit.
|
110
116
|
// If that doesn't work, kill it, then wait at most 5 seconds
|
111
117
|
// for it to exit.
|
112
|
-
time_t begin =
|
118
|
+
time_t begin = syscalls::time(NULL);
|
113
119
|
bool done = false;
|
114
|
-
while (!done &&
|
115
|
-
if (
|
120
|
+
while (!done && syscalls::time(NULL) - begin < 5) {
|
121
|
+
if (syscalls::waitpid(pid, NULL, WNOHANG) > 0) {
|
116
122
|
done = true;
|
117
123
|
} else {
|
118
|
-
|
124
|
+
syscalls::usleep(100000);
|
119
125
|
}
|
120
126
|
}
|
127
|
+
UPDATE_TRACE_POINT();
|
121
128
|
if (!done) {
|
129
|
+
UPDATE_TRACE_POINT();
|
122
130
|
P_TRACE(2, "Spawn server did not exit in time, killing it...");
|
123
|
-
|
124
|
-
begin =
|
125
|
-
while (
|
126
|
-
if (
|
131
|
+
syscalls::kill(pid, SIGTERM);
|
132
|
+
begin = syscalls::time(NULL);
|
133
|
+
while (syscalls::time(NULL) - begin < 5) {
|
134
|
+
if (syscalls::waitpid(pid, NULL, WNOHANG) > 0) {
|
127
135
|
break;
|
128
136
|
} else {
|
129
|
-
|
137
|
+
syscalls::usleep(100000);
|
130
138
|
}
|
131
139
|
}
|
132
140
|
P_TRACE(2, "Spawn server has exited.");
|
@@ -138,11 +146,11 @@ private:
|
|
138
146
|
FILE *logFileHandle = NULL;
|
139
147
|
|
140
148
|
serverNeedsRestart = true;
|
141
|
-
if (
|
149
|
+
if (syscalls::socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) {
|
142
150
|
throw SystemException("Cannot create a Unix socket", errno);
|
143
151
|
}
|
144
152
|
if (!logFile.empty()) {
|
145
|
-
logFileHandle =
|
153
|
+
logFileHandle = syscalls::fopen(logFile.c_str(), "a");
|
146
154
|
if (logFileHandle == NULL) {
|
147
155
|
string message("Cannot open log file '");
|
148
156
|
message.append(logFile);
|
@@ -151,7 +159,8 @@ private:
|
|
151
159
|
}
|
152
160
|
}
|
153
161
|
|
154
|
-
|
162
|
+
UPDATE_TRACE_POINT();
|
163
|
+
pid = syscalls::fork();
|
155
164
|
if (pid == 0) {
|
156
165
|
if (!logFile.empty()) {
|
157
166
|
dup2(fileno(logFileHandle), STDERR_FILENO);
|
@@ -168,6 +177,14 @@ private:
|
|
168
177
|
if (!user.empty()) {
|
169
178
|
struct passwd *entry = getpwnam(user.c_str());
|
170
179
|
if (entry != NULL) {
|
180
|
+
if (initgroups(user.c_str(), entry->pw_gid) != 0) {
|
181
|
+
int e = errno;
|
182
|
+
fprintf(stderr, "*** Passenger: cannot set supplementary "
|
183
|
+
"groups for user %s: %s (%d)\n",
|
184
|
+
user.c_str(),
|
185
|
+
strerror(e),
|
186
|
+
e);
|
187
|
+
}
|
171
188
|
if (setgid(entry->pw_gid) != 0) {
|
172
189
|
int e = errno;
|
173
190
|
fprintf(stderr, "*** Passenger: cannot run spawn "
|
@@ -202,33 +219,35 @@ private:
|
|
202
219
|
// This argument is ignored by the spawn server. This works on some
|
203
220
|
// systems, such as Ubuntu Linux.
|
204
221
|
" ",
|
205
|
-
NULL);
|
222
|
+
(char *) NULL);
|
206
223
|
int e = errno;
|
207
|
-
fprintf(stderr, "*** Passenger ERROR
|
224
|
+
fprintf(stderr, "*** Passenger ERROR (%s:%d):\n"
|
225
|
+
"Could not start the spawn server: %s: %s (%d)\n",
|
226
|
+
__FILE__, __LINE__,
|
208
227
|
rubyCommand.c_str(), strerror(e), e);
|
209
228
|
fflush(stderr);
|
210
229
|
_exit(1);
|
211
230
|
} else if (pid == -1) {
|
212
231
|
int e = errno;
|
213
|
-
|
214
|
-
|
232
|
+
syscalls::close(fds[0]);
|
233
|
+
syscalls::close(fds[1]);
|
215
234
|
if (logFileHandle != NULL) {
|
216
|
-
|
235
|
+
syscalls::fclose(logFileHandle);
|
217
236
|
}
|
218
237
|
pid = 0;
|
219
238
|
throw SystemException("Unable to fork a process", e);
|
220
239
|
} else {
|
221
|
-
|
240
|
+
syscalls::close(fds[1]);
|
222
241
|
if (!logFile.empty()) {
|
223
|
-
|
242
|
+
syscalls::fclose(logFileHandle);
|
224
243
|
}
|
225
244
|
channel = MessageChannel(fds[0]);
|
226
245
|
serverNeedsRestart = false;
|
227
246
|
|
228
247
|
#ifdef TESTING_SPAWN_MANAGER
|
229
248
|
if (nextRestartShouldFail) {
|
230
|
-
|
231
|
-
|
249
|
+
syscalls::kill(pid, SIGTERM);
|
250
|
+
syscalls::usleep(500000);
|
232
251
|
}
|
233
252
|
#endif
|
234
253
|
}
|
@@ -237,41 +256,26 @@ private:
|
|
237
256
|
/**
|
238
257
|
* Send the spawn command to the spawn server.
|
239
258
|
*
|
240
|
-
* @param
|
241
|
-
* @param lowerPrivilege Whether to lower the application's privileges.
|
242
|
-
* @param lowestUser The user to fallback to if lowering privilege fails.
|
243
|
-
* @param environment The RAILS_ENV/RACK_ENV environment that should be used.
|
244
|
-
* @param spawnMethod The spawn method to use.
|
245
|
-
* @param appType The application type.
|
259
|
+
* @param PoolOptions The spawn options to use.
|
246
260
|
* @return An Application smart pointer, representing the spawned application.
|
247
261
|
* @throws SpawnException Something went wrong.
|
248
262
|
*/
|
249
|
-
ApplicationPtr sendSpawnCommand(
|
250
|
-
|
251
|
-
bool lowerPrivilege,
|
252
|
-
const string &lowestUser,
|
253
|
-
const string &environment,
|
254
|
-
const string &spawnMethod,
|
255
|
-
const string &appType
|
256
|
-
) {
|
263
|
+
ApplicationPtr sendSpawnCommand(const PoolOptions &PoolOptions) {
|
264
|
+
TRACE_POINT();
|
257
265
|
vector<string> args;
|
258
266
|
int ownerPipe;
|
259
267
|
|
260
268
|
try {
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
lowestUser.c_str(),
|
265
|
-
environment.c_str(),
|
266
|
-
spawnMethod.c_str(),
|
267
|
-
appType.c_str(),
|
268
|
-
NULL);
|
269
|
+
args.push_back("spawn_application");
|
270
|
+
PoolOptions.toVector(args);
|
271
|
+
channel.write(args);
|
269
272
|
} catch (const SystemException &e) {
|
270
273
|
throw SpawnException(string("Could not write 'spawn_application' "
|
271
274
|
"command to the spawn server: ") + e.sys());
|
272
275
|
}
|
273
276
|
|
274
277
|
try {
|
278
|
+
UPDATE_TRACE_POINT();
|
275
279
|
// Read status.
|
276
280
|
if (!channel.read(args)) {
|
277
281
|
throw SpawnException("The spawn server has exited unexpectedly.");
|
@@ -299,6 +303,7 @@ private:
|
|
299
303
|
throw SpawnException(string("Could not read from the spawn server: ") + e.sys());
|
300
304
|
}
|
301
305
|
|
306
|
+
UPDATE_TRACE_POINT();
|
302
307
|
try {
|
303
308
|
ownerPipe = channel.readFileDescriptor();
|
304
309
|
} catch (const SystemException &e) {
|
@@ -312,14 +317,15 @@ private:
|
|
312
317
|
}
|
313
318
|
|
314
319
|
if (args.size() != 3) {
|
315
|
-
|
320
|
+
UPDATE_TRACE_POINT();
|
321
|
+
syscalls::close(ownerPipe);
|
316
322
|
throw SpawnException("The spawn server sent an invalid message.");
|
317
323
|
}
|
318
324
|
|
319
325
|
pid_t pid = atoi(args[0]);
|
320
|
-
bool usingAbstractNamespace = args[2] == "true";
|
321
326
|
|
322
|
-
|
327
|
+
UPDATE_TRACE_POINT();
|
328
|
+
if (args[2] == "unix") {
|
323
329
|
int ret;
|
324
330
|
do {
|
325
331
|
ret = chmod(args[1].c_str(), S_IRUSR | S_IWUSR);
|
@@ -328,18 +334,16 @@ private:
|
|
328
334
|
ret = chown(args[1].c_str(), getuid(), getgid());
|
329
335
|
} while (ret == -1 && errno == EINTR);
|
330
336
|
}
|
331
|
-
return ApplicationPtr(new Application(appRoot,
|
332
|
-
|
337
|
+
return ApplicationPtr(new Application(PoolOptions.appRoot,
|
338
|
+
pid, args[1], args[2], ownerPipe));
|
333
339
|
}
|
334
340
|
|
335
341
|
/**
|
336
342
|
* @throws boost::thread_interrupted
|
337
343
|
*/
|
338
344
|
ApplicationPtr
|
339
|
-
handleSpawnException(const SpawnException &e, const
|
340
|
-
|
341
|
-
const string &environment, const string &spawnMethod,
|
342
|
-
const string &appType) {
|
345
|
+
handleSpawnException(const SpawnException &e, const PoolOptions &PoolOptions) {
|
346
|
+
TRACE_POINT();
|
343
347
|
bool restarted;
|
344
348
|
try {
|
345
349
|
P_DEBUG("Spawn server died. Attempting to restart it...");
|
@@ -355,8 +359,7 @@ private:
|
|
355
359
|
restarted = false;
|
356
360
|
}
|
357
361
|
if (restarted) {
|
358
|
-
return sendSpawnCommand(
|
359
|
-
environment, spawnMethod, appType);
|
362
|
+
return sendSpawnCommand(PoolOptions);
|
360
363
|
} else {
|
361
364
|
throw SpawnException("The spawn server died unexpectedly, and restarting it failed.");
|
362
365
|
}
|
@@ -369,6 +372,7 @@ private:
|
|
369
372
|
* @throws SystemException Something went wrong.
|
370
373
|
*/
|
371
374
|
void sendReloadCommand(const string &appRoot) {
|
375
|
+
TRACE_POINT();
|
372
376
|
try {
|
373
377
|
channel.write("reload", appRoot.c_str(), NULL);
|
374
378
|
} catch (const SystemException &e) {
|
@@ -378,6 +382,7 @@ private:
|
|
378
382
|
}
|
379
383
|
|
380
384
|
void handleReloadException(const SystemException &e, const string &appRoot) {
|
385
|
+
TRACE_POINT();
|
381
386
|
bool restarted;
|
382
387
|
try {
|
383
388
|
P_DEBUG("Spawn server died. Attempting to restart it...");
|
@@ -434,6 +439,7 @@ public:
|
|
434
439
|
const string &logFile = "",
|
435
440
|
const string &rubyCommand = "ruby",
|
436
441
|
const string &user = "") {
|
442
|
+
TRACE_POINT();
|
437
443
|
this->spawnServerCommand = spawnServerCommand;
|
438
444
|
this->logFile = logFile;
|
439
445
|
this->rubyCommand = rubyCommand;
|
@@ -454,76 +460,45 @@ public:
|
|
454
460
|
}
|
455
461
|
|
456
462
|
~SpawnManager() throw() {
|
463
|
+
TRACE_POINT();
|
457
464
|
if (pid != 0) {
|
465
|
+
UPDATE_TRACE_POINT();
|
458
466
|
this_thread::disable_interruption di;
|
459
467
|
this_thread::disable_syscall_interruption dsi;
|
460
468
|
P_TRACE(2, "Shutting down spawn manager (PID " << pid << ").");
|
461
469
|
channel.close();
|
462
|
-
|
470
|
+
syscalls::waitpid(pid, NULL, 0);
|
463
471
|
P_TRACE(2, "Spawn manager exited.");
|
464
472
|
}
|
465
473
|
}
|
466
474
|
|
467
475
|
/**
|
468
|
-
* Spawn a new instance of
|
476
|
+
* Spawn a new instance of an application. Spawning details are to be passed
|
477
|
+
* via the <tt>PoolOptions</tt> parameter.
|
469
478
|
*
|
470
479
|
* If the spawn server died during the spawning process, then the server
|
471
480
|
* will be automatically restarted, and another spawn attempt will be made.
|
472
481
|
* If restarting the server fails, or if the second spawn attempt fails,
|
473
482
|
* then an exception will be thrown.
|
474
483
|
*
|
475
|
-
*
|
476
|
-
*
|
477
|
-
* application's <tt>config/environment.rb</tt>, and to the default
|
478
|
-
* group of that user.
|
479
|
-
*
|
480
|
-
* If that user doesn't exist on the system, or if that user is root,
|
481
|
-
* then it will be attempted to switch to the username given by
|
482
|
-
* <tt>lowestUser</tt> (and to the default group of that user).
|
483
|
-
* If <tt>lowestUser</tt> doesn't exist either, or if switching user failed
|
484
|
-
* (because the spawn server process does not have the privilege to do so),
|
485
|
-
* then the application will be spawned anyway, without reporting an error.
|
486
|
-
*
|
487
|
-
* It goes without saying that lowering privilege is only possible if
|
488
|
-
* the spawn server is running as root (and thus, by induction, that
|
489
|
-
* Passenger and Apache's control process are also running as root).
|
490
|
-
* Note that if Apache is listening on port 80, then its control process must
|
491
|
-
* be running as root. See "doc/Security of user switching.txt" for
|
492
|
-
* a detailed explanation.
|
493
|
-
*
|
494
|
-
* @param appRoot The application root of a RoR application, i.e. the folder that
|
495
|
-
* contains 'app/', 'public/', 'config/', etc. This must be a valid directory,
|
496
|
-
* but the path does not have to be absolute.
|
497
|
-
* @param lowerPrivilege Whether to lower the application's privileges.
|
498
|
-
* @param lowestUser The user to fallback to if lowering privilege fails.
|
499
|
-
* @param environment The RAILS_ENV/RACK_ENV environment that should be used. May not be empty.
|
500
|
-
* @param spawnMethod The spawn method to use. Either "smart" or "conservative".
|
501
|
-
* See the Ruby class SpawnManager for details.
|
502
|
-
* @param appType The application type. Either "rails" or "rack".
|
484
|
+
* @param PoolOptions An object containing the details for this spawn operation,
|
485
|
+
* such as which application to spawn. See PoolOptions for details.
|
503
486
|
* @return A smart pointer to an Application object, which represents the application
|
504
487
|
* instance that has been spawned. Use this object to communicate with the
|
505
488
|
* spawned application.
|
506
489
|
* @throws SpawnException Something went wrong.
|
507
490
|
* @throws boost::thread_interrupted
|
508
491
|
*/
|
509
|
-
ApplicationPtr spawn(
|
510
|
-
|
511
|
-
|
512
|
-
const string &lowestUser = "nobody",
|
513
|
-
const string &environment = "production",
|
514
|
-
const string &spawnMethod = "smart",
|
515
|
-
const string &appType = "rails"
|
516
|
-
) {
|
517
|
-
mutex::scoped_lock l(lock);
|
492
|
+
ApplicationPtr spawn(const PoolOptions &PoolOptions) {
|
493
|
+
TRACE_POINT();
|
494
|
+
boost::mutex::scoped_lock l(lock);
|
518
495
|
try {
|
519
|
-
return sendSpawnCommand(
|
520
|
-
environment, spawnMethod, appType);
|
496
|
+
return sendSpawnCommand(PoolOptions);
|
521
497
|
} catch (const SpawnException &e) {
|
522
498
|
if (e.hasErrorPage()) {
|
523
499
|
throw;
|
524
500
|
} else {
|
525
|
-
return handleSpawnException(e,
|
526
|
-
lowestUser, environment, spawnMethod, appType);
|
501
|
+
return handleSpawnException(e, PoolOptions);
|
527
502
|
}
|
528
503
|
}
|
529
504
|
}
|
@@ -544,6 +519,7 @@ public:
|
|
544
519
|
* restart was attempted, but it failed.
|
545
520
|
*/
|
546
521
|
void reload(const string &appRoot) {
|
522
|
+
TRACE_POINT();
|
547
523
|
this_thread::disable_interruption di;
|
548
524
|
this_thread::disable_syscall_interruption dsi;
|
549
525
|
try {
|
@@ -27,6 +27,9 @@
|
|
27
27
|
#include <boost/date_time/microsec_time_clock.hpp>
|
28
28
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
29
29
|
|
30
|
+
#include <oxt/system_calls.hpp>
|
31
|
+
#include <oxt/backtrace.hpp>
|
32
|
+
|
30
33
|
#include <string>
|
31
34
|
#include <sstream>
|
32
35
|
#include <map>
|
@@ -44,7 +47,8 @@
|
|
44
47
|
|
45
48
|
#include "ApplicationPool.h"
|
46
49
|
#include "Logging.h"
|
47
|
-
#include "
|
50
|
+
#include "FileChecker.h"
|
51
|
+
#include "CachedFileStat.h"
|
48
52
|
#ifdef PASSENGER_USE_DUMMY_SPAWN_MANAGER
|
49
53
|
#include "DummySpawnManager.h"
|
50
54
|
#else
|
@@ -55,6 +59,7 @@ namespace Passenger {
|
|
55
59
|
|
56
60
|
using namespace std;
|
57
61
|
using namespace boost;
|
62
|
+
using namespace oxt;
|
58
63
|
|
59
64
|
class ApplicationPoolServer;
|
60
65
|
|
@@ -99,37 +104,100 @@ private:
|
|
99
104
|
static const unsigned int GET_TIMEOUT = 5000; // In milliseconds.
|
100
105
|
|
101
106
|
friend class ApplicationPoolServer;
|
107
|
+
struct Domain;
|
102
108
|
struct AppContainer;
|
103
109
|
|
110
|
+
typedef shared_ptr<Domain> DomainPtr;
|
104
111
|
typedef shared_ptr<AppContainer> AppContainerPtr;
|
105
112
|
typedef list<AppContainerPtr> AppContainerList;
|
106
|
-
typedef
|
107
|
-
|
113
|
+
typedef map<string, DomainPtr> DomainMap;
|
114
|
+
|
115
|
+
struct Domain {
|
116
|
+
AppContainerList instances;
|
117
|
+
unsigned int size;
|
118
|
+
unsigned long maxRequests;
|
119
|
+
FileChecker restartFileChecker;
|
120
|
+
CachedFileStat alwaysRestartFileStatter;
|
121
|
+
|
122
|
+
Domain(const PoolOptions &options)
|
123
|
+
: restartFileChecker(determineRestartDir(options) + "/restart.txt"),
|
124
|
+
alwaysRestartFileStatter(determineRestartDir(options) + "/always_restart.txt")
|
125
|
+
{
|
126
|
+
}
|
127
|
+
|
128
|
+
private:
|
129
|
+
static string determineRestartDir(const PoolOptions &options) {
|
130
|
+
if (options.restartDir.empty()) {
|
131
|
+
return options.appRoot + "/tmp";
|
132
|
+
} else if (options.restartDir[0] == '/') {
|
133
|
+
return options.restartDir;
|
134
|
+
} else {
|
135
|
+
return options.appRoot + "/" + options.restartDir;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
};
|
108
139
|
|
109
140
|
struct AppContainer {
|
110
141
|
ApplicationPtr app;
|
142
|
+
time_t startTime;
|
111
143
|
time_t lastUsed;
|
112
144
|
unsigned int sessions;
|
145
|
+
unsigned int processed;
|
113
146
|
AppContainerList::iterator iterator;
|
114
147
|
AppContainerList::iterator ia_iterator;
|
148
|
+
|
149
|
+
AppContainer() {
|
150
|
+
startTime = time(NULL);
|
151
|
+
processed = 0;
|
152
|
+
}
|
153
|
+
|
154
|
+
/**
|
155
|
+
* Returns the uptime of this AppContainer so far, as a string.
|
156
|
+
*/
|
157
|
+
string uptime() const {
|
158
|
+
time_t seconds = time(NULL) - startTime;
|
159
|
+
stringstream result;
|
160
|
+
|
161
|
+
if (seconds >= 60) {
|
162
|
+
time_t minutes = seconds / 60;
|
163
|
+
if (minutes >= 60) {
|
164
|
+
time_t hours = minutes / 60;
|
165
|
+
minutes = minutes % 60;
|
166
|
+
result << hours << "h ";
|
167
|
+
}
|
168
|
+
|
169
|
+
seconds = seconds % 60;
|
170
|
+
result << minutes << "m ";
|
171
|
+
}
|
172
|
+
result << seconds << "s";
|
173
|
+
return result.str();
|
174
|
+
}
|
115
175
|
};
|
116
176
|
|
177
|
+
/**
|
178
|
+
* A data structure which contains data that's shared between a
|
179
|
+
* StandardApplicationPool and a SessionCloseCallback object.
|
180
|
+
* This is because the StandardApplicationPool's life time could be
|
181
|
+
* different from a SessionCloseCallback's.
|
182
|
+
*/
|
117
183
|
struct SharedData {
|
118
|
-
mutex lock;
|
184
|
+
boost::mutex lock;
|
119
185
|
condition activeOrMaxChanged;
|
120
186
|
|
121
|
-
|
187
|
+
DomainMap domains;
|
122
188
|
unsigned int max;
|
123
189
|
unsigned int count;
|
124
190
|
unsigned int active;
|
125
191
|
unsigned int maxPerApp;
|
126
192
|
AppContainerList inactiveApps;
|
127
|
-
map<string, time_t> restartFileTimes;
|
128
193
|
map<string, unsigned int> appInstanceCount;
|
129
194
|
};
|
130
195
|
|
131
196
|
typedef shared_ptr<SharedData> SharedDataPtr;
|
132
197
|
|
198
|
+
/**
|
199
|
+
* Function object which will be called when a session has been closed.
|
200
|
+
*/
|
133
201
|
struct SessionCloseCallback {
|
134
202
|
SharedDataPtr data;
|
135
203
|
weak_ptr<AppContainer> container;
|
@@ -141,28 +209,42 @@ private:
|
|
141
209
|
}
|
142
210
|
|
143
211
|
void operator()() {
|
144
|
-
mutex::scoped_lock l(data->lock);
|
212
|
+
boost::mutex::scoped_lock l(data->lock);
|
145
213
|
AppContainerPtr container(this->container.lock());
|
146
214
|
|
147
215
|
if (container == NULL) {
|
148
216
|
return;
|
149
217
|
}
|
150
218
|
|
151
|
-
|
152
|
-
it = data->
|
153
|
-
if (it != data->
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
219
|
+
DomainMap::iterator it;
|
220
|
+
it = data->domains.find(container->app->getAppRoot());
|
221
|
+
if (it != data->domains.end()) {
|
222
|
+
Domain *domain = it->second.get();
|
223
|
+
AppContainerList *instances = &domain->instances;
|
224
|
+
|
225
|
+
container->processed++;
|
226
|
+
if (domain->maxRequests > 0 && container->processed >= domain->maxRequests) {
|
227
|
+
instances->erase(container->iterator);
|
228
|
+
domain->size--;
|
229
|
+
if (instances->empty()) {
|
230
|
+
data->domains.erase(container->app->getAppRoot());
|
231
|
+
}
|
232
|
+
data->count--;
|
164
233
|
data->active--;
|
165
234
|
data->activeOrMaxChanged.notify_all();
|
235
|
+
} else {
|
236
|
+
container->lastUsed = time(NULL);
|
237
|
+
container->sessions--;
|
238
|
+
if (container->sessions == 0) {
|
239
|
+
instances->erase(container->iterator);
|
240
|
+
instances->push_front(container);
|
241
|
+
container->iterator = instances->begin();
|
242
|
+
data->inactiveApps.push_back(container);
|
243
|
+
container->ia_iterator = data->inactiveApps.end();
|
244
|
+
container->ia_iterator--;
|
245
|
+
data->active--;
|
246
|
+
data->activeOrMaxChanged.notify_all();
|
247
|
+
}
|
166
248
|
}
|
167
249
|
}
|
168
250
|
}
|
@@ -174,24 +256,22 @@ private:
|
|
174
256
|
SpawnManager spawnManager;
|
175
257
|
#endif
|
176
258
|
SharedDataPtr data;
|
177
|
-
thread *cleanerThread;
|
259
|
+
boost::thread *cleanerThread;
|
178
260
|
bool detached;
|
179
261
|
bool done;
|
180
|
-
bool useGlobalQueue;
|
181
262
|
unsigned int maxIdleTime;
|
182
263
|
unsigned int waitingOnGlobalQueue;
|
183
264
|
condition cleanerThreadSleeper;
|
184
265
|
|
185
266
|
// Shortcuts for instance variables in SharedData. Saves typing in get().
|
186
|
-
mutex &lock;
|
267
|
+
boost::mutex &lock;
|
187
268
|
condition &activeOrMaxChanged;
|
188
|
-
|
269
|
+
DomainMap &domains;
|
189
270
|
unsigned int &max;
|
190
271
|
unsigned int &count;
|
191
272
|
unsigned int &active;
|
192
273
|
unsigned int &maxPerApp;
|
193
274
|
AppContainerList &inactiveApps;
|
194
|
-
map<string, time_t> &restartFileTimes;
|
195
275
|
map<string, unsigned int> &appInstanceCount;
|
196
276
|
|
197
277
|
/**
|
@@ -199,25 +279,38 @@ private:
|
|
199
279
|
*/
|
200
280
|
bool inline verifyState() {
|
201
281
|
#if PASSENGER_DEBUG
|
202
|
-
//
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
282
|
+
// Invariants for _domains_.
|
283
|
+
DomainMap::const_iterator it;
|
284
|
+
unsigned int totalSize = 0;
|
285
|
+
for (it = domains.begin(); it != domains.end(); it++) {
|
286
|
+
const string &appRoot = it->first;
|
287
|
+
Domain *domain = it->second.get();
|
288
|
+
AppContainerList *instances = &domain->instances;
|
289
|
+
|
290
|
+
P_ASSERT(domain->size <= count, false,
|
291
|
+
"domains['" << appRoot << "'].size (" << domain->size <<
|
292
|
+
") <= count (" << count << ")");
|
293
|
+
totalSize += domain->size;
|
294
|
+
|
295
|
+
// Invariants for Domain.
|
296
|
+
|
297
|
+
P_ASSERT(!instances->empty(), false,
|
298
|
+
"domains['" << appRoot << "'].instances is nonempty.");
|
207
299
|
|
208
300
|
AppContainerList::const_iterator prev_lit;
|
209
301
|
AppContainerList::const_iterator lit;
|
210
|
-
prev_lit =
|
302
|
+
prev_lit = instances->begin();
|
211
303
|
lit = prev_lit;
|
212
304
|
lit++;
|
213
|
-
for (; lit !=
|
305
|
+
for (; lit != instances->end(); lit++) {
|
214
306
|
if ((*prev_lit)->sessions > 0) {
|
215
307
|
P_ASSERT((*lit)->sessions > 0, false,
|
216
|
-
"
|
217
|
-
"
|
308
|
+
"domains['" << appRoot << "'].instances "
|
309
|
+
"is sorted from nonactive to active");
|
218
310
|
}
|
219
311
|
}
|
220
312
|
}
|
313
|
+
P_ASSERT(totalSize == count, false, "(sum of all d.size in domains) == count");
|
221
314
|
|
222
315
|
P_ASSERT(active <= count, false,
|
223
316
|
"active (" << active << ") < count (" << count << ")");
|
@@ -227,9 +320,7 @@ private:
|
|
227
320
|
return true;
|
228
321
|
}
|
229
322
|
|
230
|
-
|
231
|
-
string toString(LockActionType lockAction) const {
|
232
|
-
unique_lock<mutex> l(lock, lockAction);
|
323
|
+
string toStringWithoutLock() const {
|
233
324
|
stringstream result;
|
234
325
|
|
235
326
|
result << "----------- General information -----------" << endl;
|
@@ -237,23 +328,27 @@ private:
|
|
237
328
|
result << "count = " << count << endl;
|
238
329
|
result << "active = " << active << endl;
|
239
330
|
result << "inactive = " << inactiveApps.size() << endl;
|
240
|
-
result << "Using global queue: " << (useGlobalQueue ? "yes" : "no") << endl;
|
241
331
|
result << "Waiting on global queue: " << waitingOnGlobalQueue << endl;
|
242
332
|
result << endl;
|
243
333
|
|
244
|
-
result << "-----------
|
245
|
-
|
246
|
-
for (it =
|
247
|
-
|
334
|
+
result << "----------- Domains -----------" << endl;
|
335
|
+
DomainMap::const_iterator it;
|
336
|
+
for (it = domains.begin(); it != domains.end(); it++) {
|
337
|
+
Domain *domain = it->second.get();
|
338
|
+
AppContainerList *instances = &domain->instances;
|
248
339
|
AppContainerList::const_iterator lit;
|
249
340
|
|
250
341
|
result << it->first << ": " << endl;
|
251
|
-
for (lit =
|
342
|
+
for (lit = instances->begin(); lit != instances->end(); lit++) {
|
252
343
|
AppContainer *container = lit->get();
|
253
344
|
char buf[128];
|
254
345
|
|
255
|
-
snprintf(buf, sizeof(buf),
|
256
|
-
|
346
|
+
snprintf(buf, sizeof(buf),
|
347
|
+
"PID: %-5lu Sessions: %-2u Processed: %-5u Uptime: %s",
|
348
|
+
(unsigned long) container->app->getPid(),
|
349
|
+
container->sessions,
|
350
|
+
container->processed,
|
351
|
+
container->uptime().c_str());
|
257
352
|
result << " " << buf << endl;
|
258
353
|
}
|
259
354
|
result << endl;
|
@@ -261,45 +356,14 @@ private:
|
|
261
356
|
return result.str();
|
262
357
|
}
|
263
358
|
|
264
|
-
bool needsRestart(const string &appRoot) {
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
struct stat buf;
|
269
|
-
bool result;
|
270
|
-
int ret;
|
271
|
-
|
272
|
-
do {
|
273
|
-
ret = stat(restartFile.c_str(), &buf);
|
274
|
-
} while (ret == -1 && errno == EINTR);
|
275
|
-
if (ret == 0) {
|
276
|
-
do {
|
277
|
-
ret = unlink(restartFile.c_str());
|
278
|
-
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
|
279
|
-
if (ret == 0 || errno == ENOENT) {
|
280
|
-
restartFileTimes.erase(appRoot);
|
281
|
-
result = true;
|
282
|
-
} else {
|
283
|
-
map<string, time_t>::const_iterator it;
|
284
|
-
|
285
|
-
it = restartFileTimes.find(appRoot);
|
286
|
-
if (it == restartFileTimes.end()) {
|
287
|
-
result = true;
|
288
|
-
} else {
|
289
|
-
result = buf.st_mtime != restartFileTimes[appRoot];
|
290
|
-
}
|
291
|
-
restartFileTimes[appRoot] = buf.st_mtime;
|
292
|
-
}
|
293
|
-
} else {
|
294
|
-
restartFileTimes.erase(appRoot);
|
295
|
-
result = false;
|
296
|
-
}
|
297
|
-
return result;
|
359
|
+
bool needsRestart(const string &appRoot, Domain *domain, const PoolOptions &options) {
|
360
|
+
return domain->alwaysRestartFileStatter.refresh(options.statThrottleRate) == 0
|
361
|
+
|| domain->restartFileChecker.changed(options.statThrottleRate);
|
298
362
|
}
|
299
363
|
|
300
364
|
void cleanerThreadMainLoop() {
|
301
365
|
this_thread::disable_syscall_interruption dsi;
|
302
|
-
unique_lock<mutex> l(lock);
|
366
|
+
unique_lock<boost::mutex> l(lock);
|
303
367
|
try {
|
304
368
|
while (!done && !this_thread::interruption_requested()) {
|
305
369
|
xtime xt;
|
@@ -316,31 +380,31 @@ private:
|
|
316
380
|
}
|
317
381
|
}
|
318
382
|
|
319
|
-
time_t now =
|
383
|
+
time_t now = syscalls::time(NULL);
|
320
384
|
AppContainerList::iterator it;
|
321
385
|
for (it = inactiveApps.begin(); it != inactiveApps.end(); it++) {
|
322
386
|
AppContainer &container(*it->get());
|
323
387
|
ApplicationPtr app(container.app);
|
324
|
-
|
388
|
+
Domain *domain = domains[app->getAppRoot()].get();
|
389
|
+
AppContainerList *instances = &domain->instances;
|
325
390
|
|
326
|
-
if (
|
391
|
+
if (maxIdleTime > 0 &&
|
392
|
+
(now - container.lastUsed > (time_t) maxIdleTime)) {
|
327
393
|
P_DEBUG("Cleaning idle app " << app->getAppRoot() <<
|
328
394
|
" (PID " << app->getPid() << ")");
|
329
|
-
|
395
|
+
instances->erase(container.iterator);
|
330
396
|
|
331
397
|
AppContainerList::iterator prev = it;
|
332
398
|
prev--;
|
333
399
|
inactiveApps.erase(it);
|
334
400
|
it = prev;
|
335
401
|
|
336
|
-
|
402
|
+
domain->size--;
|
337
403
|
|
338
404
|
count--;
|
339
405
|
}
|
340
|
-
if (
|
341
|
-
|
342
|
-
appInstanceCount.erase(app->getAppRoot());
|
343
|
-
data->restartFileTimes.erase(app->getAppRoot());
|
406
|
+
if (instances->empty()) {
|
407
|
+
domains.erase(app->getAppRoot());
|
344
408
|
}
|
345
409
|
}
|
346
410
|
}
|
@@ -350,34 +414,31 @@ private:
|
|
350
414
|
}
|
351
415
|
|
352
416
|
/**
|
417
|
+
* Spawn a new application instance, or use an existing one that's in the pool.
|
418
|
+
*
|
353
419
|
* @throws boost::thread_interrupted
|
354
420
|
* @throws SpawnException
|
355
421
|
* @throws SystemException
|
356
422
|
*/
|
357
|
-
pair<AppContainerPtr,
|
358
|
-
spawnOrUseExisting(
|
359
|
-
mutex::scoped_lock &l,
|
360
|
-
const string &appRoot,
|
361
|
-
bool lowerPrivilege,
|
362
|
-
const string &lowestUser,
|
363
|
-
const string &environment,
|
364
|
-
const string &spawnMethod,
|
365
|
-
const string &appType
|
366
|
-
) {
|
423
|
+
pair<AppContainerPtr, Domain *>
|
424
|
+
spawnOrUseExisting(boost::mutex::scoped_lock &l, const PoolOptions &options) {
|
367
425
|
beginning_of_function:
|
368
426
|
|
427
|
+
TRACE_POINT();
|
369
428
|
this_thread::disable_interruption di;
|
370
429
|
this_thread::disable_syscall_interruption dsi;
|
430
|
+
const string &appRoot(options.appRoot);
|
371
431
|
AppContainerPtr container;
|
372
|
-
|
432
|
+
Domain *domain;
|
433
|
+
AppContainerList *instances;
|
373
434
|
|
374
435
|
try {
|
375
|
-
|
436
|
+
DomainMap::iterator it(domains.find(appRoot));
|
376
437
|
|
377
|
-
if (it !=
|
438
|
+
if (it != domains.end() && needsRestart(appRoot, it->second.get(), options)) {
|
378
439
|
AppContainerList::iterator it2;
|
379
|
-
|
380
|
-
for (it2 =
|
440
|
+
instances = &it->second->instances;
|
441
|
+
for (it2 = instances->begin(); it2 != instances->end(); it2++) {
|
381
442
|
container = *it2;
|
382
443
|
if (container->sessions == 0) {
|
383
444
|
inactiveApps.erase(container->ia_iterator);
|
@@ -385,49 +446,50 @@ private:
|
|
385
446
|
active--;
|
386
447
|
}
|
387
448
|
it2--;
|
388
|
-
|
449
|
+
instances->erase(container->iterator);
|
389
450
|
count--;
|
390
451
|
}
|
391
|
-
|
392
|
-
appInstanceCount.erase(appRoot);
|
452
|
+
domains.erase(appRoot);
|
393
453
|
spawnManager.reload(appRoot);
|
394
|
-
it =
|
454
|
+
it = domains.end();
|
395
455
|
activeOrMaxChanged.notify_all();
|
396
456
|
}
|
397
457
|
|
398
|
-
if (it !=
|
399
|
-
|
458
|
+
if (it != domains.end()) {
|
459
|
+
domain = it->second.get();
|
460
|
+
instances = &domain->instances;
|
400
461
|
|
401
|
-
if (
|
402
|
-
container =
|
403
|
-
|
404
|
-
|
405
|
-
container->iterator =
|
462
|
+
if (instances->front()->sessions == 0) {
|
463
|
+
container = instances->front();
|
464
|
+
instances->pop_front();
|
465
|
+
instances->push_back(container);
|
466
|
+
container->iterator = instances->end();
|
406
467
|
container->iterator--;
|
407
468
|
inactiveApps.erase(container->ia_iterator);
|
408
469
|
active++;
|
409
470
|
activeOrMaxChanged.notify_all();
|
410
471
|
} else if (count >= max || (
|
411
|
-
maxPerApp != 0 &&
|
472
|
+
maxPerApp != 0 && domain->size >= maxPerApp )
|
412
473
|
) {
|
413
|
-
if (useGlobalQueue) {
|
474
|
+
if (options.useGlobalQueue) {
|
475
|
+
UPDATE_TRACE_POINT();
|
414
476
|
waitingOnGlobalQueue++;
|
415
477
|
activeOrMaxChanged.wait(l);
|
416
478
|
waitingOnGlobalQueue--;
|
417
479
|
goto beginning_of_function;
|
418
480
|
} else {
|
419
|
-
AppContainerList::iterator it(
|
420
|
-
AppContainerList::iterator smallest(
|
481
|
+
AppContainerList::iterator it(instances->begin());
|
482
|
+
AppContainerList::iterator smallest(instances->begin());
|
421
483
|
it++;
|
422
|
-
for (; it !=
|
484
|
+
for (; it != instances->end(); it++) {
|
423
485
|
if ((*it)->sessions < (*smallest)->sessions) {
|
424
486
|
smallest = it;
|
425
487
|
}
|
426
488
|
}
|
427
489
|
container = *smallest;
|
428
|
-
|
429
|
-
|
430
|
-
container->iterator =
|
490
|
+
instances->erase(smallest);
|
491
|
+
instances->push_back(container);
|
492
|
+
container->iterator = instances->end();
|
431
493
|
container->iterator--;
|
432
494
|
}
|
433
495
|
} else {
|
@@ -435,57 +497,57 @@ private:
|
|
435
497
|
{
|
436
498
|
this_thread::restore_interruption ri(di);
|
437
499
|
this_thread::restore_syscall_interruption rsi(dsi);
|
438
|
-
container->app = spawnManager.spawn(
|
439
|
-
lowerPrivilege, lowestUser, environment,
|
440
|
-
spawnMethod, appType);
|
500
|
+
container->app = spawnManager.spawn(options);
|
441
501
|
}
|
442
502
|
container->sessions = 0;
|
443
|
-
|
444
|
-
container->iterator =
|
503
|
+
instances->push_back(container);
|
504
|
+
container->iterator = instances->end();
|
445
505
|
container->iterator--;
|
446
|
-
|
506
|
+
domain->size++;
|
447
507
|
count++;
|
448
508
|
active++;
|
449
509
|
activeOrMaxChanged.notify_all();
|
450
510
|
}
|
451
511
|
} else {
|
452
512
|
if (active >= max) {
|
513
|
+
UPDATE_TRACE_POINT();
|
453
514
|
activeOrMaxChanged.wait(l);
|
454
515
|
goto beginning_of_function;
|
455
|
-
}
|
456
|
-
if (count == max) {
|
516
|
+
} else if (count == max) {
|
457
517
|
container = inactiveApps.front();
|
458
518
|
inactiveApps.pop_front();
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
appInstanceCount.erase(container->app->getAppRoot());
|
519
|
+
domain = domains[container->app->getAppRoot()].get();
|
520
|
+
instances = &domain->instances;
|
521
|
+
instances->erase(container->iterator);
|
522
|
+
if (instances->empty()) {
|
523
|
+
domains.erase(container->app->getAppRoot());
|
465
524
|
} else {
|
466
|
-
|
525
|
+
domain->size--;
|
467
526
|
}
|
468
527
|
count--;
|
469
528
|
}
|
529
|
+
|
530
|
+
UPDATE_TRACE_POINT();
|
470
531
|
container = ptr(new AppContainer());
|
471
532
|
{
|
472
533
|
this_thread::restore_interruption ri(di);
|
473
534
|
this_thread::restore_syscall_interruption rsi(dsi);
|
474
|
-
container->app = spawnManager.spawn(
|
475
|
-
environment, spawnMethod, appType);
|
535
|
+
container->app = spawnManager.spawn(options);
|
476
536
|
}
|
477
537
|
container->sessions = 0;
|
478
|
-
it =
|
479
|
-
if (it ==
|
480
|
-
|
481
|
-
|
482
|
-
|
538
|
+
it = domains.find(appRoot);
|
539
|
+
if (it == domains.end()) {
|
540
|
+
domain = new Domain(options);
|
541
|
+
domain->size = 1;
|
542
|
+
domain->maxRequests = options.maxRequests;
|
543
|
+
domains[appRoot] = ptr(domain);
|
483
544
|
} else {
|
484
|
-
|
485
|
-
|
545
|
+
domain = it->second.get();
|
546
|
+
domain->size++;
|
486
547
|
}
|
487
|
-
|
488
|
-
|
548
|
+
instances = &domain->instances;
|
549
|
+
instances->push_back(container);
|
550
|
+
container->iterator = instances->end();
|
489
551
|
container->iterator--;
|
490
552
|
count++;
|
491
553
|
active++;
|
@@ -509,7 +571,7 @@ private:
|
|
509
571
|
throw SpawnException(message);
|
510
572
|
}
|
511
573
|
|
512
|
-
return make_pair(container,
|
574
|
+
return make_pair(container, domain);
|
513
575
|
}
|
514
576
|
|
515
577
|
public:
|
@@ -529,7 +591,6 @@ public:
|
|
529
591
|
* running as root. If the empty string is given, or if
|
530
592
|
* the <tt>user</tt> is not a valid username, then
|
531
593
|
* the spawn manager will be run as the current user.
|
532
|
-
* @param rubyCommand The Ruby interpreter's command.
|
533
594
|
* @throws SystemException An error occured while trying to setup the spawn server.
|
534
595
|
* @throws IOException The specified log file could not be opened.
|
535
596
|
*/
|
@@ -544,25 +605,24 @@ public:
|
|
544
605
|
data(new SharedData()),
|
545
606
|
lock(data->lock),
|
546
607
|
activeOrMaxChanged(data->activeOrMaxChanged),
|
547
|
-
|
608
|
+
domains(data->domains),
|
548
609
|
max(data->max),
|
549
610
|
count(data->count),
|
550
611
|
active(data->active),
|
551
612
|
maxPerApp(data->maxPerApp),
|
552
613
|
inactiveApps(data->inactiveApps),
|
553
|
-
restartFileTimes(data->restartFileTimes),
|
554
614
|
appInstanceCount(data->appInstanceCount)
|
555
615
|
{
|
616
|
+
TRACE_POINT();
|
556
617
|
detached = false;
|
557
618
|
done = false;
|
558
619
|
max = DEFAULT_MAX_POOL_SIZE;
|
559
620
|
count = 0;
|
560
621
|
active = 0;
|
561
|
-
useGlobalQueue = false;
|
562
622
|
waitingOnGlobalQueue = 0;
|
563
623
|
maxPerApp = DEFAULT_MAX_INSTANCES_PER_APP;
|
564
624
|
maxIdleTime = DEFAULT_MAX_IDLE_TIME;
|
565
|
-
cleanerThread = new thread(
|
625
|
+
cleanerThread = new boost::thread(
|
566
626
|
bind(&StandardApplicationPool::cleanerThreadMainLoop, this),
|
567
627
|
CLEANER_THREAD_STACK_SIZE
|
568
628
|
);
|
@@ -572,7 +632,7 @@ public:
|
|
572
632
|
if (!detached) {
|
573
633
|
this_thread::disable_interruption di;
|
574
634
|
{
|
575
|
-
mutex::scoped_lock l(lock);
|
635
|
+
boost::mutex::scoped_lock l(lock);
|
576
636
|
done = true;
|
577
637
|
cleanerThreadSleeper.notify_one();
|
578
638
|
}
|
@@ -581,28 +641,27 @@ public:
|
|
581
641
|
delete cleanerThread;
|
582
642
|
}
|
583
643
|
|
584
|
-
virtual Application::SessionPtr get(
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
const string &appType = "rails"
|
591
|
-
) {
|
644
|
+
virtual Application::SessionPtr get(const string &appRoot) {
|
645
|
+
return ApplicationPool::get(appRoot);
|
646
|
+
}
|
647
|
+
|
648
|
+
virtual Application::SessionPtr get(const PoolOptions &options) {
|
649
|
+
TRACE_POINT();
|
592
650
|
using namespace boost::posix_time;
|
593
651
|
unsigned int attempt = 0;
|
594
|
-
|
595
|
-
|
652
|
+
// TODO: We should probably add a timeout to the following
|
653
|
+
// lock. This way we can fail gracefully if the server's under
|
654
|
+
// rediculous load. Though I'm not sure how much it really helps.
|
655
|
+
unique_lock<boost::mutex> l(lock);
|
596
656
|
|
597
657
|
while (true) {
|
598
658
|
attempt++;
|
599
659
|
|
600
|
-
pair<AppContainerPtr,
|
601
|
-
spawnOrUseExisting(l,
|
602
|
-
environment, spawnMethod, appType)
|
660
|
+
pair<AppContainerPtr, Domain *> p(
|
661
|
+
spawnOrUseExisting(l, options)
|
603
662
|
);
|
604
|
-
AppContainerPtr &container
|
605
|
-
|
663
|
+
AppContainerPtr &container = p.first;
|
664
|
+
Domain *domain = p.second;
|
606
665
|
|
607
666
|
container->lastUsed = time(NULL);
|
608
667
|
container->sessions++;
|
@@ -610,13 +669,26 @@ public:
|
|
610
669
|
P_ASSERT(verifyState(), Application::SessionPtr(),
|
611
670
|
"State is valid:\n" << toString(false));
|
612
671
|
try {
|
672
|
+
UPDATE_TRACE_POINT();
|
613
673
|
return container->app->connect(SessionCloseCallback(data, container));
|
614
674
|
} catch (const exception &e) {
|
615
675
|
container->sessions--;
|
676
|
+
|
677
|
+
AppContainerList &instances(domain->instances);
|
678
|
+
instances.erase(container->iterator);
|
679
|
+
domain->size--;
|
680
|
+
if (instances.empty()) {
|
681
|
+
domains.erase(options.appRoot);
|
682
|
+
}
|
683
|
+
count--;
|
684
|
+
active--;
|
685
|
+
activeOrMaxChanged.notify_all();
|
686
|
+
P_ASSERT(verifyState(), Application::SessionPtr(),
|
687
|
+
"State is valid: " << toString(false));
|
616
688
|
if (attempt == MAX_GET_ATTEMPTS) {
|
617
689
|
string message("Cannot connect to an existing "
|
618
690
|
"application instance for '");
|
619
|
-
message.append(appRoot);
|
691
|
+
message.append(options.appRoot);
|
620
692
|
message.append("': ");
|
621
693
|
try {
|
622
694
|
const SystemException &syse =
|
@@ -626,17 +698,6 @@ public:
|
|
626
698
|
message.append(e.what());
|
627
699
|
}
|
628
700
|
throw IOException(message);
|
629
|
-
} else {
|
630
|
-
list.erase(container->iterator);
|
631
|
-
if (list.empty()) {
|
632
|
-
apps.erase(appRoot);
|
633
|
-
appInstanceCount.erase(appRoot);
|
634
|
-
}
|
635
|
-
count--;
|
636
|
-
active--;
|
637
|
-
activeOrMaxChanged.notify_all();
|
638
|
-
P_ASSERT(verifyState(), Application::SessionPtr(),
|
639
|
-
"State is valid.");
|
640
701
|
}
|
641
702
|
}
|
642
703
|
}
|
@@ -645,10 +706,9 @@ public:
|
|
645
706
|
}
|
646
707
|
|
647
708
|
virtual void clear() {
|
648
|
-
mutex::scoped_lock l(lock);
|
649
|
-
|
709
|
+
boost::mutex::scoped_lock l(lock);
|
710
|
+
domains.clear();
|
650
711
|
inactiveApps.clear();
|
651
|
-
restartFileTimes.clear();
|
652
712
|
appInstanceCount.clear();
|
653
713
|
count = 0;
|
654
714
|
active = 0;
|
@@ -656,13 +716,13 @@ public:
|
|
656
716
|
}
|
657
717
|
|
658
718
|
virtual void setMaxIdleTime(unsigned int seconds) {
|
659
|
-
mutex::scoped_lock l(lock);
|
719
|
+
boost::mutex::scoped_lock l(lock);
|
660
720
|
maxIdleTime = seconds;
|
661
721
|
cleanerThreadSleeper.notify_one();
|
662
722
|
}
|
663
723
|
|
664
724
|
virtual void setMax(unsigned int max) {
|
665
|
-
mutex::scoped_lock l(lock);
|
725
|
+
boost::mutex::scoped_lock l(lock);
|
666
726
|
this->max = max;
|
667
727
|
activeOrMaxChanged.notify_all();
|
668
728
|
}
|
@@ -676,15 +736,11 @@ public:
|
|
676
736
|
}
|
677
737
|
|
678
738
|
virtual void setMaxPerApp(unsigned int maxPerApp) {
|
679
|
-
mutex::scoped_lock l(lock);
|
739
|
+
boost::mutex::scoped_lock l(lock);
|
680
740
|
this->maxPerApp = maxPerApp;
|
681
741
|
activeOrMaxChanged.notify_all();
|
682
742
|
}
|
683
743
|
|
684
|
-
virtual void setUseGlobalQueue(bool value) {
|
685
|
-
this->useGlobalQueue = value;
|
686
|
-
}
|
687
|
-
|
688
744
|
virtual pid_t getSpawnServerPid() const {
|
689
745
|
return spawnManager.getServerPid();
|
690
746
|
}
|
@@ -695,13 +751,58 @@ public:
|
|
695
751
|
*/
|
696
752
|
virtual string toString(bool lockMutex = true) const {
|
697
753
|
if (lockMutex) {
|
698
|
-
|
754
|
+
unique_lock<boost::mutex> l(lock);
|
755
|
+
return toStringWithoutLock();
|
699
756
|
} else {
|
700
|
-
return
|
757
|
+
return toStringWithoutLock();
|
701
758
|
}
|
702
759
|
}
|
760
|
+
|
761
|
+
/**
|
762
|
+
* Returns an XML description of the internal state of the
|
763
|
+
* application pool.
|
764
|
+
*/
|
765
|
+
virtual string toXml() const {
|
766
|
+
unique_lock<boost::mutex> l(lock);
|
767
|
+
stringstream result;
|
768
|
+
DomainMap::const_iterator it;
|
769
|
+
|
770
|
+
result << "<?xml version=\"1.0\" encoding=\"iso8859-1\" ?>\n";
|
771
|
+
result << "<info>";
|
772
|
+
|
773
|
+
result << "<domains>";
|
774
|
+
for (it = domains.begin(); it != domains.end(); it++) {
|
775
|
+
Domain *domain = it->second.get();
|
776
|
+
AppContainerList *instances = &domain->instances;
|
777
|
+
AppContainerList::const_iterator lit;
|
778
|
+
|
779
|
+
result << "<domain>";
|
780
|
+
result << "<name>" << escapeForXml(it->first) << "</name>";
|
781
|
+
|
782
|
+
result << "<instances>";
|
783
|
+
for (lit = instances->begin(); lit != instances->end(); lit++) {
|
784
|
+
AppContainer *container = lit->get();
|
785
|
+
|
786
|
+
result << "<instance>";
|
787
|
+
result << "<pid>" << container->app->getPid() << "</pid>";
|
788
|
+
result << "<sessions>" << container->sessions << "</sessions>";
|
789
|
+
result << "<processed>" << container->processed << "</processed>";
|
790
|
+
result << "<uptime>" << container->uptime() << "</uptime>";
|
791
|
+
result << "</instance>";
|
792
|
+
}
|
793
|
+
result << "</instances>";
|
794
|
+
|
795
|
+
result << "</domain>";
|
796
|
+
}
|
797
|
+
result << "</domains>";
|
798
|
+
|
799
|
+
result << "</info>";
|
800
|
+
return result.str();
|
801
|
+
}
|
703
802
|
};
|
704
803
|
|
804
|
+
typedef shared_ptr<StandardApplicationPool> StandardApplicationPoolPtr;
|
805
|
+
|
705
806
|
} // namespace Passenger
|
706
807
|
|
707
808
|
#endif /* _PASSENGER_STANDARD_APPLICATION_POOL_H_ */
|