]>
git.saurik.com Git - redis.git/blob - client-libraries/ruby/lib/redis.rb
28e304a6469a8ab974ee04e34044c237bd8b19a4
2 require File
.join(File
.dirname(__FILE__
),'pipeline')
5 if (RUBY_VERSION >= '1.9')
10 RedisTimer
= SystemTimer
18 "set"=>true, "setnx"=>true, "rpush"=>true, "lpush"=>true, "lset"=>true,
19 "lrem"=>true, "sadd"=>true, "srem"=>true, "sismember"=>true,
20 "echo"=>true, "getset"=>true, "smove"=>true
23 ConvertToBool
= lambda
do |r
|
32 "exists" => ConvertToBool
,
33 "sismember"=> ConvertToBool
,
34 "sadd"=> ConvertToBool
,
35 "srem"=> ConvertToBool
,
36 "smove"=> ConvertToBool
,
37 "move"=> ConvertToBool
,
38 "setnx"=> ConvertToBool
,
39 "del"=> ConvertToBool
,
40 "renamenx"=> ConvertToBool
,
41 "expire"=> ConvertToBool
,
42 "keys" => lambda
{|r
| r
.split(" ")},
46 k
,v
= kv
.split(":",2).map
{|x
| x
.chomp
}
54 "flush_db" => "flushdb",
55 "flush_all" => "flushall",
56 "last_save" => "lastsave",
59 "randkey" => "randomkey",
60 "list_length" => "llen",
61 "push_tail" => "rpush",
62 "push_head" => "lpush",
66 "list_range" => "lrange",
67 "list_trim" => "ltrim",
68 "list_index" => "lindex",
71 "set_delete" => "srem",
72 "set_count" => "scard",
73 "set_member?" => "sismember",
74 "set_members" => "smembers",
75 "set_intersect" => "sinter",
76 "set_intersect_store" => "sinterstore",
77 "set_inter_store" => "sinterstore",
78 "set_union" => "sunion",
79 "set_union_store" => "sunionstore",
80 "set_diff" => "sdiff",
81 "set_diff_store" => "sdiffstore",
82 "set_move" => "smove",
83 "set_unless_exists" => "setnx",
84 "rename_unless_exists" => "renamenx",
88 def initialize(opts
={})
89 @host = opts
[:host] || '127.0.0.1'
90 @port = opts
[:port] || 6379
92 @timeout = opts
[:timeout] || 5
93 $debug = opts
[:debug] || false
98 "Redis Client connected to #{@host}:#{@port} against DB #{@db}"
101 def connect_to_server
102 @sock = connect_to(@host,@port,@timeout == 0 ? nil : @timeout)
103 call_command(["select",@db]) if @db !
= 0
106 def connect_to(host
, port
, timeout
=nil)
107 # We support connect() timeout only if system_timer is availabe
108 # or if we are running against Ruby >= 1.9
109 # Timeout reading from the socket instead will be supported anyway.
110 if @timeout !
= 0 and RedisTimer
112 sock
= TCPSocket
.new(host
, port
)
113 rescue Timeout
::Error
115 raise Timeout
::Error, "Timeout connecting to the server"
118 sock
= TCPSocket
.new(host
, port
)
120 sock
.setsockopt Socket
::IPPROTO_TCP, Socket
::TCP_NODELAY, 1
122 # If the timeout is set we set the low level socket options in order
123 # to make sure a blocking read will return after the specified number
124 # of seconds. This hack is from memcached ruby client.
126 secs
= Integer(timeout
)
127 usecs
= Integer((timeout
- secs
) * 1_000_000)
128 optval
= [secs
, usecs
].pack("l_2")
129 sock
.setsockopt Socket
::SOL_SOCKET, Socket
::SO_RCVTIMEO, optval
130 sock
.setsockopt Socket
::SOL_SOCKET, Socket
::SO_SNDTIMEO, optval
135 def method_missing(*argv)
139 def call_command(argv)
140 puts
argv.inspect
if $debug
141 # this wrapper to raw_call_command handle reconnection on socket
142 # error. We try to reconnect just one time, otherwise let the error
144 connect_to_server
if !
@sock
146 raw_call_command(argv)
147 rescue Errno
::ECONNRESET
150 raw_call_command(argv)
154 def raw_call_command(argvp
)
155 pipeline
= argvp
[0].is_a
?(Array
)
167 argv[0] = argv[0].to_s
.downcase
168 argv[0] = Aliases
[argv[0]] if Aliases
[argv[0]]
169 if BulkCommands
[argv[0]] and argv.length
> 1
171 argv[-1] = bulk
.length
173 command
<< argv.join(' ') +
"\r\n"
174 command
<< bulk +
"\r\n" if bulk
179 results
= argvv
.map
do |argv|
180 processor
= ReplyProcessor
[argv[0]]
181 processor
? processor
.call(read_reply
) : read_reply
184 return pipeline
? results
: results
[0]
188 raise "SELECT not allowed, use the :db option when creating the object"
199 def set(key
, value
, expiry
=nil)
200 call_command([:set, key
, value
])
201 expire(key
, expiry
) unless expiry
.nil?
204 def sort(key
, opts
={})
207 cmd
<< "BY #{opts[:by]}" if opts
[:by]
208 cmd
<< "GET #{[opts[:get]].flatten * ' GET '}" if opts
[:get]
209 cmd
<< "#{opts[:order]}" if opts
[:order]
210 cmd
<< "LIMIT #{opts[:limit].join(' ')}" if opts
[:limit]
214 def incr(key
,increment
=nil)
215 call_command(increment
? ["incrby",key
,increment
] : ["incr",key
])
218 def decr(key
,decrement
=nil)
219 call_command(decrement
? ["decrby",key
,decrement
] : ["decr",key
])
222 # Ruby defines a now deprecated type method so we need to override it here
223 # since it will never hit method_missing
225 call_command(['type', key
])
229 call_command(['quit'])
230 rescue Errno
::ECONNRESET
233 def pipelined(&block
)
234 pipeline
= Pipeline
.new
self
240 # We read the first byte using read() mainly because gets() is
241 # immune to raw socket timeouts.
243 rtype
= @sock.read(1)
245 # We want to make sure it reconnects on the next command after the
246 # timeout. Otherwise the server may reply in the meantime leaving
247 # the protocol in a desync status.
249 raise Errno
::EAGAIN, "Timeout reading from the socket"
252 raise Errno
::ECONNRESET,"Connection lost" if !rtype
263 return nil if bulklen == -1
264 data = @sock.read(bulklen)
269 return nil if bulklen == -1
276 raise "Protocol error
, got
'#{rtype}' as initial reply byte
"