redis 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +8 -0
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +190 -0
  4. data/Rakefile +194 -79
  5. data/benchmarking/logging.rb +62 -0
  6. data/benchmarking/pipeline.rb +51 -0
  7. data/benchmarking/speed.rb +21 -0
  8. data/benchmarking/suite.rb +24 -0
  9. data/benchmarking/thread_safety.rb +38 -0
  10. data/benchmarking/worker.rb +71 -0
  11. data/examples/basic.rb +15 -0
  12. data/examples/dist_redis.rb +43 -0
  13. data/examples/incr-decr.rb +17 -0
  14. data/examples/list.rb +26 -0
  15. data/examples/pubsub.rb +31 -0
  16. data/examples/sets.rb +36 -0
  17. data/examples/unicorn/config.ru +3 -0
  18. data/examples/unicorn/unicorn.rb +20 -0
  19. data/lib/redis.rb +612 -156
  20. data/lib/redis/client.rb +98 -57
  21. data/lib/redis/connection.rb +9 -134
  22. data/lib/redis/connection/command_helper.rb +45 -0
  23. data/lib/redis/connection/hiredis.rb +49 -0
  24. data/lib/redis/connection/registry.rb +12 -0
  25. data/lib/redis/connection/ruby.rb +131 -0
  26. data/lib/redis/connection/synchrony.rb +125 -0
  27. data/lib/redis/distributed.rb +161 -5
  28. data/lib/redis/pipeline.rb +6 -0
  29. data/lib/redis/version.rb +3 -0
  30. data/redis.gemspec +24 -0
  31. data/test/commands_on_hashes_test.rb +32 -0
  32. data/test/commands_on_lists_test.rb +60 -0
  33. data/test/commands_on_sets_test.rb +78 -0
  34. data/test/commands_on_sorted_sets_test.rb +109 -0
  35. data/test/commands_on_strings_test.rb +80 -0
  36. data/test/commands_on_value_types_test.rb +88 -0
  37. data/test/connection_handling_test.rb +87 -0
  38. data/test/db/.gitignore +1 -0
  39. data/test/distributed_blocking_commands_test.rb +53 -0
  40. data/test/distributed_commands_on_hashes_test.rb +12 -0
  41. data/test/distributed_commands_on_lists_test.rb +24 -0
  42. data/test/distributed_commands_on_sets_test.rb +85 -0
  43. data/test/distributed_commands_on_strings_test.rb +50 -0
  44. data/test/distributed_commands_on_value_types_test.rb +73 -0
  45. data/test/distributed_commands_requiring_clustering_test.rb +148 -0
  46. data/test/distributed_connection_handling_test.rb +25 -0
  47. data/test/distributed_internals_test.rb +18 -0
  48. data/test/distributed_key_tags_test.rb +53 -0
  49. data/test/distributed_persistence_control_commands_test.rb +24 -0
  50. data/test/distributed_publish_subscribe_test.rb +101 -0
  51. data/test/distributed_remote_server_control_commands_test.rb +31 -0
  52. data/test/distributed_sorting_test.rb +21 -0
  53. data/test/distributed_test.rb +60 -0
  54. data/test/distributed_transactions_test.rb +34 -0
  55. data/test/encoding_test.rb +16 -0
  56. data/test/error_replies_test.rb +53 -0
  57. data/test/helper.rb +145 -0
  58. data/test/internals_test.rb +157 -0
  59. data/test/lint/hashes.rb +114 -0
  60. data/test/lint/internals.rb +41 -0
  61. data/test/lint/lists.rb +93 -0
  62. data/test/lint/sets.rb +66 -0
  63. data/test/lint/sorted_sets.rb +167 -0
  64. data/test/lint/strings.rb +137 -0
  65. data/test/lint/value_types.rb +84 -0
  66. data/test/persistence_control_commands_test.rb +22 -0
  67. data/test/pipelining_commands_test.rb +123 -0
  68. data/test/publish_subscribe_test.rb +158 -0
  69. data/test/redis_mock.rb +80 -0
  70. data/test/remote_server_control_commands_test.rb +63 -0
  71. data/test/sorting_test.rb +44 -0
  72. data/test/synchrony_driver.rb +57 -0
  73. data/test/test.conf +8 -0
  74. data/test/thread_safety_test.rb +30 -0
  75. data/test/transactions_test.rb +100 -0
  76. data/test/unknown_commands_test.rb +14 -0
  77. data/test/url_param_test.rb +60 -0
  78. metadata +128 -19
  79. data/README.markdown +0 -129
