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,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"