pseudo_cleaner 0.0.35 → 0.0.36

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YzliYTc5NmFlMGQyM2E2OTZiNmNkZmI1NWQzOGViMWZmZjRiNWFiZA==
4
+ MjIyM2E5NGJmZGQ4YmRhMzBkOTMzMDEwYmRmY2RjNmZhMmY1YzljNw==
5
5
  data.tar.gz: !binary |-
6
- Nzk4NTNhODc2ZmQ0NGU5YWIyZjVkNmI4YWYyMjBiZmFlYWE3OWQ1ZQ==
6
+ YmM3ZjJmZDFhMmRlMjNmMDU0ZTVjNDM3NzA3YjYxMjRjYTgyMTEwZg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MGZkODUwODZiOGFjMzhjYTY0MjI4M2FmYmFhOWVhNDM5MjM1YjRmODE3N2Y5
10
- N2M1ZjNhNDk3YWZjYzBjYmQ5NTU0MGJhMzQ0ODYyNzI5ZDQ0NmJkZjE2YTc5
11
- NmM0MTU1YzI3YzI2MWU5ZjVhZTljOGQ5NzczZDA0ZGZmNDA3ODU=
9
+ ODAzYzRjZGJjNjIzMTUxOGZlNTAyNjUxYWNmODY1ZGZkNTRhMGUwOWU4Y2Y3
10
+ ZjliZWJlZWQzY2JhMDQ4ODdmYjc1YTUwZGJjYTY5NDAwYjU1YmRmMGE5Njlm
11
+ N2JmNzVhNGJhYzc2N2EzZmY0MjBiNTQyMzY3MTYxYWRjNWZlYWQ=
12
12
  data.tar.gz: !binary |-
13
- NWNmMTQxNzFkZWZhOGI2MGNjZjU4YmFmMmU0NzJhOGI4ZTBiNmFkNDBlMTZk
14
- Y2NjNjU4NTk5NjI2OWIyY2EyMGIxY2UwZGNlOTYwYzhjZjJlZTY1OWRlNGIy
15
- OTNiYTEzMDc4YzUzMzI4YjY1NzQzODgxMTM1MzYyN2U2MTg2MDI=
13
+ MWJkNjdmZjI1MzNlYjQ3MmJjN2Y4MmRiNDYwMGNiZTYxODBiYTM5ZmIxZWFk
14
+ YmY5NTA3OWI5NTFjYWQ0N2ViMDZjNzFjZWE5MzFlNjcxNjBmNjgyMGViMTU1
15
+ ZGYwZjAzZmU5MWE4ZGU3ZGY3OWI5MGQ1NTI1ZmU0MTNhMWJlYTk=
@@ -4,7 +4,7 @@ module PseudoCleaner
4
4
  class MasterCleaner
5
5
  @@suite_cleaner = nil
6
6
  @@cleaner_classes = nil
7
- @@redis_classes = nil
7
+ # @@redis_classes = nil
8
8
  @@cleaner_classes_sorted = false
9
9
  @@report_table = nil
10
10
  @@report_error = false
@@ -72,10 +72,10 @@ module PseudoCleaner
72
72
  end
73
73
  end
74
74
 
75
- def clean_redis(redis)
76
- @@redis_classes ||= []
77
- @@redis_classes << redis
78
- end
75
+ # def clean_redis(redis)
76
+ # @@redis_classes ||= []
77
+ # @@redis_classes << redis
78
+ # end
79
79
 
80
80
  def database_cleaner
81
81
  if Object.const_defined?("ActiveRecord", false) && ActiveRecord.const_defined?("Base", false)
@@ -252,7 +252,7 @@ module PseudoCleaner
252
252
 
253
253
  PseudoCleaner::MasterCleaner.create_table_cleaners
254
254
  PseudoCleaner::MasterCleaner.create_custom_cleaners