@@ -0,0 +1,12 @@
1
+ class Redis
2
+ module Connection
3
+
4
+ # Store a list of loaded connection drivers in the Connection module.
5
+ # Redis::Client uses the last required driver by default, and will be aware
6
+ # of the loaded connection drivers if the user chooses to override the
7
+ # default connection driver.
8
+ def self.drivers
9
+ @drivers ||= []
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,131 @@
1
+ require "redis/connection/registry"
2
+ require "redis/connection/command_helper"
3
+ require "socket"
4
+
5
+ class Redis
6
+ module Connection
7
+ class Ruby
8
+ include Redis::Connection::CommandHelper
9
+
10
+ MINUS = "-".freeze
11
+ PLUS = "+".freeze
12
+ COLON = ":".freeze
13
+ DOLLAR = "$".freeze
14
+ ASTERISK = "*".freeze
15
+
16
+ def initialize
17
+ @sock = nil
18
+ end
19
+
20
+ def connected?
21
+ !! @sock
22
+ end
23
+
24
+ def connect(host, port, timeout)
25
+ with_timeout(timeout.to_f / 1_000_000) do
26
+ @sock = TCPSocket.new(host, port)
27
+ @sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
28
+ end
29
+ end
30
+
31
+ def connect_unix(path, timeout)
32
+ with_timeout(timeout.to_f / 1_000_000) do
33
+ @sock = UNIXSocket.new(path)
34
+ end
35
+ end
36
+
37
+ def disconnect
38
+ @sock.close
39
+ rescue
40
+ ensure
41
+ @sock = nil
42
+ end
43
+
44
+ def timeout=(usecs)
45
+ secs = Integer(usecs / 1_000_000)
46
+ usecs = Integer(usecs - (secs * 1_000_000)) # 0 - 999_999
47
+
48
+ optval = [secs, usecs].pack("l_2")
49
+
50
+ begin
51
+ @sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
52
+ @sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
53
+ rescue Errno::ENOPROTOOPT
54
+ end
55
+ end
56
+
57
+ def write(command)
58
+ @sock.syswrite(build_command(*command).join(COMMAND_DELIMITER))
59
+ end
60
+
61
+ def read
62
+ # We read the first byte using read() mainly because gets() is
63
+ # immune to raw socket timeouts.
64
+ reply_type = @sock.read(1)
65
+
66
+ raise Errno::ECONNRESET unless reply_type
67
+
68
+ format_reply(reply_type, @sock.gets)
69
+ end
70
+
71
+ def format_reply(reply_type, line)
72
+ case reply_type
73
+ when MINUS then format_error_reply(line)
74
+ when PLUS then format_status_reply(line)
75
+ when COLON then format_integer_reply(line)
76
+ when DOLLAR then format_bulk_reply(line)
77
+ when ASTERISK then format_multi_bulk_reply(line)
78
+ else raise ProtocolError.new(reply_type)
79
+ end
80
+ end
81
+
82
+ def format_error_reply(line)
83
+ RuntimeError.new(line.strip)
84
+ end
85
+
86
+ def format_status_reply(line)
87
+ line.strip
88
+ end
89
+
90
+ def format_integer_reply(line)
91
+ line.to_i
92
+ end
93
+
94
+ def format_bulk_reply(line)
95
+ bulklen = line.to_i
96
+ return if bulklen == -1
97
+ reply = encode(@sock.read(bulklen))
98
+ @sock.read(2) # Discard CRLF.
99
+ reply
100
+ end
101
+
102
+ def format_multi_bulk_reply(line)
103
+ n = line.to_i
104
+ return if n == -1
105
+
106
+ Array.new(n) { read }
107
+ end
108
+
109
+ protected
110
+
111
+ begin
112
+ require "system_timer"
113
+
114
+ def with_timeout(seconds, &block)
115
+ SystemTimer.timeout_after(seconds, &block)
116
+ end
117
+
118
+ rescue LoadError
119
+ warn "WARNING: using the built-in Timeout class which is known to have issues when used for opening connections. Install the SystemTimer gem if you want to make sure the Redis client will not hang." unless RUBY_VERSION >= "1.9" || RUBY_PLATFORM =~ /java/
120
+
121
+ require "timeout"
122
+
123
+ def with_timeout(seconds, &block)
124
+ Timeout.timeout(seconds, &block)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ Redis::Connection.drivers << Redis::Connection::Ruby
@@ -0,0 +1,125 @@
1
+ require "redis/connection/command_helper"
2
+ require "redis/connection/registry"
3
+ require "em-synchrony"
4
+ require "hiredis/reader"
5
+
6
+ class Redis
7
+ module Connection
8
+ class RedisClient < EventMachine::Connection
9
+ include EventMachine::Deferrable
10
+
11
+ def post_init
12
+ @req = nil
13
+ @reader = ::Hiredis::Reader.new
14
+ end
15
+
16
+ def connection_completed
17
+ succeed
18
+ end
19
+
20
+ def receive_data(data)
21
+ @reader.feed(data)
22
+
23
+ begin
24
+ until (reply = @reader.gets) == false
25
+ @req.succeed [:reply, reply]
26
+ end
27
+ rescue RuntimeError => err
28
+ @req.fail [:error, ::Redis::ProtocolError.new(err.message)]
29
+ end
30
+ end
31
+
32
+ def read
33
+ @req = EventMachine::DefaultDeferrable.new
34
+ EventMachine::Synchrony.sync @req
35
+ end
36
+
37
+ def send(data)
38
+ callback { send_data data }
39
+ end
40
+
41
+ def unbind
42
+ if @req
43
+ @req.fail [:error, Errno::ECONNRESET]
44
+ @req = nil
45
+ else
46
+ fail
47
+ end
48
+ end
49
+ end
50
+
51
+ class Synchrony
52
+ include Redis::Connection::CommandHelper
53
+
54
+ def initialize
55
+ @timeout = 5_000_000
56
+ @state = :disconnected
57
+ @connection = nil
58
+ end
59
+
60
+ def connected?
61
+ @state == :connected
62
+ end
63
+
64
+ def timeout=(usecs)
65
+ @timeout = usecs
66
+ end
67
+
68
+ def connect(host, port, timeout)
69
+ conn = EventMachine.connect(host, port, RedisClient) do |c|
70
+ c.pending_connect_timeout = [Float(timeout / 1_000_000), 0.1].max
71
+ end
72
+
73
+ setup_connect_callbacks(conn, Fiber.current)
74
+ end
75
+
76
+ def connect_unix(path, timeout)
77
+ conn = EventMachine.connect_unix_domain(path, RedisClient)
78
+ setup_connect_callbacks(conn, Fiber.current)
79
+ end
80
+
81
+ def disconnect
82
+ @state = :disconnected
83
+ @connection.close_connection
84
+ @connection = nil
85
+ end
86
+
87
+ def write(command)
88
+ @connection.send(build_command(*command).join(COMMAND_DELIMITER))
89
+ end
90
+
91
+ def read
92
+ type, payload = @connection.read
93
+
94
+ if type == :reply
95
+ payload
96
+ elsif type == :error
97
+ raise payload
98
+ else
99
+ raise "Unknown type #{type.inspect}"
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def setup_connect_callbacks(conn, f)
106
+ conn.callback do
107
+ @connection = conn
108
+ @state = :connected
109
+ f.resume conn
110
+ end
111
+
112
+ conn.errback do
113
+ @connection = conn
114
+ f.resume :refused
115
+ end
116
+
117
+ r = Fiber.yield
118
+ raise Errno::ECONNREFUSED if r == :refused
119
+ r
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ Redis::Connection.drivers << Redis::Connection::Synchrony
@@ -23,7 +23,7 @@ class Redis
23
23
  end
