pseudo_cleaner 0.0.43 → 0.0.44

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  require "redis"
2
- require "redis-namespace"
2
+ # require "redis-namespace"
3
3
  require "pseudo_cleaner/master_cleaner"
4
4
  require "pseudo_cleaner/configuration"
5
5
  require "pseudo_cleaner/logger"
@@ -36,27 +36,215 @@ module PseudoCleaner
36
36
  # I'm not a huge fan of sleeps. In the non-rails world, I used to be able to do a sleep(0) to signal the system to
37
37
  # check if somebody else needed to do some work. Testing with Rails, I find I have to actually sleep, so I do a
38
38
  # very short time like 0.01.
39
+
39
40
  class RedisCleaner
40
- FLUSH_COMMANDS =
41
+ # copied from Redis::Namespace
42
+ COMMANDS = {
43
+ "append" => [:first],
44
+ "auth" => [],
45
+ "bgrewriteaof" => [],
46
+ "bgsave" => [],
47
+ "bitcount" => [:first],
48
+ "bitop" => [:exclude_first],
49
+ "blpop" => [:exclude_last, :first],
50
+ "brpop" => [:exclude_last, :first],
51
+ "brpoplpush" => [:exclude_last],
52
+ "config" => [],
53
+ "dbsize" => [],
54
+ "debug" => [:exclude_first],
55
+ "decr" => [:first],
56
+ "decrby" => [:first],
57
+ "del" => [:all],
58
+ "discard" => [],
59
+ "disconnect!" => [],
60
+ "dump" => [:first],
61
+ "echo" => [],
62
+ "exists" => [:first],
63
+ "expire" => [:first],
64
+ "expireat" => [:first],
65
+ "eval" => [:eval_style],
66
+ "evalsha" => [:eval_style],
67
+ "exec" => [],
68
+ "flushall" => [],
69
+ "flushdb" => [],
70
+ "get" => [:first],
71
+ "getbit" => [:first],
72
+ "getrange" => [:first],
73
+ "getset" => [:first],
74
+ "hset" => [:first],
75
+ "hsetnx" => [:first],
76
+ "hget" => [:first],
77
+ "hincrby" => [:first],
78
+ "hincrbyfloat" => [:first],
79
+ "hmget" => [:first],
80
+ "hmset" => [:first],
81
+ "hdel" => [:first],
82
+ "hexists" => [:first],
83
+ "hlen" => [:first],
84
+ "hkeys" => [:first],
85
+ "hscan" => [:first],
86
+ "hscan_each" => [:first],
87
+ "hvals" => [:first],
88
+ "hgetall" => [:first],
89
+ "incr" => [:first],
90
+ "incrby" => [:first],
91
+ "incrbyfloat" => [:first],
92
+ "info" => [],
93
+ "keys" => [:first, :all],
94
+ "lastsave" => [],
95
+ "lindex" => [:first],
96
+ "linsert" => [:first],
97
+ "llen" => [:first],
98
+ "lpop" => [:first],
99
+ "lpush" => [:first],
100
+ "lpushx" => [:first],
101
+ "lrange" => [:first],
102
+ "lrem" => [:first],
103
+ "lset" => [:first],
104
+ "ltrim" => [:first],
105
+ "mapped_hmset" => [:first],
106
+ "mapped_hmget" => [:first],
107
+ "mapped_mget" => [:all, :all],
108
+ "mapped_mset" => [:all],
109
+ "mapped_msetnx" => [:all],
110
+ "mget" => [:all],
111
+ "monitor" => [:monitor],
112
+ "move" => [:first],
113
+ "multi" => [],
114
+ "mset" => [:alternate],
115
+ "msetnx" => [:alternate],
116
+ "object" => [:exclude_first],
117
+ "persist" => [:first],
118
+ "pexpire" => [:first],
119
+ "pexpireat" => [:first],
120
+ "pfadd" => [:first],
121
+ "pfcount" => [:all],
122
+ "pfmerge" => [:all],
123
+ "ping" => [],
124
+ "psetex" => [:first],
125
+ "psubscribe" => [:all],
126
+ "pttl" => [:first],
127
+ "publish" => [:first],
128
+ "punsubscribe" => [:all],
129
+ "quit" => [],
130
+ "randomkey" => [],
131
+ "rename" => [:all],
132
+ "renamenx" => [:all],
133
+ "restore" => [:first],
134
+ "rpop" => [:first],
135
+ "rpoplpush" => [:all],
136
+ "rpush" => [:first],
137
+ "rpushx" => [:first],
138
+ "sadd" => [:first],
139
+ "save" => [],
140
+ "scard" => [:first],
141
+ "scan" => [:scan_style, :second],
142
+ "scan_each" => [:scan_style, :all],
143
+ "script" => [],
144
+ "sdiff" => [:all],
145
+ "sdiffstore" => [:all],
146
+ "select" => [],
147
+ "set" => [:first],
148
+ "setbit" => [:first],
149
+ "setex" => [:first],
150
+ "setnx" => [:first],
151
+ "setrange" => [:first],
152
+ "shutdown" => [],
153
+ "sinter" => [:all],
154
+ "sinterstore" => [:all],
155
+ "sismember" => [:first],
156
+ "slaveof" => [],
157
+ "smembers" => [:first],
158
+ "smove" => [:exclude_last],
159
+ "sort" => [:sort],
160
+ "spop" => [:first],
161
+ "srandmember" => [:first],
162
+ "srem" => [:first],
163
+ "sscan" => [:first],
164
+ "sscan_each" => [:first],
165
+ "strlen" => [:first],
166
+ "subscribe" => [:all],
167
+ "sunion" => [:all],
168
+ "sunionstore" => [:all],
169
+ "ttl" => [:first],
170
+ "type" => [:first],
171
+ "unsubscribe" => [:all],
172
+ "unwatch" => [:all],
173
+ "watch" => [:all],
174
+ "zadd" => [:first],
175
+ "zcard" => [:first],
176
+ "zcount" => [:first],
177
+ "zincrby" => [:first],
178
+ "zinterstore" => [:exclude_options],
179
+ "zrange" => [:first],
180
+ "zrangebylex" => [:first],
181
+ "zrangebyscore" => [:first],
182
+ "zrank" => [:first],
183
+ "zrem" => [:first],
184
+ "zremrangebyrank" => [:first],
185
+ "zremrangebyscore" => [:first],
186
+ "zremrangebylex" => [:first],
187
+ "zrevrange" => [:first],
188
+ "zrevrangebyscore" => [:first],
189
+ "zrevrangebylex" => [:first],
190
+ "zrevrank" => [:first],
191
+ "zscan" => [:first],
192
+ "zscan_each" => [:first],
193
+ "zscore" => [:first],
194
+ "zunionstore" => [:exclude_options],
195
+ "[]" => [:first],
196
+ "[]=" => [:first]
197
+ }
198
+
199
+ FLUSH_COMMANDS =
41
200
  [
42
201
  "flushall",
43
202
  "flushdb"
44
203
  ]
