redis 2.1.1 → 2.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.
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,3 @@
1
+ run lambda { |env|
2
+ [200, {"Content-Type" => "text/plain"}, [$redis.randomkey]]
3
+ }
@@ -0,0 +1,20 @@
1
+ require "redis"
2
+
3
+ worker_processes 3
4
+
5
+ # If you set the connection to Redis *before* forking,
6
+ # you will cause forks to share a file descriptor.
7
+ #
8
+ # This causes a concurrency problem by which one fork
9
+ # can read or write to the socket while others are
10
+ # performing other operations.
11
+ #
12
+ # Most likely you'll be getting ProtocolError exceptions
13
+ # mentioning a wrong initial byte in the reply.
14
+ #
15
+ # Thus we need to connect to Redis after forking the
16
+ # worker processes.
17
+
18
+ after_fork do |server, worker|
19
+ $redis = Redis.connect
20
+ end
@@ -1,8 +1,6 @@
1
- require 'socket'
1
+ require "monitor"
2
2
 
3
3
  class Redis
4
- VERSION = "2.1.1"
5
-
6
4
  class ProtocolError < RuntimeError
7
5
  def initialize(reply_type)
8
6
  super(<<-EOS.gsub(/(?:^|\n)\s*/, " "))
@@ -15,6 +13,12 @@ class Redis
15
13
  end
16
14
  end
17
15
 
16
+ module DisableThreadSafety
17
+ def synchronize
18
+ yield
19
+ end
20
+ end
21
+
18
22
  def self.deprecate(message, trace = caller[0])
19
23
  $stderr.puts "\n#{message} (in #{trace})"
20
24
  end
@@ -44,414 +48,770 @@ class Redis
44
48
  Thread.current[:redis] = redis
45
49
  end
46
50
 
51
+ include MonitorMixin
52
+
47
53
  def initialize(options = {})
48
- if options[:thread_safe]
49
- @client = Client::ThreadSafe.new(options)
54
+ @client = Client.new(options)
55
+
56
+ if options[:thread_safe] == false
57
+ # Override #synchronize
58
+ extend DisableThreadSafety
50
59
  else
51
- @client = Client.new(options)
60
+ # Monitor#initialize
61
+ super()
52
62
  end
53
63
  end
54
64
 
65
+ # Run code without the client reconnecting
66
+ def without_reconnect(&block)
67
+ synchronize do
68
+ @client.without_reconnect(&block)
69
+ end
70
+ end
71
+
72
+ # Authenticate to the server.
55
73
  def auth(password)
56
- @client.call(:auth, password)
74
+ synchronize do
75
+ @client.call(:auth, password)
76
+ end
57
77
  end
58
78
 
79
+ # Change the selected database for the current connection.
59
80
  def select(db)
60
- @client.db = db
61
- @client.call(:select, db)
81
+ synchronize do
82
+ @client.db = db
83
+ @client.call(:select, db)
84
+ end
62
85
  end
63
86
 
87
+ # Get information and statistics about the server.
64
88
  def info
