passenger 5.0.0.beta3 → 5.0.0.rc1

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 (218) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.asc +7 -7
  3. data.tar.gz.asc +7 -7
  4. data/.editorconfig +11 -5
  5. data/CHANGELOG +38 -0
  6. data/CONTRIBUTING.md +1 -4
  7. data/Gemfile +0 -1
  8. data/Gemfile.lock +0 -2
  9. data/Rakefile +33 -33
  10. data/bin/passenger +1 -1
  11. data/bin/passenger-config +1 -1
  12. data/bin/passenger-install-apache2-module +800 -800
  13. data/bin/passenger-install-nginx-module +592 -592
  14. data/bin/passenger-memory-stats +127 -127
  15. data/bin/passenger-status +216 -216
  16. data/build/agents.rb +127 -127
  17. data/build/apache2.rb +87 -87
  18. data/build/basics.rb +60 -60
  19. data/build/common_library.rb +165 -165
  20. data/build/cplusplus_support.rb +51 -51
  21. data/build/cxx_tests.rb +268 -268
  22. data/build/debian.rb +143 -143
  23. data/build/documentation.rb +58 -58
  24. data/build/integration_tests.rb +81 -81
  25. data/build/misc.rb +132 -132
  26. data/build/nginx.rb +20 -20
  27. data/build/node_tests.rb +7 -7
  28. data/build/oxt_tests.rb +14 -14
  29. data/build/packaging.rb +570 -570
  30. data/build/preprocessor.rb +260 -260
  31. data/build/rake_extensions.rb +71 -71
  32. data/build/ruby_extension.rb +29 -29
  33. data/build/ruby_tests.rb +6 -6
  34. data/build/test_basics.rb +37 -37
  35. data/debian.template/control.template +3 -5
  36. data/dev/copy_boost_headers +134 -134
  37. data/dev/install_scripts_bootstrap_code.rb +25 -25
  38. data/dev/list_tests +20 -20
  39. data/dev/ruby_server.rb +223 -223
  40. data/dev/runner +18 -18
  41. data/doc/ServerOptimizationGuide.txt.md +55 -2
  42. data/doc/Users guide Nginx.txt +0 -26
  43. data/doc/Users guide Standalone.txt +5 -1
  44. data/doc/users_guide_snippets/tips.txt +9 -0
  45. data/ext/common/ApplicationPool2/Group.h +23 -11
  46. data/ext/common/ApplicationPool2/Implementation.cpp +32 -7
  47. data/ext/common/ApplicationPool2/Pool.h +22 -17
  48. data/ext/common/ApplicationPool2/SmartSpawner.h +4 -1
  49. data/ext/common/ApplicationPool2/Spawner.h +1 -1
  50. data/ext/common/Constants.h +1 -1
  51. data/ext/common/agents/Base.cpp +35 -20
  52. data/ext/common/agents/HelperAgent/Main.cpp +8 -1
  53. data/ext/common/agents/HelperAgent/OptionParser.h +18 -4
  54. data/ext/common/agents/HelperAgent/RequestHandler.h +2 -83
  55. data/ext/common/agents/HelperAgent/RequestHandler/ForwardResponse.cpp +54 -1
  56. data/ext/common/agents/HelperAgent/RequestHandler/InitRequest.cpp +7 -4
  57. data/ext/common/agents/Main.cpp +1 -1
  58. data/ext/common/agents/Watchdog/Main.cpp +54 -19
  59. data/ext/nginx/Configuration.c +7 -0
  60. data/ext/nginx/ContentHandler.c +9 -1
  61. data/helper-scripts/backtrace-sanitizer.rb +106 -87
  62. data/helper-scripts/crash-watch.rb +32 -0
  63. data/helper-scripts/download_binaries/extconf.rb +38 -38
  64. data/helper-scripts/meteor-loader.rb +107 -107
  65. data/helper-scripts/prespawn +101 -101
  66. data/helper-scripts/rack-loader.rb +96 -96
  67. data/helper-scripts/rack-preloader.rb +137 -137
  68. data/lib/phusion_passenger.rb +292 -292
  69. data/lib/phusion_passenger/abstract_installer.rb +438 -438
  70. data/lib/phusion_passenger/active_support3_extensions/init.rb +168 -170
  71. data/lib/phusion_passenger/admin_tools.rb +20 -20
  72. data/lib/phusion_passenger/admin_tools/instance.rb +178 -178
  73. data/lib/phusion_passenger/admin_tools/instance_registry.rb +61 -61
  74. data/lib/phusion_passenger/admin_tools/memory_stats.rb +267 -267
  75. data/lib/phusion_passenger/apache2/config_options.rb +182 -182
  76. data/lib/phusion_passenger/common_library.rb +479 -485
  77. data/lib/phusion_passenger/config/about_command.rb +161 -161
  78. data/lib/phusion_passenger/config/admin_command_command.rb +129 -129
  79. data/lib/phusion_passenger/config/agent_compiler.rb +121 -121
  80. data/lib/phusion_passenger/config/build_native_support_command.rb +43 -43
  81. data/lib/phusion_passenger/config/command.rb +25 -25
  82. data/lib/phusion_passenger/config/compile_agent_command.rb +62 -62
  83. data/lib/phusion_passenger/config/compile_nginx_engine_command.rb +88 -73
  84. data/lib/phusion_passenger/config/detach_process_command.rb +72 -72
  85. data/lib/phusion_passenger/config/download_agent_command.rb +246 -227
  86. data/lib/phusion_passenger/config/download_nginx_engine_command.rb +245 -224
  87. data/lib/phusion_passenger/config/install_agent_command.rb +144 -132
  88. data/lib/phusion_passenger/config/install_standalone_runtime_command.rb +205 -185
  89. data/lib/phusion_passenger/config/installation_utils.rb +204 -204
  90. data/lib/phusion_passenger/config/list_instances_command.rb +64 -64
  91. data/lib/phusion_passenger/config/main.rb +152 -152
  92. data/lib/phusion_passenger/config/nginx_engine_compiler.rb +319 -300
  93. data/lib/phusion_passenger/config/reopen_logs_command.rb +67 -67
  94. data/lib/phusion_passenger/config/restart_app_command.rb +155 -155
  95. data/lib/phusion_passenger/config/system_metrics_command.rb +13 -13
  96. data/lib/phusion_passenger/config/utils.rb +95 -95
  97. data/lib/phusion_passenger/config/validate_install_command.rb +198 -198
  98. data/lib/phusion_passenger/console_text_template.rb +25 -25
  99. data/lib/phusion_passenger/constants.rb +90 -90
  100. data/lib/phusion_passenger/debug_logging.rb +106 -106
  101. data/lib/phusion_passenger/loader_shared_helpers.rb +447 -432
  102. data/lib/phusion_passenger/message_channel.rb +312 -312
  103. data/lib/phusion_passenger/message_client.rb +176 -176
  104. data/lib/phusion_passenger/native_support.rb +369 -369
  105. data/lib/phusion_passenger/nginx/config_options.rb +297 -297
  106. data/lib/phusion_passenger/packaging.rb +131 -131
  107. data/lib/phusion_passenger/platform_info.rb +360 -360
  108. data/lib/phusion_passenger/platform_info/apache.rb +767 -767
  109. data/lib/phusion_passenger/platform_info/apache_detector.rb +199 -199
  110. data/lib/phusion_passenger/platform_info/binary_compatibility.rb +107 -107
  111. data/lib/phusion_passenger/platform_info/compiler.rb +570 -570
  112. data/lib/phusion_passenger/platform_info/curl.rb +32 -32
  113. data/lib/phusion_passenger/platform_info/cxx_portability.rb +188 -188
  114. data/lib/phusion_passenger/platform_info/depcheck.rb +372 -372
  115. data/lib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +109 -109
  116. data/lib/phusion_passenger/platform_info/depcheck_specs/compiler_toolchain.rb +4 -4
  117. data/lib/phusion_passenger/platform_info/depcheck_specs/gems.rb +10 -34
  118. data/lib/phusion_passenger/platform_info/depcheck_specs/libs.rb +101 -101
  119. data/lib/phusion_passenger/platform_info/depcheck_specs/ruby.rb +5 -5
  120. data/lib/phusion_passenger/platform_info/depcheck_specs/utilities.rb +13 -13
  121. data/lib/phusion_passenger/platform_info/linux.rb +55 -55
  122. data/lib/phusion_passenger/platform_info/operating_system.rb +149 -149
  123. data/lib/phusion_passenger/platform_info/ruby.rb +468 -448
  124. data/lib/phusion_passenger/platform_info/zlib.rb +9 -9
  125. data/lib/phusion_passenger/plugin.rb +66 -66
  126. data/lib/phusion_passenger/preloader_shared_helpers.rb +126 -126
  127. data/lib/phusion_passenger/public_api.rb +191 -191
  128. data/lib/phusion_passenger/rack/out_of_band_gc.rb +93 -94
  129. data/lib/phusion_passenger/rack/thread_handler_extension.rb +231 -227
  130. data/lib/phusion_passenger/request_handler.rb +567 -577
  131. data/lib/phusion_passenger/request_handler/thread_handler.rb +379 -381
  132. data/lib/phusion_passenger/ruby_core_enhancements.rb +86 -86
  133. data/lib/phusion_passenger/ruby_core_io_enhancements.rb +74 -74
  134. data/lib/phusion_passenger/simple_benchmarking.rb +25 -25
  135. data/lib/phusion_passenger/standalone/app_finder.rb +153 -150
  136. data/lib/phusion_passenger/standalone/command.rb +44 -40
  137. data/lib/phusion_passenger/standalone/config_utils.rb +53 -53
  138. data/lib/phusion_passenger/standalone/control_utils.rb +38 -59
  139. data/lib/phusion_passenger/standalone/main.rb +73 -73
  140. data/lib/phusion_passenger/standalone/start_command.rb +697 -685
  141. data/lib/phusion_passenger/standalone/start_command/builtin_engine.rb +193 -155
  142. data/lib/phusion_passenger/standalone/start_command/nginx_engine.rb +162 -133
  143. data/lib/phusion_passenger/standalone/status_command.rb +64 -64
  144. data/lib/phusion_passenger/standalone/stop_command.rb +72 -72
  145. data/lib/phusion_passenger/standalone/version_command.rb +9 -9
  146. data/lib/phusion_passenger/union_station/connection.rb +32 -32
  147. data/lib/phusion_passenger/union_station/core.rb +251 -251
  148. data/lib/phusion_passenger/union_station/transaction.rb +126 -126
  149. data/lib/phusion_passenger/utils.rb +199 -167
  150. data/lib/phusion_passenger/utils/ansi_colors.rb +128 -128
  151. data/lib/phusion_passenger/utils/download.rb +196 -196
  152. data/lib/phusion_passenger/utils/file_system_watcher.rb +158 -158
  153. data/lib/phusion_passenger/utils/hosts_file_parser.rb +101 -101
  154. data/lib/phusion_passenger/utils/lock.rb +31 -31
  155. data/lib/phusion_passenger/utils/native_support_utils.rb +31 -31
  156. data/lib/phusion_passenger/utils/progress_bar.rb +26 -26
  157. data/lib/phusion_passenger/utils/shellwords.rb +20 -20
  158. data/lib/phusion_passenger/utils/terminal_choice_menu.rb +206 -206
  159. data/lib/phusion_passenger/utils/unseekable_socket.rb +272 -272
  160. data/lib/phusion_passenger/vendor/crash_watch/app.rb +129 -0
  161. data/lib/phusion_passenger/vendor/crash_watch/gdb_controller.rb +341 -0
  162. data/lib/phusion_passenger/vendor/crash_watch/version.rb +24 -0
  163. data/lib/phusion_passenger/vendor/daemon_controller.rb +877 -0
  164. data/lib/phusion_passenger/vendor/daemon_controller/lock_file.rb +127 -0
  165. data/lib/phusion_passenger/vendor/daemon_controller/spawn.rb +26 -0
  166. data/lib/phusion_passenger/vendor/daemon_controller/version.rb +29 -0
  167. data/packaging/rpm/passenger_spec/passenger.spec.template +0 -1
  168. data/passenger.gemspec +0 -1
  169. data/resources/templates/config/nginx_engine_compiler/possible_solutions_for_download_and_extraction_problems.txt.erb +27 -0
  170. data/resources/templates/standalone/config.erb +19 -15
  171. data/test/integration_tests/apache2_tests.rb +566 -566
  172. data/test/integration_tests/downloaded_binaries_tests.rb +126 -125
  173. data/test/integration_tests/native_packaging_spec.rb +296 -296
  174. data/test/integration_tests/nginx_tests.rb +393 -393
  175. data/test/integration_tests/shared/example_webapp_tests.rb +282 -280
  176. data/test/integration_tests/source_packaging_test.rb +138 -138
  177. data/test/integration_tests/spec_helper.rb +5 -5
  178. data/test/integration_tests/standalone_tests.rb +367 -367
  179. data/test/ruby/debug_logging_spec.rb +133 -133
  180. data/test/ruby/message_channel_spec.rb +186 -186
  181. data/test/ruby/rack/loader_spec.rb +28 -28
  182. data/test/ruby/rack/preloader_spec.rb +34 -34
  183. data/test/ruby/rails3.0/loader_spec.rb +12 -12
  184. data/test/ruby/rails3.0/preloader_spec.rb +18 -18
  185. data/test/ruby/rails3.1/loader_spec.rb +12 -12
  186. data/test/ruby/rails3.1/preloader_spec.rb +18 -18
  187. data/test/ruby/rails3.2/loader_spec.rb +12 -12
  188. data/test/ruby/rails3.2/preloader_spec.rb +18 -18
  189. data/test/ruby/rails4.0/loader_spec.rb +12 -12
  190. data/test/ruby/rails4.0/preloader_spec.rb +18 -18
  191. data/test/ruby/rails4.1/loader_spec.rb +12 -12
  192. data/test/ruby/rails4.1/preloader_spec.rb +18 -18
  193. data/test/ruby/request_handler_spec.rb +730 -730
  194. data/test/ruby/shared/loader_sharedspec.rb +224 -224
  195. data/test/ruby/shared/rails/union_station_extensions_sharedspec.rb +327 -327
  196. data/test/ruby/shared/ruby_loader_sharedspec.rb +47 -47
  197. data/test/ruby/spec_helper.rb +65 -65
  198. data/test/ruby/standalone/runtime_installer_spec.rb +384 -384
  199. data/test/ruby/union_station_spec.rb +276 -276
  200. data/test/ruby/utils/file_system_watcher_spec.rb +220 -220
  201. data/test/ruby/utils/hosts_file_parser.rb +248 -248
  202. data/test/ruby/utils/tee_input_spec.rb +215 -215
  203. data/test/ruby/utils/unseekable_socket_spec.rb +57 -57
  204. data/test/ruby/utils_spec.rb +21 -21
  205. data/test/stub/rack/config.ru +87 -87
  206. data/test/stub/rack/library.rb +8 -8
  207. data/test/stub/rack/start.rb +30 -30
  208. data/test/support/apache2_controller.rb +191 -191
  209. data/test/support/nginx_controller.rb +90 -99
  210. data/test/support/placebo-preloader.rb +57 -57
  211. data/test/support/test_helper.rb +435 -435
  212. metadata +11 -21
  213. metadata.gz.asc +7 -7
  214. data/lib/phusion_passenger/standalone/command2.rb +0 -292
  215. data/lib/phusion_passenger/standalone/start2_command.rb +0 -799
  216. data/resources/templates/standalone/download_tool_missing.txt.erb +0 -18
  217. data/resources/templates/standalone/possible_solutions_for_download_and_extraction_problems.txt.erb +0 -17
  218. data/resources/templates/standalone/run_installer_as_root.txt.erb +0 -8