45
- SET_COMMANDS =
204
+ NUM_CHANGED_COMMANDS =
46
205
  [
47
206
  "sadd",
48
207
  "zadd",
49
208
  "srem",
50
209
  "zrem",
51
210
  "zremrangebyrank",
52
- "zremrangebyscore"
211
+ "zremrangebyscore",
212
+ "zremrangebylex",
213
+ "hsetnx",
214
+ "hdel",
215
+ "linsert",
216
+ "lpushx",
217
+ "rpushx",
218
+ "lrem",
219
+ "mapped_msetnx",
220
+ "msetnx",
221
+ "move",
222
+ "persist",
223
+ "renamenx",
224
+ "sdiffstore",
225
+ "setnx",
226
+ "sinterstore",
227
+ "smove",
228
+ "sunionstore",
229
+ "zinterstore",
230
+ "zunionstore",
53
231
  ]
54
- WRITE_COMMANDS =
232
+ NIL_FAIL_COMMANDS =
233
+ [
234
+ "lpop",
235
+ "rpop",
236
+ "rpoplpush",
237
+ "spop",
238
+ ]
239
+ POP_COMMANDS =
55
240
  [
56
- "append",
57
- "bitop",
58
241
  "blpop",
59
242
  "brpop",
243
+ ]
244
+ WRITE_COMMANDS =
245
+ [
246
+ "append",
247
+ "bitop",
60
248
  "brpoplpush",
61
249
  "decr",
62
250
  "decrby",
@@ -65,57 +253,35 @@ module PseudoCleaner
65
253
  "expireat",
66
254
  "getset",
67
255
  "hset",
68
- "hsetnx",
69
256
  "hincrby",
70
257
  "hincrbyfloat",
71
258
  "hmset",
72
- "hdel",
73
259
  "incr",
74
260
  "incrby",
75
261
  "incrbyfloat",
76
- "linsert",
77
- "lpop",
78
262
  "lpush",
79
- "lpushx",
80
- "lrem",
81
263
  "lset",
82
264
  "ltrim",
83
265
  "mapped_hmset",
84
266
  "mapped_mset",
85
- "mapped_msetnx",
86
- "move",
87
267
  "mset",
88
- "msetnx",
89
- "persist",
90
268
  "pexpire",
91
269
  "pexpireat",
92
270
  "psetex",
93
271
  "rename",
94
- "renamenx",
95
272
  "restore",
96
- "rpop",
97
- "rpoplpush",
98
273
  "rpush",
99
- "rpushx",
100
- "sdiffstore",
101
274
  "set",
102
275
  "setbit",
103
276
  "setex",
104
- "setnx",
105
277
  "setrange",
106
- "sinterstore",
107
- "smove",
108
278
  "sort",
109
- "spop",
110
- "sunionstore",
111
279
  "zincrby",
112
- "zinterstore",
113
280
  "[]=",
114
281
  ]