255
- PseudoCleaner::MasterCleaner.create_redis_cleaners
255
+ # PseudoCleaner::MasterCleaner.create_redis_cleaners
256
256
  end
257
257
 
258
258
  @@cleaner_classes
@@ -309,13 +309,13 @@ module PseudoCleaner
309
309
  end
310
310
  end
311
311
 
312
- def create_redis_cleaners
313
- if @@redis_classes
314
- @@redis_classes.each do |redis|
315
- PseudoCleaner::MasterCleaner.cleaner_classes << [redis, nil, PseudoCleaner::RedisCleaner]
316
- end
317
- end
318
- end
312
+ # def create_redis_cleaners
313
+ # if @@redis_classes
314
+ # @@redis_classes.each do |redis|
315
+ # PseudoCleaner::MasterCleaner.cleaner_classes << [redis, nil, PseudoCleaner::RedisMonitorCleaner]
316
+ # end
317
+ # end
318
+ # end
319
319
 
320
320
  def find_file_class(seeder_file, seeder_root)
321
321
  check_class = Object
@@ -37,13 +37,20 @@ module PseudoCleaner
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
  class RedisCleaner
40
- # SUITE_KEY = "PseudoDelete::RedisCleaner:initial_redis_state"
41
-
42
40
  FLUSH_COMMANDS =
43
41
  [
44
42
  "flushall",
45
43
  "flushdb"
46
44
  ]
45
+ SET_COMMANDS =
46
+ [
47
+ "sadd",
48
+ "zadd",
49
+ "srem",
50
+ "zrem",
51
+ "zremrangebyrank",
52
+ "zremrangebyscore"
53
+ ]
47
54
  WRITE_COMMANDS =
48
55
  [
49
56
  "append",
@@ -90,7 +97,6 @@ module PseudoCleaner
90
97
  "rpoplpush",
91
98
  "rpush",
92
99
  "rpushx",
93
- "sadd",
94
100
  "sdiffstore",
95
101
  "set",
96
102
  "setbit",
@@ -101,14 +107,9 @@ module PseudoCleaner
101
107
  "smove",
102
108
  "sort",
103
109
  "spop",
104
- "srem",
105
110
  "sunionstore",
106
- "zadd",
107
111
  "zincrby",
108
112
  "zinterstore",
109
- "zrem",
110
- "zremrangebyrank",
111
- "zremrangebyscore",
112
113
  ]
113
114
  READ_COMMANDS =
114
115
  [
@@ -160,179 +161,168 @@ module PseudoCleaner
160
161
  "zscore",
161
162
  ]
162
163
 
163
- attr_reader :monitor_thread
164
164
  attr_reader :initial_keys
165
165
  attr_accessor :options
166
166
 
167
- class RedisMessage
168
- attr_reader :message
169
- attr_reader :time_stamp
170
- attr_reader :db
171
- attr_reader :host
172
- attr_reader :port
173
- attr_reader :command
174
- attr_reader :cur_pos
175
-
176
- def initialize(message_string)
177
- @message = message_string
167
+ def initialize(start_method, end_method, table, options)
168
+ @initial_keys = SortedSet.new
169
+ @monitor_thread = nil
170
+ @redis_name = nil
171
+ @suite_altered_keys = SortedSet.new
172
+ @updated_keys = SortedSet.new
173
+ @multi_commands = []
174
+ @in_multi = false
175
+ @in_redis_cleanup = false
176
+ @suspend_tracking = false
178
177
 
179
- parse_message
178
+ unless PseudoCleaner::MasterCleaner::VALID_START_METHODS.include?(start_method)
179
+ raise "You must specify a valid start function from: #{PseudoCleaner::MasterCleaner::VALID_START_METHODS}."
180
180
  end
