renoir 0.1.1 → 0.2.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 +4 -4
- data/README.md +28 -1
- data/lib/renoir/client.rb +47 -17
- data/lib/renoir/connection_adapters/base.rb +1 -1
- data/lib/renoir/connection_adapters/redis.rb +22 -7
- data/lib/renoir/pipeline.rb +21 -0
- data/lib/renoir/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c38bafe64d4e6e17eb9e8ac7bfda4518a16831f
|
4
|
+
data.tar.gz: 934d5766ccfa78fe3d7113f937ced20a2d9e1ae5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29202c8ae95394db795908d472645f1134c04a50ead0833c6fd7c7348e3b251b4f9a9f2f12d0e91f621c041cd379430fdd0cb81e920f77467a103f629a6b73a5
|
7
|
+
data.tar.gz: 2521e02fd50177c9e2a380eb5025122177964d1d708ed4b2693873d417ec96771c27653a77271a326f4bae11b8aa9e956252dae49cce8c8c7ee0f113de89f07a
|
data/README.md
CHANGED
@@ -46,10 +46,37 @@ rc = Renoir::Client.new(
|
|
46
46
|
|
47
47
|
# redis-rb options
|
48
48
|
timeout: 100,
|
49
|
-
password: 'password'
|
49
|
+
password: 'password',
|
50
|
+
driver: :hiredis
|
50
51
|
)
|
51
52
|
```
|
52
53
|
|
54
|
+
### Pipelining
|
55
|
+
|
56
|
+
Command pipelining is supported although "future" variable is not available at this point.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
rc.pipeliend do |pipeline|
|
60
|
+
pipeline.set('hoge{1}', 123)
|
61
|
+
pipeline.get('hoge{1}')
|
62
|
+
pipeline.get('fuga{1}')
|
63
|
+
end
|
64
|
+
# => ["OK", "123", nil]
|
65
|
+
```
|
66
|
+
|
67
|
+
If pipelined commands use different slot of key, it fails without dispatching command.
|
68
|
+
|
69
|
+
You can also execute commands atomically with `#multi`:
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
rc.multi do |pipeline|
|
73
|
+
pipeline.set('hoge{1}', 123)
|
74
|
+
pipeline.get('hoge{1}')
|
75
|
+
pipeline.get('fuga{1}')
|
76
|
+
end
|
77
|
+
# => ["OK", "123", nil]
|
78
|
+
```
|
79
|
+
|
53
80
|
### Dispatch command to nodes directly
|
54
81
|
|
55
82
|
Renoir dispatches a command only if a slot is determined by the command. This also includes no-keys commands like `KEYS`, `BGSAVE` and so on.
|
data/lib/renoir/client.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require "renoir/cluster_info"
|
3
|
+
require "renoir/pipeline"
|
3
4
|
require "renoir/connection_adapters"
|
4
5
|
require "renoir/crc16"
|
5
6
|
|
@@ -50,23 +51,30 @@ module Renoir
|
|
50
51
|
end
|
51
52
|
|
52
53
|
def eval(*args, &block)
|
53
|
-
call(eval, *args, &block)
|
54
|
+
call(:eval, *args, &block)
|
54
55
|
end
|
55
56
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
fail "No way to dispatch this command to Redis Cluster." if slots.size != 1
|
60
|
-
slot = slots.first
|
57
|
+
def multi(&block)
|
58
|
+
commands = pipeline_commands(&block)
|
59
|
+
slot = get_slot_from_commands(commands)
|
61
60
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
61
|
+
refresh_slots
|
62
|
+
call_with_redirection(slot, [[:multi]] + commands + [[:exec]])
|
63
|
+
end
|
64
|
+
|
65
|
+
def pipelined(&block)
|
66
|
+
commands = pipeline_commands(&block)
|
67
|
+
slot = get_slot_from_commands(commands)
|
68
|
+
|
69
|
+
refresh_slots
|
70
|
+
call_with_redirection(slot, commands)
|
71
|
+
end
|
72
|
+
|
73
|
+
def call(*command, &block)
|
74
|
+
slot = get_slot_from_commands([command])
|
68
75
|
|
69
|
-
|
76
|
+
refresh_slots
|
77
|
+
call_with_redirection(slot, [command], &block)[0]
|
70
78
|
end
|
71
79
|
|
72
80
|
def close
|
@@ -102,7 +110,22 @@ module Renoir
|
|
102
110
|
CRC16.crc16(key) % REDIS_CLUSTER_HASH_SLOTS
|
103
111
|
end
|
104
112
|
|
105
|
-
def
|
113
|
+
def get_slot_from_commands(commands)
|
114
|
+
keys = commands.flat_map { |command| @adapter_class.get_keys_from_command(command) }.uniq
|
115
|
+
slots = keys.map { |key| key_slot(key) }.uniq
|
116
|
+
fail "No way to dispatch this command to Redis Cluster." if slots.size != 1
|
117
|
+
slots.first
|
118
|
+
end
|
119
|
+
|
120
|
+
def pipeline_commands(&block)
|
121
|
+
pipeline = Pipeline.new(
|
122
|
+
connection_adapter: @options[:connection_adapter]
|
123
|
+
)
|
124
|
+
yield pipeline
|
125
|
+
pipeline.commands
|
126
|
+
end
|
127
|
+
|
128
|
+
def call_with_redirection(slot, commands, &block)
|
106
129
|
nodes = @cluster_info.nodes.dup
|
107
130
|
node = @cluster_info.slot_node(slot) || nodes.sample
|
108
131
|
|
@@ -114,7 +137,7 @@ module Renoir
|
|
114
137
|
nodes.delete(node)
|
115
138
|
|
116
139
|
conn = fetch_connection(node)
|
117
|
-
reply = conn.call(
|
140
|
+
reply = conn.call(commands, asking, &block)
|
118
141
|
case reply
|
119
142
|
when ConnectionAdapters::Reply::RedirectionError
|
120
143
|
asking = reply.ask
|
@@ -140,10 +163,17 @@ module Renoir
|
|
140
163
|
end
|
141
164
|
|
142
165
|
def refresh_slots
|
166
|
+
refresh = @refresh_slots_mutex.synchronize do
|
167
|
+
refresh = @refresh_slots
|
168
|
+
@refresh_slots = false
|
169
|
+
refresh
|
170
|
+
end
|
171
|
+
return unless refresh
|
172
|
+
|
143
173
|
slots = nil
|
144
174
|
@cluster_info.nodes.each do |node|
|
145
175
|
conn = fetch_connection(node)
|
146
|
-
reply = conn.call(["cluster", "slots"])
|
176
|
+
reply = conn.call([["cluster", "slots"]])
|
147
177
|
case reply
|
148
178
|
when ConnectionAdapters::Reply::RedirectionError
|
149
179
|
fail "never reach here"
|
@@ -152,7 +182,7 @@ module Renoir
|
|
152
182
|
@logger.warn("CLUSTER SLOTS command failed: node_name=#{node[:name]}, message=#{reply.cause}")
|
153
183
|
end
|
154
184
|
else
|
155
|
-
slots = reply
|
185
|
+
slots = reply[0]
|
156
186
|
break
|
157
187
|
end
|
158
188
|
end
|
@@ -59,15 +59,30 @@ module Renoir
|
|
59
59
|
@conn = ::Redis.new(options.merge(host: host, port: port))
|
60
60
|
end
|
61
61
|
|
62
|
-
def call(
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
def call(commands, asking=false, &block)
|
63
|
+
if commands[0][0].to_sym == :multi
|
64
|
+
fail 'EXEC command is required for MULTI' if commands[-1][0].to_sym != :exec
|
65
|
+
commands = commands[1..-2]
|
66
|
+
multi = true
|
67
|
+
end
|
68
|
+
|
69
|
+
if multi || asking
|
70
|
+
replies = @conn.multi do |tx|
|
71
|
+
tx.asking if asking
|
72
|
+
commands.each do |command, *args|
|
73
|
+
tx.send(command, *args, &block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
asking ? replies.slice(1..-1) : replies
|
77
|
+
elsif commands.size > 1
|
78
|
+
@conn.pipelined do |pipeline|
|
79
|
+
commands.each do |command, *args|
|
80
|
+
pipeline.send(command, *args, &block)
|
81
|
+
end
|
68
82
|
end
|
69
83
|
else
|
70
|
-
|
84
|
+
command, *args = commands[0]
|
85
|
+
[@conn.send(command, *args, &block)]
|
71
86
|
end
|
72
87
|
rescue ::Redis::CommandError => e
|
73
88
|
errv = e.to_s.split
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Renoir
|
2
|
+
class Pipeline
|
3
|
+
attr_reader :commands
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
@commands = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def eval(*args)
|
10
|
+
call(:eval, *args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(*command)
|
14
|
+
@commands << command
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(command, *args, &block)
|
18
|
+
call(command, *args, &block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/renoir/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: renoir
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroshi Saito
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-01-
|
11
|
+
date: 2017-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- lib/renoir/connection_adapters/redis.rb
|
91
91
|
- lib/renoir/connection_adapters/reply.rb
|
92
92
|
- lib/renoir/crc16.rb
|
93
|
+
- lib/renoir/pipeline.rb
|
93
94
|
- lib/renoir/version.rb
|
94
95
|
- renoir.gemspec
|
95
96
|
homepage: https://github.com/saidie/renoir
|
@@ -112,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
113
|
version: '0'
|
113
114
|
requirements: []
|
114
115
|
rubyforge_project:
|
115
|
-
rubygems_version: 2.5.
|
116
|
+
rubygems_version: 2.5.1
|
116
117
|
signing_key:
|
117
118
|
specification_version: 4
|
118
119
|
summary: Reliable Redis Cluster client library
|