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