redis 3.0.7 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/.gitignore +2 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +29 -2
- data/Gemfile +4 -0
- data/README.md +15 -1
- data/Rakefile +12 -347
- data/lib/redis.rb +54 -0
- data/lib/redis/client.rb +33 -13
- data/lib/redis/distributed.rb +23 -0
- data/lib/redis/version.rb +1 -1
- data/test/bitpos_test.rb +69 -0
- data/test/commands_on_hyper_log_log_test.rb +21 -0
- data/test/distributed_commands_on_hyper_log_log_test.rb +22 -0
- data/test/fork_safety_test.rb +65 -0
- data/test/helper.rb +18 -6
- data/test/internals_test.rb +22 -6
- data/test/lint/hyper_log_log.rb +48 -0
- metadata +82 -12
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Njk4NjUzM2ZiOTk2NTU0Y2FkYzg5NzU4NDc0Zjg1MmJiMDUwYjFlMg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MTAxMTMzZmVjY2E2YjI1NzQ3Y2M1YTI5NDk3ZWQ5ZjVmZmExYTMwYg==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NjkwNTI4ZTg3OTVhNTkwYWViNGQzY2NmZGJiODQ1ZTc1MzNmNzdjNjE0NTkx
|
10
|
+
NzljZTdhZTg1ZjEyYTYxYTJjYmJkYmIwZjYzZTdkNmFlOTNmNDZlY2YzMTY1
|
11
|
+
MTgyZmRmZjNlNTEwNzZlYWJmM2Q3YTkxZTEyZDc1MjZhNWNlODc=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NDQ0NDIyZmVmMWVmMmE5ZGU4ZDQyYzAxODljYTEzODM2YjY5YzAyMWZjNzdh
|
14
|
+
NTEwMjcwZDM2OWRhYWY4ZjUzMTRmOWU5MTNjMDM3ZDM2YjM0YTRhMDc3NGY0
|
15
|
+
MjQ5ZTFhYjg5ODM5NDlmZjMyMDkxMTg1NmI3YjgyZWQwNmQzN2Y=
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -9,6 +9,7 @@ rvm:
|
|
9
9
|
- 1.9.2
|
10
10
|
- 1.9.3
|
11
11
|
- 2.0.0
|
12
|
+
- 2.1.0
|
12
13
|
- jruby-18mode
|
13
14
|
- jruby-19mode
|
14
15
|
|
@@ -17,6 +18,7 @@ gemfile:
|
|
17
18
|
|
18
19
|
env:
|
19
20
|
global:
|
21
|
+
- VERBOSE=true
|
20
22
|
- TIMEOUT=1
|
21
23
|
matrix:
|
22
24
|
- conn=ruby REDIS_BRANCH=2.6
|
@@ -51,5 +53,4 @@ notifications:
|
|
51
53
|
- irc.freenode.net#redis-rb
|
52
54
|
email:
|
53
55
|
- damian.janowski@gmail.com
|
54
|
-
- michel@soveran.com
|
55
56
|
- pcnoordhuis@gmail.com
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,33 @@
|
|
1
|
-
# (unreleased)
|
1
|
+
# 4.x (unreleased)
|
2
2
|
|
3
|
-
|
3
|
+
## Planned breaking changes:
|
4
|
+
* `Redis#client` will no longer expose the underlying `Redis::Client`;
|
5
|
+
it has not yet been determined how 4.0 will expose the underlying
|
6
|
+
functionality, but we will make every attempt to provide a final minor
|
7
|
+
release of 3.x that provides the new interfaces in order to facilitate
|
8
|
+
a smooth transition.
|
9
|
+
|
10
|
+
* Ruby 1.8.7 (and the 1.8 modes of JRuby and Rubinius) will no longer be
|
11
|
+
supported; 1.8.x entered end-of-life in June of 2012 and stopped receiving
|
12
|
+
security updates in June of 2013; continuing to support it would prevent
|
13
|
+
the use of newer features of Ruby.
|
14
|
+
|
15
|
+
# 3.1.x (unreleased)
|
16
|
+
|
17
|
+
* Added debug log sanitization (#428).
|
18
|
+
|
19
|
+
* Added support for HyperLogLog commands (Redis 2.8.9, #432).
|
20
|
+
|
21
|
+
* Added support for `BITPOS` command (Redis 2.9.11, #412).
|
22
|
+
|
23
|
+
* The client will now automatically reconnect after a fork (#414).
|
24
|
+
|
25
|
+
* If you want to disable the fork-safety check and prefer to share the
|
26
|
+
connection across child processes, you can now pass the `inherit_socket`
|
27
|
+
option (#409).
|
28
|
+
|
29
|
+
* If you want the client to attempt to reconnect more than once, you can now
|
30
|
+
pass the `reconnect_attempts` option (#347)
|
4
31
|
|
5
32
|
# 3.0.7
|
6
33
|
|
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
# redis-rb [![Build Status][travis-image]][travis-link]
|
1
|
+
# redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link]
|
2
2
|
|
3
3
|
[travis-image]: https://secure.travis-ci.org/redis/redis-rb.png?branch=master
|
4
4
|
[travis-link]: http://travis-ci.org/redis/redis-rb
|
5
5
|
[travis-home]: http://travis-ci.org/
|
6
|
+
[inchpages-image]: http://inch-pages.github.io/github/redis/redis-rb.png
|
7
|
+
[inchpages-link]: http://inch-pages.github.io/github/redis/redis-rb
|
6
8
|
|
7
9
|
A Ruby client library for [Redis][redis-home].
|
8
10
|
|
@@ -156,6 +158,18 @@ end
|
|
156
158
|
# => 1
|
157
159
|
```
|
158
160
|
|
161
|
+
## Expert-Mode Options
|
162
|
+
|
163
|
+
- `inherit_socket: true`: disable safety check that prevents a forked child
|
164
|
+
from sharing a socket with its parent; this is potentially useful in order to mitigate connection churn when:
|
165
|
+
- many short-lived forked children of one process need to talk
|
166
|
+
to redis, AND
|
167
|
+
- your own code prevents the parent process from using the redis
|
168
|
+
connection while a child is alive
|
169
|
+
|
170
|
+
Improper use of `inherit_socket` will result in corrupted and/or incorrect
|
171
|
+
responses.
|
172
|
+
|
159
173
|
## Alternate drivers
|
160
174
|
|
161
175
|
By default, redis-rb uses Ruby's socket library to talk with Redis.
|
data/Rakefile
CHANGED
@@ -1,12 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require 'rubygems/package_task'
|
3
|
-
require 'rake/testtask'
|
1
|
+
require "rake/testtask"
|
4
2
|
|
5
3
|
ENV["REDIS_BRANCH"] ||= "unstable"
|
6
4
|
|
7
|
-
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
8
|
-
require 'redis/version'
|
9
|
-
|
10
5
|
REDIS_DIR = File.expand_path(File.join("..", "test"), __FILE__)
|
11
6
|
REDIS_CNF = File.join(REDIS_DIR, "test.conf")
|
12
7
|
REDIS_PID = File.join(REDIS_DIR, "db", "redis.pid")
|
@@ -34,6 +29,10 @@ task :start => BINARY do
|
|
34
29
|
abort "could not start redis-server"
|
35
30
|
end
|
36
31
|
end
|
32
|
+
|
33
|
+
at_exit do
|
34
|
+
Rake::Task["stop"].invoke
|
35
|
+
end
|
37
36
|
end
|
38
37
|
|
39
38
|
desc "Stop the Redis server"
|
@@ -44,12 +43,18 @@ task :stop do
|
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
46
|
+
desc "Clean up testing artifacts"
|
47
|
+
task :clean do
|
48
|
+
FileUtils.rm_f(BINARY)
|
49
|
+
end
|
50
|
+
|
47
51
|
file BINARY do
|
48
52
|
branch = ENV.fetch("REDIS_BRANCH")
|
49
53
|
|
50
54
|
sh <<-SH
|
51
55
|
mkdir -p tmp;
|
52
56
|
cd tmp;
|
57
|
+
rm -rf redis-#{branch};
|
53
58
|
wget https://github.com/antirez/redis/archive/#{branch}.tar.gz -O #{branch}.tar.gz;
|
54
59
|
tar xf #{branch}.tar.gz;
|
55
60
|
cd redis-#{branch};
|
@@ -58,346 +63,6 @@ file BINARY do
|
|
58
63
|
end
|
59
64
|
|
60
65
|
Rake::TestTask.new do |t|
|
61
|
-
t.options = "-v"
|
66
|
+
t.options = "-v" if $VERBOSE
|
62
67
|
t.test_files = FileList["test/*_test.rb"]
|
63
68
|
end
|
64
|
-
|
65
|
-
task :doc => ["doc:generate", "doc:prepare"]
|
66
|
-
|
67
|
-
namespace :doc do
|
68
|
-
task :generate do
|
69
|
-
require "shellwords"
|
70
|
-
|
71
|
-
`rm -rf doc`
|
72
|
-
|
73
|
-
current_branch = `git branch`[/^\* (.*)$/, 1]
|
74
|
-
|
75
|
-
begin
|
76
|
-
tags = `git tag -l`.split("\n").sort.reverse
|
77
|
-
|
78
|
-
tags.each do |tag|
|
79
|
-
`git checkout -q #{tag} 2>/dev/null`
|
80
|
-
|
81
|
-
unless $?.success?
|
82
|
-
$stderr.puts "Need a clean working copy. Please git-stash away."
|
83
|
-
exit 1
|
84
|
-
end
|
85
|
-
|
86
|
-
puts tag
|
87
|
-
|
88
|
-
`mkdir -p doc/#{tag}`
|
89
|
-
|
90
|
-
files = `git ls-tree -r HEAD lib`.split("\n").map do |line|
|
91
|
-
line[/\t(.*)$/, 1]
|
92
|
-
end
|
93
|
-
|
94
|
-
opts = [
|
95
|
-
"--title", "A Ruby client for Redis",
|
96
|
-
"--output", "doc/#{tag}",
|
97
|
-
"--no-cache",
|
98
|
-
"--no-save",
|
99
|
-
"-q",
|
100
|
-
*files
|
101
|
-
]
|
102
|
-
|
103
|
-
`yardoc #{Shellwords.shelljoin opts}`
|
104
|
-
end
|
105
|
-
ensure
|
106
|
-
`git checkout -q #{current_branch}`
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
task :prepare do
|
111
|
-
versions = `git tag -l`.split("\n").grep(/^v/).sort
|
112
|
-
latest_version = versions.last
|
113
|
-
|
114
|
-
File.open("doc/.htaccess", "w") do |file|
|
115
|
-
file.puts "RedirectMatch 302 ^/?$ /#{latest_version}"
|
116
|
-
end
|
117
|
-
|
118
|
-
File.open("doc/robots.txt", "w") do |file|
|
119
|
-
file.puts "User-Agent: *"
|
120
|
-
|
121
|
-
(versions - [latest_version]).each do |version|
|
122
|
-
file.puts "Disallow: /#{version}"
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
google_analytics = <<-EOS
|
127
|
-
<script type="text/javascript">
|
128
|
-
|
129
|
-
var _gaq = _gaq || [];
|
130
|
-
_gaq.push(['_setAccount', 'UA-11356145-2']);
|
131
|
-
_gaq.push(['_trackPageview']);
|
132
|
-
|
133
|
-
(function() {
|
134
|
-
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
135
|
-
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
136
|
-
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
137
|
-
})();
|
138
|
-
|
139
|
-
</script>
|
140
|
-
EOS
|
141
|
-
|
142
|
-
Dir["doc/**/*.html"].each do |path|
|
143
|
-
lines = IO.readlines(path)
|
144
|
-
|
145
|
-
File.open(path, "w") do |file|
|
146
|
-
lines.each do |line|
|
147
|
-
if line.include?("</head>")
|
148
|
-
file.write(google_analytics)
|
149
|
-
end
|
150
|
-
|
151
|
-
file.write(line)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
task :deploy do
|
158
|
-
system "rsync --del -avz doc/ redis-rb.keyvalue.org:deploys/redis-rb.keyvalue.org/"
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
class Source
|
163
|
-
|
164
|
-
MATCHER = "(?:\\s{%d}#[^\\n]*\\n)*^\\s{%d}def ([a-z_?]+)(?:\(.*?\))?\\n.*?^\\s{%d}end\\n\\n"
|
165
|
-
|
166
|
-
def initialize(data, options = {})
|
167
|
-
@doc = parse(File.read(data), options)
|
168
|
-
end
|
169
|
-
|
170
|
-
def methods
|
171
|
-
@doc.select do |d|
|
172
|
-
d.is_a?(Method)
|
173
|
-
end.map do |d|
|
174
|
-
d.name
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def move(a, b)
|
179
|
-
ao = @doc.find { |m| m.is_a?(Method) && m.name == a }
|
180
|
-
bo = @doc.find { |m| m.is_a?(Method) && m.name == b }
|
181
|
-
ai = @doc.index(ao)
|
182
|
-
bi = @doc.index(bo)
|
183
|
-
|
184
|
-
@doc.delete_at(ai)
|
185
|
-
@doc.insert(bi, ao)
|
186
|
-
|
187
|
-
nil
|
188
|
-
end
|
189
|
-
|
190
|
-
def to_s
|
191
|
-
@doc.join
|
192
|
-
end
|
193
|
-
|
194
|
-
protected
|
195
|
-
|
196
|
-
def parse(data, options = {})
|
197
|
-
re = Regexp.new(MATCHER % ([options[:indent]] * 3), Regexp::MULTILINE)
|
198
|
-
tail = data.dup
|
199
|
-
doc = []
|
200
|
-
|
201
|
-
while match = re.match(tail)
|
202
|
-
doc << match.pre_match
|
203
|
-
doc << Method.new(match)
|
204
|
-
tail = match.post_match
|
205
|
-
end
|
206
|
-
|
207
|
-
doc << tail if tail
|
208
|
-
doc
|
209
|
-
end
|
210
|
-
|
211
|
-
class Method
|
212
|
-
|
213
|
-
def initialize(match)
|
214
|
-
@match = match
|
215
|
-
end
|
216
|
-
|
217
|
-
def name
|
218
|
-
@match[1]
|
219
|
-
end
|
220
|
-
|
221
|
-
def to_s
|
222
|
-
@match[0]
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
namespace :commands do
|
228
|
-
def redis_commands
|
229
|
-
$redis_commands ||= doc.keys.map do |key|
|
230
|
-
key.split(" ").first.downcase
|
231
|
-
end.uniq
|
232
|
-
end
|
233
|
-
|
234
|
-
def doc
|
235
|
-
$doc ||= begin
|
236
|
-
require "open-uri"
|
237
|
-
require "json"
|
238
|
-
|
239
|
-
JSON.parse(open("https://github.com/antirez/redis-doc/raw/master/commands.json").read)
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
task :order do
|
244
|
-
require "json"
|
245
|
-
|
246
|
-
reference = if File.exist?(".order")
|
247
|
-
JSON.parse(File.read(".order"))
|
248
|
-
else
|
249
|
-
{}
|
250
|
-
end
|
251
|
-
|
252
|
-
buckets = {}
|
253
|
-
doc.each do |k, v|
|
254
|
-
buckets[v["group"]] ||= []
|
255
|
-
buckets[v["group"]] << k.split.first.downcase
|
256
|
-
buckets[v["group"]].uniq!
|
257
|
-
end
|
258
|
-
|
259
|
-
result = (reference.keys + (buckets.keys - reference.keys)).map do |g|
|
260
|
-
[g, reference[g] + (buckets[g] - reference[g])]
|
261
|
-
end
|
262
|
-
|
263
|
-
File.open(".order", "w") do |f|
|
264
|
-
f.write(JSON.pretty_generate(Hash[result]))
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
def reorder(file, options = {})
|
269
|
-
require "json"
|
270
|
-
require "set"
|
271
|
-
|
272
|
-
STDERR.puts "reordering #{file}..."
|
273
|
-
|
274
|
-
reference = if File.exist?(".order")
|
275
|
-
JSON.parse(File.read(".order"))
|
276
|
-
else
|
277
|
-
{}
|
278
|
-
end
|
279
|
-
|
280
|
-
dst = Source.new(file, options)
|
281
|
-
|
282
|
-
src_methods = reference.map { |k, v| v }.flatten
|
283
|
-
dst_methods = dst.methods
|
284
|
-
|
285
|
-
src_set = Set.new(src_methods)
|
286
|
-
dst_set = Set.new(dst_methods)
|
287
|
-
|
288
|
-
intersection = src_set & dst_set
|
289
|
-
intersection.delete("initialize")
|
290
|
-
|
291
|
-
loop do
|
292
|
-
src_methods = reference.map { |k, v| v }.flatten
|
293
|
-
dst_methods = dst.methods
|
294
|
-
|
295
|
-
src_methods = src_methods.select do |m|
|
296
|
-
intersection.include?(m)
|
297
|
-
end
|
298
|
-
|
299
|
-
dst_methods = dst_methods.select do |m|
|
300
|
-
intersection.include?(m)
|
301
|
-
end
|
302
|
-
|
303
|
-
if src_methods == dst_methods
|
304
|
-
break
|
305
|
-
end
|
306
|
-
|
307
|
-
rv = yield(src_methods, dst_methods, dst)
|
308
|
-
break if rv == false
|
309
|
-
end
|
310
|
-
|
311
|
-
File.open(file, "w") do |f|
|
312
|
-
f.write(dst.to_s)
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
task :reorder do
|
317
|
-
blk = lambda do |src_methods, dst_methods, dst|
|
318
|
-
src_methods.zip(dst_methods).each do |a, b|
|
319
|
-
if a != b
|
320
|
-
dst.move(a, b)
|
321
|
-
break
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
reorder "lib/redis.rb", :indent => 2, &blk
|
327
|
-
reorder "lib/redis/distributed.rb", :indent => 4, &blk
|
328
|
-
end
|
329
|
-
|
330
|
-
def missing(file, options = {})
|
331
|
-
src = Source.new(file, options)
|
332
|
-
|
333
|
-
defined_methods = src.methods.map(&:downcase)
|
334
|
-
required_methods = redis_commands.map(&:downcase)
|
335
|
-
|
336
|
-
STDOUT.puts "missing in #{file}:"
|
337
|
-
STDOUT.puts (required_methods - defined_methods).inspect
|
338
|
-
end
|
339
|
-
|
340
|
-
task :missing do
|
341
|
-
missing "lib/redis.rb", :indent => 2
|
342
|
-
missing "lib/redis/distributed.rb", :indent => 4
|
343
|
-
end
|
344
|
-
|
345
|
-
def document(file)
|
346
|
-
source = File.read(file)
|
347
|
-
|
348
|
-
doc.each do |name, command|
|
349
|
-
source.sub!(/(?:^ *# .*\n)*(^ *#\n(^ *# .+?\n)*)*^( *)def #{name.downcase}(\(|$)/) do
|
350
|
-
extra_comments, indent, extra_args = $1, $3, $4
|
351
|
-
comment = "#{indent}# #{command["summary"].strip}."
|
352
|
-
|
353
|
-
IO.popen("par p#{2 + indent.size} 80", "r+") do |io|
|
354
|
-
io.puts comment
|
355
|
-
io.close_write
|
356
|
-
comment = io.read
|
357
|
-
end
|
358
|
-
|
359
|
-
"#{comment}#{extra_comments}#{indent}def #{name.downcase}#{extra_args}"
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
File.open(file, "w") { |f| f.write(source) }
|
364
|
-
end
|
365
|
-
|
366
|
-
task :doc do
|
367
|
-
document "lib/redis.rb"
|
368
|
-
document "lib/redis/distributed.rb"
|
369
|
-
end
|
370
|
-
|
371
|
-
task :verify do
|
372
|
-
require "redis"
|
373
|
-
require "stringio"
|
374
|
-
|
375
|
-
require "./test/helper"
|
376
|
-
|
377
|
-
OPTIONS[:logger] = Logger.new("./tmp/log")
|
378
|
-
|
379
|
-
Rake::Task["test:ruby"].invoke
|
380
|
-
|
381
|
-
redis = Redis.new
|
382
|
-
|
383
|
-
report = ["Command", "\033[0mDefined?\033[0m", "\033[0mTested?\033[0m"]
|
384
|
-
|
385
|
-
yes, no = "\033[1;32mYes\033[0m", "\033[1;31mNo\033[0m"
|
386
|
-
|
387
|
-
log = File.read("./tmp/log")
|
388
|
-
|
389
|
-
redis_commands.sort.each do |name, _|
|
390
|
-
defined, tested = redis.respond_to?(name), log[">> #{name.upcase}"]
|
391
|
-
|
392
|
-
next if defined && tested
|
393
|
-
|
394
|
-
report << name
|
395
|
-
report << (defined ? yes : no)
|
396
|
-
report << (tested ? yes : no)
|
397
|
-
end
|
398
|
-
|
399
|
-
IO.popen("rs 0 3", "w") do |io|
|
400
|
-
io.puts report.join("\n")
|
401
|
-
end
|
402
|
-
end
|
403
|
-
end
|
data/lib/redis.rb
CHANGED
@@ -906,6 +906,27 @@ class Redis
|
|
906
906
|
end
|
907
907
|
end
|
908
908
|
|
909
|
+
# Return the position of the first bit set to 1 or 0 in a string.
|
910
|
+
#
|
911
|
+
# @param [String] key
|
912
|
+
# @param [Fixnum] bit whether to look for the first 1 or 0 bit
|
913
|
+
# @param [Fixnum] start start index
|
914
|
+
# @param [Fixnum] stop stop index
|
915
|
+
# @return [Fixnum] the position of the first 1/0 bit.
|
916
|
+
# -1 if looking for 1 and it is not found or start and stop are given.
|
917
|
+
def bitpos(key, bit, start=nil, stop=nil)
|
918
|
+
if stop and not start
|
919
|
+
raise(ArgumentError, 'stop parameter specified without start parameter')
|
920
|
+
end
|
921
|
+
|
922
|
+
synchronize do |client|
|
923
|
+
command = [:bitpos, key, bit]
|
924
|
+
command << start if start
|
925
|
+
command << stop if stop
|
926
|
+
client.call(command)
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
909
930
|
# Set the string value of a key and return its old value.
|
910
931
|
#
|
911
932
|
# @param [String] key
|
@@ -2415,6 +2436,39 @@ class Redis
|
|
2415
2436
|
end
|
2416
2437
|
end
|
2417
2438
|
|
2439
|
+
# Add one or more members to a HyperLogLog structure.
|
2440
|
+
#
|
2441
|
+
# @param [String] key
|
2442
|
+
# @param [String, Array<String>] member one member, or array of members
|
2443
|
+
# @return [Boolean] true if at least 1 HyperLogLog internal register was altered. false otherwise.
|
2444
|
+
def pfadd(key, member)
|
2445
|
+
synchronize do |client|
|
2446
|
+
client.call([:pfadd, key, member], &_boolify)
|
2447
|
+
end
|
2448
|
+
end
|
2449
|
+
|
2450
|
+
# Get the approximate cardinality of members added to HyperLogLog structure.
|
2451
|
+
#
|
2452
|
+
# @param [String] key
|
2453
|
+
# @return [Fixnum]
|
2454
|
+
def pfcount(key)
|
2455
|
+
synchronize do |client|
|
2456
|
+
client.call([:pfcount, key])
|
2457
|
+
end
|
2458
|
+
end
|
2459
|
+
|
2460
|
+
# Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of
|
2461
|
+
# the observed Sets of the source HyperLogLog structures.
|
2462
|
+
#
|
2463
|
+
# @param [String] dest_key destination key
|
2464
|
+
# @param [String, Array<String>] source_key source key, or array of keys
|
2465
|
+
# @return [Boolean]
|
2466
|
+
def pfmerge(dest_key, *source_key)
|
2467
|
+
synchronize do |client|
|
2468
|
+
client.call([:pfmerge, dest_key, *source_key], &_boolify_set)
|
2469
|
+
end
|
2470
|
+
end
|
2471
|
+
|
2418
2472
|
def id
|
2419
2473
|
@original_client.id
|
2420
2474
|
end
|
data/lib/redis/client.rb
CHANGED
@@ -16,7 +16,9 @@ class Redis
|
|
16
16
|
:db => 0,
|
17
17
|
:driver => nil,
|
18
18
|
:id => nil,
|
19
|
-
:tcp_keepalive => 0
|
19
|
+
:tcp_keepalive => 0,
|
20
|
+
:reconnect_attempts => 1,
|
21
|
+
:inherit_socket => false
|
20
22
|
}
|
21
23
|
|
22
24
|
def options
|
@@ -59,6 +61,10 @@ class Redis
|
|
59
61
|
@options[:driver]
|
60
62
|
end
|
61
63
|
|
64
|
+
def inherit_socket?
|
65
|
+
@options[:inherit_socket]
|
66
|
+
end
|
67
|
+
|
62
68
|
attr_accessor :logger
|
63
69
|
attr_reader :connection
|
64
70
|
attr_reader :command_map
|
@@ -218,8 +224,11 @@ class Redis
|
|
218
224
|
|
219
225
|
def io
|
220
226
|
yield
|
221
|
-
rescue TimeoutError
|
222
|
-
|
227
|
+
rescue TimeoutError => e1
|
228
|
+
# Add a message to the exception without destroying the original stack
|
229
|
+
e2 = TimeoutError.new("Connection timed out")
|
230
|
+
e2.set_backtrace(e1.backtrace)
|
231
|
+
raise e2
|
223
232
|
rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EBADF, Errno::EINVAL => e
|
224
233
|
raise ConnectionError, "Connection lost (%s)" % [e.class.name.split("::").last]
|
225
234
|
end
|
@@ -271,13 +280,23 @@ class Redis
|
|
271
280
|
|
272
281
|
begin
|
273
282
|
commands.each do |name, *args|
|
274
|
-
|
283
|
+
logged_args = args.map do |a|
|
284
|
+
case
|
285
|
+
when a.respond_to?(:inspect) then a.inspect
|
286
|
+
when a.respond_to?(:to_s) then a.to_s
|
287
|
+
else
|
288
|
+
# handle poorly-behaved descendants of BasicObject
|
289
|
+
klass = a.instance_exec { (class << self; self end).superclass }
|
290
|
+
"\#<#{klass}:#{a.__id__}>"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
@logger.debug("[Redis] command=#{name.to_s.upcase} args=#{logged_args.join(' ')}")
|
275
294
|
end
|
276
295
|
|
277
296
|
t1 = Time.now
|
278
297
|
yield
|
279
298
|
ensure
|
280
|
-
@logger.debug("Redis
|
299
|
+
@logger.debug("[Redis] call_time=%0.2f ms" % ((Time.now - t1) * 1000)) if t1
|
281
300
|
end
|
282
301
|
end
|
283
302
|
|
@@ -291,26 +310,27 @@ class Redis
|
|
291
310
|
end
|
292
311
|
|
293
312
|
def ensure_connected
|
294
|
-
|
313
|
+
attempts = 0
|
295
314
|
|
296
315
|
begin
|
316
|
+
attempts += 1
|
317
|
+
|
297
318
|
if connected?
|
298
|
-
|
319
|
+
unless inherit_socket? || Process.pid == @pid
|
299
320
|
raise InheritedError,
|
300
321
|
"Tried to use a connection from a child process without reconnecting. " +
|
301
|
-
"You need to reconnect to Redis after forking
|
322
|
+
"You need to reconnect to Redis after forking " +
|
323
|
+
"or set :inherit_socket to true."
|
302
324
|
end
|
303
325
|
else
|
304
326
|
connect
|
305
327
|
end
|
306
328
|
|
307
|
-
tries += 1
|
308
|
-
|
309
329
|
yield
|
310
|
-
rescue ConnectionError
|
330
|
+
rescue ConnectionError, InheritedError
|
311
331
|
disconnect
|
312
332
|
|
313
|
-
if
|
333
|
+
if attempts <= @options[:reconnect_attempts] && @reconnect
|
314
334
|
retry
|
315
335
|
else
|
316
336
|
raise
|
@@ -359,7 +379,7 @@ class Redis
|
|
359
379
|
|
360
380
|
# Use default when option is not specified or nil
|
361
381
|
defaults.keys.each do |key|
|
362
|
-
options[key]
|
382
|
+
options[key] = defaults[key] if options[key].nil?
|
363
383
|
end
|
364
384
|
|
365
385
|
if options[:path]
|
data/lib/redis/distributed.rb
CHANGED
@@ -323,6 +323,11 @@ class Redis
|
|
323
323
|
end
|
324
324
|
end
|
325
325
|
|
326
|
+
# Return the position of the first bit set to 1 or 0 in a string.
|
327
|
+
def bitpos(key, bit, start=nil, stop=nil)
|
328
|
+
node_for(key).bitpos(key, bit, start, stop)
|
329
|
+
end
|
330
|
+
|
326
331
|
# Set the string value of a key and return its old value.
|
327
332
|
def getset(key, value)
|
328
333
|
node_for(key).getset(key, value)
|
@@ -781,6 +786,24 @@ class Redis
|
|
781
786
|
on_each_node(:script, subcommand, *args)
|
782
787
|
end
|
783
788
|
|
789
|
+
# Add one or more members to a HyperLogLog structure.
|
790
|
+
def pfadd(key, member)
|
791
|
+
node_for(key).pfadd(key, member)
|
792
|
+
end
|
793
|
+
|
794
|
+
# Get the approximate cardinality of members added to HyperLogLog structure.
|
795
|
+
def pfcount(key)
|
796
|
+
node_for(key).pfcount(key)
|
797
|
+
end
|
798
|
+
|
799
|
+
# Merge multiple HyperLogLog values into an unique value that will approximate the cardinality of the union of
|
800
|
+
# the observed Sets of the source HyperLogLog structures.
|
801
|
+
def pfmerge(dest_key, *source_key)
|
802
|
+
ensure_same_node(:pfmerge, [dest_key, *source_key]) do |node|
|
803
|
+
node.pfmerge(dest_key, *source_key)
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
784
807
|
def _eval(cmd, args)
|
785
808
|
script = args.shift
|
786
809
|
options = args.pop if args.last.is_a?(Hash)
|
data/lib/redis/version.rb
CHANGED
data/test/bitpos_test.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
unless defined?(Enumerator)
|
6
|
+
Enumerator = Enumerable::Enumerator
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestBitpos < Test::Unit::TestCase
|
10
|
+
|
11
|
+
include Helper::Client
|
12
|
+
|
13
|
+
def test_bitpos_empty_zero
|
14
|
+
target_version "2.9.11" do
|
15
|
+
r.del "foo"
|
16
|
+
assert_equal 0, r.bitpos("foo", 0)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_bitpos_empty_one
|
21
|
+
target_version "2.9.11" do
|
22
|
+
r.del "foo"
|
23
|
+
assert_equal -1, r.bitpos("foo", 1)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_bitpos_zero
|
28
|
+
target_version "2.9.11" do
|
29
|
+
r.set "foo", "\xff\xf0\x00"
|
30
|
+
assert_equal 12, r.bitpos("foo", 0)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_bitpos_one
|
35
|
+
target_version "2.9.11" do
|
36
|
+
r.set "foo", "\x00\x0f\x00"
|
37
|
+
assert_equal 12, r.bitpos("foo", 1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_bitpos_zero_end_is_given
|
42
|
+
target_version "2.9.11" do
|
43
|
+
r.set "foo", "\xff\xff\xff"
|
44
|
+
assert_equal 24, r.bitpos("foo", 0)
|
45
|
+
assert_equal 24, r.bitpos("foo", 0, 0)
|
46
|
+
assert_equal -1, r.bitpos("foo", 0, 0, -1)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_bitpos_one_intervals
|
51
|
+
target_version "2.9.11" do
|
52
|
+
r.set "foo", "\x00\xff\x00"
|
53
|
+
assert_equal 8, r.bitpos("foo", 1, 0, -1)
|
54
|
+
assert_equal 8, r.bitpos("foo", 1, 1, -1)
|
55
|
+
assert_equal -1, r.bitpos("foo", 1, 2, -1)
|
56
|
+
assert_equal -1, r.bitpos("foo", 1, 2, 200)
|
57
|
+
assert_equal 8, r.bitpos("foo", 1, 1, 1)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_bitpos_raise_exception_if_stop_not_start
|
62
|
+
target_version "2.9.11" do
|
63
|
+
assert_raises(ArgumentError) do
|
64
|
+
r.bitpos("foo", 0, nil, 2)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
+
require "lint/hyper_log_log"
|
5
|
+
|
6
|
+
class TestCommandsOnHyperLogLog < Test::Unit::TestCase
|
7
|
+
|
8
|
+
include Helper::Client
|
9
|
+
include Lint::HyperLogLog
|
10
|
+
|
11
|
+
def test_pfmerge
|
12
|
+
target_version "2.8.9" do
|
13
|
+
r.pfadd "foo", "s1"
|
14
|
+
r.pfadd "bar", "s2"
|
15
|
+
|
16
|
+
assert_equal true, r.pfmerge("res", "foo", "bar")
|
17
|
+
assert_equal 2, r.pfcount("res")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
+
require "lint/hyper_log_log"
|
5
|
+
|
6
|
+
class TestDistributedCommandsOnHyperLogLog < Test::Unit::TestCase
|
7
|
+
|
8
|
+
include Helper::Distributed
|
9
|
+
include Lint::HyperLogLog
|
10
|
+
|
11
|
+
def test_pfmerge
|
12
|
+
target_version "2.8.9" do
|
13
|
+
assert_raise Redis::Distributed::CannotDistribute do
|
14
|
+
r.pfadd "foo", "s1"
|
15
|
+
r.pfadd "bar", "s2"
|
16
|
+
|
17
|
+
assert r.pfmerge("res", "foo", "bar")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path("helper", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
class TestForkSafety < Test::Unit::TestCase
|
6
|
+
|
7
|
+
include Helper::Client
|
8
|
+
include Helper::Skipable
|
9
|
+
|
10
|
+
driver(:ruby, :hiredis) do
|
11
|
+
def test_fork_safety
|
12
|
+
redis = Redis.new(OPTIONS)
|
13
|
+
redis.set "foo", 1
|
14
|
+
|
15
|
+
child_pid = fork do
|
16
|
+
begin
|
17
|
+
# InheritedError triggers a reconnect,
|
18
|
+
# so we need to disable reconnects to force
|
19
|
+
# the exception bubble up
|
20
|
+
redis.without_reconnect do
|
21
|
+
redis.set "foo", 2
|
22
|
+
end
|
23
|
+
rescue Redis::InheritedError
|
24
|
+
exit 127
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
_, status = Process.wait2(child_pid)
|
29
|
+
|
30
|
+
assert_equal 127, status.exitstatus
|
31
|
+
assert_equal "1", redis.get("foo")
|
32
|
+
|
33
|
+
rescue NotImplementedError => error
|
34
|
+
raise unless error.message =~ /fork is not available/
|
35
|
+
return skip(error.message)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_fork_safety_with_enabled_inherited_socket
|
39
|
+
redis = Redis.new(OPTIONS.merge(:inherit_socket => true))
|
40
|
+
redis.set "foo", 1
|
41
|
+
|
42
|
+
child_pid = fork do
|
43
|
+
begin
|
44
|
+
# InheritedError triggers a reconnect,
|
45
|
+
# so we need to disable reconnects to force
|
46
|
+
# the exception bubble up
|
47
|
+
redis.without_reconnect do
|
48
|
+
redis.set "foo", 2
|
49
|
+
end
|
50
|
+
rescue Redis::InheritedError
|
51
|
+
exit 127
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
_, status = Process.wait2(child_pid)
|
56
|
+
|
57
|
+
assert_equal 0, status.exitstatus
|
58
|
+
assert_equal "2", redis.get("foo")
|
59
|
+
|
60
|
+
rescue NotImplementedError => error
|
61
|
+
raise unless error.message =~ /fork is not available/
|
62
|
+
return skip(error.message)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/test/helper.rb
CHANGED
@@ -40,14 +40,13 @@ def init(redis)
|
|
40
40
|
Make sure Redis is running on localhost, port #{PORT}.
|
41
41
|
This testing suite connects to the database 15.
|
42
42
|
|
43
|
-
|
44
|
-
visit <http://redis.io/download/>.
|
43
|
+
Try this once:
|
45
44
|
|
46
|
-
|
47
|
-
rake start
|
45
|
+
$ rake clean
|
48
46
|
|
49
|
-
|
50
|
-
|
47
|
+
Then run the build again:
|
48
|
+
|
49
|
+
$ rake
|
51
50
|
|
52
51
|
EOS
|
53
52
|
exit 1
|
@@ -215,4 +214,17 @@ module Helper
|
|
215
214
|
Redis::Distributed.new(NODES, _format_options(options).merge(:driver => ENV["conn"]))
|
216
215
|
end
|
217
216
|
end
|
217
|
+
|
218
|
+
# Basic support for `skip` in 1.8.x
|
219
|
+
# Note: YOU MUST use `return skip(message)` in order to appropriately bail
|
220
|
+
# from a running test.
|
221
|
+
module Skipable
|
222
|
+
Skipped = Class.new(RuntimeError)
|
223
|
+
|
224
|
+
def skip(message = nil, bt = caller)
|
225
|
+
return super if defined?(super)
|
226
|
+
|
227
|
+
$stderr.puts("SKIPPED: #{self} #{message || 'no reason given'}")
|
228
|
+
end
|
229
|
+
end
|
218
230
|
end
|
data/test/internals_test.rb
CHANGED
@@ -9,8 +9,8 @@ class TestInternals < Test::Unit::TestCase
|
|
9
9
|
def test_logger
|
10
10
|
r.ping
|
11
11
|
|
12
|
-
assert log.string
|
13
|
-
|
12
|
+
assert log.string["[Redis] command=PING"]
|
13
|
+
assert log.string =~ /\[Redis\] call_time=\d+\.\d+ ms/
|
14
14
|
end
|
15
15
|
|
16
16
|
def test_logger_with_pipelining
|
@@ -19,8 +19,8 @@ class TestInternals < Test::Unit::TestCase
|
|
19
19
|
r.get "foo"
|
20
20
|
end
|
21
21
|
|
22
|
-
assert log.string["SET foo bar"]
|
23
|
-
assert log.string["GET foo"]
|
22
|
+
assert log.string[" command=SET args=\"foo\" \"bar\""]
|
23
|
+
assert log.string[" command=GET args=\"foo\""]
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_recovers_from_failed_commands
|
@@ -157,7 +157,7 @@ class TestInternals < Test::Unit::TestCase
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
-
def close_on_ping(seq)
|
160
|
+
def close_on_ping(seq, options = {})
|
161
161
|
$request = 0
|
162
162
|
|
163
163
|
command = lambda do
|
@@ -169,7 +169,7 @@ class TestInternals < Test::Unit::TestCase
|
|
169
169
|
rv
|
170
170
|
end
|
171
171
|
|
172
|
-
redis_mock(:ping => command, :timeout => 0.1) do |redis|
|
172
|
+
redis_mock({:ping => command}, {:timeout => 0.1}.merge(options)) do |redis|
|
173
173
|
yield(redis)
|
174
174
|
end
|
175
175
|
end
|
@@ -218,6 +218,22 @@ class TestInternals < Test::Unit::TestCase
|
|
218
218
|
end
|
219
219
|
end
|
220
220
|
|
221
|
+
def test_retry_with_custom_reconnect_attempts
|
222
|
+
close_on_ping([0, 1], :reconnect_attempts => 2) do |redis|
|
223
|
+
assert_equal "2", redis.ping
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_retry_with_custom_reconnect_attempts_can_still_fail
|
228
|
+
close_on_ping([0, 1, 2], :reconnect_attempts => 2) do |redis|
|
229
|
+
assert_raise Redis::ConnectionError do
|
230
|
+
redis.ping
|
231
|
+
end
|
232
|
+
|
233
|
+
assert !redis.client.connected?
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
221
237
|
def test_don_t_retry_when_second_read_in_pipeline_raises_econnreset
|
222
238
|
close_on_ping([1]) do |redis|
|
223
239
|
assert_raise Redis::ConnectionError do
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Lint
|
2
|
+
|
3
|
+
module HyperLogLog
|
4
|
+
|
5
|
+
def test_pfadd
|
6
|
+
target_version "2.8.9" do
|
7
|
+
assert_equal true, r.pfadd("foo", "s1")
|
8
|
+
assert_equal true, r.pfadd("foo", "s2")
|
9
|
+
assert_equal false, r.pfadd("foo", "s1")
|
10
|
+
|
11
|
+
assert_equal 2, r.pfcount("foo")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_variadic_pfadd
|
16
|
+
target_version "2.8.9" do
|
17
|
+
assert_equal true, r.pfadd("foo", ["s1", "s2"])
|
18
|
+
assert_equal true, r.pfadd("foo", ["s1", "s2", "s3"])
|
19
|
+
|
20
|
+
assert_equal 3, r.pfcount("foo")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_pfcount
|
25
|
+
target_version "2.8.9" do
|
26
|
+
assert_equal 0, r.pfcount("foo")
|
27
|
+
|
28
|
+
assert_equal true, r.pfadd("foo", "s1")
|
29
|
+
|
30
|
+
assert_equal 1, r.pfcount("foo")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_variadic_pfcount
|
35
|
+
target_version "2.8.9" do
|
36
|
+
assert_equal 0, r.pfcount(["foo", "bar"])
|
37
|
+
|
38
|
+
assert_equal true, r.pfadd("foo", "s1")
|
39
|
+
assert_equal true, r.pfadd("bar", "s1")
|
40
|
+
assert_equal true, r.pfadd("bar", "s2")
|
41
|
+
|
42
|
+
assert_equal 2, r.pfcount(["foo", "bar"])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ezra Zygmuntowicz
|
@@ -16,26 +16,25 @@ authors:
|
|
16
16
|
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date: 2014-
|
19
|
+
date: 2014-06-06 00:00:00.000000000 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: rake
|
23
23
|
requirement: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - '>='
|
25
|
+
- - ! '>='
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
type: :development
|
29
29
|
prerelease: false
|
30
30
|
version_requirements: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - '>='
|
32
|
+
- - ! '>='
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
|
-
description:
|
36
|
-
|
37
|
-
|
38
|
-
client-side sharding, pipelining, and an obsession for performance.
|
35
|
+
description: ! " A Ruby client that tries to match Redis' API one-to-one, while
|
36
|
+
still\n providing an idiomatic interface. It features thread-safety,\n client-side
|
37
|
+
sharding, pipelining, and an obsession for performance.\n"
|
39
38
|
email:
|
40
39
|
- redis-db@googlegroups.com
|
41
40
|
executables: []
|
@@ -48,6 +47,7 @@ files:
|
|
48
47
|
- .travis/Gemfile
|
49
48
|
- .yardopts
|
50
49
|
- CHANGELOG.md
|
50
|
+
- Gemfile
|
51
51
|
- LICENSE
|
52
52
|
- README.md
|
53
53
|
- Rakefile
|
@@ -79,9 +79,11 @@ files:
|
|
79
79
|
- lib/redis/subscribe.rb
|
80
80
|
- lib/redis/version.rb
|
81
81
|
- redis.gemspec
|
82
|
+
- test/bitpos_test.rb
|
82
83
|
- test/blocking_commands_test.rb
|
83
84
|
- test/command_map_test.rb
|
84
85
|
- test/commands_on_hashes_test.rb
|
86
|
+
- test/commands_on_hyper_log_log_test.rb
|
85
87
|
- test/commands_on_lists_test.rb
|
86
88
|
- test/commands_on_sets_test.rb
|
87
89
|
- test/commands_on_sorted_sets_test.rb
|
@@ -91,6 +93,7 @@ files:
|
|
91
93
|
- test/db/.gitkeep
|
92
94
|
- test/distributed_blocking_commands_test.rb
|
93
95
|
- test/distributed_commands_on_hashes_test.rb
|
96
|
+
- test/distributed_commands_on_hyper_log_log_test.rb
|
94
97
|
- test/distributed_commands_on_lists_test.rb
|
95
98
|
- test/distributed_commands_on_sets_test.rb
|
96
99
|
- test/distributed_commands_on_sorted_sets_test.rb
|
@@ -109,11 +112,13 @@ files:
|
|
109
112
|
- test/distributed_transactions_test.rb
|
110
113
|
- test/encoding_test.rb
|
111
114
|
- test/error_replies_test.rb
|
115
|
+
- test/fork_safety_test.rb
|
112
116
|
- test/helper.rb
|
113
117
|
- test/helper_test.rb
|
114
118
|
- test/internals_test.rb
|
115
119
|
- test/lint/blocking_commands.rb
|
116
120
|
- test/lint/hashes.rb
|
121
|
+
- test/lint/hyper_log_log.rb
|
117
122
|
- test/lint/lists.rb
|
118
123
|
- test/lint/sets.rb
|
119
124
|
- test/lint/sorted_sets.rb
|
@@ -148,18 +153,83 @@ require_paths:
|
|
148
153
|
- lib
|
149
154
|
required_ruby_version: !ruby/object:Gem::Requirement
|
150
155
|
requirements:
|
151
|
-
- - '>='
|
156
|
+
- - ! '>='
|
152
157
|
- !ruby/object:Gem::Version
|
153
158
|
version: '0'
|
154
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
160
|
requirements:
|
156
|
-
- - '>='
|
161
|
+
- - ! '>='
|
157
162
|
- !ruby/object:Gem::Version
|
158
163
|
version: '0'
|
159
164
|
requirements: []
|
160
165
|
rubyforge_project:
|
161
|
-
rubygems_version: 2.
|
166
|
+
rubygems_version: 2.2.2
|
162
167
|
signing_key:
|
163
168
|
specification_version: 4
|
164
169
|
summary: A Ruby client library for Redis
|
165
|
-
test_files:
|
170
|
+
test_files:
|
171
|
+
- test/bitpos_test.rb
|
172
|
+
- test/blocking_commands_test.rb
|
173
|
+
- test/command_map_test.rb
|
174
|
+
- test/commands_on_hashes_test.rb
|
175
|
+
- test/commands_on_hyper_log_log_test.rb
|
176
|
+
- test/commands_on_lists_test.rb
|
177
|
+
- test/commands_on_sets_test.rb
|
178
|
+
- test/commands_on_sorted_sets_test.rb
|
179
|
+
- test/commands_on_strings_test.rb
|
180
|
+
- test/commands_on_value_types_test.rb
|
181
|
+
- test/connection_handling_test.rb
|
182
|
+
- test/db/.gitkeep
|
183
|
+
- test/distributed_blocking_commands_test.rb
|
184
|
+
- test/distributed_commands_on_hashes_test.rb
|
185
|
+
- test/distributed_commands_on_hyper_log_log_test.rb
|
186
|
+
- test/distributed_commands_on_lists_test.rb
|
187
|
+
- test/distributed_commands_on_sets_test.rb
|
188
|
+
- test/distributed_commands_on_sorted_sets_test.rb
|
189
|
+
- test/distributed_commands_on_strings_test.rb
|
190
|
+
- test/distributed_commands_on_value_types_test.rb
|
191
|
+
- test/distributed_commands_requiring_clustering_test.rb
|
192
|
+
- test/distributed_connection_handling_test.rb
|
193
|
+
- test/distributed_internals_test.rb
|
194
|
+
- test/distributed_key_tags_test.rb
|
195
|
+
- test/distributed_persistence_control_commands_test.rb
|
196
|
+
- test/distributed_publish_subscribe_test.rb
|
197
|
+
- test/distributed_remote_server_control_commands_test.rb
|
198
|
+
- test/distributed_scripting_test.rb
|
199
|
+
- test/distributed_sorting_test.rb
|
200
|
+
- test/distributed_test.rb
|
201
|
+
- test/distributed_transactions_test.rb
|
202
|
+
- test/encoding_test.rb
|
203
|
+
- test/error_replies_test.rb
|
204
|
+
- test/fork_safety_test.rb
|
205
|
+
- test/helper.rb
|
206
|
+
- test/helper_test.rb
|
207
|
+
- test/internals_test.rb
|
208
|
+
- test/lint/blocking_commands.rb
|
209
|
+
- test/lint/hashes.rb
|
210
|
+
- test/lint/hyper_log_log.rb
|
211
|
+
- test/lint/lists.rb
|
212
|
+
- test/lint/sets.rb
|
213
|
+
- test/lint/sorted_sets.rb
|
214
|
+
- test/lint/strings.rb
|
215
|
+
- test/lint/value_types.rb
|
216
|
+
- test/persistence_control_commands_test.rb
|
217
|
+
- test/pipelining_commands_test.rb
|
218
|
+
- test/publish_subscribe_test.rb
|
219
|
+
- test/remote_server_control_commands_test.rb
|
220
|
+
- test/scanning_test.rb
|
221
|
+
- test/scripting_test.rb
|
222
|
+
- test/sorting_test.rb
|
223
|
+
- test/support/connection/hiredis.rb
|
224
|
+
- test/support/connection/ruby.rb
|
225
|
+
- test/support/connection/synchrony.rb
|
226
|
+
- test/support/redis_mock.rb
|
227
|
+
- test/support/wire/synchrony.rb
|
228
|
+
- test/support/wire/thread.rb
|
229
|
+
- test/synchrony_driver.rb
|
230
|
+
- test/test.conf
|
231
|
+
- test/thread_safety_test.rb
|
232
|
+
- test/transactions_test.rb
|
233
|
+
- test/unknown_commands_test.rb
|
234
|
+
- test/url_param_test.rb
|
235
|
+
has_rdoc:
|