24
24
 
25
25
  def node_for(key)
26
- @ring.get_node(key_tag(key) || key)
26
+ @ring.get_node(key_tag(key.to_s) || key.to_s)
27
27
  end
28
28
 
29
29
  def nodes
@@ -34,94 +34,139 @@ class Redis
34
34
  @ring.add_node Redis.connect(@default_options.merge(:url => url))
35
35
  end
36
36
 
37
+ # Close the connection.
37
38
  def quit
38
39
  on_each_node :quit
39
40
  end
40
41
 
42
+ # Change the selected database for the current connection.
41
43
  def select(db)
42
44
  on_each_node :select, db
43
45
  end
44
46
 
47
+ # Ping the server.
45
48
  def ping
46
49
  on_each_node :ping
47
50
  end
48
51
 
52
+ # Remove all keys from all databases.
49
53
  def flushall
50
54
  on_each_node :flushall
51
55
  end
52
56
 
57
+ # Determine if a key exists.
53
58
  def exists(key)
54
59
  node_for(key).exists(key)
55
60
  end
56
61
 
57
- def del(*keys)
58
- on_each_node(:del, *keys)
62
+ # Delete a key.
63
+ def del(*args)
64
+ keys_per_node = args.group_by { |key| node_for(key) }
65
+ keys_per_node.inject(0) do |sum, (node, keys)|
66
+ sum + node.del(*keys)
67
+ end
59
68
  end