181
+ unless PseudoCleaner::MasterCleaner::VALID_END_METHODS.include?(end_method)
182
+ raise "You must specify a valid end function from: #{PseudoCleaner::MasterCleaner::VALID_END_METHODS}."
183
+ end
184
+
185
+ @options = options
186
+
187
+ @options[:table_start_method] ||= start_method
188
+ @options[:table_end_method] ||= end_method
189
+ @options[:output_diagnostics] ||= PseudoCleaner::Configuration.current_instance.output_diagnostics ||
190
+ PseudoCleaner::Configuration.current_instance.post_transaction_analysis
181
191
 
182
- def parse_message
183
- if @message =~ /[0-9]+\.[0-9]+ \[[0-9]+ [^:]+:[^\]]+\] \"[^\"]+\"/
184
- end_pos = @message.index(" ")
185
- @time_stamp = @message[0..end_pos - 1]
192
+ @redis = table
193
+ end
186
194
 
187
- @cur_pos = end_pos + 2 # " ["
188
- end_pos = @message.index(" ", @cur_pos)
189
- @db = @message[@cur_pos..end_pos - 1].to_i
195
+ # Ruby defines a now deprecated type method so we need to override it here
196
+ # since it will never hit method_missing
197
+ def type(key)
198
+ redis.type(key)
199
+ end
190
200
 
191
- @cur_pos = end_pos + 1
192
- end_pos = @message.index(":", @cur_pos)
193
- @host = @message[@cur_pos..end_pos - 1]
201
+ alias_method :self_respond_to?, :respond_to?
194
202
 
195
- @cur_pos = end_pos + 1
196
- end_pos = @message.index("]", @cur_pos)
197
- @port = @message[@cur_pos..end_pos - 1].to_i
203
+ # emulate Ruby 1.9+ and keep respond_to_missing? logic together.
204
+ def respond_to?(command, include_private=false)
205
+ super or respond_to_missing?(command, include_private)
206
+ end
198
207
 
199
- @cur_pos = end_pos + 2 # "] "
200
- @command = next_value.downcase
201
- else
202
- @command = @message
203
- end
204
- end
208
+ def updated_keys
209
+ @updated_keys ||= SortedSet.new
210
+ end
205
211
 
206
- def next_value
207
- in_quote = (@message[@cur_pos] == '"')
208
- if in_quote
209
- @cur_pos += 1
210
- end_pos = @cur_pos
211
- while (end_pos && end_pos < @message.length)
212
- end_pos = @message.index("\"", end_pos)
212
+ def method_missing(command, *args, &block)
213
+ normalized_command = command.to_s.downcase
213
214
 
214
- num_backslashes = 0
215
- back_pos = end_pos
215
+ if redis.respond_to?(normalized_command)
216
+ if normalized_command == "pipelined" ||
217
+ (normalized_command == "multi" && block)
218
+ @in_multi = true
219
+ normalized_command = "exec"
220
+ end
216
221
 
217
- while @message[back_pos - 1] == "\\"
218
- num_backslashes += 1
219
- back_pos -= 1
220
- end
222
+ response = redis.send(command, *args, &block)
221
223
 
222
- break if (num_backslashes % 2) == 0
223
- end_pos += 1
224
- end
224
+ if @in_multi && !(["exec", "discard"].include?(normalized_command))
225
+ @multi_commands << [normalized_command, *args]
225
226
  else
226
- end_pos = @message.index(" ", @cur_pos)
227
+ process_command(response, normalized_command, *args)
227
228
  end
228
- the_value = @message[@cur_pos..end_pos - 1]
229
- end_pos += 1 if in_quote
230
229
 
231
- @cur_pos = end_pos + 1
232
-
233
- the_value.gsub("\\\\", "\\").gsub("\\\"", "\"")
230
+ response
231
+ else
232
+ super
234
233
  end
234
+ end
235
235
 
