redis 1.0.2 → 1.0.3
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.
- 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
|
|