115
- READ_COMMANDS =
282
+ READ_COMMANDS =
116
283
  [
117
284
  "bitcount",
118
- "bitop",
119
285
  "dump",
120
286
  "exists",
121
287
  "get",
@@ -136,7 +302,6 @@ module PseudoCleaner
136
302
  "mapped_hmget",
137
303
  "mapped_mget",
138
304
  "mget",
139
- "persist",
140
305
  "scard",
141
306
  "scan",
142
307
  "scan_each",
@@ -151,10 +316,13 @@ module PseudoCleaner
151
316
  "type",
152
317
  "zcard",
153
318
  "zcount",
319
+ "zlexcount",
154
320
  "zrange",
321
+ "zrangebylex",
155
322
  "zrangebyscore",
156
323
  "zrank",
157
324
  "zrevrange",
325
+ "zrevrangebylex",
158
326
  "zrevrangebyscore",
159
327
  "zrevrank",
160
328
  "zscan",
@@ -162,20 +330,35 @@ module PseudoCleaner
162
330
  "zscore",
163
331
  "[]",
164
332
  ]
165
-
166
- attr_reader :initial_keys
333
+ ALL_COMMANDS =
334
+ READ_COMMANDS +
335
+ FLUSH_COMMANDS +
336
+ NUM_CHANGED_COMMANDS +
337
+ NIL_FAIL_COMMANDS +
338
+ POP_COMMANDS +
339
+ WRITE_COMMANDS
340
+
341
+ OVERRIDE_COMMANDS =
342
+ {
343
+ "sdiffstore" => [:first],
344
+ "sinterstore" => [:first],
345
+ "zinterstore" => [:first],
346
+ "sunionstore" => [:first],
347
+ "zunionstore" => [:first],
348
+ }
167
349
  attr_accessor :options
168
350
 
169
351
  def initialize(start_method, end_method, table, options)
