]> git.saurik.com Git - redis.git/blame - client-libraries/ruby/lib/redis.rb
Redis-rb sync
[redis.git] / client-libraries / ruby / lib / redis.rb
CommitLineData
ed9b544e 1require 'socket'
38210f7f 2require 'set'
3require File.join(File.dirname(__FILE__),'server')
57172ffb 4require File.join(File.dirname(__FILE__),'pipeline')
29fac617 5
38210f7f 6class RedisError < StandardError
7end
8class RedisRenameError < StandardError
29fac617 9end
d7fc9edb 10
ed9b544e 11class Redis
38210f7f 12 ERR = "-".freeze
13 OK = 'OK'.freeze
14 PONG = 'PONG'.freeze
15 SINGLE = '+'.freeze
16 BULK = '$'.freeze
17 MULTI = '*'.freeze
18 INT = ':'.freeze
19
20 attr_reader :server
21
22 def initialize(opts={})
23 @opts = {:host => 'localhost', :port => '6379', :db => 0}.merge(opts)
24 $debug = @opts[:debug]
25 @db = @opts[:db]
26 @server = Server.new(@opts[:host], @opts[:port], (@opts[:timeout]||10))
27 end
ed9b544e 28
38210f7f 29 def pipelined
30 pipeline = Pipeline.new(self)
31 yield pipeline
32 pipeline.finish
33 end
29fac617 34
38210f7f 35 def to_s
36 "#{host}:#{port} -> #{@db}"
37 end
38
39 def port
40 @opts[:port]
41 end
42
43 def host
44 @opts[:host]
45 end
46
47 def quit
48 execute_command("QUIT\r\n", true)
49 end
29fac617 50
38210f7f 51 def ping
52 execute_command("PING\r\n") == PONG
53 end
29fac617 54
38210f7f 55 def select_db(index)
56 @db = index
57 execute_command("SELECT #{index}\r\n")
58 end
59
60 def flush_db
61 execute_command("FLUSHDB\r\n") == OK
62 end
29fac617 63
38210f7f 64 def flush_all
65 puts "Warning!\nFlushing *ALL* databases!\n5 Seconds to Hit ^C!"
66 trap('INT') {quit; return false}
67 sleep 5
68 execute_command("FLUSHALL\r\n") == OK
69 end
70
71 def last_save
72 execute_command("LASTSAVE\r\n").to_i
73 end
74
75 def bgsave
76 execute_command("BGSAVE\r\n") == OK
77 end
78
79 def info
80 info = {}
81 x = execute_command("INFO\r\n")
82 x.each_line do |kv|
83 k,v = kv.split(':', 2)
84 k,v = k.chomp, v = v.chomp
85 info[k.to_sym] = v
86 end
87 info
88 end
89
90 def keys(glob)
91 execute_command("KEYS #{glob}\r\n").split(' ')
92 end
29fac617 93
38210f7f 94 def rename!(oldkey, newkey)
95 execute_command("RENAME #{oldkey} #{newkey}\r\n")
96 end
97
98 def rename(oldkey, newkey)
99 case execute_command("RENAMENX #{oldkey} #{newkey}\r\n")
100 when -1
101 raise RedisRenameError, "source key: #{oldkey} does not exist"
102 when 0
103 raise RedisRenameError, "target key: #{oldkey} already exists"
104 when -3
105 raise RedisRenameError, "source and destination keys are the same"
106 when 1
107 true
69664139 108 end
38210f7f 109 end
110
111 def key?(key)
112 execute_command("EXISTS #{key}\r\n") == 1
113 end
114
115 def delete(key)
116 execute_command("DEL #{key}\r\n") == 1
117 end
118
119 def [](key)
120 get(key)
121 end
57172ffb 122
38210f7f 123 def get(key)
124 execute_command("GET #{key}\r\n")
125 end
126
127 def mget(*keys)
128 execute_command("MGET #{keys.join(' ')}\r\n")
129 end
130
131 def incr(key, increment=nil)
132 if increment
133 execute_command("INCRBY #{key} #{increment}\r\n")
134 else
135 execute_command("INCR #{key}\r\n")
136 end
137 end
138
139 def decr(key, decrement=nil)
140 if decrement
141 execute_command("DECRBY #{key} #{decrement}\r\n")
142 else
143 execute_command("DECR #{key}\r\n")
144 end
145 end
146
147 def randkey
148 execute_command("RANDOMKEY\r\n")
149 end
150
151 def list_length(key)
152 case i = execute_command("LLEN #{key}\r\n")
153 when -2
154 raise RedisError, "key: #{key} does not hold a list value"
155 else
156 i
69664139 157 end
38210f7f 158 end
159
160 def type?(key)
161 execute_command("TYPE #{key}\r\n")
162 end
163
164 def push_tail(key, val)
165 execute_command("RPUSH #{key} #{value_to_wire(val)}\r\n")
166 end
167
168 def push_head(key, val)
169 execute_command("LPUSH #{key} #{value_to_wire(val)}\r\n")
170 end
171
172 def pop_head(key)
173 execute_command("LPOP #{key}\r\n")
174 end
175
176 def pop_tail(key)
177 execute_command("RPOP #{key}\r\n")
178 end
179
180 def list_set(key, index, val)
181 execute_command("LSET #{key} #{index} #{value_to_wire(val)}\r\n") == OK
182 end
29fac617 183
38210f7f 184 def list_range(key, start, ending)
185 execute_command("LRANGE #{key} #{start} #{ending}\r\n")
186 end
187
188 def list_trim(key, start, ending)
189 execute_command("LTRIM #{key} #{start} #{ending}\r\n")
190 end
191
192 def list_index(key, index)
193 execute_command("LINDEX #{key} #{index}\r\n")
194 end
195
196 def list_rm(key, count, val)
197 case num = execute_command("LREM #{key} #{count} #{value_to_wire(val)}\r\n")
198 when -1
199 raise RedisError, "key: #{key} does not exist"
200 when -2
201 raise RedisError, "key: #{key} does not hold a list value"
202 else
203 num
69664139 204 end
38210f7f 205 end
d7fc9edb 206
38210f7f 207 def set_add(key, member)
208 case execute_command("SADD #{key} #{value_to_wire(member)}\r\n")
209 when 1
210 true
211 when 0
212 false
213 when -2
214 raise RedisError, "key: #{key} contains a non set value"
69664139 215 end
38210f7f 216 end
d7fc9edb 217
38210f7f 218 def set_delete(key, member)
219 case execute_command("SREM #{key} #{value_to_wire(member)}\r\n")
220 when 1
221 true
222 when 0
223 false
224 when -2
225 raise RedisError, "key: #{key} contains a non set value"
69664139 226 end
38210f7f 227 end
d7fc9edb 228
38210f7f 229 def set_count(key)
230 case i = execute_command("SCARD #{key}\r\n")
231 when -2
232 raise RedisError, "key: #{key} contains a non set value"
233 else
234 i
d7fc9edb 235 end
38210f7f 236 end
69664139 237
38210f7f 238 def set_member?(key, member)
239 case execute_command("SISMEMBER #{key} #{value_to_wire(member)}\r\n")
240 when 1
241 true
242 when 0
243 false
244 when -2
245 raise RedisError, "key: #{key} contains a non set value"
ed9b544e 246 end
38210f7f 247 end
248
249 def set_members(key)
250 Set.new(execute_command("SMEMBERS #{key}\r\n"))
251 end
252
253 def set_intersect(*keys)
254 Set.new(execute_command("SINTER #{keys.join(' ')}\r\n"))
255 end
256
257 def set_inter_store(destkey, *keys)
258 execute_command("SINTERSTORE #{destkey} #{keys.join(' ')}\r\n")
259 end
260
261 def set_union(*keys)
262 Set.new(execute_command("SUNION #{keys.join(' ')}\r\n"))
263 end
264
265 def set_union_store(destkey, *keys)
266 execute_command("SUNIONSTORE #{destkey} #{keys.join(' ')}\r\n")
267 end
268
269 def set_diff(*keys)
270 Set.new(execute_command("SDIFF #{keys.join(' ')}\r\n"))
271 end
272
273 def set_diff_store(destkey, *keys)
274 execute_command("SDIFFSTORE #{destkey} #{keys.join(' ')}\r\n")
275 end
276
277 def set_move(srckey, destkey, member)
278 execute_command("SMOVE #{srckey} #{destkey} #{value_to_wire(member)}\r\n") == 1
279 end
69664139 280
38210f7f 281 def sort(key, opts={})
282 cmd = "SORT #{key}"
283 cmd << " BY #{opts[:by]}" if opts[:by]
284 cmd << " GET #{[opts[:get]].flatten * ' GET '}" if opts[:get]
285 cmd << " INCR #{opts[:incr]}" if opts[:incr]
286 cmd << " DEL #{opts[:del]}" if opts[:del]
287 cmd << " DECR #{opts[:decr]}" if opts[:decr]
288 cmd << " #{opts[:order]}" if opts[:order]
289 cmd << " LIMIT #{opts[:limit].join(' ')}" if opts[:limit]
290 cmd << "\r\n"
291 execute_command(cmd)
292 end
293
294 def []=(key, val)
295 set(key,val)
296 end
297
298 def set(key, val, expiry=nil)
299 s = execute_command("SET #{key} #{value_to_wire(val)}\r\n") == OK
300 return expire(key, expiry) if s && expiry
301 s
302 end
303
304 def dbsize
305 execute_command("DBSIZE\r\n")
306 end
307
308 def expire(key, expiry=nil)
309 execute_command("EXPIRE #{key} #{expiry}\r\n") == 1
310 end
311
312 def set_unless_exists(key, val)
313 execute_command("SETNX #{key} #{value_to_wire(val)}\r\n") == 1
314 end
315
316 def bulk_reply
317 begin
318 x = read
319 puts "bulk_reply read value is #{x.inspect}" if $debug
320 return x
321 rescue => e
322 puts "error in bulk_reply #{e}" if $debug
323 nil
ed9b544e 324 end
38210f7f 325 end
326
327 def write(data)
328 puts "writing: #{data}" if $debug
329 @socket.write(data)
330 end
331
332 def read(length = 0)
333 length = read_proto unless length > 0
334 res = @socket.read(length)
335 puts "read is #{res.inspect}" if $debug
336 res
337 end
338
339 def multi_bulk
340 res = read_proto
341 puts "mb res is #{res.inspect}" if $debug
342 list = []
343 Integer(res).times do
344 vf = get_response
345 puts "curren vf is #{vf.inspect}" if $debug
346 list << vf
347 puts "current list is #{list.inspect}" if $debug
ed9b544e 348 end
38210f7f 349 list
350 end
351
352 def get_reply
353 begin
354 r = read(1)
355 raise RedisError if (r == "\r" || r == "\n")
356 rescue RedisError
357 retry
ed9b544e 358 end
38210f7f 359 r
360 end
361
362 def status_code_reply
363 begin
364 res = read_proto
365 if res.index('-') == 0
366 raise RedisError, res
367 else
368 true
369 end
370 rescue RedisError
371 raise RedisError
372 end
373 end
374
375 def execute_command(command, ignore_response=false)
376 ss = server.socket
377 unless ss.object_id == @socket.object_id
378 @socket = ss
379 puts "Socket changed, selecting DB" if $debug
380 unless command[0..6] == 'SELECT'
381 #BTM - Ugh- DRY but better than infinite recursion
382 write("SELECT #{@db}\r\n")
383 get_response
384 end
385 end
386 write(command)
387 get_response unless ignore_response
388 rescue Errno::ECONNRESET, Errno::EPIPE, NoMethodError, Timeout::Error => e
389 raise RedisError, "Connection error"
390 end
69664139 391
38210f7f 392 def get_response
393 rtype = get_reply
394 puts "reply_type is #{rtype.inspect}" if $debug
395 case rtype
396 when SINGLE
397 single_line
398 when BULK
399 bulk_reply
400 when MULTI
401 multi_bulk
402 when INT
403 integer_reply
404 when ERR
405 raise RedisError, single_line
406 else
407 raise RedisError, "Unknown response.."
408 end
409 end
410
411 def integer_reply
412 Integer(read_proto)
413 end
414
415 def single_line
416 buff = ""
417 while buff[-2..-1] != "\r\n"
418 buff << read(1)
57172ffb 419 end
38210f7f 420 puts "single_line value is #{buff[0..-3].inspect}" if $debug
421 buff[0..-3]
422 end
423
424 def read_socket
425 begin
426 socket = @server.socket
427 while res = socket.read(8096)
428 break if res.size != 8096
429 end
430 #Timeout or server down
431 rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNREFUSED => e
432 server.close
433 puts "Client (#{server.inspect}) disconnected from server: #{e.inspect}\n" if $debug
434 retry
435 rescue Timeout::Error => e
436 #BTM - Ignore this error so we don't go into an endless loop
437 puts "Client (#{server.inspect}) Timeout\n" if $debug
438 #Server down
439 rescue NoMethodError => e
440 puts "Client (#{server.inspect}) tryin server that is down: #{e.inspect}\n Dying!" if $debug
441 raise Errno::ECONNREFUSED
442 #exit
443 end
444 end
445
446 def read_proto
447 res = @socket.readline
448 x = res.chomp
449 puts "read_proto is #{x.inspect}\n\n" if $debug
450 x.to_i
451 end
d7fc9edb 452
38210f7f 453 private
454 def value_to_wire(value)
455 value_str = value.to_s
456 if value_str.respond_to?(:bytesize)
457 value_size = value_str.bytesize
458 else
459 value_size = value_str.size
ed9b544e 460 end
38210f7f 461 "#{value_size}\r\n#{value_str}"
462 end
463
27dd1526 464end