236
- def keys
237
- unless defined?(@message_keys)
238
- @message_keys = []
239
-
240
- if Redis::Namespace::COMMANDS.include? command
241
- handling = Redis::Namespace::COMMANDS[command.to_s.downcase]
236
+ def process_command(response, *args)
237
+ unless @in_redis_cleanup || @suspend_tracking
238
+ if "multi" == args[0]
239
+ @in_multi = true
240
+ @multi_commands = []
241
+ elsif ["exec", "pipelined"].include?(args[0])
242
+ begin
243
+ raise "exec response does not match sent commands" unless response.length == @multi_commands.length
244
+
245
+ response.each_with_index do |command_response, index|
246
+ process_command(command_response, *(@multi_commands[index]))
247
+ end
248
+ ensure
249
+ @in_multi = false
250
+ @multi_commands = []
251
+ end
252
+ elsif "discard" == args[0]
253
+ @in_multi = false
254
+ @multi_commands = []
255
+ elsif WRITE_COMMANDS.include?(args[0])
256
+ updated_keys.merge(extract_keys(*args))
257
+ elsif SET_COMMANDS.include?(args[0])
258
+ if [true, false].include?(response) ? response : (response > 0)
259
+ updated_keys.merge(extract_keys(*args))
260
+ end
261
+ end
262
+ end
263
+ end
242
264
 
243
- (before, after) = handling
265
+ def respond_to_missing?(command, include_all=false)
266
+ return true if WRITE_COMMANDS.include?(command.to_s.downcase)
244
267
 
245
- case before
246
- when :first
247
- @message_keys << next_value
268
+ # blind passthrough is deprecated and will be removed in 2.0
269
+ if redis.respond_to?(command, include_all)
270
+ return true
271
+ end
248
272
 
249
- when :all
250
- while @cur_pos < @message.length
251
- @message_keys << next_value
252
- end
273
+ defined?(super) && super
274
+ end
253
275
 
254
- when :exclude_first
255
- next_value
256
- while @cur_pos < @message.length
257
- @message_keys << next_value
258
- end
276
+ def extract_keys(command, *args)
277
+ handling = Redis::Namespace::COMMANDS[command.to_s.downcase]
278
+ message_keys = []
259
279
 
260
- when :exclude_last
261
- while @cur_pos < @message.length
262
- @message_keys << next_value
263
- end
264
- @message_keys.delete_at(@message_keys.length - 1)
265
-
266
- when :exclude_options
267
- options = ["weights", "aggregate", "sum", "min", "max"]
268
- while @cur_pos < @message.length
269
- @message_keys << next_value
270
- if options.include?(@message_keys[-1].downcase)
271
- @message_keys.delete_at(@message_keys.length - 1)
272
- break
273
- end
274
- end
280
+ (before, after) = handling
275
281
 
276
- when :alternate
277
- while @cur_pos < @message.length
278
- @message_keys << next_value
279
- next_value
280
- end
282
+ case before
283
+ when :first
284
+ message_keys << args[0] if args[0]
281
285
 
282
- when :sort
283
- next_value
286
+ when :all
287
+ args.each do |arg|
288
+ message_keys << arg
289
+ end
284
290
 
285
- while @cur_pos < @message.length
286
- a_value = next_value
287
- if a_value.downcase == "store"
288
- @message_keys[0] = next_value
289
- end
290
- end
291
+ when :exclude_first
292
+ args.each do |arg|
293
+ message_keys << arg
294
+ end
295
+ message_keys.shift
291
296
 
292
- # when :eval_style
293
- #
294
- # when :scan_style
295
- end
297
+ when :exclude_last
298
+ args.each do |arg|
299
+ message_keys << arg
296
300
  end
297
- end
301
+ message_keys.pop unless message_keys.length == 1
298
302
 
299
- @message_keys
300
- end
303
+ when :exclude_options
304
+ args.each do |arg|
305
+ message_keys << arg unless arg.is_a?(Hash)
306
+ end
301
307
 