@@ -26,73 +26,73 @@ require 'fileutils'
26
26
  PhusionPassenger.require_passenger_lib 'admin_tools/instance'
27
27
 
28
28
  module PhusionPassenger
29
- module AdminTools
29
+ module AdminTools
30
30
 
31
- class InstanceRegistry
32
- def initialize(path = nil)
33
- @path = path || default_path
34
- end
31
+ class InstanceRegistry
32
+ def initialize(path = nil)
33
+ @path = path || default_path
34
+ end
35
35
 
36
- def list(options = {})
37
- options = {
38
- :clean_stale_or_corrupted => true
39
- }.merge(options)
40
- instances = []
36
+ def list(options = {})
37
+ options = {
38
+ :clean_stale_or_corrupted => true
39
+ }.merge(options)
40
+ instances = []
41
41
 
42
- Dir["#{@path}/passenger.*"].each do |dir|
43
- instance = Instance.new(dir)
44
- case instance.state
45
- when :good
46
- if instance.locked?
47
- instances << instance
48
- elsif options[:clean_stale_or_corrupted]
49
- cleanup(dir)
50
- end
51
- when :structure_version_unsupported
52
- next
53
- when :corrupted
54
- if !instance.locked? && options[:clean_stale_or_corrupted]
55
- cleanup(dir)
56
- end
57
- when :not_finalized
58
- if instance.stale? && options[:clean_stale_or_corrupted]
59
- cleanup(dir)
60
- end
61
- end
62
- end
63
- return instances
64
- end
42
+ Dir["#{@path}/passenger.*"].each do |dir|
43
+ instance = Instance.new(dir)
44
+ case instance.state
45
+ when :good
46
+ if instance.locked?
47
+ instances << instance
48
+ elsif options[:clean_stale_or_corrupted]
49
+ cleanup(dir)
50
+ end
51
+ when :structure_version_unsupported
52
+ next
53
+ when :corrupted
54
+ if !instance.locked? && options[:clean_stale_or_corrupted]
55
+ cleanup(dir)
56
+ end
57
+ when :not_finalized
58
+ if instance.stale? && options[:clean_stale_or_corrupted]
59
+ cleanup(dir)
60
+ end
61
+ end
62
+ end
63
+ return instances
64
+ end
65
65
 