170
- @initial_keys = SortedSet.new
171
- @monitor_thread = nil
172
- @redis_name = nil
173
- @suite_altered_keys = SortedSet.new
174
- @updated_keys = SortedSet.new
175
- @multi_commands = []
176
- @in_multi = false
177
- @in_redis_cleanup = false
178
- @suspend_tracking = false
352
+ @redis = table
353
+ @redis_name = nil
354
+
355
+ clear_set :@initial_keys
356
+ clear_set :@suite_altered_keys
357
+ clear_set :@updated_keys
358
+ clear_list_array :@multi_commands
359
+ set_value_bool :@in_multi, false
360
+ set_value_bool :@in_redis_cleanup, false
361
+ set_value_bool :@suspend_tracking, false
179
362
 
180
363
  unless PseudoCleaner::MasterCleaner::VALID_START_METHODS.include?(start_method)
181
364
  raise "You must specify a valid start function from: #{PseudoCleaner::MasterCleaner::VALID_START_METHODS}."
@@ -190,8 +373,6 @@ module PseudoCleaner
190
373
  @options[:table_end_method] ||= end_method
191
374
  @options[:output_diagnostics] ||= PseudoCleaner::Configuration.current_instance.output_diagnostics ||
192
375
  PseudoCleaner::Configuration.current_instance.post_transaction_analysis
193
-
194
- @redis = table
195
376
  end
196
377
 
197
378
  # Ruby defines a now deprecated type method so we need to override it here
@@ -207,25 +388,30 @@ module PseudoCleaner
207
388
  super or respond_to_missing?(command, include_private)
208
389
  end
209
390
 
210
- def updated_keys
211
- @updated_keys ||= SortedSet.new
212
- end
213
-
214
391
  def method_missing(command, *args, &block)
215
392
  normalized_command = command.to_s.downcase
216
393
 
217
394
  if redis.respond_to?(normalized_command)
218
395
  if (normalized_command == "pipelined" ||
219
396
  (normalized_command == "multi" && block)) &&
220
- !@suspend_tracking
221
- @in_multi = true
397
+ !get_value_bool(:@suspend_tracking)
398
+ set_value_bool :@in_multi, true
222
399
  normalized_command = "exec"
223
400
  end
224
401
 
402
+ initial_keys = nil
403
+ if FLUSH_COMMANDS.include?(normalized_command)
404
+ initial_keys = get_set(:@initial_keys)
405
+ end
406
+
225
407
  response = redis.send(command, *args, &block)
226
408
 
227
- if @in_multi && !(["exec", "discard"].include?(normalized_command))
228
- @multi_commands << [normalized_command, *args]
409
+ if FLUSH_COMMANDS.include?(normalized_command)
410
+ add_set_values :@updated_keys, *initial_keys.to_a
411
+ end
412
+
413
+ if get_value_bool(:@in_multi) && !(["exec", "discard"].include?(normalized_command))
414
+ append_list_value_array :@multi_commands, [normalized_command, *args]
229
415
  else
230
416
  process_command(response, normalized_command, *args)
231
417
  end
@@ -237,14 +423,15 @@ module PseudoCleaner
237
423
  end
238
424
 
239
425
  def process_command(response, *args)
240
- unless @in_redis_cleanup || @suspend_tracking
426
+ unless get_value_bool(:@in_redis_cleanup) || get_value_bool(:@suspend_tracking)
241
427
  if "multi" == args[0]
242
- @in_multi = true
243
- @multi_commands = []
428
+ set_value_bool :@in_multi, true
429
+ clear_list_array :@multi_commands
244
430
  elsif ["exec", "pipelined"].include?(args[0])
245
431
  begin
246
- if (!response && @multi_commands.length > 0) || (response && response.length != @multi_commands.length)
247
- puts "exec response does not match sent commands.\n response: #{response}\n commands: #{@multi_commands}"
432
+ if (!response && get_list_length(:@multi_commands) > 0) ||
433
+ (response && response.length != get_list_length(:@multi_commands))
434
+ puts "exec response does not match sent commands.\n response: #{response}\n commands: #{get_list_array(:@multi_commands)}"
248
435
 
249
436
  # make the response length match the commands length.
250
437
  # so far the only time this has happened was when a multi returned nil which SHOULD indicate a failure
@@ -253,26 +440,26 @@ module PseudoCleaner
253
440
  # to assume that redis DID change and record it as such. Even if I am wrong, for the cleaner, it
