Class: GarbageMan::Collector

Inherits:
Object
  • Object
show all
Includes:
Messages, Status, Singleton
Defined in:
lib/garbageman/collector.rb

Defined Under Namespace

Modules: Messages, Status

Constant Summary

Constants included from Messages

Messages::CANT_TURN_OFF, Messages::CAN_NOT_DISABLE_GC, Messages::CONNECTIONS_DID_NOT_DRAIN_IN_TIME, Messages::DISABLE_GC, Messages::QUEUING_REQUESTS, Messages::WAITED_TOO_LONG

Constants included from Status

Status::NEXT_SERVER, Status::SELECTED, Status::STARTING, Status::WILL_COLLECT

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCollector

Returns a new instance of Collector.



31
32
33
34
35
36
37
# 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

Instance Attribute Details

#after_gc_callbacksObject (readonly)

Returns the value of attribute after_gc_callbacks.



29
30
31
# File 'lib/garbageman/collector.rb', line 29

def after_gc_callbacks
  @after_gc_callbacks
end

#before_gc_callbacksObject (readonly)

Returns the value of attribute before_gc_callbacks.



29
30
31
# File 'lib/garbageman/collector.rb', line 29

def before_gc_callbacks
  @before_gc_callbacks
end

#fiber_pollObject (readonly)

Returns the value of attribute fiber_poll.



29
30
31
# File 'lib/garbageman/collector.rb', line 29

def fiber_poll
  @fiber_poll
end

#last_gc_finished_atObject (readonly)

Returns the value of attribute last_gc_finished_at.



29
30
31
# File 'lib/garbageman/collector.rb', line 29

def last_gc_finished_at
  @last_gc_finished_at
end

#request_countObject

Returns the value of attribute request_count.



28
29
30
# File 'lib/garbageman/collector.rb', line 28

def request_count
  @request_count
end

#selected_to_collect_atObject (readonly)

Returns the value of attribute selected_to_collect_at.



29
30
31
# File 'lib/garbageman/collector.rb', line 29

def selected_to_collect_at
  @selected_to_collect_at
end

#show_gc_timesObject

Returns the value of attribute show_gc_times.



28
29
30
# File 'lib/garbageman/collector.rb', line 28

def show_gc_times
  @show_gc_times
end

#will_collectObject

Returns the value of attribute will_collect.



28
29
30
# File 'lib/garbageman/collector.rb', line 28

def will_collect
  @will_collect
end

#will_select_next_serverObject

Returns the value of attribute will_select_next_server.



28
29
30
# File 'lib/garbageman/collector.rb', line 28

def will_select_next_server
  @will_select_next_server
end

Instance Method Details

#collectObject



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# 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?
    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
  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_yamlObject



133
134
135
136
137
# File 'lib/garbageman/collector.rb', line 133

def create_gc_yaml
  return unless server_index
  return if File.exists?(Config.gc_yaml_file) && ! current_server?
  write_gc_yaml server_index, SELECTED
end

#debug(msg) ⇒ Object



141
142
143
# File 'lib/garbageman/collector.rb', line 141

def debug(msg)
  logger.debug msg
end

#healthy?Boolean

Returns:

  • (Boolean)


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 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) ⇒ Object



145
146
147
# File 'lib/garbageman/collector.rb', line 145

def info(msg)
  logger.info msg
end

#loggerObject



139
# File 'lib/garbageman/collector.rb', line 139

def logger; GarbageMan.logger; end

#process_resident_memory_size_in_kbObject



121
122
123
124
125
126
127
128
129
130
131
# File 'lib/garbageman/collector.rb', line 121

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) ⇒ Object

for use with rack-fiber_pool



40
41
42
# File 'lib/garbageman/collector.rb', line 40

def register_fiber_pool(pool)
  @fiber_poll = pool
end

#select_next_serverObject



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/garbageman/collector.rb', line 153

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) ⇒ Object



149
150
151
# File 'lib/garbageman/collector.rb', line 149

def warn(msg)
  logger.warn msg
end