rack-mini-profiler 2.3.4 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'digest'
4
+ require 'securerandom'
4
5
 
5
6
  module Rack
6
7
  class MiniProfiler
@@ -133,85 +134,127 @@ unviewed_ids: #{get_unviewed_ids(user)}
133
134
  )
134
135
  end
135
136
 
136
- def push_snapshot(page_struct, config)
137
- zset_key = snapshot_zset_key()
138
- hash_key = snapshot_hash_key()
137
+ def push_snapshot(page_struct, group_name, config)
138
+ group_zset_key = group_snapshot_zset_key(group_name)
139
+ group_hash_key = group_snapshot_hash_key(group_name)
140
+ overview_zset_key = snapshot_overview_zset_key
139
141
 
140
142
  id = page_struct[:id]
141
- score = page_struct.duration_ms
142
- limit = config.snapshots_limit
143
+ score = page_struct.duration_ms.to_s
144
+
145
+ per_group_limit = config.max_snapshots_per_group.to_s
146
+ groups_limit = config.max_snapshot_groups.to_s
143
147
  bytes = Marshal.dump(page_struct)
144
148
 
145
149
  lua = <<~LUA
146
- local zset_key = KEYS[1]
147
- local hash_key = KEYS[2]
150
+ local group_zset_key = KEYS[1]
151
+ local group_hash_key = KEYS[2]
152
+ local overview_zset_key = KEYS[3]
153
+
148
154
  local id = ARGV[1]
149
155
  local score = tonumber(ARGV[2])
150
- local bytes = ARGV[3]
151
- local limit = tonumber(ARGV[4])
152
- redis.call("ZADD", zset_key, score, id)
153
- redis.call("HSET", hash_key, id, bytes)
154
- if redis.call("ZCARD", zset_key) > limit then
155
- local lowest_snapshot_id = redis.call("ZRANGE", zset_key, 0, 0)[1]
156
- redis.call("ZREM", zset_key, lowest_snapshot_id)
157
- redis.call("HDEL", hash_key, lowest_snapshot_id)
156
+ local group_name = ARGV[3]
157
+ local per_group_limit = tonumber(ARGV[4])
158
+ local groups_limit = tonumber(ARGV[5])
159
+ local prefix = ARGV[6]
160
+ local bytes = ARGV[7]
161
+
162
+ local current_group_score = redis.call("ZSCORE", overview_zset_key, group_name)
163
+ if current_group_score == false or score > tonumber(current_group_score) then
164
+ redis.call("ZADD", overview_zset_key, score, group_name)
165
+ end
166
+
167
+ local do_save = true
168
+ local overview_size = redis.call("ZCARD", overview_zset_key)
169
+ while (overview_size > groups_limit) do
170
+ local lowest_group = redis.call("ZRANGE", overview_zset_key, 0, 0)[1]
171
+ redis.call("ZREM", overview_zset_key, lowest_group)
172
+ if lowest_group == group_name then
173
+ do_save = false
174
+ else
175
+ local lowest_group_zset_key = prefix .. "-mp-group-snapshot-zset-key-" .. lowest_group
176
+ local lowest_group_hash_key = prefix .. "-mp-group-snapshot-hash-key-" .. lowest_group
177
+ redis.call("DEL", lowest_group_zset_key, lowest_group_hash_key)
178
+ end
179
+ overview_size = overview_size - 1
180
+ end
181
+
182
+ if do_save then
183
+ redis.call("ZADD", group_zset_key, score, id)
184
+ local group_size = redis.call("ZCARD", group_zset_key)
185
+ while (group_size > per_group_limit) do
186
+ local lowest_snapshot_id = redis.call("ZRANGE", group_zset_key, 0, 0)[1]
187
+ redis.call("ZREM", group_zset_key, lowest_snapshot_id)
188
+ if lowest_snapshot_id == id then
189
+ do_save = false
190
+ else
191
+ redis.call("HDEL", group_hash_key, lowest_snapshot_id)
192
+ end
193
+ group_size = group_size - 1
194
+ end
195
+ if do_save then
196
+ redis.call("HSET", group_hash_key, id, bytes)
197
+ end
158
198
  end
159
199
  LUA