66
- def find_by_name(name, options = {})
67
- return list(options).find { |instance| instance.name == name }
68
- end
66
+ def find_by_name(name, options = {})
67
+ return list(options).find { |instance| instance.name == name }
68
+ end
69
69
 
70
- def find_by_name_prefix(name, options = {})
71
- prefix = /^#{Regexp.escape name}/
72
- results = list(options).find_all { |instance| instance.name =~ prefix }
73
- if results.size <= 1
74
- return results.first
75
- else
76
- return :ambiguous
77
- end
78
- end
70
+ def find_by_name_prefix(name, options = {})
71
+ prefix = /^#{Regexp.escape name}/
72
+ results = list(options).find_all { |instance| instance.name =~ prefix }
73
+ if results.size <= 1
74
+ return results.first
75
+ else
76
+ return :ambiguous
77
+ end
78
+ end
79
79
 
80
- private
81
- def default_path
82
- ["PASSENGER_INSTANCE_REGISTRY_DIR", "TMPDIR"].each do |name|
83
- if ENV.has_key?(name) && !ENV[name].empty?
84
- return ENV[name]
85
- end
86
- end
87
- return "/tmp"
88
- end
80
+ private
81
+ def default_path
82
+ ["PASSENGER_INSTANCE_REGISTRY_DIR", "TMPDIR"].each do |name|
83
+ if ENV.has_key?(name) && !ENV[name].empty?
84
+ return ENV[name]
85
+ end
86
+ end
87
+ return "/tmp"
88
+ end
89
89
 