65
- Hash[*@client.call(:info).split(/:|\r\n/)]
89
+ synchronize do
90
+ reply = @client.call(:info)
91
+
92
+ if reply.kind_of?(String)
93
+ Hash[*reply.split(/:|\r\n/).grep(/^[^#]/)]
94
+ else
95
+ reply
96
+ end
97
+ end
66
98
  end
67
99
 
68
100
  def config(action, *args)
69
- response = @client.call(:config, action, *args)
70
- response = Hash[*response] if action == :get
71
- response
101
+ synchronize do
102
+ reply = @client.call(:config, action, *args)
103
+
104
+ if reply.kind_of?(Array) && action == :get
105
+ Hash[*reply]
106
+ else
107
+ reply
108
+ end
109
+ end
72
110
  end
73
111
 
112
+ # Remove all keys from the current database.
74
113
  def flushdb
75
- @client.call(:flushdb)
114
+ synchronize do
115
+ @client.call(:flushdb)
116
+ end
76
117
  end
77
118
 
119
+ # Remove all keys from all databases.
78
120
  def flushall
79
- @client.call(:flushall)
121
+ synchronize do
122
+ @client.call(:flushall)
123
+ end
80
124
  end
81
125
 
126
+ # Synchronously save the dataset to disk.
82
127
  def save
83
- @client.call(:save)
128
+ synchronize do
129
+ @client.call(:save)
130
+ end
84
131
  end
85
132
 
133
+ # Asynchronously save the dataset to disk.
86
134
  def bgsave
87
- @client.call(:bgsave)
135
+ synchronize do
136
+ @client.call(:bgsave)
137
+ end
88
138
  end
89
139
 
140
+ # Asynchronously rewrite the append-only file.
90
141
  def bgrewriteaof
91
- @client.call(:bgrewriteaof)
142
+ synchronize do
143
+ @client.call(:bgrewriteaof)
144
+ end
92
145
  end
93
146
 
147
+ # Get the value of a key.
94
148
  def get(key)
95
- @client.call(:get, key)
149
+ synchronize do
150
+ @client.call(:get, key)
151
+ end
96
152
  end
97
153
 
154
+ # Returns the bit value at offset in the string value stored at key.
155
+ def getbit(key, offset)
156
+ synchronize do
157
+ @client.call(:getbit, key, offset)
158
+ end
159
+ end
160
+
161
+ # Get a substring of the string stored at a key.
162
+ def getrange(key, start, stop)
163
+ synchronize do
164
+ @client.call(:getrange, key, start, stop)
165
+ end
166
+ end
167
+
168
+ # Set the string value of a key and return its old value.
98
169
  def getset(key, value)
99
- @client.call(:getset, key, value)
170
+ synchronize do
171
+ @client.call(:getset, key, value)
172
+ end
100
173
  end
101
174
 
175
+ # Get the values of all the given keys.
102
176
  def mget(*keys)
103
- @client.call(:mget, *keys)
177
+ synchronize do
178
+ @client.call(:mget, *keys)
179
+ end
104
180
  end
105
181
 
182
+ # Append a value to a key.
106
183
  def append(key, value)
107
- @client.call(:append, key, value)
184
+ synchronize do
185
+ @client.call(:append, key, value)
186
+ end
108
187
  end
109
188
 
110
189
  def substr(key, start, stop)
111
- @client.call(:substr, key, start, stop)
190
+ synchronize do
191
+ @client.call(:substr, key, start, stop)
192
+ end
112
193
  end
113
194
 
195
+ # Get the length of the value stored in a key.
114
196
  def strlen(key)
115
- @client.call(:strlen, key)
197
+ synchronize do
198
+ @client.call(:strlen, key)
199
+ end
116
200
  end
117
201
 
202
+ # Get all the fields and values in a hash.
118
203
  def hgetall(key)
119
- Hash[*@client.call(:hgetall, key)]
204
+ synchronize do
205
+ reply = @client.call(:hgetall, key)
206
+
207
+ if reply.kind_of?(Array)
208
+ Hash[*reply]
209
+ else
210
+ reply
211
+ end
212
+ end
120
213
  end
121
214
 
215
+ # Get the value of a hash field.
122
216
  def hget(key, field)
123
- @client.call(:hget, key, field)
217
+ synchronize do
218
+ @client.call(:hget, key, field)
219
+ end
124
220
  end
125
221
 
222
+ # Delete a hash field.
126
223
  def hdel(key, field)
127
- @client.call(:hdel, key, field)
224
+ synchronize do
225
+ @client.call(:hdel, key, field)
226
+ end
128
227
  end
129
228
 
229
+ # Get all the fields in a hash.
130
230
  def hkeys(key)
131
- @client.call(:hkeys, key)
231
+ synchronize do
232
+ @client.call(:hkeys, key)
233
+ end
132
234
  end
133
235
 
236
+ # Find all keys matching the given pattern.
134
237
  def keys(pattern = "*")
135
- _array @client.call(:keys, pattern)
238
+ synchronize do
239
+ reply = @client.call(:keys, pattern)
240
+
241
+ if reply.kind_of?(String)
242
+ reply.split(" ")
243
+ else
244
+ reply
245
+ end
246
+ end
136
247
  end
137
248
 
249
+ # Return a random key from the keyspace.
138
250
  def randomkey
139
- @client.call(:randomkey)
251
+ synchronize do
252
+ @client.call(:randomkey)
253
+ end
140
254
  end
141
255
 
256
+ # Echo the given string.
142
257
  def echo(value)
143
- @client.call(:echo, value)
258
+ synchronize do
259
+ @client.call(:echo, value)
260
+ end
144
261
  end
145
262
 
263
+ # Ping the server.
146
264
  def ping
147
- @client.call(:ping)
265
+ synchronize do
266
+ @client.call(:ping)
267
+ end
148
268
  end
149
269
 
270
+ # Get the UNIX time stamp of the last successful save to disk.
150
271
  def lastsave
151
- @client.call(:lastsave)
272
+ synchronize do
273
+ @client.call(:lastsave)
274
+ end
152
275
  end
153
276
 
277
+ # Return the number of keys in the selected database.
154
278
  def dbsize
155
- @client.call(:dbsize)
279
+ synchronize do
280
+ @client.call(:dbsize)
281
+ end
156
282
  end
157
283
 
284
+ # Determine if a key exists.
158
285
  def exists(key)
159
- _bool @client.call(:exists, key)
286
+ synchronize do
287
+ _bool @client.call(:exists, key)
288
+ end
160
289
  end
161
290
 
291
+ # Get the length of a list.
162
292
  def llen(key)
163
- @client.call(:llen, key)
293
+ synchronize do
294
+ @client.call(:llen, key)
295
+ end
164
296
  end
165
297
 
298
+ # Get a range of elements from a list.
166
299
  def lrange(key, start, stop)
167
- @client.call(:lrange, key, start, stop)
300
+ synchronize do
301
+ @client.call(:lrange, key, start, stop)
302
+ end
168
303
  end
169
304
 
305
+ # Trim a list to the specified range.
170
306
  def ltrim(key, start, stop)
171
- @client.call(:ltrim, key, start, stop)
307
+ synchronize do
308
+ @client.call(:ltrim, key, start, stop)
309
+ end
172
310
  end
173
311
 
312
+ # Get an element from a list by its index.
174
313
  def lindex(key, index)
175
- @client.call(:lindex, key, index)
314
+ synchronize do
315
+ @client.call(:lindex, key, index)
316
+ end
176
317
  end
177
318
 
319
+ # Insert an element before or after another element in a list.
178
320
  def linsert(key, where, pivot, value)
179
- @client.call(:linsert, key, where, pivot, value)
321
+ synchronize do
322
+ @client.call(:linsert, key, where, pivot, value)
323
+ end
180
324
  end
181
325
 
326
+ # Set the value of an element in a list by its index.
182
327
  def lset(key, index, value)
183
- @client.call(:lset, key, index, value)
328
+ synchronize do
329
+ @client.call(:lset, key, index, value)
330
+ end
184
331
  end
185
332
 
333
+ # Remove elements from a list.
186
334
  def lrem(key, count, value)
187
- @client.call(:lrem, key, count, value)
335
+ synchronize do
336
+ @client.call(:lrem, key, count, value)
337
+ end
188
338
  end
189
339
 
340
+ # Append a value to a list.
190
341
  def rpush(key, value)
191
- @client.call(:rpush, key, value)
342
+ synchronize do
343
+ @client.call(:rpush, key, value)
344
+ end
192
345
  end
193
346
 
347
+ # Append a value to a list, only if the list exists.
194
348
  def rpushx(key, value)
195
- @client.call(:rpushx, key, value)
349
+ synchronize do
350
+ @client.call(:rpushx, key, value)
351
+ end
196
352
  end
197
353
 
354
+ # Prepend a value to a list.
198
355
  def lpush(key, value)
199
- @client.call(:lpush, key, value)
356
+ synchronize do
357
+ @client.call(:lpush, key, value)
358
+ end
200
359
  end
201
360
 
361
+ # Prepend a value to a list, only if the list exists.
202
362
  def lpushx(key, value)
203
- @client.call(:lpushx, key, value)
363
+ synchronize do
364
+ @client.call(:lpushx, key, value)
365
+ end
204
366
  end
205
367
 
368
+ # Remove and get the last element in a list.
206
369
  def rpop(key)
207
- @client.call(:rpop, key)
370
+ synchronize do
371
+ @client.call(:rpop, key)
372
+ end
208
373
  end
209
374
 
375
+ # Remove and get the first element in a list, or block until one is available.
210
376
  def blpop(*args)
211
- @client.call_without_timeout(:blpop, *args)
377
+ synchronize do
378
+ @client.call_without_timeout(:blpop, *args)
379
+ end
212
380
  end
213
381
 
382
+ # Remove and get the last element in a list, or block until one is available.
214
383
  def brpop(*args)
215
- @client.call_without_timeout(:brpop, *args)
384
+ synchronize do
385
+ @client.call_without_timeout(:brpop, *args)
386
+ end
387
+ end
388
+
389
+ # Pop a value from a list, push it to another list and return it; or block
390
+ # until one is available.
391
+ def brpoplpush(source, destination, timeout)
392
+ synchronize do
393
+ @client.call_without_timeout(:brpoplpush, source, destination, timeout)
394
+ end
216
395
  end
217
396
 
397
+ # Remove the last element in a list, append it to another list and return it.
218
398
  def rpoplpush(source, destination)
219
- @client.call(:rpoplpush, source, destination)
399
+ synchronize do
400
+ @client.call(:rpoplpush, source, destination)
401
+ end
220
402
  end
221
403
 
404
+ # Remove and get the first element in a list.
222
405
  def lpop(key)
223
- @client.call(:lpop, key)
406
+ synchronize do
407
+ @client.call(:lpop, key)
408
+ end
224
409
  end
225
410
 
411
+ # Get all the members in a set.
226
412
  def smembers(key)
227
- @client.call(:smembers, key)
413
+ synchronize do
414
+ @client.call(:smembers, key)
415
+ end
228
416
  end
229
417
 
418
+ # Determine if a given value is a member of a set.
230
419
  def sismember(key, member)
231
- _bool @client.call(:sismember, key, member)
420
+ synchronize do
421
+ _bool @client.call(:sismember, key, member)
422
+ end
232
423
  end
233
424
 
425
+ # Add a member to a set.
234
426
  def sadd(key, value)
235
- _bool @client.call(:sadd, key, value)
427
+ synchronize do
428
+ _bool @client.call(:sadd, key, value)
429
+ end
236
430
  end
237
431
 
432
+ # Remove a member from a set.
238
433
  def srem(key, value)
239
- _bool @client.call(:srem, key, value)
434
+ synchronize do
435
+ _bool @client.call(:srem, key, value)
436
+ end
240
437
  end
241
438
 
439
+ # Move a member from one set to another.
242
440
  def smove(source, destination, member)
243
- _bool @client.call(:smove, source, destination, member)
441
+ synchronize do
442
+ _bool @client.call(:smove, source, destination, member)
443
+ end
244
444
  end
245
445
 
446
+ # Remove and return a random member from a set.
246
447
  def spop(key)
247
- @client.call(:spop, key)
448
+ synchronize do
449
+ @client.call(:spop, key)
450
+ end
248
451
  end
249
452
 
453
+ # Get the number of members in a set.
250
454
  def scard(key)
251
- @client.call(:scard, key)
455
+ synchronize do
456
+ @client.call(:scard, key)
457
+ end
252
458
  end
253
459
 
460
+ # Intersect multiple sets.
254
461
  def sinter(*keys)
255
- @client.call(:sinter, *keys)
462
+ synchronize do
463
+ @client.call(:sinter, *keys)
464
+ end
256
465
  end
257
466
 
467
+ # Intersect multiple sets and store the resulting set in a key.
258
468
  def sinterstore(destination, *keys)
259
- @client.call(:sinterstore, destination, *keys)
469
+ synchronize do
470
+ @client.call(:sinterstore, destination, *keys)
471
+ end
260
472
  end
261
473
 
474
+ # Add multiple sets.
262
475
  def sunion(*keys)
263
- @client.call(:sunion, *keys)
476
+ synchronize do
477
+ @client.call(:sunion, *keys)
478
+ end
264
479
  end
265
480
 
481
+ # Add multiple sets and store the resulting set in a key.
266
482
  def sunionstore(destination, *keys)
267
- @client.call(:sunionstore, destination, *keys)
483
+ synchronize do
484
+ @client.call(:sunionstore, destination, *keys)
485
+ end
268
486
  end
269
487
 
488
+ # Subtract multiple sets.
270
489
  def sdiff(*keys)
271
- @client.call(:sdiff, *keys)
490
+ synchronize do
491
+ @client.call(:sdiff, *keys)
492
+ end
272
493
  end
273
494
 
495
+ # Subtract multiple sets and store the resulting set in a key.
274
496
  def sdiffstore(destination, *keys)
275
- @client.call(:sdiffstore, destination, *keys)
497
+ synchronize do
498
+ @client.call(:sdiffstore, destination, *keys)
499
+ end
276
500
  end
277
501
 
502
+ # Get a random member from a set.
278
503
  def srandmember(key)
279
- @client.call(:srandmember, key)
504
+ synchronize do
505
+ @client.call(:srandmember, key)
506
+ end
280
507
  end
281
508
 
509
+ # Add a member to a sorted set, or update its score if it already exists.
282
510
  def zadd(key, score, member)
283
- _bool @client.call(:zadd, key, score, member)
511
+ synchronize do
512
+ _bool @client.call(:zadd, key, score, member)
513
+ end
284
514
  end
285
515
 
516
+ # Determine the index of a member in a sorted set.
286
517
  def zrank(key, member)
287
- @client.call(:zrank, key, member)
518
+ synchronize do
519
+ @client.call(:zrank, key, member)
520
+ end
288
521
  end
289
522
 
523
+ # Determine the index of a member in a sorted set, with scores ordered from
524
+ # high to low.
290
525
  def zrevrank(key, member)
291
- @client.call(:zrevrank, key, member)
526
+ synchronize do
527
+ @client.call(:zrevrank, key, member)
528
+ end
292
529
  end
293
530
 
531
+ # Increment the score of a member in a sorted set.
294
532
  def zincrby(key, increment, member)
295
- @client.call(:zincrby, key, increment, member)
533
+ synchronize do
534
+ @client.call(:zincrby, key, increment, member)
535
+ end
296
536
  end
297
537
 
538
+ # Get the number of members in a sorted set.
298
539
  def zcard(key)
299
- @client.call(:zcard, key)
540
+ synchronize do
541
+ @client.call(:zcard, key)
542
+ end
300
543
  end
301
544
 
545
+ # Return a range of members in a sorted set, by index.
302
546
  def zrange(key, start, stop, options = {})
303
547
  command = CommandOptions.new(options) do |c|
548
+ c.bool :withscores
304
549
  c.bool :with_scores
305
550
  end
306
551
 
307
- @client.call(:zrange, key, start, stop, *command.to_a)
552
+ synchronize do
553
+ @client.call(:zrange, key, start, stop, *command.to_a)
554
+ end
308
555
  end
309
556
 
557
+ # Return a range of members in a sorted set, by score.
310
558
  def zrangebyscore(key, min, max, options = {})
311
559
  command = CommandOptions.new(options) do |c|
312
560
  c.splat :limit
561
+ c.bool :withscores
313
562
  c.bool :with_scores
314
563
  end
315
564
 
316
- @client.call(:zrangebyscore, key, min, max, *command.to_a)
565
+ synchronize do
566
+ @client.call(:zrangebyscore, key, min, max, *command.to_a)
567
+ end
317
568
  end
318
569
 
570
+ # Count the members in a sorted set with scores within the given values.
319
571
  def zcount(key, start, stop)
320
- @client.call(:zcount, key, start, stop)
572
+ synchronize do
573
+ @client.call(:zcount, key, start, stop)
574
+ end
321
575
  end
322
576
 
577
+ # Return a range of members in a sorted set, by index, with scores ordered
578
+ # from high to low.
323
579
  def zrevrange(key, start, stop, options = {})
324
580
  command = CommandOptions.new(options) do |c|
581
+ c.bool :withscores
325
582
  c.bool :with_scores
326
583
  end
327
584
 
328
- @client.call(:zrevrange, key, start, stop, *command.to_a)
585
+ synchronize do
586
+ @client.call(:zrevrange, key, start, stop, *command.to_a)
587
+ end
329
588
  end
330
589
 
590
+ # Return a range of members in a sorted set, by score, with scores ordered
591
+ # from high to low.
592
+ def zrevrangebyscore(key, max, min, options = {})
593
+ command = CommandOptions.new(options) do |c|
594
+ c.splat :limit
595
+ c.bool :withscores
596
+ c.bool :with_scores
597
+ end
598
+
599
+ synchronize do
600
+ @client.call(:zrevrangebyscore, key, max, min, *command.to_a)
601
+ end
602
+ end
603
+
604
+ # Remove all members in a sorted set within the given scores.
331
605
  def zremrangebyscore(key, min, max)
332
- @client.call(:zremrangebyscore, key, min, max)
606
+ synchronize do
607
+ @client.call(:zremrangebyscore, key, min, max)
608
+ end
333
609
  end
334
610
 
611
+ # Remove all members in a sorted set within the given indexes.
335
612
  def zremrangebyrank(key, start, stop)
336
- @client.call(:zremrangebyrank, key, start, stop)
613
+ synchronize do
614
+ @client.call(:zremrangebyrank, key, start, stop)
615
+ end
337
616
  end
338
617
 
618
+ # Get the score associated with the given member in a sorted set.
339
619
  def zscore(key, member)
340
- @client.call(:zscore, key, member)
620
+ synchronize do
621
+ @client.call(:zscore, key, member)
622
+ end
341
623
  end
342
624
 
625
+ # Remove a member from a sorted set.
343
626
  def zrem(key, member)
344
- _bool @client.call(:zrem, key, member)
627
+ synchronize do
628
+ _bool @client.call(:zrem, key, member)
629
+ end
345
630
  end
346
631
 
632
+ # Intersect multiple sorted sets and store the resulting sorted set in a new
633
+ # key.
347
634
  def zinterstore(destination, keys, options = {})
348
635
  command = CommandOptions.new(options) do |c|
349
636
  c.splat :weights
350
637
  c.value :aggregate
351
638
  end
352
639
 
353
- @client.call(:zinterstore, destination, keys.size, *(keys + command.to_a))
640
+ synchronize do
641
+ @client.call(:zinterstore, destination, keys.size, *(keys + command.to_a))
642
+ end
354
643
  end
355
644
 
645
+ # Add multiple sorted sets and store the resulting sorted set in a new key.
356
646
  def zunionstore(destination, keys, options = {})
357
647
  command = CommandOptions.new(options) do |c|
358
648
  c.splat :weights
359
649
  c.value :aggregate
360
650
  end
361
651
 
362
- @client.call(:zunionstore, destination, keys.size, *(keys + command.to_a))
652
+ synchronize do
653
+ @client.call(:zunionstore, destination, keys.size, *(keys + command.to_a))
654
+ end
363
655
  end
364
656
 
657
+ # Move a key to another database.
365
658
  def move(key, db)
366
- _bool @client.call(:move, key, db)
659
+ synchronize do
660
+ _bool @client.call(:move, key, db)
661
+ end
367
662
  end
368
663
 
664
+ # Set the value of a key, only if the key does not exist.
369
665
  def setnx(key, value)
370
- _bool @client.call(:setnx, key, value)
666
+ synchronize do
667
+ _bool @client.call(:setnx, key, value)
668
+ end
371
669
  end
372
670
 
671
+ # Delete a key.
373
672
  def del(*keys)
374
- @client.call(:del, *keys)
673
+ synchronize do
674
+ @client.call(:del, *keys)
675
+ end
375
676
  end
376
677
 
678
+ # Rename a key.
377
679
  def rename(old_name, new_name)
378
- @client.call(:rename, old_name, new_name)
680
+ synchronize do
681
+ @client.call(:rename, old_name, new_name)
682
+ end
379
683
  end
380
684
 
685
+ # Rename a key, only if the new key does not exist.
381
686
  def renamenx(old_name, new_name)
382
- _bool @client.call(:renamenx, old_name, new_name)
687
+ synchronize do
688
+ _bool @client.call(:renamenx, old_name, new_name)
689
+ end
383
690
  end
384
691
 
692
+ # Set a key's time to live in seconds.
385
693
  def expire(key, seconds)
386
- _bool @client.call(:expire, key, seconds)
694
+ synchronize do
695
+ _bool @client.call(:expire, key, seconds)
696
+ end
387
697
  end
388
698
 
699
+ # Remove the expiration from a key.
389
700
  def persist(key)
390
- _bool @client.call(:persist, key)
701
+ synchronize do
702
+ _bool @client.call(:persist, key)
703
+ end
391
704
  end
392
705
 
706
+ # Get the time to live for a key.
393
707
  def ttl(key)
394
- @client.call(:ttl, key)
708
+ synchronize do
709
+ @client.call(:ttl, key)
710
+ end
395
711
  end
396
712
 
713
+ # Set the expiration for a key as a UNIX timestamp.
397
714
  def expireat(key, unix_time)
398
- _bool @client.call(:expireat, key, unix_time)
715
+ synchronize do
716
+ _bool @client.call(:expireat, key, unix_time)
717
+ end
399
718
  end
400
719
 
720
+ # Set the string value of a hash field.
401
721
  def hset(key, field, value)
402
- _bool @client.call(:hset, key, field, value)
722
+ synchronize do
723
+ _bool @client.call(:hset, key, field, value)
724
+ end
403
725
  end
404
726
 
727
+ # Set the value of a hash field, only if the field does not exist.
405
728
  def hsetnx(key, field, value)
406
- _bool @client.call(:hsetnx, key, field, value)
729
+ synchronize do
730
+ _bool @client.call(:hsetnx, key, field, value)
731
+ end
407
732
  end
408
733
 
734
+ # Set multiple hash fields to multiple values.
409
735
  def hmset(key, *attrs)
410
- @client.call(:hmset, key, *attrs)
736
+ synchronize do
737
+ @client.call(:hmset, key, *attrs)
738
+ end
411
739
  end
412
740
 
413
741
  def mapped_hmset(key, hash)
414
742
  hmset(key, *hash.to_a.flatten)
415
743
  end
416
744
 
745
+ # Get the values of all the given hash fields.
417
746
  def hmget(key, *fields)
418
- @client.call(:hmget, key, *fields)
747
+ synchronize do
748
+ @client.call(:hmget, key, *fields)
749
+ end
419
750
  end
420
751
 
421
752
  def mapped_hmget(key, *fields)
422
- Hash[*fields.zip(hmget(key, *fields)).flatten]
753
+ reply = hmget(key, *fields)
754
+
755
+ if reply.kind_of?(Array)
756
+ Hash[*fields.zip(reply).flatten]
757
+ else
758
+ reply
759
+ end
423
760
  end
424
761
 
762
+ # Get the number of fields in a hash.
425
763
  def hlen(key)
426
- @client.call(:hlen, key)
764
+ synchronize do
765
+ @client.call(:hlen, key)
766
+ end
427
767
  end
428
768
 
769
+ # Get all the values in a hash.
429
770
  def hvals(key)
430
- @client.call(:hvals, key)
771
+ synchronize do
772
+ @client.call(:hvals, key)
773
+ end
431
774
  end
432
775
 
776
+ # Increment the integer value of a hash field by the given number.
433
777
  def hincrby(key, field, increment)
434
- @client.call(:hincrby, key, field, increment)
778
+ synchronize do
779
+ @client.call(:hincrby, key, field, increment)
780
+ end
435
781
  end
436
782
 
783
+ # Discard all commands issued after MULTI.
437
784
  def discard
438
- @client.call(:discard)
785
+ synchronize do
786
+ @client.call(:discard)
787
+ end
439
788
  end
440
789
 
790
+ # Determine if a hash field exists.
441
791
  def hexists(key, field)
442
- _bool @client.call(:hexists, key, field)
792
+ synchronize do
793
+ _bool @client.call(:hexists, key, field)
794
+ end
443
795
  end
444
796
 
797
+ # Listen for all requests received by the server in real time.
445
798
  def monitor(&block)
446
- @client.call_loop(:monitor, &block)
799
+ synchronize do
800
+ @client.call_loop(:monitor, &block)
801
+ end
447
802
  end
448
803
 
449
804
  def debug(*args)
450
- @client.call(:debug, *args)
805
+ synchronize do
806
+ @client.call(:debug, *args)
807
+ end
451
808
  end
452
809
 
810
+ # Internal command used for replication.
453
811
  def sync
454
- @client.call(:sync)
812
+ synchronize do
813
+ @client.call(:sync)
814
+ end
455
815
  end
456
816
 
457
817
  def [](key)
@@ -462,24 +822,50 @@ class Redis
462
822
  set(key, value)
463
823
  end
464
824
 
825
+ # Set the string value of a key.
465
826
  def set(key, value)
466
- @client.call(:set, key, value)
827
+ synchronize do
828
+ @client.call(:set, key, value)
829
+ end
467
830
  end
468
831
 
832
+ # Sets or clears the bit at offset in the string value stored at key.
833
+ def setbit(key, offset, value)
834
+ synchronize do
835
+ @client.call(:setbit, key, offset, value)
836
+ end
837
+ end
838
+
839
+ # Set the value and expiration of a key.
469
840
  def setex(key, ttl, value)
470
- @client.call(:setex, key, ttl, value)
841
+ synchronize do
842
+ @client.call(:setex, key, ttl, value)
843
+ end
844
+ end
845
+
846
+ # Overwrite part of a string at key starting at the specified offset.
847
+ def setrange(key, offset, value)
848
+ synchronize do
849
+ @client.call(:setrange, key, offset, value)
850
+ end
471
851
  end
472
852
 
853
+ # Set multiple keys to multiple values.
473
854
  def mset(*args)
474
- @client.call(:mset, *args)
855
+ synchronize do
856
+ @client.call(:mset, *args)
857
+ end
475
858
  end
476
859
 
477
860
  def mapped_mset(hash)
478
861
  mset(*hash.to_a.flatten)
479
862
  end
480
863
 
864
+ # Set multiple keys to multiple values, only if none of the keys exist.
481
865
  def msetnx(*args)
482
- @client.call(:msetnx, *args)
866
+ synchronize do
867
+ @client.call(:msetnx, *args)
868
+ end
483
869
  end
484
870
 
485
871
  def mapped_msetnx(hash)
@@ -487,9 +873,16 @@ class Redis
487
873
  end
488
874
 
489
875
  def mapped_mget(*keys)
490
- Hash[*keys.zip(mget(*keys)).flatten]
876
+ reply = mget(*keys)
877
+
878
+ if reply.kind_of?(Array)
879
+ Hash[*keys.zip(reply).flatten]
880
+ else
881
+ reply
882
+ end
491
883
  end
492
884
 
885
+ # Sort the elements in a list, set or sorted set.
493
886
  def sort(key, options = {})
494
887
  command = CommandOptions.new(options) do |c|
495
888
  c.value :by
@@ -499,115 +892,181 @@ class Redis
499
892
  c.value :store
500
893
  end
501
894
 
502
- @client.call(:sort, key, *command.to_a)
895
+ synchronize do
896
+ @client.call(:sort, key, *command.to_a)
897
+ end
503
898
  end
504
899
 
900
+ # Increment the integer value of a key by one.
505
901
  def incr(key)
506
- @client.call(:incr, key)
902
+ synchronize do
903
+ @client.call(:incr, key)
904
+ end
507
905
  end
508
906
 
907
+ # Increment the integer value of a key by the given number.
509
908
  def incrby(key, increment)
510
- @client.call(:incrby, key, increment)
909
+ synchronize do
910
+ @client.call(:incrby, key, increment)
911
+ end
511
912
  end
512
913
 
914
+ # Decrement the integer value of a key by one.
513
915
  def decr(key)
514
- @client.call(:decr, key)
916
+ synchronize do
917
+ @client.call(:decr, key)
918
+ end
515
919
  end
516
920
 
921
+ # Decrement the integer value of a key by the given number.
517
922
  def decrby(key, decrement)
518
- @client.call(:decrby, key, decrement)
923
+ synchronize do
924
+ @client.call(:decrby, key, decrement)
925
+ end
519
926
  end
520
927
 
928
+ # Determine the type stored at key.
521
929
  def type(key)
522
- @client.call(:type, key)
930
+ synchronize do
931
+ @client.call(:type, key)
932
+ end
523
933
  end
524
934
 
935
+ # Close the connection.
525
936
  def quit
526
- @client.call(:quit)
527
- rescue Errno::ECONNRESET
528
- ensure
529
- @client.disconnect
937
+ synchronize do
938
+ begin
939
+ @client.call(:quit)
940
+ rescue Errno::ECONNRESET
941
+ ensure
942
+ @client.disconnect
943
+ end
944
+ end
530
945
  end
531
946
 
947
+ # Synchronously save the dataset to disk and then shut down the server.
532
948
  def shutdown
533
- @client.call(:shutdown)
949
+ synchronize do
950
+ @client.call(:shutdown)
951
+ end
534
952
  end
535
953
 
954
+ # Make the server a slave of another instance, or promote it as master.
536
955
  def slaveof(host, port)
537
- @client.call(:slaveof, host, port)
956
+ synchronize do
957
+ @client.call(:slaveof, host, port)
958
+ end
538
959
  end
539
960
 
540
- def pipelined
541
- original, @client = @client, Pipeline.new
542
- yield
543
- original.call_pipelined(@client.commands) unless @client.commands.empty?
544
- ensure
545
- @client = original
961
+ def pipelined(options = {})
962
+ synchronize do
963
+ begin
964
+ original, @client = @client, Pipeline.new
965
+ yield
966
+ original.call_pipelined(@client.commands, options) unless @client.commands.empty?
967
+ ensure
968
+ @client = original
969
+ end
970
+ end
546
971
  end
547
972
 
973
+ # Watch the given keys to determine execution of the MULTI/EXEC block.
548
974
  def watch(*keys)
549
- @client.call(:watch, *keys)
975
+ synchronize do
976
+ @client.call(:watch, *keys)
977
+ end
550
978
  end
551
979
 
980
+ # Forget about all watched keys.
552
981
  def unwatch
553
- @client.call(:unwatch)
982
+ synchronize do
983
+ @client.call(:unwatch)
984
+ end
554
985
  end
555
986
 
987
+ # Execute all commands issued after MULTI.
556
988
  def exec
557
- @client.call(:exec)
989
+ synchronize do
990
+ @client.call(:exec)
991
+ end
558
992
  end
559
993
 
560
- def multi(&block)
561
- result = @client.call :multi
562
-
563
- return result unless block_given?
564
-
565
- begin
566
- yield(self)
567
- rescue Exception => e
568
- discard
569
- raise e
994
+ # Mark the start of a transaction block.
995
+ def multi
996
+ synchronize do
997
+ if !block_given?
998
+ @client.call :multi
999
+ else
1000
+ result = pipelined(:raise => false) do
1001
+ multi
1002
+ yield(self)
1003
+ exec
1004
+ end
1005
+
1006
+ result.last
1007
+ end
570
1008
  end
571
-
572
- exec
573
1009
  end
574
1010
 
1011
+ # Post a message to a channel.
575
1012
  def publish(channel, message)
576
- @client.call(:publish, channel, message)
1013
+ synchronize do
1014
+ @client.call(:publish, channel, message)
1015
+ end
577
1016
  end
578
1017
 
579
1018
  def subscribed?
580
- @client.kind_of? SubscribedClient
1019
+ synchronize do
1020
+ @client.kind_of? SubscribedClient
1021
+ end
581
1022
  end
582
1023
 
1024
+ # Stop listening for messages posted to the given channels.
583
1025
  def unsubscribe(*channels)
584
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
585
- @client.unsubscribe(*channels)
1026
+ synchronize do
1027
+ raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
1028
+ @client.unsubscribe(*channels)
1029
+ end
586
1030
  end
587
1031
 
1032
+ # Stop listening for messages posted to channels matching the given patterns.
588
1033
  def punsubscribe(*channels)
589
- raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
590
- @client.punsubscribe(*channels)
1034
+ synchronize do
1035
+ raise RuntimeError, "Can't unsubscribe if not subscribed." unless subscribed?
1036
+ @client.punsubscribe(*channels)
1037
+ end
591
1038
  end
592
1039
 
1040
+ # Listen for messages published to the given channels.
593
1041
  def subscribe(*channels, &block)
594
- subscription(:subscribe, channels, block)
1042
+ synchronize do
1043
+ subscription(:subscribe, channels, block)
1044
+ end
595
1045
  end
596
1046
 
1047
+ # Listen for messages published to channels matching the given patterns.
597
1048
  def psubscribe(*channels, &block)
598
- subscription(:psubscribe, channels, block)
1049
+ synchronize do
1050
+ subscription(:psubscribe, channels, block)
1051
+ end
599
1052
  end
600
1053
 
601
1054
  def id
602
- @client.id
1055
+ synchronize do
1056
+ @client.id
1057
+ end
603
1058
  end
604
1059
 
605
1060
  def inspect
606
- "#<Redis client v#{Redis::VERSION} connected to #{id} (Redis v#{info["redis_version"]})>"
1061
+ synchronize do
1062
+ "#<Redis client v#{Redis::VERSION} connected to #{id} (Redis v#{info["redis_version"]})>"
1063
+ end
607
1064
  end
608
1065
 
609
1066
  def method_missing(command, *args)
610
- @client.call(command, *args)
1067
+ synchronize do
1068
+ @client.call(command, *args)
1069
+ end
611
1070
  end
612
1071
 
613
1072
  class CommandOptions
@@ -652,10 +1111,6 @@ private
652
1111
  value == 1
653
1112
  end
654
1113
 
655
- def _array(value)
656
- value.kind_of?(Array) ? value : value.split(" ")
657
- end
658
-
659
1114
  def subscription(method, channels, block)
660
1115
  return @client.call(method, *channels) if subscribed?
661
1116
 
@@ -669,7 +1124,8 @@ private
669
1124
 
670
1125
  end
671
1126
 
672
- require "redis/connection" unless defined?(Redis::Connection)
1127
+ require "redis/version"
1128
+ require "redis/connection"
673
1129
  require "redis/client"
674
1130
  require "redis/pipeline"
675
1131
  require "redis/subscribe"