160
200
  redis.eval(
161
201
  lua,
162
- keys: [zset_key, hash_key],
163
- argv: [id, score, bytes, limit]
202
+ keys: [group_zset_key, group_hash_key, overview_zset_key],
203
+ argv: [id, score, group_name, per_group_limit, groups_limit, @prefix, bytes]
164
204
  )
165
205
  end
166
206
 
167
- def fetch_snapshots(batch_size: 200, &blk)
168
- zset_key = snapshot_zset_key()
169
- hash_key = snapshot_hash_key()
170
- iteration = 0
171
- corrupt_snapshots = []
172
- while true
173
- ids = redis.zrange(
174
- zset_key,
175
- batch_size * iteration,
176
- batch_size * iteration + batch_size - 1
177
- )
178
- break if ids.size == 0
179
- batch = redis.mapped_hmget(hash_key, *ids).to_a
180
- batch.map! do |id, bytes|
181
- begin
182
- # rubocop:disable Security/MarshalLoad
183
- Marshal.load(bytes)
184
- # rubocop:enable Security/MarshalLoad
185
- rescue
186
- corrupt_snapshots << id
187
- nil
188
- end
207
+ def fetch_snapshots_overview
208
+ overview_zset_key = snapshot_overview_zset_key
209
+ groups = redis
210
+ .zrange(overview_zset_key, 0, -1, withscores: true)
211
+ .map { |(name, worst_score)| [name, { worst_score: worst_score }] }
212
+
213
+ prefixed_group_names = groups.map { |(group_name, _)| group_snapshot_zset_key(group_name) }
214
+ metadata = redis.eval(<<~LUA, keys: prefixed_group_names)
215
+ local metadata = {}
216
+ for i, k in ipairs(KEYS) do
217
+ local best = redis.call("ZRANGE", k, 0, 0, "WITHSCORES")[2]
218
+ local count = redis.call("ZCARD", k)
219
+ metadata[i] = {best, count}
189
220
  end
190
- batch.compact!
191
- blk.call(batch) if batch.size != 0
192
- break if ids.size < batch_size
193
- iteration += 1
221
+ return metadata
222
+ LUA
223
+ groups.each.with_index do |(_, hash), index|
224
+ best, count = metadata[index]
225
+ hash[:best_score] = best.to_f
226
+ hash[:snapshots_count] = count.to_i
227
+ end
228
+ groups.to_h
229
+ end
230
+
231
+ def fetch_snapshots_group(group_name)
232
+ group_hash_key = group_snapshot_hash_key(group_name)
233
+ snapshots = []
234
+ corrupt_snapshots = []
235
+ redis.hgetall(group_hash_key).each do |id, bytes|
236
+ # rubocop:disable Security/MarshalLoad
237
+ snapshots << Marshal.load(bytes)
238
+ # rubocop:enable Security/MarshalLoad
239
+ rescue
240
+ corrupt_snapshots << id
194
241
  end
195
242
  if corrupt_snapshots.size > 0
196
- redis.pipelined do |pipeline|
197
- pipeline.zrem(zset_key, corrupt_snapshots)
198
- pipeline.hdel(hash_key, corrupt_snapshots)
199
- end
243
+ cleanup_corrupt_snapshots(corrupt_snapshots, group_name)
200
244
  end
245
+ snapshots
201
246
  end
202
247
 
203
- def load_snapshot(id)
204
- hash_key = snapshot_hash_key()
205
- bytes = redis.hget(hash_key, id)
248
+ def load_snapshot(id, group_name)
249
+ group_hash_key = group_snapshot_hash_key(group_name)
250
+ bytes = redis.hget(group_hash_key, id)
251
+ return if !bytes
206
252
  begin
207
253
  # rubocop:disable Security/MarshalLoad
208
254
  Marshal.load(bytes)
209
255
  # rubocop:enable Security/MarshalLoad
210
256
  rescue
211
- redis.pipelined do |pipeline|
212
- pipeline.zrem(snapshot_zset_key(), id)
213
- pipeline.hdel(hash_key, id)
214
- end
257
+ cleanup_corrupt_snapshots([id], group_name)
215
258
  nil
216
259
  end
217
260
  end
@@ -237,12 +280,20 @@ unviewed_ids: #{get_unviewed_ids(user)}
237
280
  @snapshot_counter_key ||= "#{@prefix}-mini-profiler-snapshots-counter"
238
281
  end
239
282
 
