pseudo_cleaner 0.0.43 → 0.0.44

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,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