class GarbageMan::Collector
Constants
- WRITE_MOVE_OPTIONS
Attributes
after_gc_callbacks[R]
before_gc_callbacks[R]
fiber_poll[R]
last_gc_finished_at[R]
request_count[RW]
selected_to_collect_at[R]
show_gc_times[RW]
will_collect[RW]
will_select_next_server[RW]
Public Class Methods
new()
click to toggle source
# File lib/garbageman/collector.rb, line 31 def initialize @show_gc_times = true @show_memory_released = false @before_gc_callbacks = [] @after_gc_callbacks = [] reset end
Public Instance Methods
collect()
click to toggle source
# File lib/garbageman/collector.rb, line 70 def collect # if we are starting to queue requests turn on gc, we could be in trouble if Config.check_request_queue? && queuing? warn QUEUING_REQUESTS GC.enable elsif waited_too_long_to_gc? warn (WAITED_TOO_LONG % (Time.now - @last_gc_finished_at)) GC.enable end unless can_collect? @can_collect_at ||= Time.now return unless (Time.now - @can_collect_at) >= Config.time_to_wait_before_collecting return unless will_collect # return unless been selected to gc if waited_too_long_for_connections_to_drain? warn CONNECTIONS_DID_NOT_DRAIN_IN_TIME else return end end File.open(Config.gc_last_collected_file, 'w') { |f| f.write Time.now.to_i.to_s } before_gc_callbacks.each(&:call) write_gc_yaml server_index, STARTING debug "starting gc" memory_used = @show_memory_released ? process_resident_memory_size_in_kb : 0 starts = Time.now GC.enable Config.gc_starts.times do GC.start sleep(Config.gc_sleep) if Config.gc_sleep > 0 end @last_gc_finished_at = Time.now diff = (@last_gc_finished_at - starts) * 1000 info "GC took #{'%.2f' % diff}ms for #{@request_count} requests" if @show_gc_times info "GC freed #{memory_used - process_resident_memory_size_in_kb}kb of memory" if @show_memory_released warn "was running GC and received #{Thin::Backends::Base.num_connections} connections " if Thin::Backends::Base.num_connections > 0 write_gc_yaml server_index, NEXT_SERVER after_gc_callbacks.each(&:call) reset if can_disable? debug DISABLE_GC GC.disable else warn CANT_TURN_OFF GC.enable end end
create_gc_yaml()
click to toggle source
creates the gc yaml file or resets the status back to selected
# File lib/garbageman/collector.rb, line 137 def create_gc_yaml return unless server_index if File.exists?(Config.gc_yaml_file) return unless current_server? else return unless server_index == 0 end write_gc_yaml server_index, SELECTED end
debug(msg)
click to toggle source
# File lib/garbageman/collector.rb, line 149 def debug(msg) logger.debug msg end
healthy?()
click to toggle source
# File lib/garbageman/collector.rb, line 44 def healthy? unless can_disable? warn CAN_NOT_DISABLE_GC GC.enable return true end if select_next_server? if @will_select_next_server select_next_server else # wait until we receive another request before selecting the next server @will_select_next_server = true end return true end if should_collect? @selected_to_collect_at ||= Time.now write_gc_yaml server_index, WILL_COLLECT false else true end end
info(msg)
click to toggle source
# File lib/garbageman/collector.rb, line 153 def info(msg) logger.info msg end
logger()
click to toggle source
# File lib/garbageman/collector.rb, line 147 def logger; GarbageMan.logger; end
process_resident_memory_size_in_kb()
click to toggle source
# File lib/garbageman/collector.rb, line 124 def process_resident_memory_size_in_kb if File.exists?('/proc/self/statm') File.read('/proc/self/statm').split(' ')[1] else headers, stats = `ps v #{Process.pid}`.split "\n" return 0 unless headers && stats headers = headers.strip.gsub(/ +/, ' ').split(' ') stats = stats.strip.gsub(/ +/, ' ').split(' ') Hash[headers.zip(stats)]['RSS'].to_i end end
register_fiber_pool(pool)
click to toggle source
for use with rack-fiber_pool
# File lib/garbageman/collector.rb, line 40 def register_fiber_pool(pool) @fiber_poll = pool end
select_next_server()
click to toggle source
# File lib/garbageman/collector.rb, line 161 def select_next_server return unless @will_select_next_server return unless @request_count >= Config.num_request_before_selecting_next_server @will_select_next_server = false Config.thin_config['servers'].times do |i| next_server_index = (server_index + i + 1) % num_servers file = socket_file next_server_index next unless File.exists?(file) debug "selected #{next_server_index}" write_gc_yaml next_server_index, SELECTED return true end false end
warn(msg)
click to toggle source
# File lib/garbageman/collector.rb, line 157 def warn(msg) logger.warn msg end
Private Instance Methods
busy?()
click to toggle source
# File lib/garbageman/collector.rb, line 211 def busy? fiber_poll && fiber_poll.busy_fibers.size > 0 end
can_collect?()
click to toggle source
no traffic and we've been selected by health check
# File lib/garbageman/collector.rb, line 224 def can_collect? @will_collect && ! busy? && Thin::Backends::Base.num_connections == 0 end
can_disable?()
click to toggle source
# File lib/garbageman/collector.rb, line 255 def can_disable? uses_sockets? && not_queuing? && not_forcing_gc? && enough_running_servers? end
current_server?()
click to toggle source
# File lib/garbageman/collector.rb, line 233 def current_server? config = Config.gc_config config && config['gc'] && config['gc']['server'] && config['gc']['server'] == server_index end
enough_running_servers?()
click to toggle source
make sure there are 3 or more servers running before disabling gc
# File lib/garbageman/collector.rb, line 271 def enough_running_servers? num_servers >= Config.min_servers_to_disable_gc && num_running_servers >= Config.min_servers_to_disable_gc end
forcing_gc?()
click to toggle source
# File lib/garbageman/collector.rb, line 243 def forcing_gc? File.exists?(Config.enable_gc_file) end
not_forcing_gc?()
click to toggle source
# File lib/garbageman/collector.rb, line 247 def not_forcing_gc? ! forcing_gc? end
not_queuing?()
click to toggle source
# File lib/garbageman/collector.rb, line 219 def not_queuing? ! queuing? end
num_running_servers()
click to toggle source
# File lib/garbageman/collector.rb, line 262 def num_running_servers count = 0 Config.thin_config['servers'].times do |i| count += 1 if i == server_index || File.exists?(socket_file(i)) end count end
num_servers()
click to toggle source
# File lib/garbageman/collector.rb, line 183 def num_servers Config.thin_config['servers'] end
queuing?()
click to toggle source
# File lib/garbageman/collector.rb, line 215 def queuing? fiber_poll && fiber_poll.queue.size > 0 end
reset()
click to toggle source
# File lib/garbageman/collector.rb, line 203 def reset @request_count = 0 @will_collect = false @will_select_next_server = false @selected_to_collect_at = nil @can_collect_at = nil end
select_next_server?()
click to toggle source
# File lib/garbageman/collector.rb, line 238 def select_next_server? config = Config.gc_config config && config['gc'] && config['gc']['server'] && config['gc']['server'] == server_index && config['gc']['status'] == 'next_server' end
server_index()
click to toggle source
# File lib/garbageman/collector.rb, line 179 def server_index Thin::Backends::Base.server_index end
should_collect?()
click to toggle source
if the request count is high enough and it is our turn
# File lib/garbageman/collector.rb, line 229 def should_collect? @will_collect = (@request_count >= Config.num_request_before_collecting && current_server?) end
socket_file(index)
click to toggle source
# File lib/garbageman/collector.rb, line 275 def socket_file(index) Config.thin_config['socket'].sub '.sock', ".#{index}.sock" end
uses_sockets?()
click to toggle source
# File lib/garbageman/collector.rb, line 251 def uses_sockets? Config.thin_config.has_key?('socket') end
waited_too_long_for_connections_to_drain?()
click to toggle source
# File lib/garbageman/collector.rb, line 284 def waited_too_long_for_connections_to_drain? @selected_to_collect_at && (Time.now - @selected_to_collect_at) >= Config.max_connection_drain_time end
waited_too_long_to_gc?()
click to toggle source
# File lib/garbageman/collector.rb, line 279 def waited_too_long_to_gc? return false unless @last_gc_finished_at (Time.now - @last_gc_finished_at) >= Config.max_time_without_gc end
write_gc_yaml(index, status)
click to toggle source
# File lib/garbageman/collector.rb, line 188 def write_gc_yaml(index, status) config = {'gc' => { 'server' => index, 'status' => status, 'request_count' => @request_count, 'will_collect' => @will_collect, 'will_select_next_server' => @will_select_next_server, 'selected_to_collect_at' => @selected_to_collect_at.to_s } } File.open(Config.gc_yaml_tmp_file, 'w') { |f| f.write config.to_yaml } # atomic write FileUtils.mv Config.gc_yaml_tmp_file, Config.gc_yaml_file, WRITE_MOVE_OPTIONS end