302
- def to_s
303
- {
304
- time_stamp: time_stamp,
305
- db: db,
306
- host: host,
307
- port: port,
308
- command: command,
309
- message: message,
310
- cur_pos: cur_pos
311
- }.to_s
312
- end
313
- end
308
+ when :alternate
309
+ args.each_with_index do |arg, i|
310
+ message_keys << arg if i.even?
311
+ end
314
312
 
315
- def initialize(start_method, end_method, table, options)
316
- @initial_keys = SortedSet.new
317
- @monitor_thread = nil
318
- @redis_name = nil
319
- @suite_altered_keys = SortedSet.new
313
+ when :sort
314
+ if args[-1].is_a?(Hash)
315
+ if args[1][:store]
316
+ message_keys << args[1][:store]
317
+ end
318
+ end
320
319
 
321
- unless PseudoCleaner::MasterCleaner::VALID_START_METHODS.include?(start_method)
322
- raise "You must specify a valid start function from: #{PseudoCleaner::MasterCleaner::VALID_START_METHODS}."
323
- end
324
- unless PseudoCleaner::MasterCleaner::VALID_END_METHODS.include?(end_method)
325
- raise "You must specify a valid end function from: #{PseudoCleaner::MasterCleaner::VALID_END_METHODS}."
320
+ # when :eval_style
321
+ #
322
+ # when :scan_style
326
323
  end
327
324
 
328
- @options = options
329
-
330
- @options[:table_start_method] ||= start_method
331
- @options[:table_end_method] ||= end_method
332
- @options[:output_diagnostics] ||= PseudoCleaner::Configuration.current_instance.output_diagnostics ||
333
- PseudoCleaner::Configuration.current_instance.post_transaction_analysis
334
-
335
- @redis = table
325
+ message_keys
336
326
  end
337
327
 
338
328
  def <=>(right_object)
@@ -359,15 +349,19 @@ module PseudoCleaner
359
349
  def suite_start test_strategy
360
350
  @test_strategy ||= test_strategy
361
351
 
362
- # if redis.type(PseudoCleaner::RedisCleaner::SUITE_KEY) == "set"
363
- # @initial_keys = SortedSet.new(redis.smembers(PseudoCleaner::RedisCleaner::SUITE_KEY))
364
- # report_end_of_suite_state "before suite start"
365
- # end
366
- # redis.del PseudoCleaner::RedisCleaner::SUITE_KEY
367
-
368
352
  start_monitor
369
353
  end
370
354
 
355
+ def suspend_tracking(&block)
356
+ begin
357
+ @suspend_tracking = true
358
+
359
+ block.yield
360
+ ensure
361
+ @suspend_tracking = false
362
+ end
363
+ end
364
+
371
365
  def test_start test_strategy
372
366
  @test_strategy ||= test_strategy
373
367
 
@@ -407,21 +401,12 @@ module PseudoCleaner
407
401
 
408
402
  def suite_end test_strategy
409
403
  report_end_of_suite_state "suite end"
410
-
411
- if monitor_thread
412
- monitor_thread.kill
413
- @monitor_thread = nil
414
- end
415
404
  end
416
405
 
417
406
  def reset_suite
418
407
  report_end_of_suite_state "reset suite"
419
408
 
420
- if monitor_thread
421
- monitor_thread.kill
422
- @monitor_thread = nil
423
- start_monitor
424
- end
409
+ start_monitor
425
410
  end
426
411
 
427
412
  def ignore_regexes
@@ -485,14 +470,6 @@ module PseudoCleaner
485
470
  end
486
471
  end
487
472
 
488
- def synchronize_key
489
- @synchronize_key ||= "redis_cleaner::synchronization_key_#{rand(1..1_000_000_000_000_000_000)}_#{rand(1..1_000_000_000_000_000_000)}"
490
- end
491
-
492
- def synchronize_end_key
493
- @synchronize_end_key ||= "redis_cleaner::synchronization_end_key_#{rand(1..1_000_000_000_000_000_000)}_#{rand(1..1_000_000_000_000_000_000)}"
494
- end
495
-
496
473
  def report_end_of_suite_state report_reason