60
69
 
70
+ # Determine the type stored at key.
61
71
  def type(key)
62
72
  node_for(key).type(key)
63
73
  end
64
74
 
75
+ # Find all keys matching the given pattern.
65
76
  def keys(glob = "*")
66
77
  on_each_node(:keys, glob).flatten
67
78
  end
68
79
 
80
+ # Return a random key from the keyspace.
69
81
  def randomkey
70
82
  raise CannotDistribute, :randomkey
71
83
  end
72
84
 
85
+ # Rename a key.
73
86
  def rename(old_name, new_name)
74
87
  ensure_same_node(:rename, old_name, new_name) do |node|
75
88
  node.rename(old_name, new_name)
76
89
  end
77
90
  end
78
91
 
92
+ # Rename a key, only if the new key does not exist.
79
93
  def renamenx(old_name, new_name)
80
94
  ensure_same_node(:renamenx, old_name, new_name) do |node|
81
95
  node.renamenx(old_name, new_name)
82
96
  end
83
97
  end
84
98
 
99
+ # Return the number of keys in the selected database.
85
100
  def dbsize
86
101
  on_each_node :dbsize
87
102
  end
88
103
 
104
+ # Set a key's time to live in seconds.
89
105
  def expire(key, seconds)
90
106
  node_for(key).expire(key, seconds)
91
107
  end
92
108
 
109
+ # Set the expiration for a key as a UNIX timestamp.
93
110
  def expireat(key, unix_time)
94
111
  node_for(key).expireat(key, unix_time)
95
112
  end
96
113
 
114
+ # Remove the expiration from a key.
97
115
  def persist(key)
98
116
  node_for(key).persist(key)
99
117
  end
100
118
 
119
+ # Get the time to live for a key.
101
120
  def ttl(key)
102
121
  node_for(key).ttl(key)
103
122
  end
104
123
 
124
+ # Move a key to another database.
105
125
  def move(key, db)
106
126
  node_for(key).move(key, db)
107
127
  end
108
128
 
129
+ # Remove all keys from the current database.
109
130
  def flushdb
110
131
  on_each_node :flushdb
111
132
  end
112
133
 
134
+ # Set the string value of a key.
113
135
  def set(key, value)
114
136
  node_for(key).set(key, value)
115
137
  end
116
138
 
139
+ # Sets or clears the bit at offset in the string value stored at key.
140
+ def setbit(key, offset, value)
141
+ node_for(key).setbit(key, offset, value)
142
+ end
143
+
144
+ # Overwrite part of a string at key starting at the specified offset.
145
+ def setrange(key, offset, value)
146
+ node_for(key).setrange(key, offset, value)
147
+ end
148
+
149
+ # Set the value and expiration of a key.
117
150
  def setex(key, ttl, value)
118
151
  node_for(key).setex(key, ttl, value)
119
152
  end
120
153
 
154
+ # Get the value of a key.
121
155
  def get(key)
122
156
  node_for(key).get(key)
123
157
  end
124
158
 