90
- def cleanup(path)
91
- puts "*** Cleaning stale instance directory #{path}"
92
- FileUtils.chmod_R(0700, path) rescue nil
93
- FileUtils.remove_entry_secure(path)
94
- end
95
- end
90
+ def cleanup(path)
91
+ puts "*** Cleaning stale instance directory #{path}"
92
+ FileUtils.chmod_R(0700, path) rescue nil
93
+ FileUtils.remove_entry_secure(path)
94
+ end
95
+ end
96
96
 
97
- end # module AdminTools
97
+ end # module AdminTools
98
98
  end # module PhusionPassenger
@@ -25,276 +25,276 @@ PhusionPassenger.require_passenger_lib 'platform_info/apache'
25
25
  PhusionPassenger.require_passenger_lib 'platform_info/operating_system'
26
26
 
27
27
  module PhusionPassenger
28
- module AdminTools
28
+ module AdminTools
29
29
 
30
- class MemoryStats
31
- # Information about a single process.
32
- class Process
33
- attr_accessor :pid
34
- attr_accessor :ppid
35
- attr_accessor :threads
36
- attr_accessor :vm_size # in KB
37
- attr_accessor :rss # in KB
38
- attr_accessor :cpu
39
- attr_accessor :name
40
- attr_accessor :private_dirty_rss # in KB
41
-
42
- def vm_size_in_mb
43
- return sprintf("%.1f MB", vm_size / 1024.0)
44
- end
30
+ class MemoryStats
31
+ # Information about a single process.
32
+ class Process
33
+ attr_accessor :pid
34
+ attr_accessor :ppid
35
+ attr_accessor :threads
36
+ attr_accessor :vm_size # in KB
37
+ attr_accessor :rss # in KB
38
+ attr_accessor :cpu
39
+ attr_accessor :name
40
+ attr_accessor :private_dirty_rss # in KB
45
41
 