254
441
  # doesn't matter, and there is no harm.
255
442
  response ||= []
256
- @multi_commands.each_with_index do |command, index|
443
+ get_list_array(:@multi_commands).each_with_index do |command, index|
257
444
  if response.length < index
258
445
  response << true
259
446
  end
260
447
  end
261
448
  end
262
449
 
263
- @multi_commands.each_with_index do |command, index|
450
+ get_list_array(:@multi_commands).each_with_index do |command, index|
264
451
  process_command(response[index], *command)
265
452
  end
266
453
  ensure
267
- @in_multi = false
268
- @multi_commands = []
454
+ set_value_bool :@in_multi, false
455
+ clear_list_array :@multi_commands
269
456
  end
270
457
  elsif "discard" == args[0]
271
- @in_multi = false
272
- @multi_commands = []
458
+ set_value_bool :@in_multi, false
459
+ clear_list_array :@multi_commands
273
460
  elsif WRITE_COMMANDS.include?(args[0])
274
- updated_keys.merge(extract_keys(*args))
275
- elsif SET_COMMANDS.include?(args[0])
461
+ add_set_values :@updated_keys, *extract_keys(*args)
462
+ elsif NUM_CHANGED_COMMANDS.include?(args[0])
276
463
  update_key = true
277
464
  if [true, false].include?(response)
278
465
  update_key = response
@@ -281,14 +468,22 @@ module PseudoCleaner
281
468
  end
282
469
 
283
470
  if update_key
284
- updated_keys.merge(extract_keys(*args))
471
+ add_set_values :@updated_keys, extract_keys(*args)
472
+ end
473
+ elsif POP_COMMANDS.include?(args[0])
474
+ if response
475
+ add_set_value :@updated_keys, response[0]
476
+ end
477
+ elsif NIL_FAIL_COMMANDS.include?(args[0])
478
+ if response
479
+ add_set_values :@updated_keys, extract_keys(*args)
285
480
  end
286
481
  end
287
482
  end
288
483
  end
289
484
 
290
485
  def respond_to_missing?(command, include_all=false)
291
- return true if WRITE_COMMANDS.include?(command.to_s.downcase)
486
+ return true if ALL_COMMANDS.include?(command.to_s.downcase)
292
487
 
293
488
  # blind passthrough is deprecated and will be removed in 2.0
294
489
  if redis.respond_to?(command, include_all)
@@ -298,30 +493,50 @@ module PseudoCleaner
298
493
  defined?(super) && super
299
494
  end
300
495
 
496
+ def extract_key(arg)
497
+ if arg.is_a?(Array)
498
+ arg
499
+ elsif arg.is_a?(Hash)
500
+ arg.keys
501
+ else
502
+ [arg]
503
+ end
504
+ end
505
+
301
506
  def extract_keys(command, *args)
302
- handling = Redis::Namespace::COMMANDS[command.to_s.downcase]
507
+ handling = OVERRIDE_COMMANDS[command.to_s.downcase] || PseudoCleaner::RedisCleaner::COMMANDS[command.to_s.downcase]
303
508
  message_keys = []
304
509
 
305
510
  (before, after) = handling
306
511
 
307
512
  case before
308
513
  when :first
309
- message_keys << args[0] if args[0]
514
+ if args[0]
515
+ extract_key(args[0]).each do |key|
516
+ message_keys << key
517
+ end
518
+ end
310
519
 
311
520
  when :all
312
521
  args.each do |arg|
313
- message_keys << arg
522
+ extract_key(arg).each do |key|
523
+ message_keys << key
524
+ end
314
525
  end
315
526
 
316
527
  when :exclude_first
317
528
  args.each do |arg|
318
- message_keys << arg
529
+ extract_key(arg).each do |key|
530
+ message_keys << key
531
+ end
319
532
  end
320
533
  message_keys.shift
321
534
 
322
535
  when :exclude_last
323
536
  args.each do |arg|