159
+ # Returns the bit value at offset in the string value stored at key.
160
+ def getbit(key, offset)
161
+ node_for(key).getbit(key, offset)
162
+ end
163
+
164
+ # Get a substring of the string stored at a key.
165
+ def getrange(key, start, stop)
166
+ node_for(key).getrange(key, start, stop)
167
+ end
168
+
169
+ # Set the string value of a key and return its old value.
125
170
  def getset(key, value)
126
171
  node_for(key).getset(key, value)
127
172
  end
@@ -130,6 +175,7 @@ class Redis
130
175
  get(key)
131
176
  end
132
177
 
178
+ # Append a value to a key.
133
179
  def append(key, value)
134
180
  node_for(key).append(key, value)
135
181
  end
@@ -142,6 +188,7 @@ class Redis
142
188
  set(key, value)
143
189
  end
144
190
 
191
+ # Get the values of all the given keys.
145
192
  def mget(*keys)
146
193
  raise CannotDistribute, :mget
147
194
  end
@@ -150,10 +197,12 @@ class Redis
150
197
  raise CannotDistribute, :mapped_mget
151
198
  end
152
199
 
200
+ # Set the value of a key, only if the key does not exist.
153
201
  def setnx(key, value)
154
202
  node_for(key).setnx(key, value)
155
203
  end
156
204
 
205
+ # Set multiple keys to multiple values.
157
206
  def mset(*args)
158
207
  raise CannotDistribute, :mset
159
208
  end
@@ -162,6 +211,7 @@ class Redis
162
211
  mset(*hash.to_a.flatten)
163
212
  end
164
213
 
214
+ # Set multiple keys to multiple values, only if none of the keys exist.
165
215
  def msetnx(*args)
166
216
  raise CannotDistribute, :msetnx
167
217
  end
@@ -170,246 +220,335 @@ class Redis
170
220
  raise CannotDistribute, :mapped_msetnx
171
221
  end
172
222
 
223
+ # Increment the integer value of a key by one.
173
224
  def incr(key)
174
225
  node_for(key).incr(key)
175
226
  end
176
227
 
228
+ # Increment the integer value of a key by the given number.
177
229
  def incrby(key, increment)
178
230
  node_for(key).incrby(key, increment)
179
231
  end
180
232
 
233
+ # Decrement the integer value of a key by one.
181
234
  def decr(key)
182
235
  node_for(key).decr(key)
183
236
  end
184
237
 
238
+ # Decrement the integer value of a key by the given number.
185
239
  def decrby(key, decrement)
186
240
  node_for(key).decrby(key, decrement)
187
241
  end
188
242
 
243
+ # Append a value to a list.
189
244
  def rpush(key, value)
190
245
  node_for(key).rpush(key, value)
191
246
  end
192
247
 
248
+ # Prepend a value to a list.
193
249
  def lpush(key, value)
194
250
  node_for(key).lpush(key, value)
195
251
  end
196
252
 
253
+ # Get the length of a list.
197
254
  def llen(key)
198
255
  node_for(key).llen(key)
199
256
  end
200
257
 
258
+ # Get a range of elements from a list.
201
259
  def lrange(key, start, stop)
202
260
  node_for(key).lrange(key, start, stop)
203
261
  end
204
262
 
263
+ # Trim a list to the specified range.
205
264
  def ltrim(key, start, stop)
206
265
  node_for(key).ltrim(key, start, stop)
207
266
  end
208
267
 
268
+ # Get an element from a list by its index.
209
269
  def lindex(key, index)
210
270
  node_for(key).lindex(key, index)
211
271
  end
212
272
 
273
+ # Set the value of an element in a list by its index.
213
274
  def lset(key, index, value)
214
275
  node_for(key).lset(key, index, value)
215
276
  end
216
277
 
278
+ # Remove elements from a list.
217
279
  def lrem(key, count, value)
218
280
  node_for(key).lrem(key, count, value)
219
281
  end
220
282
 
283
+ # Remove and get the first element in a list.
221
284
  def lpop(key)
222
285
  node_for(key).lpop(key)
223
286
  end
224
287
 
288
+ # Remove and get the last element in a list.
225
289
  def rpop(key)
226
290
  node_for(key).rpop(key)
227
291
  end
228
292
 
293
+ # Remove the last element in a list, append it to another list and return
294
+ # it.
229
295
  def rpoplpush(source, destination)
230
296
  ensure_same_node(:rpoplpush, source, destination) do |node|