46
- def rss_in_mb
47
- return sprintf("%.1f MB", rss / 1024.0)
48
- end
49
-
50
- def private_dirty_rss_in_mb
51
- if private_dirty_rss.is_a?(Numeric)
52
- return sprintf("%.1f MB", private_dirty_rss / 1024.0)
53
- else
54
- return "?"
55
- end
56
- end
57
-
58
- def to_a
59
- return [pid, ppid, vm_size_in_mb, private_dirty_rss_in_mb, rss_in_mb, name]
60
- end
61
- end
62
-
63
- # Returns a list of Apache processes, which may be the empty list if Apache is
64
- # not running. If the Apache executable name is unknown then nil will be returned.
65
- def apache_processes
66
- @apache_processes ||= begin
67
- if PlatformInfo.httpd
68
- processes = list_processes(:exe => PlatformInfo.httpd)
69
- if processes.empty?
70
- # On some Linux distros, the Apache worker processes
71
- # are called "httpd.worker"
72
- processes = list_processes(:exe => "#{PlatformInfo.httpd}.worker")
73
- end
74
- processes
75
- else
76
- nil
77
- end
78
- end
79
- end
80
-
81
- # Returns a list of Nginx processes, which may be the empty list if
82
- # Nginx is not running.
83
- def nginx_processes
84
- @nginx_processes ||= list_processes(:exe => "nginx")
85
- end
86
-
87
- # Returns a list of Phusion Passenger processes, which may be the empty list if
88
- # Phusion Passenger is not running.
89
- def passenger_processes
90
- @passenger_processes ||= list_processes(:match =>
91
- /((^| )Passenger|(^| )Rails:|(^| )Rack:|wsgi-loader.py)/)
92
- end
93
-
94
- # Returns the sum of the memory usages of all given processes.
95
- # Returns a pair [usage, accurate]. +usage+ is the summed memory usage in KB,
96
- # and +accurate+ indicates whether this sum is accurate. This may be false
97
- # if some process's memory usage cannot be determined.
98
- def sum_memory_usage(processes)
99
- total = 0
100
- if should_show_private_dirty_rss?
101
- accurate = true
102
- processes.each do |p|
103
- if p.private_dirty_rss.is_a?(Numeric)
104
- total += p.private_dirty_rss
105
- else
106
- accurate = true
107
- end
108
- end
109
- return [total, accurate]
110
- else
111
- processes.each do |p|
112
- total += p.rss
113
- end
114
- return [total, true]
115
- end
116
- end
117
-
118
- def platform_provides_private_dirty_rss_information?
119
- return os_name == "linux"
120
- end
121
-
122
- # Returns whether root privileges are required in order to measure private dirty RSS.
123
- # Only meaningful if #platform_provides_private_dirty_rss_information? returns true.
124
- def root_privileges_required_for_private_dirty_rss?
125
- all_processes = (apache_processes || []) + nginx_processes + passenger_processes
126
- return all_processes.any?{ |p| p.private_dirty_rss.nil? }
127
- end
128
-
129
- def should_show_private_dirty_rss?
130
- return platform_provides_private_dirty_rss_information? &&
131
- (::Process.euid == 0 || root_privileges_required_for_private_dirty_rss?)
132
- end
133
-
134
- # Determine the system's RAM usage, not including swap.
135
- # Returns a tuple [total, used] where both numbers are in KB, or nil
136
- # if the system's RAM usage cannot be determined.
137
- def system_ram_usage
138
- @total_system_ram ||= begin
139
- case os_name
140
- when /linux/
141
- free_text = `free -k`
142
-
143
- free_text =~ %r{Mem:(.+)$}
144
- line = $1.strip
145
- total = line.split(/ +/).first.to_i
146
-
147
- free_text =~ %r{buffers/cache:(.+)$}
148
- line = $1.strip
149
- used = line.split(/ +/).first.to_i
150
-
151
- [total, used]
152
- when /macosx/
153
- vm_stat = `vm_stat`
154
- vm_stat =~ /page size of (\d+) bytes/
155
- page_size = $1
156
- vm_stat =~ /Pages free: +(\d+)/
157
- free = $1
158
- vm_stat =~ /Pages active: +(\d+)/
159
- active = $1
160
- vm_stat =~ /Pages inactive: +(\d+)/
161
- inactive = $1
162
- vm_stat =~ /Pages wired down: +(\d+)/
163
- wired = $1
164
-
165
- if page_size && free && active && inactive && wired
166
- page_size = page_size.to_i
167
- free = free.to_i * page_size / 1024
168
- active = active.to_i * page_size / 1024
169
- inactive = inactive.to_i * page_size / 1024
170
- wired = wired.to_i * page_size / 1024
171
-
172
- used = active + wired
173
- [free + inactive + used, used]
174
- else
175
- nil
176
- end
177
- else
178
- `top` =~ /(\d+)(K|M) Active, (\d+)(K|M) Inact, (\d+)(K|M) Wired,.*?(\d+)(K|M) Free/
179
- if $1 && $2 && $3 && $4 && $5 && $6 && $7 && $8
180
- to_kb = lambda do |number, unit|
181
- if unit == 'K'
182
- number.to_i
183
- else
184
- number.to_i * 1024
185
- end
186
- end
187
-
188
- active = to_kb.call($1, $2)
189
- inactive = to_kb.call($3, $4)
190
- wired = to_kb.call($5, $6)
191
- free = to_kb.call($7, $8)
192
-
193
- used = active + wired
194
- [free + inactive + used, used]
195
- else
196
- nil
197
- end
198
- end
199
- end
200
- end
42
+ def vm_size_in_mb
43
+ return sprintf("%.1f MB", vm_size / 1024.0)
44
+ end
201
45
 
