redis-store 1.4.1 → 1.5.0
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 +5 -5
- data/.gitignore +2 -0
- data/.travis.yml +20 -4
- data/Appraisals +8 -0
- data/CHANGELOG.md +18 -0
- data/Gemfile +5 -0
- data/Rakefile +8 -0
- data/gemfiles/redis_3_x.gemfile +7 -0
- data/gemfiles/redis_4_x.gemfile +7 -0
- data/lib/redis/distributed_store.rb +5 -5
- data/lib/redis/store.rb +11 -2
- data/lib/redis/store/factory.rb +23 -17
- data/lib/redis/store/namespace.rb +4 -3
- data/lib/redis/store/serialization.rb +4 -3
- data/lib/redis/store/version.rb +1 -1
- data/redis-store.gemspec +1 -0
- data/test/redis/distributed_store_test.rb +44 -0
- data/test/redis/store/factory_test.rb +20 -0
- data/test/redis/store/namespace_test.rb +27 -2
- data/test/redis/store/serialization_test.rb +23 -12
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 10e6007fb1a0708fe88d7627a23a2b5e8e0303e9ee81ec886d27a5c6fdb7ed07
|
4
|
+
data.tar.gz: 9415f933dae0284fe8114cf6d350561bc23c58bcf9f1182d734f36fdf8436707
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69a4d72561bf0b9da2c88cc7a32d37a7ca06bb758a60d338bc4c12added10c1549f818f6e0e68af3854e0911a92f591c3c3094455d731f7a48d1cb1b47a9a700
|
7
|
+
data.tar.gz: da5fee4e7926a6032ca82fa7ee924c0a676124bffb55c84d5f553f066eb0ca47678cad583403ccc5979d04b7ddcdeb98652edf906472db364713baf483bc64e3
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,19 +1,35 @@
|
|
1
1
|
language: ruby
|
2
2
|
sudo: false
|
3
3
|
cache: bundler
|
4
|
+
notifications:
|
5
|
+
webhooks: https://www.travisbuddy.com
|
6
|
+
on_success: never
|
7
|
+
|
8
|
+
# 1.9.3 has Bundler 1.7.6 with the "undefined method `spec' for nil" bug
|
4
9
|
before_install: gem install bundler
|
5
|
-
|
10
|
+
|
6
11
|
rvm:
|
7
12
|
- 1.9.3
|
8
|
-
- 2.0
|
13
|
+
- 2.0
|
9
14
|
- 2.1
|
10
15
|
- 2.2
|
11
|
-
- 2.3
|
16
|
+
- 2.3
|
17
|
+
- 2.4
|
12
18
|
- ruby-head
|
13
19
|
- jruby-head
|
14
|
-
|
20
|
+
|
21
|
+
gemfile:
|
22
|
+
- gemfiles/redis_3_x.gemfile
|
23
|
+
- gemfiles/redis_4_x.gemfile
|
15
24
|
|
16
25
|
matrix:
|
17
26
|
allow_failures:
|
18
27
|
- rvm: jruby-head
|
19
28
|
- rvm: ruby-head
|
29
|
+
exclude:
|
30
|
+
- rvm: 1.9.3
|
31
|
+
gemfile: gemfiles/redis_4_x.gemfile
|
32
|
+
- rvm: 2.0
|
33
|
+
gemfile: gemfiles/redis_4_x.gemfile
|
34
|
+
- rvm: 2.1
|
35
|
+
gemfile: gemfiles/redis_4_x.gemfile
|
data/Appraisals
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.5.0
|
4
|
+
|
5
|
+
Breaking Changes
|
6
|
+
|
7
|
+
* None
|
8
|
+
|
9
|
+
Added
|
10
|
+
|
11
|
+
* [Support for Redis v4 and above](https://github.com/redis-store/redis-store/pull/292)
|
12
|
+
* [Support for distributed mget/read_multi in Redis v4](https://github.com/redis-store/redis-store/pull/282)
|
13
|
+
* [Tests for Namespace#flushdb](https://github.com/redis-store/redis-store/pull/299)
|
14
|
+
* [Support for UNIX Socket path connections](https://github.com/redis-store/redis-store/pull/298)
|
15
|
+
* [HashRing configuration for DistributedStore](https://github.com/redis-store/redis-store/pull/304)
|
16
|
+
|
17
|
+
Fixed
|
18
|
+
|
19
|
+
* [Inefficient use of KEYS when calling FLUSHDB without a namespace](https://github.com/redis-store/redis-store/pull/297)
|
20
|
+
|
3
21
|
## 1.4.1
|
4
22
|
|
5
23
|
Breaking Changes
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -2,3 +2,11 @@ require 'bundler/setup'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'bundler/gem_tasks'
|
4
4
|
require 'redis-store/testing/tasks'
|
5
|
+
require 'appraisal'
|
6
|
+
|
7
|
+
|
8
|
+
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
9
|
+
task :default do
|
10
|
+
sh "appraisal install && rake appraisal default"
|
11
|
+
end
|
12
|
+
end
|
@@ -6,12 +6,12 @@ class Redis
|
|
6
6
|
attr_reader :ring
|
7
7
|
|
8
8
|
def initialize(addresses, options = { })
|
9
|
-
nodes = addresses.map do |address|
|
10
|
-
::Redis::Store.new _merge_options(address, options)
|
11
|
-
end
|
12
|
-
|
13
9
|
_extend_namespace options
|
14
|
-
@ring = Redis::HashRing.new
|
10
|
+
@ring = options[:ring] || Redis::HashRing.new([], options[:replicas] || Redis::HashRing::POINTS_PER_SERVER)
|
11
|
+
|
12
|
+
addresses.each do |address|
|
13
|
+
@ring.add_node(::Redis::Store.new _merge_options(address, options))
|
14
|
+
end
|
15
15
|
end
|
16
16
|
|
17
17
|
def nodes
|
data/lib/redis/store.rb
CHANGED
@@ -42,8 +42,17 @@ class Redis
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def to_s
|
45
|
-
|
46
|
-
|
45
|
+
"Redis Client connected to #{location} against DB #{@client.db}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def location
|
49
|
+
if @client.path
|
50
|
+
@client.path
|
51
|
+
else
|
52
|
+
h = @client.host
|
53
|
+
h = "[#{h}]" if h.include?(":")
|
54
|
+
"#{h}:#{@client.port}"
|
55
|
+
end
|
47
56
|
end
|
48
57
|
|
49
58
|
private
|
data/lib/redis/store/factory.rb
CHANGED
@@ -62,27 +62,33 @@ class Redis
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def self.host_options?(options)
|
65
|
-
|
66
|
-
options
|
67
|
-
else
|
68
|
-
nil # just to be clear
|
69
|
-
end
|
65
|
+
options.keys.any? {|n| [:host, :db, :port, :path].include?(n) }
|
70
66
|
end
|
71
67
|
|
72
68
|
def self.extract_host_options_from_uri(uri)
|
73
69
|
uri = URI.parse(uri)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
70
|
+
if uri.scheme == "unix"
|
71
|
+
options = { :path => uri.path }
|
72
|
+
else
|
73
|
+
_, db, namespace = if uri.path
|
74
|
+
uri.path.split(/\//)
|
75
|
+
end
|
76
|
+
|
77
|
+
options = {
|
78
|
+
:host => uri.hostname,
|
79
|
+
:port => uri.port || DEFAULT_PORT,
|
80
|
+
:password => uri.password.nil? ? nil : CGI::unescape(uri.password.to_s)
|
81
|
+
}
|
82
|
+
|
83
|
+
options[:db] = db.to_i if db
|
84
|
+
options[:namespace] = namespace if namespace
|
85
|
+
end
|
86
|
+
if uri.query
|
87
|
+
query = Hash[URI.decode_www_form(uri.query)]
|
88
|
+
query.each do |(key, value)|
|
89
|
+
options[key.to_sym] = value
|
90
|
+
end
|
91
|
+
end
|
86
92
|
|
87
93
|
options
|
88
94
|
end
|
@@ -47,14 +47,14 @@ class Redis
|
|
47
47
|
super(*keys.map {|key| interpolate(key) }) if keys.any?
|
48
48
|
end
|
49
49
|
|
50
|
-
def mget(*keys)
|
50
|
+
def mget(*keys, &blk)
|
51
51
|
options = (keys.pop if keys.last.is_a? Hash) || {}
|
52
52
|
if keys.any?
|
53
53
|
# Serialization gets extended before Namespace does, so we need to pass options further
|
54
54
|
if singleton_class.ancestors.include? Serialization
|
55
|
-
super(*keys.map {|key| interpolate(key) }, options)
|
55
|
+
super(*keys.map {|key| interpolate(key) }, options, &blk)
|
56
56
|
else
|
57
|
-
super(*keys.map {|key| interpolate(key) })
|
57
|
+
super(*keys.map {|key| interpolate(key) }, &blk)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
@@ -72,6 +72,7 @@ class Redis
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def flushdb
|
75
|
+
return super unless namespace_str
|
75
76
|
keys.each_slice(FLUSHDB_BATCH_SIZE) { |key_slice| del(*key_slice) }
|
76
77
|
end
|
77
78
|
|
@@ -17,10 +17,11 @@ class Redis
|
|
17
17
|
_unmarshal super(key), options
|
18
18
|
end
|
19
19
|
|
20
|
-
def mget(*keys)
|
20
|
+
def mget(*keys, &blk)
|
21
21
|
options = keys.pop if keys.last.is_a?(Hash)
|
22
|
-
super(*keys)
|
23
|
-
_unmarshal
|
22
|
+
super(*keys) do |reply|
|
23
|
+
reply.map! { |value| _unmarshal value, options }
|
24
|
+
blk ? blk.call(reply) : reply
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
data/lib/redis/store/version.rb
CHANGED
data/redis-store.gemspec
CHANGED
@@ -39,6 +39,50 @@ describe "Redis::DistributedStore" do
|
|
39
39
|
@dmr.get("rabbit").must_equal(@rabbit)
|
40
40
|
end
|
41
41
|
|
42
|
+
it "mget" do
|
43
|
+
@dmr.set "rabbit2", @white_rabbit
|
44
|
+
begin
|
45
|
+
@dmr.mget "rabbit", "rabbit2" do |rabbits|
|
46
|
+
rabbit, rabbit2 = rabbits
|
47
|
+
rabbits.length.must_equal(2)
|
48
|
+
rabbit.must_equal(@rabbit)
|
49
|
+
rabbit2.must_equal(@white_rabbit)
|
50
|
+
end
|
51
|
+
rescue Redis::Distributed::CannotDistribute
|
52
|
+
# Not supported on redis-rb < 4, and hence Ruby < 2.2.
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "mapped_mget" do
|
57
|
+
@dmr.set "rabbit2", @white_rabbit
|
58
|
+
begin
|
59
|
+
result = @dmr.mapped_mget("rabbit", "rabbit2")
|
60
|
+
result.keys.must_equal %w[ rabbit rabbit2 ]
|
61
|
+
result["rabbit"].must_equal @rabbit
|
62
|
+
result["rabbit2"].must_equal @white_rabbit
|
63
|
+
rescue Redis::Distributed::CannotDistribute
|
64
|
+
# Not supported on redis-rb < 4, and hence Ruby < 2.2.
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "passes through ring replica options" do
|
69
|
+
dmr = Redis::DistributedStore.new [
|
70
|
+
{:host => "localhost", :port => "6380", :db => 0},
|
71
|
+
{:host => "localhost", :port => "6381", :db => 0}
|
72
|
+
], replicas: 1024
|
73
|
+
dmr.ring.replicas.must_equal 1024
|
74
|
+
end
|
75
|
+
|
76
|
+
it "uses a custom ring object" do
|
77
|
+
my_ring = Redis::HashRing.new
|
78
|
+
dmr = Redis::DistributedStore.new [
|
79
|
+
{:host => "localhost", :port => "6380", :db => 0},
|
80
|
+
{:host => "localhost", :port => "6381", :db => 0}
|
81
|
+
], ring: my_ring
|
82
|
+
dmr.ring.must_equal my_ring
|
83
|
+
dmr.ring.nodes.length.must_equal 2
|
84
|
+
end
|
85
|
+
|
42
86
|
describe '#redis_version' do
|
43
87
|
it 'returns redis version' do
|
44
88
|
@dmr.nodes.first.expects(:redis_version)
|
@@ -22,6 +22,11 @@ describe "Redis::Store::Factory" do
|
|
22
22
|
store.to_s.must_equal("Redis Client connected to localhost:6380 against DB 0")
|
23
23
|
end
|
24
24
|
|
25
|
+
it "uses specified path" do
|
26
|
+
store = Redis::Store::Factory.create :path => "/var/run/redis.sock"
|
27
|
+
store.to_s.must_equal("Redis Client connected to /var/run/redis.sock against DB 0")
|
28
|
+
end
|
29
|
+
|
25
30
|
it "uses specified db" do
|
26
31
|
store = Redis::Store::Factory.create :host => "localhost", :port => 6380, :db => 13
|
27
32
|
store.to_s.must_equal("Redis Client connected to localhost:6380 against DB 13")
|
@@ -115,6 +120,11 @@ describe "Redis::Store::Factory" do
|
|
115
120
|
store.to_s.must_equal("Redis Client connected to 127.0.0.1:6380 against DB 0")
|
116
121
|
end
|
117
122
|
|
123
|
+
it "uses specified path" do
|
124
|
+
store = Redis::Store::Factory.create "unix:///var/run/redis.sock"
|
125
|
+
store.to_s.must_equal("Redis Client connected to /var/run/redis.sock against DB 0")
|
126
|
+
end
|
127
|
+
|
118
128
|
it "uses specified db" do
|
119
129
|
store = Redis::Store::Factory.create "redis://127.0.0.1:6380/13"
|
120
130
|
store.to_s.must_equal("Redis Client connected to 127.0.0.1:6380 against DB 13")
|
@@ -125,6 +135,16 @@ describe "Redis::Store::Factory" do
|
|
125
135
|
store.to_s.must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist")
|
126
136
|
end
|
127
137
|
|
138
|
+
it "uses specified via query namespace" do
|
139
|
+
store = Redis::Store::Factory.create "redis://127.0.0.1:6379/0?namespace=theplaylist"
|
140
|
+
store.to_s.must_equal("Redis Client connected to 127.0.0.1:6379 against DB 0 with namespace theplaylist")
|
141
|
+
end
|
142
|
+
|
143
|
+
it "uses specified namespace with path" do
|
144
|
+
store = Redis::Store::Factory.create "unix:///var/run/redis.sock?db=2&namespace=theplaylist"
|
145
|
+
store.to_s.must_equal("Redis Client connected to /var/run/redis.sock against DB 2 with namespace theplaylist")
|
146
|
+
end
|
147
|
+
|
128
148
|
it "uses specified password" do
|
129
149
|
store = Redis::Store::Factory.create "redis://:secret@127.0.0.1:6379/0/theplaylist"
|
130
150
|
store.instance_variable_get(:@client).password.must_equal("secret")
|
@@ -139,8 +139,18 @@ describe "Redis::Store::Namespace" do
|
|
139
139
|
end
|
140
140
|
|
141
141
|
it "should namespace mget" do
|
142
|
-
|
143
|
-
|
142
|
+
client.expects(:call).with([:mget, "#{@namespace}:rabbit", "#{@namespace}:white_rabbit"]).returns(%w[ foo bar ])
|
143
|
+
store.mget "rabbit", "white_rabbit" do |result|
|
144
|
+
result.must_equal(%w[ foo bar ])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should namespace mapped_mget" do
|
149
|
+
client.expects(:process).with([[:mget, "#{@namespace}:rabbit", "#{@namespace}:white_rabbit"]]).returns(%w[ foo bar ])
|
150
|
+
result = store.mapped_mget "rabbit", "white_rabbit"
|
151
|
+
result.keys.must_equal %w[ rabbit white_rabbit ]
|
152
|
+
result["rabbit"].must_equal "foo"
|
153
|
+
result["white_rabbit"].must_equal "bar"
|
144
154
|
end
|
145
155
|
|
146
156
|
it "should namespace expire" do
|
@@ -157,5 +167,20 @@ describe "Redis::Store::Namespace" do
|
|
157
167
|
client.expects(:call).with([:watch,"#{@namespace}:rabbit"]).once
|
158
168
|
store.watch("rabbit")
|
159
169
|
end
|
170
|
+
|
171
|
+
it "wraps flushdb with appropriate KEYS * calls" do
|
172
|
+
client.expects(:call).with([:flushdb]).never
|
173
|
+
client.expects(:call).with([:keys,"#{@namespace}:*"]).once.returns(["rabbit"])
|
174
|
+
client.expects(:call).with([:del,"#{@namespace}:rabbit"]).once
|
175
|
+
store.flushdb
|
176
|
+
end
|
177
|
+
|
178
|
+
it "skips flushdb wrapping if the namespace is nil" do
|
179
|
+
client.expects(:call).with([:flushdb])
|
180
|
+
client.expects(:call).with([:keys]).never
|
181
|
+
store.with_namespace(nil) do
|
182
|
+
store.flushdb
|
183
|
+
end
|
184
|
+
end
|
160
185
|
end
|
161
186
|
end
|
@@ -97,28 +97,39 @@ describe "Redis::Serialization" do
|
|
97
97
|
@store.get("rabbit", :raw => true).must_equal(%(#<OpenStruct color="white">))
|
98
98
|
end
|
99
99
|
|
100
|
-
it "
|
100
|
+
it "unmarshals on multi get" do
|
101
101
|
@store.set "rabbit2", @white_rabbit
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
102
|
+
@store.mget "rabbit", "rabbit2" do |rabbits|
|
103
|
+
rabbit, rabbit2 = rabbits
|
104
|
+
rabbits.length.must_equal(2)
|
105
|
+
rabbit.must_equal(@rabbit)
|
106
|
+
rabbit2.must_equal(@white_rabbit)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "unmarshals on mapped_mget" do
|
111
|
+
@store.set "rabbit2", @white_rabbit
|
112
|
+
result = @store.mapped_mget("rabbit", "rabbit2")
|
113
|
+
result.keys.must_equal %w[ rabbit rabbit2 ]
|
114
|
+
result["rabbit"].must_equal @rabbit
|
115
|
+
result["rabbit2"].must_equal @white_rabbit
|
107
116
|
end
|
108
117
|
|
109
118
|
if RUBY_VERSION.match /1\.9/
|
110
119
|
it "doesn't unmarshal on multi get if raw option is true" do
|
111
120
|
@store.set "rabbit2", @white_rabbit
|
112
|
-
|
113
|
-
|
114
|
-
|
121
|
+
@store.mget "rabbit", "rabbit2", :raw => true do |rabbit, rabbit2|
|
122
|
+
rabbit.must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF")
|
123
|
+
rabbit2.must_equal("\x04\bU:\x0FOpenStruct{\x06:\ncolorI\"\nwhite\x06:\x06EF")
|
124
|
+
end
|
115
125
|
end
|
116
126
|
else
|
117
127
|
it "doesn't unmarshal on multi get if raw option is true" do
|
118
128
|
@store.set "rabbit2", @white_rabbit
|
119
|
-
|
120
|
-
|
121
|
-
|
129
|
+
@store.mget "rabbit", "rabbit2", :raw => true do |rabbit, rabbit2|
|
130
|
+
rabbit.must_include("\x04\bU:\x0FOpenStruct{\x06:\tname")
|
131
|
+
rabbit2.must_include("\x04\bU:\x0FOpenStruct{\x06:\ncolor")
|
132
|
+
end
|
122
133
|
end
|
123
134
|
end
|
124
135
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -142,6 +142,20 @@ dependencies:
|
|
142
142
|
- - ">="
|
143
143
|
- !ruby/object:Gem::Version
|
144
144
|
version: '0'
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: appraisal
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '2.0'
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '2.0'
|
145
159
|
description: Namespaced Rack::Session, Rack::Cache, I18n and cache Redis stores for
|
146
160
|
Ruby web frameworks.
|
147
161
|
email:
|
@@ -152,11 +166,14 @@ extra_rdoc_files: []
|
|
152
166
|
files:
|
153
167
|
- ".gitignore"
|
154
168
|
- ".travis.yml"
|
169
|
+
- Appraisals
|
155
170
|
- CHANGELOG.md
|
156
171
|
- Gemfile
|
157
172
|
- MIT-LICENSE
|
158
173
|
- README.md
|
159
174
|
- Rakefile
|
175
|
+
- gemfiles/redis_3_x.gemfile
|
176
|
+
- gemfiles/redis_4_x.gemfile
|
160
177
|
- lib/redis-store.rb
|
161
178
|
- lib/redis/distributed_store.rb
|
162
179
|
- lib/redis/store.rb
|
@@ -198,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
215
|
version: '0'
|
199
216
|
requirements: []
|
200
217
|
rubyforge_project: redis-store
|
201
|
-
rubygems_version: 2.
|
218
|
+
rubygems_version: 2.7.3
|
202
219
|
signing_key:
|
203
220
|
specification_version: 4
|
204
221
|
summary: Redis stores for Ruby frameworks
|