redis 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -2
- data/lib/redis.rb +1 -1
- data/lib/redis/client.rb +122 -71
- data/lib/redis/subscribe.rb +14 -12
- metadata +7 -18
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ GEM_VERSION = Redis::VERSION
|
|
12
12
|
AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark', 'Brian McKinney', 'Salvatore Sanfilippo', 'Luca Guidi']
|
13
13
|
EMAIL = "ez@engineyard.com"
|
14
14
|
HOMEPAGE = "http://github.com/ezmobius/redis-rb"
|
15
|
-
SUMMARY = "Ruby client library for
|
15
|
+
SUMMARY = "Ruby client library for Redis, the key value storage server"
|
16
16
|
|
17
17
|
spec = Gem::Specification.new do |s|
|
18
18
|
s.name = GEM
|
@@ -25,7 +25,6 @@ spec = Gem::Specification.new do |s|
|
|
25
25
|
s.authors = AUTHORS
|
26
26
|
s.email = EMAIL
|
27
27
|
s.homepage = HOMEPAGE
|
28
|
-
s.add_development_dependency "rspec"
|
29
28
|
s.require_path = 'lib'
|
30
29
|
s.autorequire = GEM
|
31
30
|
s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,tasks,spec}/**/*")
|
data/lib/redis.rb
CHANGED
data/lib/redis/client.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
class Redis
|
2
2
|
class Client
|
3
|
+
class ProtocolError < RuntimeError
|
4
|
+
def initialize(reply_type)
|
5
|
+
super("Protocol error, got '#{reply_type}' as initial reply byte")
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
3
9
|
OK = "OK".freeze
|
4
10
|
MINUS = "-".freeze
|
5
11
|
PLUS = "+".freeze
|
@@ -215,8 +221,8 @@ class Redis
|
|
215
221
|
end
|
216
222
|
|
217
223
|
def sort(key, options = {})
|
218
|
-
cmd = [
|
219
|
-
cmd << key
|
224
|
+
cmd = []
|
225
|
+
cmd << "SORT #{key}"
|
220
226
|
cmd << "BY #{options[:by]}" if options[:by]
|
221
227
|
cmd << "GET #{[options[:get]].flatten * ' GET '}" if options[:get]
|
222
228
|
cmd << "#{options[:order]}" if options[:order]
|
@@ -226,11 +232,21 @@ class Redis
|
|
226
232
|
end
|
227
233
|
|
228
234
|
def incr(key, increment = nil)
|
229
|
-
|
235
|
+
if increment
|
236
|
+
deprecated("incr with an increment", :incrby, caller[0])
|
237
|
+
incrby(key, increment)
|
238
|
+
else
|
239
|
+
call_command([:incr, key])
|
240
|
+
end
|
230
241
|
end
|
231
242
|
|
232
|
-
def decr(key,decrement = nil)
|
233
|
-
|
243
|
+
def decr(key, decrement = nil)
|
244
|
+
if decrement
|
245
|
+
deprecated("decr with a decrement", :decrby, caller[0])
|
246
|
+
decrby(key, decrement)
|
247
|
+
else
|
248
|
+
call_command([:decr, key])
|
249
|
+
end
|
234
250
|
end
|
235
251
|
|
236
252
|
# Ruby defines a now deprecated type method so we need to override it here
|
@@ -270,13 +286,13 @@ class Redis
|
|
270
286
|
end
|
271
287
|
|
272
288
|
def subscribe(*classes)
|
273
|
-
# Top-level `subscribe` MUST be called with a block,
|
274
|
-
# nested `subscribe` MUST NOT be called with a block
|
275
|
-
if !@pubsub && !block_given?
|
289
|
+
# Top-level `subscribe` MUST be called with a block,
|
290
|
+
# nested `subscribe` MUST NOT be called with a block
|
291
|
+
if !@pubsub && !block_given?
|
276
292
|
raise "Top-level subscribe requires a block"
|
277
|
-
elsif @pubsub == true && block_given?
|
293
|
+
elsif @pubsub == true && block_given?
|
278
294
|
raise "Nested subscribe does not take a block"
|
279
|
-
elsif @pubsub
|
295
|
+
elsif @pubsub
|
280
296
|
# If we're already pubsub'ing, just subscribe us to some more classes
|
281
297
|
call_command [:subscribe,*classes]
|
282
298
|
return true
|
@@ -305,26 +321,21 @@ class Redis
|
|
305
321
|
end
|
306
322
|
end
|
307
323
|
|
308
|
-
|
309
|
-
|
310
|
-
return true
|
311
|
-
end
|
312
|
-
|
324
|
+
# Wrap raw_call_command to handle reconnection on socket error. We
|
325
|
+
# try to reconnect just one time, otherwise let the error araise.
|
313
326
|
def call_command(argv)
|
314
327
|
log(argv.inspect, :debug)
|
315
328
|
|
316
|
-
|
317
|
-
# error. We try to reconnect just one time, otherwise let the error
|
318
|
-
# araise.
|
319
|
-
connect_to_server if !@sock
|
329
|
+
connect_to_server unless connected?
|
320
330
|
|
321
331
|
begin
|
322
332
|
raw_call_command(argv.dup)
|
323
333
|
rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
334
|
+
if reconnect
|
335
|
+
raw_call_command(argv.dup)
|
336
|
+
else
|
337
|
+
raise Errno::ECONNRESET
|
338
|
+
end
|
328
339
|
end
|
329
340
|
end
|
330
341
|
|
@@ -332,35 +343,38 @@ class Redis
|
|
332
343
|
"#{@host}:#{@port}"
|
333
344
|
end
|
334
345
|
|
335
|
-
def connect_to(host, port
|
336
|
-
|
346
|
+
def connect_to(host, port)
|
347
|
+
|
348
|
+
# We support connect_to() timeout only if system_timer is availabe
|
337
349
|
# or if we are running against Ruby >= 1.9
|
338
350
|
# Timeout reading from the socket instead will be supported anyway.
|
339
351
|
if @timeout != 0 and Timer
|
340
352
|
begin
|
341
|
-
sock = TCPSocket.new(host, port)
|
353
|
+
@sock = TCPSocket.new(host, port)
|
342
354
|
rescue Timeout::Error
|
343
355
|
@sock = nil
|
344
356
|
raise Timeout::Error, "Timeout connecting to the server"
|
345
357
|
end
|
346
358
|
else
|
347
|
-
sock = TCPSocket.new(host, port)
|
359
|
+
@sock = TCPSocket.new(host, port)
|
348
360
|
end
|
349
|
-
|
361
|
+
|
362
|
+
@sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
350
363
|
|
351
364
|
# If the timeout is set we set the low level socket options in order
|
352
365
|
# to make sure a blocking read will return after the specified number
|
353
366
|
# of seconds. This hack is from memcached ruby client.
|
354
|
-
if timeout
|
355
|
-
|
356
|
-
|
357
|
-
|
367
|
+
set_socket_timeout!(@timeout) if @timeout
|
368
|
+
|
369
|
+
rescue Errno::ECONNREFUSED
|
370
|
+
raise Errno::ECONNREFUSED, "Unable to connect to Redis on #{host}:#{port}"
|
358
371
|
end
|
359
372
|
|
360
373
|
def connect_to_server
|
361
|
-
|
362
|
-
call_command([
|
363
|
-
call_command([
|
374
|
+
connect_to(@host, @port)
|
375
|
+
call_command([:auth, @password]) if @password
|
376
|
+
call_command([:select, @db]) if @db != 0
|
377
|
+
@sock
|
364
378
|
end
|
365
379
|
|
366
380
|
def method_missing(*argv)
|
@@ -412,10 +426,10 @@ class Redis
|
|
412
426
|
# The normal command execution is reading and processing the reply.
|
413
427
|
results = maybe_lock do
|
414
428
|
begin
|
415
|
-
set_socket_timeout(
|
429
|
+
set_socket_timeout!(0) if requires_timeout_reset?(argvv[0][0].to_s)
|
416
430
|
process_command(command, argvv)
|
417
431
|
ensure
|
418
|
-
set_socket_timeout(@
|
432
|
+
set_socket_timeout!(@timeout) if requires_timeout_reset?(argvv[0][0].to_s)
|
419
433
|
end
|
420
434
|
end
|
421
435
|
|
@@ -439,50 +453,33 @@ class Redis
|
|
439
453
|
end
|
440
454
|
|
441
455
|
def read_reply
|
456
|
+
|
442
457
|
# We read the first byte using read() mainly because gets() is
|
443
458
|
# immune to raw socket timeouts.
|
444
459
|
begin
|
445
|
-
|
460
|
+
reply_type = @sock.read(1)
|
446
461
|
rescue Errno::EAGAIN
|
462
|
+
|
447
463
|
# We want to make sure it reconnects on the next command after the
|
448
464
|
# timeout. Otherwise the server may reply in the meantime leaving
|
449
465
|
# the protocol in a desync status.
|
450
|
-
|
466
|
+
disconnect
|
467
|
+
|
451
468
|
raise Errno::EAGAIN, "Timeout reading from the socket"
|
452
469
|
end
|
453
470
|
|
454
|
-
raise Errno::ECONNRESET,"Connection lost"
|
455
|
-
|
456
|
-
|
457
|
-
when MINUS
|
458
|
-
raise MINUS + line.strip
|
459
|
-
when PLUS
|
460
|
-
line.strip
|
461
|
-
when COLON
|
462
|
-
line.to_i
|
463
|
-
when DOLLAR
|
464
|
-
bulklen = line.to_i
|
465
|
-
return nil if bulklen == -1
|
466
|
-
data = @sock.read(bulklen)
|
467
|
-
@sock.read(2) # CRLF
|
468
|
-
data
|
469
|
-
when ASTERISK
|
470
|
-
objects = line.to_i
|
471
|
-
return nil if bulklen == -1
|
472
|
-
res = []
|
473
|
-
objects.times {
|
474
|
-
res << read_reply
|
475
|
-
}
|
476
|
-
res
|
477
|
-
else
|
478
|
-
raise "Protocol error, got '#{rtype}' as initial reply byte"
|
479
|
-
end
|
471
|
+
raise Errno::ECONNRESET, "Connection lost" unless reply_type
|
472
|
+
|
473
|
+
format_reply(reply_type, @sock.gets)
|
480
474
|
end
|
481
475
|
|
476
|
+
|
482
477
|
def get_size(string)
|
483
478
|
string.respond_to?(:bytesize) ? string.bytesize : string.size
|
484
479
|
end
|
485
480
|
|
481
|
+
private
|
482
|
+
|
486
483
|
def log(str, level = :info)
|
487
484
|
@logger.send(level, str.to_s) if @logger
|
488
485
|
end
|
@@ -494,19 +491,73 @@ class Redis
|
|
494
491
|
def requires_timeout_reset?(command)
|
495
492
|
BLOCKING_COMMANDS[command] && @timeout
|
496
493
|
end
|
497
|
-
|
498
|
-
def set_socket_timeout(
|
494
|
+
|
495
|
+
def set_socket_timeout!(timeout)
|
499
496
|
secs = Integer(timeout)
|
500
497
|
usecs = Integer((timeout - secs) * 1_000_000)
|
501
498
|
optval = [secs, usecs].pack("l_2")
|
502
499
|
begin
|
503
|
-
sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
|
504
|
-
sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
|
505
|
-
rescue Exception =>
|
500
|
+
@sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
|
501
|
+
@sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
|
502
|
+
rescue Exception => e
|
506
503
|
# Solaris, for one, does not like/support socket timeouts.
|
507
|
-
log("Unable to use raw socket timeouts: #{
|
504
|
+
log("Unable to use raw socket timeouts: #{e.class.name}: #{e.message}")
|
508
505
|
end
|
509
506
|
end
|
510
507
|
|
508
|
+
def connected?
|
509
|
+
!! @sock
|
510
|
+
end
|
511
|
+
|
512
|
+
def disconnect
|
513
|
+
begin
|
514
|
+
@sock.close
|
515
|
+
rescue
|
516
|
+
ensure
|
517
|
+
@sock = nil
|
518
|
+
end
|
519
|
+
true
|
520
|
+
end
|
521
|
+
|
522
|
+
def reconnect
|
523
|
+
disconnect && connect_to_server
|
524
|
+
end
|
525
|
+
|
526
|
+
def format_reply(reply_type, line)
|
527
|
+
case reply_type
|
528
|
+
when MINUS then format_error_reply(line)
|
529
|
+
when PLUS then format_status_reply(line)
|
530
|
+
when COLON then format_integer_reply(line)
|
531
|
+
when DOLLAR then format_bulk_reply(line)
|
532
|
+
when ASTERISK then format_multi_bulk_reply(line)
|
533
|
+
else raise ProtocolError.new(reply_type)
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
def format_error_reply(line)
|
538
|
+
raise "-" + line.strip
|
539
|
+
end
|
540
|
+
|
541
|
+
def format_status_reply(line)
|
542
|
+
line.strip
|
543
|
+
end
|
544
|
+
|
545
|
+
def format_integer_reply(line)
|
546
|
+
line.to_i
|
547
|
+
end
|
548
|
+
|
549
|
+
def format_bulk_reply(line)
|
550
|
+
bulklen = line.to_i
|
551
|
+
return if bulklen == -1
|
552
|
+
reply = @sock.read(bulklen)
|
553
|
+
@sock.read(2) # Discard CRLF.
|
554
|
+
reply
|
555
|
+
end
|
556
|
+
|
557
|
+
def format_multi_bulk_reply(line)
|
558
|
+
reply = []
|
559
|
+
line.to_i.times { reply << read_reply }
|
560
|
+
reply
|
561
|
+
end
|
511
562
|
end
|
512
563
|
end
|
data/lib/redis/subscribe.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
class
|
2
|
-
|
3
|
-
|
1
|
+
class Redis
|
2
|
+
class Subscription
|
3
|
+
def subscribe(&block)
|
4
|
+
if block_given? then @subscribe = block else @subscribe end
|
5
|
+
end
|
6
|
+
|
7
|
+
def unsubscribe(&block)
|
8
|
+
if block_given? then @unsubscribe = block else @unsubscribe end
|
9
|
+
end
|
10
|
+
|
11
|
+
def message(&block)
|
12
|
+
if block_given? then @message = block else @message end
|
13
|
+
end
|
14
|
+
|
4
15
|
end
|
5
|
-
|
6
|
-
def unsubscribe(&block)
|
7
|
-
if block_given? then @unsubscribe = block else @unsubscribe end
|
8
|
-
end
|
9
|
-
|
10
|
-
def message(&block)
|
11
|
-
if block_given? then @message = block else @message end
|
12
|
-
end
|
13
|
-
|
14
16
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 1.0.
|
8
|
+
- 3
|
9
|
+
version: 1.0.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ezra Zygmuntowicz
|
@@ -19,22 +19,11 @@ autorequire: redis
|
|
19
19
|
bindir: bin
|
20
20
|
cert_chain: []
|
21
21
|
|
22
|
-
date: 2010-04-
|
22
|
+
date: 2010-04-03 00:00:00 -07:00
|
23
23
|
default_executable:
|
24
|
-
dependencies:
|
25
|
-
|
26
|
-
|
27
|
-
prerelease: false
|
28
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
29
|
-
requirements:
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
segments:
|
33
|
-
- 0
|
34
|
-
version: "0"
|
35
|
-
type: :development
|
36
|
-
version_requirements: *id001
|
37
|
-
description: Ruby client library for redis key value storage server
|
24
|
+
dependencies: []
|
25
|
+
|
26
|
+
description: Ruby client library for Redis, the key value storage server
|
38
27
|
email: ez@engineyard.com
|
39
28
|
executables: []
|
40
29
|
|
@@ -84,6 +73,6 @@ rubyforge_project:
|
|
84
73
|
rubygems_version: 1.3.6
|
85
74
|
signing_key:
|
86
75
|
specification_version: 3
|
87
|
-
summary: Ruby client library for
|
76
|
+
summary: Ruby client library for Redis, the key value storage server
|
88
77
|
test_files: []
|
89
78
|
|