231
297
  node.rpoplpush(source, destination)
232
298
  end
233
299
  end
234
300
 
301
+ # Remove and get the first element in a list, or block until one is
302
+ # available.
235
303
  def blpop(key, timeout)
236
304
  node_for(key).blpop(key, timeout)
237
305
  end
238
306
 
307
+ # Remove and get the last element in a list, or block until one is
308
+ # available.
239
309
  def brpop(key, timeout)
240
310
  node_for(key).brpop(key, timeout)
241
311
  end
242
312
 
313
+ # Pop a value from a list, push it to another list and return it; or block
314
+ # until one is available.
315
+ def brpoplpush(source, destination, timeout)
316
+ ensure_same_node(:brpoplpush, source, destination) do |node|
317
+ node.brpoplpush(source, destination, timeout)
318
+ end
319
+ end
320
+
321
+ # Add a member to a set.
243
322
  def sadd(key, value)
244
323
  node_for(key).sadd(key, value)
245
324
  end
246
325
 
326
+ # Remove a member from a set.
247
327
  def srem(key, value)
248
328
  node_for(key).srem(key, value)
249
329
  end
250
330
 
331
+ # Remove and return a random member from a set.
251
332
  def spop(key)
252
333
  node_for(key).spop(key)
253
334
  end
254
335
 
336
+ # Move a member from one set to another.
255
337
  def smove(source, destination, member)
256
338
  ensure_same_node(:smove, source, destination) do |node|
257
339
  node.smove(source, destination, member)
258
340
  end
259
341
  end
260
342
 
343
+ # Get the number of members in a set.
261
344
  def scard(key)
262
345
  node_for(key).scard(key)
263
346
  end
264
347
 
348
+ # Determine if a given value is a member of a set.
265
349
  def sismember(key, member)
266
350
  node_for(key).sismember(key, member)
267
351
  end
268
352
 
353
+ # Intersect multiple sets.
269
354
  def sinter(*keys)
270
355
  ensure_same_node(:sinter, *keys) do |node|
271
356
  node.sinter(*keys)
272
357
  end
273
358
  end
274
359
 
360
+ # Intersect multiple sets and store the resulting set in a key.
275
361
  def sinterstore(destination, *keys)
276
362
  ensure_same_node(:sinterstore, destination, *keys) do |node|
277
363
  node.sinterstore(destination, *keys)
278
364
  end
279
365
  end
280
366
 
367
+ # Add multiple sets.
281
368
  def sunion(*keys)
282
369
  ensure_same_node(:sunion, *keys) do |node|
283
370
  node.sunion(*keys)
284
371
  end
285
372
  end
286
373
 
374
+ # Add multiple sets and store the resulting set in a key.
287
375
  def sunionstore(destination, *keys)
288
376
  ensure_same_node(:sunionstore, destination, *keys) do |node|
289
377
  node.sunionstore(destination, *keys)
290
378
  end
291
379
  end
292
380
 
381
+ # Subtract multiple sets.
293
382
  def sdiff(*keys)
294
383
  ensure_same_node(:sdiff, *keys) do |node|
295
384
  node.sdiff(*keys)
296
385
  end
297
386
  end
298
387
 
388
+ # Subtract multiple sets and store the resulting set in a key.
299
389
  def sdiffstore(destination, *keys)
300
390
  ensure_same_node(:sdiffstore, destination, *keys) do |node|
301
391
  node.sdiffstore(destination, *keys)
302
392
  end
303
393
  end
304
394
 
395
+ # Get all the members in a set.
305
396
  def smembers(key)
306
397
  node_for(key).smembers(key)
307
398
  end
308
399
 
400
+ # Get a random member from a set.
309
401
  def srandmember(key)
310
402
  node_for(key).srandmember(key)
311
403
  end
312
404
 
405
+ # Add a member to a sorted set, or update its score if it already exists.
313
406
  def zadd(key, score, member)
314
407
  node_for(key).zadd(key, score, member)
315
408
  end
316
409
 
410
+ # Remove a member from a sorted set.
317
411
  def zrem(key, member)
318
412
  node_for(key).zrem(key, member)
319
413
  end
320
414
 
415
+ # Increment the score of a member in a sorted set.
321
416
  def zincrby(key, increment, member)
