Commit db3fc55258dfaf5b13982b2395865d599573a473

Authored by Marcin Ciunelis
1 parent 7dd78504
Exists in master and in 1 other branch production

Problem notices cache is more space effective

app/helpers/application_helper.rb
... ... @@ -47,8 +47,8 @@ module ApplicationHelper
47 47 end
48 48  
49 49 def tally(collection)
50   - collection.inject({}) do |tallies, value|
51   - tallies[value] = (tallies[value] || 0) + 1
  50 + collection.values.inject({}) do |tallies, tally|
  51 + tallies[tally['value']] = tally['count']
52 52 tallies
53 53 end
54 54 end
... ...
app/models/problem.rb
... ... @@ -18,9 +18,9 @@ class Problem
18 18 field :environment
19 19 field :klass
20 20 field :where
21   - field :user_agents, :type => Array, :default => []
22   - field :messages, :type => Array, :default => []
23   - field :hosts, :type => Array, :default => []
  21 + field :user_agents, :type => Hash, :default => {}
  22 + field :messages, :type => Hash, :default => {}
  23 + field :hosts, :type => Hash, :default => {}
24 24 field :comments_count, :type => Integer, :default => 0
25 25  
26 26 index :app_id
... ... @@ -128,19 +128,45 @@ class Problem
128 128 :environment => notice.environment_name,
129 129 :klass => notice.klass,
130 130 :where => notice.where,
131   - :messages => messages.push(notice.message),
132   - :hosts => hosts.push(notice.host),
133   - :user_agents => user_agents.push(notice.user_agent_string)
  131 + :messages => attribute_count_increase(:messages, notice.message),
  132 + :hosts => attribute_count_increase(:hosts, notice.host),
  133 + :user_agents => attribute_count_increase(:user_agents, notice.user_agent_string)
134 134 ) if notice
135 135 update_attributes!(attrs)
136 136 end
137 137  
138 138 def remove_cached_notice_attribures(notice)
139   - messages.delete_at(messages.index(notice.message))
140   - hosts.delete_at(hosts.index(notice.host))
141   - user_agents.delete_at(user_agents.index(notice.user_agent_string))
142   - save!
  139 + update_attributes!(
  140 + :messages => attribute_count_descrease(:messages, notice.message),
  141 + :hosts => attribute_count_descrease(:hosts, notice.host),
  142 + :user_agents => attribute_count_descrease(:user_agents, notice.user_agent_string)
  143 + )
143 144 end
144 145  
  146 + private
  147 + def attribute_count_increase(name, value)
  148 + counter, index = send(name), attribute_index(value)
  149 + if counter[index].nil?
  150 + counter[index] = {'value' => value, 'count' => 1}
  151 + else
  152 + counter[index]['count'] += 1
  153 + end
  154 + counter
  155 + end
  156 +
  157 + def attribute_count_descrease(name, value)
  158 + counter, index = send(name), attribute_index(value)
  159 + if counter[index]['count'] > 1
  160 + counter[index]['count'] -= 1
  161 + else
  162 + counter.delete(index)
  163 + end
  164 + counter
  165 + end
  166 +
  167 + def attribute_index(value)
  168 + Digest::MD5.hexdigest(value.to_s)
  169 + end
  170 +
145 171 end
146 172  
... ...
db/migrate/20111102173347_cache_problem_statistics_fix.rb 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +class CacheProblemStatisticsFix < Mongoid::Migration
  2 + def self.up
  3 + Problem.all.each do |problem|
  4 + messages = {}
  5 + hosts = {}
  6 + user_agents = {}
  7 + problem.notices.each do |notice|
  8 + messages = count_attribute(messages, notice.message)
  9 + hosts = count_attribute(hosts, notice.host)
  10 + user_agents = count_attribute(user_agents, notice.user_agent_string)
  11 + end
  12 + problem.update_attributes(:messages => messages, :hosts => hosts, :user_agents => user_agents)
  13 + end
  14 + end
  15 +
  16 + def self.down
  17 + Problem.all.each do |problem|
  18 + problem.update_attributes(:messages => {}, :hosts => {}, :user_agents => {})
  19 + end
  20 + end
  21 +
  22 + private
  23 + def self.count_attribute(counter, value)
  24 + index = Digest::MD5.hexdigest(value.to_s)
  25 + if counter[index].nil?
  26 + counter[index] = {'value' => value, 'count' => 1}
  27 + else
  28 + counter[index]['count'] += 1
  29 + end
  30 + counter
  31 + end
  32 +
  33 +end