324
- message_keys << arg
537
+ extract_key(arg).each do |key|
538
+ message_keys << key
539
+ end
325
540
  end
326
541
  message_keys.pop unless message_keys.length == 1
327
542
 
@@ -332,13 +547,17 @@ module PseudoCleaner
332
547
 
333
548
  when :alternate
334
549
  args.each_with_index do |arg, i|
335
- message_keys << arg if i.even?
550
+ if i.even?
551
+ extract_key(arg).each do |key|
552
+ message_keys << key
553
+ end
554
+ end
336
555
  end
337
556
 
338
557
  when :sort
339
558
  if args[-1].is_a?(Hash)
340
- if args[1][:store]
341
- message_keys << args[1][:store]
559
+ if args[-1][:store] || args[-1]["store"]
560
+ message_keys << (args[-1][:store] || args[-1]["store"])
342
561
  end
343
562
  end
344
563
 
@@ -375,8 +594,6 @@ module PseudoCleaner
375
594
  time = Benchmark.measure do
376
595
  puts " RedisCleaner(#{redis_name})" if PseudoCleaner::Configuration.instance.benchmark
377
596
 
378
- @test_strategy ||= test_strategy
379
-
380
597
  start_monitor
381
598
  end
382
599
 
@@ -385,17 +602,15 @@ module PseudoCleaner
385
602
 
386
603
  def suspend_tracking(&block)
387
604
  begin
388
- @suspend_tracking = true
605
+ set_value_bool :@suspend_tracking, true
389
606
 
390
607
  block.yield
391
608
  ensure
392
- @suspend_tracking = false
609
+ set_value_bool :@suspend_tracking, false
393
610
  end
394
611
  end
395
612
 
396
613
  def test_start test_strategy
397
- @test_strategy ||= test_strategy
398
-
399
614
  time = Benchmark.measure do
400
615
  puts " RedisCleaner(#{redis_name})" if PseudoCleaner::Configuration.instance.benchmark
401
616
 
@@ -404,12 +619,12 @@ module PseudoCleaner
404
619
  report_dirty_values "values altered before the test started", test_values
405
620
 
406
621
  test_values.each do |value|
407
- redis.del value unless initial_keys.include?(value)
622
+ redis.del value unless set_includes?(:@initial_keys, value)
408
623
  end
409
624
  end
410
625
  end
411
626
 
412
- @updated_keys = SortedSet.new
627
+ clear_set :@updated_keys
413
628
  end
414
629
 
415
630
  puts " RedisCleaner(#{redis_name}) time: #{time}" if PseudoCleaner::Configuration.instance.benchmark
@@ -428,9 +643,9 @@ module PseudoCleaner
428
643
  end
429
644
 
430
645
  updated_values.each do |value|
431
- if initial_keys.include?(value)
646
+ if set_includes?(:@initial_keys, value)
432
647
  report_keys << value
433
- @suite_altered_keys << value unless ignore_key(value)
648
+ add_set_value(:@suite_altered_keys, value) unless ignore_key(value)
434
649
  else
435
650
  redis.del(value)
436
651
  end
@@ -440,7 +655,7 @@ module PseudoCleaner
440
655
  end
441
656
  end
442
657
 
443
- @updated_keys = SortedSet.new
658
+ clear_set :@updated_keys
444
659
  end
445
660
 
446
661
  puts " RedisCleaner(#{redis_name}) time: #{time}" if PseudoCleaner::Configuration.instance.benchmark
@@ -450,7 +665,11 @@ module PseudoCleaner
450
665
  time = Benchmark.measure do
451
666
  puts " RedisCleaner(#{redis_name})" if PseudoCleaner::Configuration.instance.benchmark
452
667
 
453
- report_end_of_suite_state "suite end"
668
+ new_keys = report_end_of_suite_state "suite end"
669
+
670
+ new_keys.each do |key_value|
671
+ redis.del key_value
672
+ end
454
673
  end
455
674
 
456
675
  puts " RedisCleaner(#{redis_name}) time: #{time}" if PseudoCleaner::Configuration.instance.benchmark
