Class: NewRelic::Agent::StatsEngine::MetricStats::SynchronizedHash

Inherits:
Hash
  • Object
show all
Defined in:
lib/new_relic/agent/stats_engine/metric_stats.rb

Overview

A simple mutex-synchronized hash to make sure our statistics are internally consistent even in truly-threaded rubies like JRuby

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSynchronizedHash

Returns a new instance of SynchronizedHash.



13
14
15
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 13

def initialize
  @lock = Mutex.new
end

Instance Attribute Details

#lockObject (readonly)

Returns the value of attribute lock.



11
12
13
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 11

def lock
  @lock
end

Instance Method Details

#[]=(*args) ⇒ Object



24
25
26
27
28
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 24

def []=(*args)
  @lock.synchronize { super }
rescue => e
  log_error(e)
end

#clear(*args) ⇒ Object



30
31
32
33
34
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 30

def clear(*args)
  @lock.synchronize { super }
rescue => e
  log_error(e)
end

#delete(*args) ⇒ Object



36
37
38
39
40
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 36

def delete(*args)
  @lock.synchronize { super }
rescue => e
  log_error(e)
end

#delete_if(*args) ⇒ Object



42
43
44
45
46
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 42

def delete_if(*args)
  @lock.synchronize { super }
rescue => e
  log_error(e)
end

#initialize_copy(old) ⇒ Object



17
18
19
20
21
22
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 17

def initialize_copy(old)
  super
  old.each do |key, value|
    self.store(key, value.dup)
  end
end

#log_error(e) ⇒ Object



52
53
54
55
56
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 52

def log_error(e)
  backtraces = Thread.list.map { |t| log_thread(t) }.join("\n\n")
  NewRelic::Control.instance.log.warn(
    "SynchronizedHash failure: #{e.class.name}: #{e.message}\n#{backtraces}")
end

#log_thread(t) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 58

def log_thread(t)
  # Ruby 1.8 doesn't expose backtrace properly, so make sure it's there
  if t.nil? || !t.respond_to?(:backtrace) || t.backtrace.nil?
    return "#{t}\n\tNo backtrace for thread" 
  end

  backtrace = t.backtrace.map { |b| "\t#{b}" }.join("\n")
  "\t#{t}\n#{backtrace}"

rescue Exception => e
  # JRuby 1.7.0 has a nasty habit of raising a
  # java.lang.NullPointerException when we iterate through threads
  # asking for backtraces.  This line allows us to swallow java
  # exceptions without referencing their classes (since they don't
  # exist in MRI).  It also prevents us from swallowing signals or
  # other nasty things that can happen when you rescue Exception.
  NewRelic::Control.instance.log.warn(
    "Error collecting thread backtraces: #{e.class.name}: #{e.message}")
  NewRelic::Control.instance.log.debug( e.backtrace.join("\n") )

  raise e if e.class.ancestors.include? Exception
end

#resetObject



48
49
50
# File 'lib/new_relic/agent/stats_engine/metric_stats.rb', line 48

def reset
  values.each { |s| s.reset }
end