322
417
  node_for(key).zincrby(key, increment, member)
323
418
  end
324
419
 
420
+ # Return a range of members in a sorted set, by index.
325
421
  def zrange(key, start, stop, options = {})
326
422
  node_for(key).zrange(key, start, stop, options)
327
423
  end
328
424
 
425
+ # Determine the index of a member in a sorted set.
329
426
  def zrank(key, member)
330
427
  node_for(key).zrank(key, member)
331
428
  end
332
429
 
430
+ # Determine the index of a member in a sorted set, with scores ordered from
431
+ # high to low.
333
432
  def zrevrank(key, member)
334
433
  node_for(key).zrevrank(key, member)
335
434
  end
336
435
 
436
+ # Return a range of members in a sorted set, by index, with scores ordered
437
+ # from high to low.
337
438
  def zrevrange(key, start, stop, options = {})
338
439
  node_for(key).zrevrange(key, start, stop, options)
339
440
  end
340
441
 
442
+ # Remove all members in a sorted set within the given scores.
341
443
  def zremrangebyscore(key, min, max)
342
444
  node_for(key).zremrangebyscore(key, min, max)
343
445
  end
344
446
 
447
+ # Remove all members in a sorted set within the given indexes.
345
448
  def zremrangebyrank(key, start, stop)
346
449
  node_for(key).zremrangebyrank(key, start, stop)
347
450
  end
348
451
 
452
+ # Return a range of members in a sorted set, by score.
349
453
  def zrangebyscore(key, min, max, options = {})
350
454
  node_for(key).zrangebyscore(key, min, max, options)
351
455
  end
352
456
 
457
+ # Return a range of members in a sorted set, by score, with scores ordered
458
+ # from high to low.
459
+ def zrevrangebyscore(key, max, min, options = {})
460
+ node_for(key).zrevrangebyscore(key, max, min, options)
461
+ end
462
+
463
+ # Get the number of members in a sorted set.
353
464
  def zcard(key)
354
465
  node_for(key).zcard(key)
355
466
  end
356
467
 
468
+ # Get the score associated with the given member in a sorted set.
357
469
  def zscore(key, member)
358
470
  node_for(key).zscore(key, member)
359
471
  end
360
472
 
473
+ # Intersect multiple sorted sets and store the resulting sorted set in a new
474
+ # key.
361
475
  def zinterstore(destination, keys, options = {})
362
476
  ensure_same_node(:zinterstore, destination, *keys) do |node|
363
477
  node.zinterstore(destination, keys, options)
364
478
  end
365
479
  end
366
480
 
481
+ # Add multiple sorted sets and store the resulting sorted set in a new key.
367
482
  def zunionstore(destination, keys, options = {})
368
483
  ensure_same_node(:zunionstore, destination, *keys) do |node|
369
484
  node.zunionstore(destination, keys, options)
370
485
  end
371
486
  end
372
487
 
488
+ # Set the string value of a hash field.
373
489
  def hset(key, field, value)
374
490
  node_for(key).hset(key, field, value)
375
491
  end
376
492
 
493
+ # Get the value of a hash field.
377
494
  def hget(key, field)
378
495
  node_for(key).hget(key, field)
379
496
  end
380
497
 
498
+ # Delete a hash field.
381
499
  def hdel(key, field)
382
500
  node_for(key).hdel(key, field)
383
501
  end
384
502
 
503
+ # Determine if a hash field exists.
385
504
  def hexists(key, field)
386
505
  node_for(key).hexists(key, field)
387
506
  end
388
507
 
508
+ # Get the number of fields in a hash.
389
509
  def hlen(key)
390
510
  node_for(key).hlen(key)
391
511
  end
392
512
 
513
+ # Get all the fields in a hash.
393
514
  def hkeys(key)
394
515
  node_for(key).hkeys(key)
395
516
  end
396
517
 
518
+ # Get all the values in a hash.
397
519
  def hvals(key)
398
520
  node_for(key).hvals(key)
399
521
  end
400
522
 
523
+ # Get all the fields and values in a hash.
401
524
  def hgetall(key)
402
525
  node_for(key).hgetall(key)
403
526
  end
404
527
 
528
+ # Set multiple hash fields to multiple values.
405
529
  def hmset(key, *attrs)