@@ -544,64 +763,70 @@ module PseudoCleaner
544
763
  def report_end_of_suite_state report_reason
545
764
  current_keys = SortedSet.new(redis.keys)
546
765
 
547
- deleted_keys = initial_keys - current_keys
548
- new_keys = current_keys - initial_keys
766
+ initial_key_set = get_set(:@initial_keys)
767
+
768
+ deleted_keys = initial_key_set - current_keys
769
+ new_keys = current_keys - initial_key_set
549
770
 
550
771
  # filter out values we inserted that will go away on their own.
551
772
  new_keys = new_keys.select { |key| (key =~ /redis_cleaner::synchronization_(?:end_)?key_[0-9]+_[0-9]+/).nil? }
552
773
 
553
774
  report_dirty_values "new values as of #{report_reason}", new_keys
554
775
  report_dirty_values "values deleted before #{report_reason}", deleted_keys
555
- report_dirty_values "initial values changed during suite run", @suite_altered_keys
776
+ report_dirty_values "initial values changed during suite run", get_set(:@suite_altered_keys)
556
777
 
557
- @suite_altered_keys = SortedSet.new
778
+ clear_set :@suite_altered_keys
558
779
 
559
- new_keys.each do |key_value|
560
- redis.del key_value
561
- end
780
+ new_keys
562
781
  end
563
782
 
564
783
  def synchronize_test_values(&block)
565
- if @in_multi
784
+ if get_value_bool(:@in_multi)
566
785
  # Ideally we should never get here, but if we do, assume everything was changed and keep moving...
567
- @multi_commands.each do |args|
568
- if WRITE_COMMANDS.include?(args[0])
569
- updated_keys.merge(extract_keys(*args))
570
- elsif SET_COMMANDS.include?(args[0])
571
- updated_keys.merge(extract_keys(*args))
786
+ get_list_array(:@multi_commands).each do |args|
787
+ if WRITE_COMMANDS.include?(args[0]) ||
788
+ POP_COMMANDS.include?(args[0]) ||
789
+ NIL_FAIL_COMMANDS.include?(args[0]) ||
790
+ NUM_CHANGED_COMMANDS.include?(args[0])
791
+ add_set_values :@updated_keys, extract_keys(*args)
572
792
  end
573
793
  end
574
794
 
575
- @in_multi = false
576
- @multi_commands = []
795
+ set_value_bool(:@in_multi, false)
796
+ clear_list_array(:@multi_commands)
577
797
  end
578
798
 
579
- updated_values = updated_keys.dup
799
+ updated_values = get_set(:@updated_keys).dup
580
800
 
581
- @in_redis_cleanup = true
801
+ set_value_bool :@in_redis_cleanup, true
582
802
 
583
803
  begin
584
804
  block.yield updated_values
585
805
  ensure
586
- @in_redis_cleanup = false
806
+ set_value_bool :@in_redis_cleanup, false
587
807
  end
588
808
  end
589
809
 
590
810
  def start_monitor
591
- cleaner_class = self
592
-
593
- @initial_keys = SortedSet.new(redis.keys)
811
+ redis_keys = redis.keys
812
+ clear_set :@initial_keys, redis_keys
813
+ clear_set :@suite_altered_keys
814
+ clear_set :@updated_keys
815
+ clear_list_array :@multi_commands
816
+ set_value_bool :@in_multi, false
817
+ set_value_bool :@in_redis_cleanup, false
818
+ set_value_bool :@suspend_tracking, false
594
819
 
595
820
  if @options[:output_diagnostics]
596
821
  if PseudoCleaner::MasterCleaner.report_table
597
822
  Cornucopia::Util::ReportTable.new(nested_table: PseudoCleaner::MasterCleaner.report_table,
598
823
  nested_table_label: redis_name,
599
824
  suppress_blank_table: true) do |report_table|
600
- report_table.write_stats "initial keys count", @initial_keys.count
825
+ report_table.write_stats "initial keys count", redis_keys.count
601
826
  end
602
827
  else
603
828
  PseudoCleaner::Logger.write("#{redis_name}")