497
474
  current_keys = SortedSet.new(redis.keys)
498
475
 
@@ -514,30 +491,24 @@ module PseudoCleaner
514
491
  end
515
492
 
516
493
  def synchronize_test_values(&block)
517
- updated_values = nil
494
+ updated_values = updated_keys.dup
518
495
 
519
- if monitor_thread
520
- redis.setex(synchronize_key, 1, true)
521
- updated_values = queue.pop
522
- end
523
-
524
- block.yield updated_values
496
+ @in_redis_cleanup = true
525
497
 
526
- redis.setex(synchronize_end_key, 1, true)
527
- end
498
+ begin
499
+ block.yield updated_values
500
+ ensure
501
+ @in_redis_cleanup = false
502
+ end
528
503
 
529
- def queue
530
- @queue ||= Queue.new
504
+ @updated_keys = SortedSet.new
531
505
  end
532
506
 
533
507
  def start_monitor
534
508
  cleaner_class = self
535
509
 
536
510
  @initial_keys = SortedSet.new(redis.keys)
537
- # @initial_keys.add(PseudoCleaner::RedisCleaner::SUITE_KEY)
538
- # @initial_keys.each do |key_value|
539
- # redis.sadd(PseudoCleaner::RedisCleaner::SUITE_KEY, key_value)
540
- # end
511
+
541
512
  if @options[:output_diagnostics]
542
513
  if PseudoCleaner::MasterCleaner.report_table
543
514
  Cornucopia::Util::ReportTable.new(nested_table: PseudoCleaner::MasterCleaner.report_table,
@@ -550,60 +521,6 @@ module PseudoCleaner
550
521
  PseudoCleaner::Logger.write(" Initial keys count - #{@initial_keys.count}")
551
522
  end
552
523
  end
553
-
554
- unless @monitor_thread
555
- @monitor_thread = Thread.new do
556
- in_redis_cleanup = false
557
- updated_keys = SortedSet.new
558
-
559
- monitor_redis = Redis.new(cleaner_class.redis.client.options)
560
- redis_options = monitor_redis.client.options.with_indifferent_access
561
- cleaner_class_db = redis_options[:db]
562
-
563
- monitor_redis.monitor do |message|
564
- redis_message = RedisMessage.new message
565
-
566
- if redis_message.db == cleaner_class_db
567
- process_command = true
568
-
569
- if redis_message.command == "setex"
570
- if redis_message.keys[0] == cleaner_class.synchronize_key
571
- process_command = false
572
-
573
- in_redis_cleanup = true
574
- return_values = updated_keys
575
- updated_keys = SortedSet.new
576
- cleaner_class.queue << return_values
577
- elsif redis_message.keys[0] == cleaner_class.synchronize_end_key
578
- in_redis_cleanup = false
579
- cleaner_class.monitor_thread[:updated] = nil
580
- process_command = false
581
- end
582
- elsif redis_message.command == "del"
583
- if in_redis_cleanup
584
- process_command = false
585
- end
586
- end
587
-
588
- if process_command
589
- # flush...
590
- if PseudoCleaner::RedisCleaner::WRITE_COMMANDS.include? redis_message.command
591
- updated_keys.merge(redis_message.keys)
592
- elsif PseudoCleaner::RedisCleaner::FLUSH_COMMANDS.include? redis_message.command
593
- # Not sure I can get the keys at this point...
594
- # updated_keys.merge(cleaner_class.redis.keys)
595
- end
596
- end
597
- elsif "flushall" == redis_message.command
598
- # Not sure I can get the keys at this point...
599
- # updated_keys.merge(cleaner_class.redis.keys)
600
- end
601
- end
602
- end
603
-
604
- sleep(0.01)
605
- redis.get(synchronize_key)
606
- end
607
524
  end
608
525
 
609
526
  def report_record(key_name)