202
- private
203
- def os_name
204
- return PlatformInfo.os_name
205
- end
206
-
207
- # Returns a list of Process objects that match the given search criteria.
208
- #
209
- # # Search by executable path.
210
- # list_processes(:exe => '/usr/sbin/apache2')
211
- #
212
- # # Search by executable name.
213
- # list_processes(:name => 'ruby1.8')
214
- #
215
- # # Search by process name.
216
- # list_processes(:match => 'Passenger FrameworkSpawner')
217
- def list_processes(options)
218
- if options[:exe]
219
- name = options[:exe].sub(/.*\/(.*)/, '\1')
220
- if os_name =~ /linux/
221
- ps = "ps -C '#{name}'"
222
- else
223
- ps = "ps -A"
224
- options[:match] = Regexp.new(Regexp.escape(name))
225
- end
226
- elsif options[:name]
227
- if os_name =~ /linux/
228
- ps = "ps -C '#{options[:name]}'"
229
- else
230
- ps = "ps -A"
231
- options[:match] = Regexp.new(" #{Regexp.escape(options[:name])}")
232
- end
233
- elsif options[:match]
234
- ps = "ps -A"
235
- else
236
- raise ArgumentError, "Invalid options."
237
- end
238
-
239
- processes = []
240
- case os_name
241
- when /solaris/
242
- list = `#{ps} -o pid,ppid,nlwp,vsz,rss,pcpu,comm`.split("\n")
243
- threads_known = true
244
- when /macosx/
245
- list = `#{ps} -w -o pid,ppid,vsz,rss,%cpu,command`.split("\n")
246
- threads_known = false
247
- else
248
- list = `#{ps} -w -o pid,ppid,nlwp,vsz,rss,%cpu,command`.split("\n")
249
- threads_known = true
250
- end
251
- list.shift
252
- list.each do |line|
253
- line.gsub!(/^ */, '')
254
- line.gsub!(/ *$/, '')
255
-
256
- p = Process.new
257
- if threads_known
258
- p.pid, p.ppid, p.threads, p.vm_size, p.rss, p.cpu, p.name = line.split(/ +/, 7)
259
- else
260
- p.pid, p.ppid, p.vm_size, p.rss, p.cpu, p.name = line.split(/ +/, 6)
261
- end
262
- p.name.sub!(/\Aruby: /, '')
263
- p.name.sub!(/ \(ruby\)\Z/, '')
264
- if p.name !~ /^ps/ && (!options[:match] || p.name.match(options[:match]))
265
- # Convert some values to integer.
266
- [:pid, :ppid, :vm_size, :rss].each do |attr|
267
- p.send("#{attr}=", p.send(attr).to_i)
268
- end
269
- p.threads = p.threads.to_i if threads_known
46
+ def rss_in_mb
47
+ return sprintf("%.1f MB", rss / 1024.0)
48
+ end
270
49
 