604
- PseudoCleaner::Logger.write(" Initial keys count - #{@initial_keys.count}")
829
+ PseudoCleaner::Logger.write(" Initial keys count - #{redis_keys.count}")
605
830
  end
606
831
  end
607
832
  end
@@ -614,11 +839,16 @@ module PseudoCleaner
614
839
  when "list"
615
840
  key_hash[:list] = { len: redis.llen(key_name), values: redis.lrange(key_name, 0, -1) }
616
841
  when "set"
617
- key_hash[:set] = redis.smembers(key_name)
842
+ key_hash[:set] = { len: redis.scard(key_name), values: redis.smembers(key_name) }
618
843
  when "zset"
619
- key_hash[:sorted_set] = redis.smembers(key_name)
844
+ sorted_set_values = redis.zrange(key_name, 0, -1).reduce({}) do |hash, set_value|
845
+ hash[set_value] = redis.zscore(key_name, set_value)
846
+ hash
847
+ end
848
+
849
+ key_hash[:sorted_set] = { len: redis.zcard(key_name), values: sorted_set_values }
620
850
  when "hash"
621
- key_hash[:list] = { len: redis.hlen(key_name), values: redis.hgetall(key_name) }
851
+ key_hash[:hash] = { len: redis.hlen(key_name), values: redis.hgetall(key_name) }
622
852
  end
623
853
 
624
854
  if key_hash[:value].nil? &&
@@ -649,9 +879,9 @@ module PseudoCleaner
649
879
  end
650
880
  end
651
881
  else
652
- PseudoCleaner::Logger.write("********* RedisCleaner - #{message}".red.on_light_white)
653
882
  test_values.each do |key_name|
654
883
  unless ignore_key(key_name)
884
+ PseudoCleaner::Logger.write("********* RedisCleaner - #{message}".red.on_light_white) unless output_values
655
885
  output_values = true
656
886
  PseudoCleaner::Logger.write(" #{key_name}: #{report_record(key_name)}".red.on_light_white)
657
887
  end
@@ -661,5 +891,73 @@ module PseudoCleaner
661
891
  PseudoCleaner::MasterCleaner.report_error if output_values
662
892
  end
663
893
  end
894
+
895
+ def set_value_bool(value_name, bool_value)
896
+ instance_variable_set(value_name, bool_value)
897
+ end
898
+
899
+ def get_value_bool(value_name)
900
+ instance_variable_get(value_name)
901
+ end
902
+
903
+ def append_list_value_array(value_name, array_value)
904
+ array = instance_variable_get(value_name)
905
+ array << array_value
906
+ end
907
+
908
+ def get_list_length(value_name)
909
+ instance_variable_get(value_name).length
910
+ end
911
+
912
+ def get_list_array(value_name)
913
+ instance_variable_get(value_name)
914
+ end
915
+
916
+ def clear_list_array(value_name)
917
+ instance_variable_set(value_name, [])
918
+ end
919
+
920
+ def clear_set(value_name, keys = nil)
921
+ if keys
922
+ instance_variable_set(value_name, SortedSet.new(keys))
923
+ else
924
+ instance_variable_set(value_name, SortedSet.new)
925
+ end
926
+ end
927
+
928
+ def add_set_values(value_name, *values)
929
+ set = get_set(value_name)
930
+
931
+ set.merge(*values)
932
+ end
933
+
934
+ def add_set_value(value_name, value)
935
+ set = get_set(value_name)
936
+
937
+ set << value
938
+ end
939
+
940
+ def remove_set_value(value_name, value)
941
+ set = get_set(value_name)
942
+
943
+ set.delete value
944
+ end
945
+
946
+ def set_includes?(value_name, value)
947
+ set = get_set(value_name)
948
+
949
+ set.include?(value)
950
+ end
951
+
952
+ def get_set(value_name)
953
+ set = instance_variable_get(value_name)
954
+
955
+ unless set
956
+ set = SortedSet.new
957
+ instance_variable_set(value_name, set)
958
+ end
959
+
960
+ set
961
+ end
664
962
  end
665
963
  end