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.
- checksums.yaml +8 -8
- data/lib/pseudo_cleaner/redis_based_redis_cleaner.rb +144 -0
- data/lib/pseudo_cleaner/redis_cleaner.rb +412 -114
- data/lib/pseudo_cleaner/version.rb +1 -1
- data/spec/rails_helper.rb +4 -1
- data/spec/redis_based_redis_cleaner_spec.rb +35 -0
- data/spec/redis_cleaner_spec.rb +15 -0
- data/spec/shared_examples/redis_cleaner_storage.rb +280 -0
- data/spec/shared_examples/redis_cleaner_test_tracking.rb +8312 -0
- metadata +11 -2
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
@
|
171
|
-
@
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
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
|
-
|
221
|
-
|
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
|
228
|
-
|
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
|
426
|
+
unless get_value_bool(:@in_redis_cleanup) || get_value_bool(:@suspend_tracking)
|
241
427
|
if "multi" == args[0]
|
242
|
-
|
243
|
-
|
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 &&
|
247
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
268
|
-
|
454
|
+
set_value_bool :@in_multi, false
|
455
|
+
clear_list_array :@multi_commands
|
269
456
|
end
|
270
457
|
elsif "discard" == args[0]
|
271
|
-
|
272
|
-
|
458
|
+
set_value_bool :@in_multi, false
|
459
|
+
clear_list_array :@multi_commands
|
273
460
|
elsif WRITE_COMMANDS.include?(args[0])
|
274
|
-
updated_keys
|
275
|
-
elsif
|
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
|
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
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
605
|
+
set_value_bool :@suspend_tracking, true
|
389
606
|
|
390
607
|
block.yield
|
391
608
|
ensure
|
392
|
-
|
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
|
622
|
+
redis.del value unless set_includes?(:@initial_keys, value)
|
408
623
|
end
|
409
624
|
end
|
410
625
|
end
|
411
626
|
|
412
|
-
|
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
|
646
|
+
if set_includes?(:@initial_keys, value)
|
432
647
|
report_keys << value
|
433
|
-
|
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
|
-
|
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
|
-
|
548
|
-
|
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",
|
776
|
+
report_dirty_values "initial values changed during suite run", get_set(:@suite_altered_keys)
|
556
777
|
|
557
|
-
|
778
|
+
clear_set :@suite_altered_keys
|
558
779
|
|
559
|
-
new_keys
|
560
|
-
redis.del key_value
|
561
|
-
end
|
780
|
+
new_keys
|
562
781
|
end
|
563
782
|
|
564
783
|
def synchronize_test_values(&block)
|
565
|
-
if
|
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
|
-
|
568
|
-
if WRITE_COMMANDS.include?(args[0])
|
569
|
-
|
570
|
-
|
571
|
-
|
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
|
-
|
576
|
-
|
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
|
-
|
801
|
+
set_value_bool :@in_redis_cleanup, true
|
582
802
|
|
583
803
|
begin
|
584
804
|
block.yield updated_values
|
585
805
|
ensure
|
586
|
-
|
806
|
+
set_value_bool :@in_redis_cleanup, false
|
587
807
|
end
|
588
808
|
end
|
589
809
|
|
590
810
|
def start_monitor
|
591
|
-
|
592
|
-
|
593
|
-
|
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",
|
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 - #{
|
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
|
-
|
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[:
|
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
|