271
- if platform_provides_private_dirty_rss_information?
272
- p.private_dirty_rss = determine_private_dirty_rss(p.pid)
273
- end
274
- processes << p
275
- end
276
- end
277
- return processes
278
- end
279
-
280
- # Returns the private dirty RSS for the given process, in KB.
281
- def determine_private_dirty_rss(pid)
282
- total = 0
283
- File.read("/proc/#{pid}/smaps").split("\n").each do |line|
284
- line =~ /^(Private)_Dirty: +(\d+)/
285
- if $2
286
- total += $2.to_i
287
- end
288
- end
289
- if total == 0
290
- return nil
291
- else
292
- return total
293
- end
294
- rescue Errno::EACCES, Errno::ENOENT
295
- return nil
296
- end
297
- end
50
+ def private_dirty_rss_in_mb
51
+ if private_dirty_rss.is_a?(Numeric)
52
+ return sprintf("%.1f MB", private_dirty_rss / 1024.0)
53
+ else
54
+ return "?"
55
+ end
56
+ end
298
57
 
299
- end # module AdminTools
58
+ def to_a
59
+ return [pid, ppid, vm_size_in_mb, private_dirty_rss_in_mb, rss_in_mb, name]
60
+ end
61
+ end
62
+
63
+ # Returns a list of Apache processes, which may be the empty list if Apache is
64
+ # not running. If the Apache executable name is unknown then nil will be returned.
65
+ def apache_processes
66
+ @apache_processes ||= begin
67
+ if PlatformInfo.httpd
68
+ processes = list_processes(:exe => PlatformInfo.httpd)
69
+ if processes.empty?
70
+ # On some Linux distros, the Apache worker processes
71
+ # are called "httpd.worker"
72
+ processes = list_processes(:exe => "#{PlatformInfo.httpd}.worker")
73
+ end
74
+ processes
75
+ else
76
+ nil
77
+ end
78
+ end
79
+ end
80
+
81
+ # Returns a list of Nginx processes, which may be the empty list if
82
+ # Nginx is not running.
83
+ def nginx_processes
84
+ @nginx_processes ||= list_processes(:exe => "nginx")
85
+ end
86
+
87
+ # Returns a list of Phusion Passenger processes, which may be the empty list if
88
+ # Phusion Passenger is not running.
89
+ def passenger_processes
90
+ @passenger_processes ||= list_processes(:match =>
91
+ /((^| )Passenger|(^| )Rails:|(^| )Rack:|wsgi-loader.py)/)
92
+ end
93
+
94
+ # Returns the sum of the memory usages of all given processes.
95
+ # Returns a pair [usage, accurate]. +usage+ is the summed memory usage in KB,
96
+ # and +accurate+ indicates whether this sum is accurate. This may be false
97
+ # if some process's memory usage cannot be determined.
98
+ def sum_memory_usage(processes)
99
+ total = 0
100
+ if should_show_private_dirty_rss?
101
+ accurate = true
102
+ processes.each do |p|
103
+ if p.private_dirty_rss.is_a?(Numeric)
104
+ total += p.private_dirty_rss
105
+ else
106
+ accurate = true
107
+ end
108
+ end
109
+ return [total, accurate]
110
+ else
111
+ processes.each do |p|
112
+ total += p.rss
113
+ end
114
+ return [total, true]
115
+ end
116
+ end
117
+
118
+ def platform_provides_private_dirty_rss_information?
119
+ return os_name == "linux"
120
+ end
121
+
122
+ # Returns whether root privileges are required in order to measure private dirty RSS.
123
+ # Only meaningful if #platform_provides_private_dirty_rss_information? returns true.
124
+ def root_privileges_required_for_private_dirty_rss?
125
+ all_processes = (apache_processes || []) + nginx_processes + passenger_processes
126
+ return all_processes.any?{ |p| p.private_dirty_rss.nil? }
127
+ end
128
+
129
+ def should_show_private_dirty_rss?
130
+ return platform_provides_private_dirty_rss_information? &&
131
+ (::Process.euid == 0 || root_privileges_required_for_private_dirty_rss?)
132
+ end
133
+
134
+ # Determine the system's RAM usage, not including swap.
135
+ # Returns a tuple [total, used] where both numbers are in KB, or nil
136
+ # if the system's RAM usage cannot be determined.
137
+ def system_ram_usage
138
+ @total_system_ram ||= begin
139
+ case os_name
140
+ when /linux/
141
+ free_text = `free -k`
142
+
143
+ free_text =~ %r{Mem:(.+)$}
144
+ line = $1.strip
145
+ total = line.split(/ +/).first.to_i
146
+
147
+ free_text =~ %r{buffers/cache:(.+)$}
148
+ line = $1.strip
149
+ used = line.split(/ +/).first.to_i
150
+
151
+ [total, used]
152
+ when /macosx/
153
+ vm_stat = `vm_stat`
154
+ vm_stat =~ /page size of (\d+) bytes/
155
+ page_size = $1
156
+ vm_stat =~ /Pages free: +(\d+)/
157
+ free = $1
158
+ vm_stat =~ /Pages active: +(\d+)/
159
+ active = $1
160
+ vm_stat =~ /Pages inactive: +(\d+)/
161
+ inactive = $1
162
+ vm_stat =~ /Pages wired down: +(\d+)/
163
+ wired = $1
164
+
165
+ if page_size && free && active && inactive && wired
166
+ page_size = page_size.to_i
167
+ free = free.to_i * page_size / 1024
168
+ active = active.to_i * page_size / 1024
169
+ inactive = inactive.to_i * page_size / 1024
170
+ wired = wired.to_i * page_size / 1024
171
+
172
+ used = active + wired
173
+ [free + inactive + used, used]
174
+ else
175
+ nil
176
+ end
177
+ else
178
+ `top` =~ /(\d+)(K|M) Active, (\d+)(K|M) Inact, (\d+)(K|M) Wired,.*?(\d+)(K|M) Free/
179
+ if $1 && $2 && $3 && $4 && $5 && $6 && $7 && $8
180
+ to_kb = lambda do |number, unit|
181
+ if unit == 'K'
182
+ number.to_i
183
+ else
184
+ number.to_i * 1024
185
+ end
186
+ end
187
+
188
+ active = to_kb.call($1, $2)
189
+ inactive = to_kb.call($3, $4)
190
+ wired = to_kb.call($5, $6)
191
+ free = to_kb.call($7, $8)
192
+
193
+ used = active + wired
194
+ [free + inactive + used, used]
195
+ else
196
+ nil
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ private
203
+ def os_name
204
+ return PlatformInfo.os_name
205
+ end
206
+
207
+ # Returns a list of Process objects that match the given search criteria.
208
+ #
209
+ # # Search by executable path.
210
+ # list_processes(:exe => '/usr/sbin/apache2')
211
+ #
212
+ # # Search by executable name.
213
+ # list_processes(:name => 'ruby1.8')
214
+ #
215
+ # # Search by process name.
216
+ # list_processes(:match => 'Passenger FrameworkSpawner')
217
+ def list_processes(options)
218
+ if options[:exe]
219
+ name = options[:exe].sub(/.*\/(.*)/, '\1')
220
+ if os_name =~ /linux/
221
+ ps = "ps -C '#{name}'"
222
+ else
223
+ ps = "ps -A"
224
+ options[:match] = Regexp.new(Regexp.escape(name))
225
+ end
226
+ elsif options[:name]
227
+ if os_name =~ /linux/
228
+ ps = "ps -C '#{options[:name]}'"
229
+ else
230
+ ps = "ps -A"
231
+ options[:match] = Regexp.new(" #{Regexp.escape(options[:name])}")
232
+ end
233
+ elsif options[:match]
234
+ ps = "ps -A"
235
+ else
236
+ raise ArgumentError, "Invalid options."
237
+ end
238
+
239
+ processes = []
240
+ case os_name
241
+ when /solaris/
242
+ list = `#{ps} -o pid,ppid,nlwp,vsz,rss,pcpu,comm`.split("\n")
243
+ threads_known = true
244
+ when /macosx/
245
+ list = `#{ps} -w -o pid,ppid,vsz,rss,%cpu,command`.split("\n")
246
+ threads_known = false
247
+ else
248
+ list = `#{ps} -w -o pid,ppid,nlwp,vsz,rss,%cpu,command`.split("\n")
249
+ threads_known = true
250
+ end
251
+ list.shift
252
+ list.each do |line|
253
+ line.gsub!(/^ */, '')
254
+ line.gsub!(/ *$/, '')
255
+
256
+ p = Process.new
257
+ if threads_known
258
+ p.pid, p.ppid, p.threads, p.vm_size, p.rss, p.cpu, p.name = line.split(/ +/, 7)
259
+ else
260
+ p.pid, p.ppid, p.vm_size, p.rss, p.cpu, p.name = line.split(/ +/, 6)
261
+ end
262
+ p.name.sub!(/\Aruby: /, '')
263
+ p.name.sub!(/ \(ruby\)\Z/, '')
264
+ if p.name !~ /^ps/ && (!options[:match] || p.name.match(options[:match]))
265
+ # Convert some values to integer.
266
+ [:pid, :ppid, :vm_size, :rss].each do |attr|
267
+ p.send("#{attr}=", p.send(attr).to_i)
268
+ end
269
+ p.threads = p.threads.to_i if threads_known
270
+
271
+ if platform_provides_private_dirty_rss_information?
272
+ p.private_dirty_rss = determine_private_dirty_rss(p.pid)
273
+ end
274
+ processes << p
275
+ end
276
+ end
277
+ return processes
278
+ end
279
+
280
+ # Returns the private dirty RSS for the given process, in KB.
281
+ def determine_private_dirty_rss(pid)
282
+ total = 0
283
+ File.read("/proc/#{pid}/smaps").split("\n").each do |line|
284
+ line =~ /^(Private)_Dirty: +(\d+)/
285
+ if $2
286
+ total += $2.to_i
287
+ end
288
+ end
289
+ if total == 0
290
+ return nil
291
+ else
292
+ return total
293
+ end
294
+ rescue Errno::EACCES, Errno::ENOENT
295
+ return nil
296
+ end
297
+ end
298
+
299
+ end # module AdminTools
300
300
  end # module PhusionPassenger