0 34 \ No newline at end of file
... ...
spec/models/problem_spec.rb
... ... @@ -205,14 +205,14 @@ describe Problem do
205 205 @err = Factory(:err, :problem => @problem)
206 206 end
207 207  
208   - it "#messages returns [] by default" do
209   - @problem.messages.should == []
  208 + it "#messages should be empty by default" do
  209 + @problem.messages.should == {}
210 210 end
211 211  
212 212 it "adding a notice adds a string to #messages" do
213 213 lambda {
214 214 Factory(:notice, :err => @err, :message => 'ERR 1')
215   - }.should change(@problem, :messages).from([]).to(['ERR 1'])
  215 + }.should change(@problem, :messages).from({}).to({Digest::MD5.hexdigest('ERR 1') => {'value' => 'ERR 1', 'count' => 1}})
216 216 end
217 217  
218 218 it "removing a notice removes string from #messages" do
... ... @@ -220,7 +220,7 @@ describe Problem do
220 220 lambda {
221 221 @err.notices.first.destroy
222 222 @problem.reload
223   - }.should change(@problem, :messages).from(['ERR 1']).to([])
  223 + }.should change(@problem, :messages).from({Digest::MD5.hexdigest('ERR 1') => {'value' => 'ERR 1', 'count' => 1}}).to({})
224 224 end
225 225 end
226 226  
... ... @@ -231,14 +231,14 @@ describe Problem do
231 231 @err = Factory(:err, :problem => @problem)
232 232 end
233 233  
234   - it "#hosts returns [] by default" do
235   - @problem.hosts.should == []
  234 + it "#hosts should be empty by default" do
  235 + @problem.hosts.should == {}
236 236 end
237 237  
238 238 it "adding a notice adds a string to #hosts" do
239 239 lambda {
240 240 Factory(:notice, :err => @err, :request => {'url' => "http://example.com/resource/12"})
241   - }.should change(@problem, :hosts).from([]).to(['example.com'])
  241 + }.should change(@problem, :hosts).from({}).to({Digest::MD5.hexdigest('example.com') => {'value' => 'example.com', 'count' => 1}})
242 242 end
243 243  
244 244 it "removing a notice removes string from #hosts" do
... ... @@ -246,7 +246,7 @@ describe Problem do
246 246 lambda {
247 247 @err.notices.first.destroy
248 248 @problem.reload
249   - }.should change(@problem, :hosts).from(['example.com']).to([])
  249 + }.should change(@problem, :hosts).from({Digest::MD5.hexdigest('example.com') => {'value' => 'example.com', 'count' => 1}}).to({})
250 250 end
251 251 end
252 252  
... ... @@ -257,14 +257,14 @@ describe Problem do
257 257 @err = Factory(:err, :problem => @problem)
258 258 end
259 259  
260   - it "#user_agents returns [] by default" do
261   - @problem.user_agents.should == []
  260 + it "#user_agents should be empty by default" do
  261 + @problem.user_agents.should == {}
262 262 end
263 263  
264 264 it "adding a notice adds a string to #user_agents" do
265 265 lambda {
266 266 Factory(:notice, :err => @err, :request => {'cgi-data' => {'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16'}})
267   - }.should change(@problem, :user_agents).from([]).to(['Chrome 10.0.648.204'])
  267 + }.should change(@problem, :user_agents).from({}).to({Digest::MD5.hexdigest('Chrome 10.0.648.204') => {'value' => 'Chrome 10.0.648.204', 'count' => 1}})
268 268 end
269 269  
270 270 it "removing a notice removes string from #user_agents" do
... ... @@ -272,7 +272,7 @@ describe Problem do
272 272 lambda {
273 273 @err.notices.first.destroy
274 274 @problem.reload
275   - }.should change(@problem, :user_agents).from(['Chrome 10.0.648.204']).to([])
  275 + }.should change(@problem, :user_agents).from({Digest::MD5.hexdigest('Chrome 10.0.648.204') => {'value' => 'Chrome 10.0.648.204', 'count' => 1}}).to({})
276 276 end
277 277 end
278 278  
... ...