240
- def snapshot_zset_key
241
- @snapshot_zset_key ||= "#{@prefix}-mini-profiler-snapshots-zset"
283
+ def group_snapshot_zset_key(group_name)
284
+ # if you change this key, remember to change it in the LUA script in
285
+ # the push_snapshot method as well
286
+ "#{@prefix}-mp-group-snapshot-zset-key-#{group_name}"
242
287
  end
243
288
 
244
- def snapshot_hash_key
245
- @snapshot_hash_key ||= "#{@prefix}-mini-profiler-snapshots-hash"
289
+ def group_snapshot_hash_key(group_name)
290
+ # if you change this key, remember to change it in the LUA script in
291
+ # the push_snapshot method as well
292
+ "#{@prefix}-mp-group-snapshot-hash-key-#{group_name}"
293
+ end
294
+
295
+ def snapshot_overview_zset_key
296
+ "#{@prefix}-mp-overviewgroup-snapshot-zset-key"
246
297
  end
247
298
 
248
299
  def cached_redis_eval(script, script_sha, reraise: true, argv: [], keys: [])
@@ -257,12 +308,44 @@ unviewed_ids: #{get_unviewed_ids(user)}
257
308
  end
258
309
  end
259
310
 
311
+ def cleanup_corrupt_snapshots(corrupt_snapshots_ids, group_name)
312
+ group_hash_key = group_snapshot_hash_key(group_name)
313
+ group_zset_key = group_snapshot_zset_key(group_name)
314
+ overview_zset_key = snapshot_overview_zset_key
315
+ lua = <<~LUA
316
+ local group_hash_key = KEYS[1]
317
+ local group_zset_key = KEYS[2]
318
+ local overview_zset_key = KEYS[3]
319
+ local group_name = ARGV[1]
320
+ for i, k in ipairs(ARGV) do
321
+ if k ~= group_name then
322
+ redis.call("HDEL", group_hash_key, k)
323
+ redis.call("ZREM", group_zset_key, k)
324
+ end
325
+ end
326
+ if redis.call("ZCARD", group_zset_key) == 0 then
327
+ redis.call("ZREM", overview_zset_key, group_name)
328
+ redis.call("DEL", group_hash_key, group_zset_key)
329
+ else
330
+ local worst_score = tonumber(redis.call("ZRANGE", group_zset_key, -1, -1, "WITHSCORES")[2])
331
+ redis.call("ZADD", overview_zset_key, worst_score, group_name)
332
+ end
333
+ LUA
334
+ redis.eval(
335
+ lua,
336
+ keys: [group_hash_key, group_zset_key, overview_zset_key],
337
+ argv: [group_name, *corrupt_snapshots_ids]
338
+ )
339
+ end
340
+
260
341
  # only used in tests
261
342
  def wipe_snapshots_data
343
+ keys = redis.keys(group_snapshot_hash_key('*'))
344
+ keys += redis.keys(group_snapshot_zset_key('*'))
262
345
  redis.del(
263
- snapshot_counter_key(),
264
- snapshot_zset_key(),
265
- snapshot_hash_key(),
346
+ keys,
347
+ snapshot_overview_zset_key,
348
+ snapshot_counter_key
266
349
  )
267
350
  end
268
351
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mini_profiler/storage/abstract_store'
4
+ require 'mini_profiler/storage/memcache_store'
5
+ require 'mini_profiler/storage/memory_store'
6
+ require 'mini_profiler/storage/redis_store'
7
+ require 'mini_profiler/storage/file_store'
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module Rack
4
6
  class MiniProfiler
5
7
  module TimerStruct
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'erb'
4
+
3
5
  module Rack
4
6
  class MiniProfiler
5
7
 
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mini_profiler/timer_struct/base'
4
+ require 'mini_profiler/timer_struct/page'
5
+ require 'mini_profiler/timer_struct/sql'
6
+ require 'mini_profiler/timer_struct/custom'
7
+ require 'mini_profiler/timer_struct/client'
8
+ require 'mini_profiler/timer_struct/request'
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Rack
4
4
  class MiniProfiler
5
- VERSION = '2.3.4'
5
+ VERSION = '3.1.0'
6
6
  SOURCE_CODE_URI = 'https://github.com/MiniProfiler/rack-mini-profiler'
7
7
  end
8
8
  end