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 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 redis key value storage server"
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}/**/*")
@@ -1,7 +1,7 @@
1
1
  require 'socket'
2
2
 
3
3
  class Redis
4
- VERSION = "1.0.2"
4
+ VERSION = "1.0.3"
5
5
 
6
6
  def self.new(*attrs)
7
7
  Client.new(*attrs)
@@ -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 = ["SORT"]
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
- call_command(increment ? ["incrby",key,increment] : ["incr",key])
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
- call_command(decrement ? ["decrby",key,decrement] : ["decr",key])
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
- def unsubscribe(*classes)
309
- call_command [:unsubscribe,*classes]
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
- # this wrapper to raw_call_command handle reconnection on socket
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
- @sock.close rescue nil
325
- @sock = nil
326
- connect_to_server
327
- raw_call_command(argv.dup)
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, timeout=nil)
336
- # We support connect() timeout only if system_timer is availabe
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
- sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
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
- set_socket_timeout(sock, timeout)
356
- end
357
- sock
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
- @sock = connect_to(@host, @port, @timeout == 0 ? nil : @timeout)
362
- call_command(["auth",@password]) if @password
363
- call_command(["select",@db]) unless @db == 0
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(@sock, 0) if requires_timeout_reset?(argvv[0][0].to_s)
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(@sock, @timeout) if requires_timeout_reset?(argvv[0][0].to_s)
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
- rtype = @sock.read(1)
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
- @sock = nil
466
+ disconnect
467
+
451
468
  raise Errno::EAGAIN, "Timeout reading from the socket"
452
469
  end
453
470
 
454
- raise Errno::ECONNRESET,"Connection lost" if !rtype
455
- line = @sock.gets
456
- case rtype
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(sock, 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 => ex
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: #{ex.class.name}: #{ex.message}")
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
@@ -1,14 +1,16 @@
1
- class Subscription
2
- def subscribe(&block)
3
- if block_given? then @subscribe = block else @subscribe end
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
- - 2
9
- version: 1.0.2
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-02 00:00:00 -07:00
22
+ date: 2010-04-03 00:00:00 -07:00
23
23
  default_executable:
24
- dependencies:
25
- - !ruby/object:Gem::Dependency
26
- name: rspec
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 redis key value storage server
76
+ summary: Ruby client library for Redis, the key value storage server
88
77
  test_files: []
89
78