406
530
  node_for(key).hmset(key, *attrs)
407
531
  end
408
532
 
533
+ def mapped_hmset(key, hash)
534
+ node_for(key).hmset(key, *hash.to_a.flatten)
535
+ end
536
+
537
+ # Get the values of all the given hash fields.
538
+ def hmget(key, *fields)
539
+ node_for(key).hmget(key, *fields)
540
+ end
541
+
542
+ def mapped_hmget(key, *fields)
543
+ Hash[*fields.zip(hmget(key, *fields)).flatten]
544
+ end
545
+
546
+ # Increment the integer value of a hash field by the given number.
409
547
  def hincrby(key, field, increment)
410
548
  node_for(key).hincrby(key, field, increment)
411
549
  end
412
550
 
551
+ # Sort the elements in a list, set or sorted set.
413
552
  def sort(key, options = {})
414
553
  keys = [key, options[:by], options[:store], *Array(options[:get])].compact
415
554
 
@@ -418,26 +557,32 @@ class Redis
418
557
  end
419
558
  end
420
559
 
421
- def multi(&block)
560
+ # Mark the start of a transaction block.
561
+ def multi
422
562
  raise CannotDistribute, :multi
423
563
  end
424
564
 
565
+ # Watch the given keys to determine execution of the MULTI/EXEC block.
425
566
  def watch(*keys)
426
567
  raise CannotDistribute, :watch
427
568
  end
428
569
 
570
+ # Forget about all watched keys.
429
571
  def unwatch
430
572
  raise CannotDistribute, :unwatch
431
573
  end
432
574
 
575
+ # Execute all commands issued after MULTI.
433
576
  def exec
434
577
  raise CannotDistribute, :exec
435
578
  end
436
579
 
580
+ # Discard all commands issued after MULTI.
437
581
  def discard
438
582
  raise CannotDistribute, :discard
439
583
  end
440
584
 
585
+ # Post a message to a channel.
441
586
  def publish(channel, message)
442
587
  node_for(channel).publish(channel, message)
443
588
  end
@@ -446,11 +591,13 @@ class Redis
446
591
  !! @subscribed_node
447
592
  end
448
593
 
594
+ # Stop listening for messages posted to the given channels.
449
595
  def unsubscribe(*channels)
450
596
  raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
451
597
  @subscribed_node.unsubscribe(*channels)
452
598
  end
453
599
 
600
+ # Listen for messages published to the given channels.
454
601
  def subscribe(channel, *channels, &block)
455
602
  if channels.empty?
456
603
  @subscribed_node = node_for(channel)
@@ -463,34 +610,43 @@ class Redis
463
610
  end
464
611
  end
465
612
 
613
+ # Stop listening for messages posted to channels matching the given
614
+ # patterns.
466
615
  def punsubscribe(*channels)
467
616
  raise NotImplementedError
468
617
  end
469
618
 
619
+ # Listen for messages published to channels matching the given patterns.
470
620
  def psubscribe(*channels, &block)
471
621
  raise NotImplementedError
472
622
  end
473
623
 
624
+ # Synchronously save the dataset to disk.
474
625
  def save
475
626
  on_each_node :save
476
627
  end
477
628
 
629
+ # Asynchronously save the dataset to disk.
478
630
  def bgsave
479
631
  on_each_node :bgsave
480
632
  end
481
633
 
634
+ # Get the UNIX time stamp of the last successful save to disk.
482
635
  def lastsave
483
636
  on_each_node :lastsave
484
637
  end
485
638
 
639
+ # Get information and statistics about the server.
486
640
  def info
487
641
  on_each_node :info
488
642
  end
489
643
 
644
+ # Listen for all requests received by the server in real time.
490
645
  def monitor
491
646
  raise NotImplementedError
492
647
  end
493
648
 
649
+ # Echo the given string.
494
650
  def echo(value)
495
651
  on_each_node :echo, value
496
652
  end
@@ -512,7 +668,7 @@ class Redis
512
668
  end
513
669
 
514
670
  def key_tag(key)
515
- key[@tag, 1] if @tag
671
+ key.to_s[@tag, 1] if @tag
516
672
  end
517
673
 
518
674
  def ensure_same_node(command, *keys)