]>
git.saurik.com Git - redis.git/blob - client-libraries/ruby/lib/redis.rb
2 require File
. join ( File
. dirname ( __FILE__
), 'better_timeout' )
5 class RedisError
< StandardError
26 def initialize(opts={})
27 @opts = {:host => 'localhost', :port => '6379'}.merge(opts)
31 # Time complexity: O(1)
32 # Set the string value as value of the key. The string can't be longer
33 # than 1073741824 bytes (1 GB).
35 # Return value: status code reply
37 val = redis_marshal(val)
39 write " SET
#{key} #{val.to_s.size} \r\n #{val} \r\n "
46 # Time complexity: O(1)
47 # SETNX works exactly like SET with the only difference that if the key
48 # already exists no operation is performed. SETNX actually means " SET
if Not eXists
".
50 # *Return value: integer reply, specifically:
52 # 1 if the key was set 0 if the key was not set
53 def set_unless_exists(key, val)
54 val = redis_marshal(val)
56 write " SETNX
#{key} #{val.to_s.size} \r\n #{val} \r\n "
62 # Time complexity: O(1)
63 # Get the value of the specified key. If the key does not exist the special value
64 # 'nil' is returned. If the value stored at key is not a string an error is
65 # returned because GET can only handle string values.
67 # Return value: bulk reply
70 write " GET
#{key} \r\n "
71 redis_unmarshal(bulk_reply)
77 # Time complexity: O(1)
78 # Increment the number stored at key by one. If the key does not exist or contains
79 # a value of a wrong type, set the key to the value of " 1 " (like if the previous
82 # INCRBY works just like INCR but instead to increment by 1 the increment is value.
84 # Return value: integer reply
85 def incr(key, increment=nil)
88 write " INCRBY
#{key} #{increment} \r\n "
90 write " INCR
#{key} \r\n "
101 # Time complexity: O(1) Like INCR/INCRBY but decrementing instead of incrementing.
102 def decr(key, increment=nil)
105 write " DECRBY
#{key} #{increment} \r\n "
107 write " DECR
#{key} \r\n "
114 # Time complexity: O(1)
115 # Returns a random key from the currently seleted DB.
117 # Return value: single line reply
120 write " RANDOMKEY
\r\n "
125 # RENAME oldkey newkey
127 # Atomically renames the key oldkey to newkey. If the source and destination
128 # name are the same an error is returned. If newkey already exists it is
131 # Return value: status code reply
132 def rename! ( oldkey
, newkey
)
134 write
"RENAME #{oldkey} #{newkey} \r\n "
139 # RENAMENX oldkey newkey
140 # Just like RENAME but fails if the destination key newkey already exists.
142 # *Return value: integer reply, specifically:
144 # 1 if the key was renamed 0 if the target key already exist -1 if the
145 # source key does not exist -3 if source and destination keys are the same
146 def rename ( oldkey
, newkey
)
148 write
"RENAMENX #{oldkey} #{newkey} \r\n "
151 raise RedisError
, "source key: #{oldkey} does not exist"
153 raise RedisError
, "target key: #{oldkey} already exists"
155 raise RedisError
, "source and destination keys are the same"
163 # Time complexity: O(1)
164 # Test if the specified key exists. The command returns "0" if the key
165 # exists, otherwise "1" is returned. Note that even keys set with an empty
166 # string as value will return "1".
168 # *Return value: integer reply, specifically:
170 # 1 if the key exists 0 if the key does not exist
173 write
"EXISTS #{key} \r\n "
179 # Time complexity: O(1)
180 # Remove the specified key. If the key does not exist no operation is
181 # performed. The command always returns success.
183 # *Return value: integer reply, specifically:
185 # 1 if the key was removed 0 if the key does not exist
188 write
"DEL #{key} \r\n "
194 # Time complexity: O(n) (with n being the number of keys in the DB)
195 # Returns all the keys matching the glob-style pattern as space separated strings.
196 # For example if you have in the database the keys "foo" and "foobar" the command
197 # "KEYS foo*" will return "foo foobar".
199 # Note that while the time complexity for this operation is O(n) the constant times
200 # are pretty low. For example Redis running on an entry level laptop can scan a 1
201 # million keys database in 40 milliseconds. Still it's better to consider this one
202 # of the slow commands that may ruin the DB performance if not used with care.
204 # Return value: bulk reply
207 write
"KEYS #{glob} \r\n "
208 bulk_reply
. split ( ' ' )
214 # Time complexity: O(1) Return the type of the value stored at key in form of
215 # a string. The type can be one of "none", "string", "list", "set". "none" is
216 # returned if the key does not exist.
218 # Return value: single line reply
221 write
"TYPE #{key} \r\n "
228 # Time complexity: O(1)
229 # Add the given string to the tail of the list contained at key. If the key
230 # does not exist an empty list is created just before the append operation.
231 # If the key exists but is not a List an error is returned.
233 # Return value: status code reply
234 def push_tail ( key
, string
)
236 write
"RPUSH #{key} #{string.to_s.size} \r\n #{string.to_s} \r\n "
242 # Time complexity: O(1)
243 # Add the given string to the head of the list contained at key. If the
244 # key does not exist an empty list is created just before the append operation.
245 # If the key exists but is not a List an error is returned.
247 # Return value: status code reply
248 def push_head ( key
, string
)
250 write
"LPUSH #{key} #{string.to_s.size} \r\n #{string.to_s} \r\n "
257 # Time complexity: O(1)
258 # Atomically return and remove the first element of the list. For example if
259 # the list contains the elements "a","b","c" LPOP will return "a" and the
260 # list will become "b","c".
262 # If the key does not exist or the list is already empty the special value
265 # Return value: bulk reply
268 write
"LPOP #{key} \r\n "
274 # This command works exactly like LPOP, but the last element instead
275 # of the first element of the list is returned/deleted.
278 write
"RPOP #{key} \r\n "
283 # LSET key index value
284 # Time complexity: O(N) (with N being the length of the list)
285 # Set the list element at index (see LINDEX for information about the index argument) with the new value. Out of range indexes will generate an error. Note that setting the first or last elements of the list is O(1).
287 # Return value: status code reply
288 def list_set ( key
, index
, val
)
290 write
"LSET #{key} #{index} #{val.to_s.size} \r\n #{val} \r\n "
297 # Time complexity: O(1)
298 # Return the length of the list stored at the specified key. If the key does not
299 # exist zero is returned (the same behaviour as for empty lists). If the value
300 # stored at key is not a list the special value -1 is returned. Note: client
301 # library should raise an exception when -1 is returned instead to pass the
302 # value back to the caller like a normal list length value.
304 # *Return value: integer reply, specifically:
306 # the length of the list as an integer
308 # 0 if the operation succeeded -2 if the specified key does not hold a list valu
311 write
"LLEN #{key} \r\n "
312 case i
= integer_reply
314 raise RedisError
, "key: #{key} does not hold a list value"
321 # LRANGE key start end
322 # Time complexity: O(n) (with n being the length of the range)
323 # Return the specified elements of the list stored at the specified key. Start
324 # and end are zero-based indexes. 0 is the first element of the list (the list head),
325 # 1 the next element and so on.
327 # For example LRANGE foobar 0 2 will return the first three elements of the list.
329 # start and end can also be negative numbers indicating offsets from the end of the list.
330 # For example -1 is the last element of the list, -2 the penultimate element and so on.
332 # Indexes out of range will not produce an error: if start is over the end of the list,
333 # or start > end, an empty list is returned. If end is over the end of the list Redis
334 # will threat it just like the last element of the list.
336 # Return value: multi bulk reply
337 def list_range ( key
, start
, ending
)
339 write
"LRANGE #{key} #{start} #{ending} \r\n "
345 # LTRIM key start end
346 # Time complexity: O(n) (with n being len of list - len of range)
347 # Trim an existing list so that it will contain only the specified range of
348 # elements specified. Start and end are zero-based indexes. 0 is the first
349 # element of the list (the list head), 1 the next element and so on.
351 # For example LTRIM foobar 0 2 will modify the list stored at foobar key so that
352 # only the first three elements of the list will remain.
354 # start and end can also be negative numbers indicating offsets from the end of
355 # the list. For example -1 is the last element of the list, -2 the penultimate
358 # Indexes out of range will not produce an error: if start is over the end of
359 # the list, or start > end, an empty list is left as value. If end over the
360 # end of the list Redis will threat it just like the last element of the list.
362 # Hint: the obvious use of LTRIM is together with LPUSH/RPUSH. For example:
364 # LPUSH mylist <someelement> LTRIM mylist 0 99
365 # The above two commands will push elements in the list taking care that the
366 # list will not grow without limits. This is very useful when using Redis
367 # to store logs for example. It is important to note that when used in this
368 # way LTRIM is an O(1) operation because in the average case just one element
369 # is removed from the tail of the list.
371 # Return value: status code reply
372 def list_trim ( key
, start
, ending
)
374 write
"LTRIM #{key} #{start} #{ending} \r\n "
380 # Time complexity: O(n) (with n being the length of the list)
381 # Return the specified element of the list stored at the specified key. 0 is
382 # the first element, 1 the second and so on. Negative indexes are supported,
383 # for example -1 is the last element, -2 the penultimate and so on.
385 # If the value stored at key is not of list type an error is returned. If
386 # the index is out of range an empty string is returned.
388 # Note that even if the average time complexity is O(n) asking for the first
389 # or the last element of the list is O(1).
391 # Return value: bulk reply
392 def list_index ( key
, index
)
394 write
"LINDEX #{key} #{index} \r\n "
400 # Time complexity O(1)
401 # Add the specified member to the set value stored at key. If member is
402 # already a member of the set no operation is performed. If key does not
403 # exist a new set with the specified member as sole member is crated. If
404 # the key exists but does not hold a set value an error is returned.
406 # *Return value: integer reply, specifically:
408 # 1 if the new element was added 0 if the new element was already a member
409 # of the set -2 if the key contains a non set value
410 def set_add ( key
, member
)
412 write
"SADD #{key} #{member.to_s.size} \r\n #{member} \r\n "
419 raise RedisError
, "key: #{key} contains a non set value"
426 # Time complexity O(1)
427 # Remove the specified member from the set value stored at key. If member
428 # was not a member of the set no operation is performed. If key does not
429 # exist or does not hold a set value an error is returned.
431 # *Return value: integer reply, specifically:
433 # 1 if the new element was removed 0 if the new element was not a member
434 # of the set -2 if the key does not hold a set value
435 def set_delete ( key
, member
)
437 write
"SREM #{key} #{member.to_s.size} \r\n #{member} \r\n "
444 raise RedisError
, "key: #{key} contains a non set value"
450 # Time complexity O(1)
451 # Return the set cardinality (number of elements). If the key does not
452 # exist 0 is returned, like for empty sets. If the key does not hold a
453 # set value -1 is returned. Client libraries should raise an error when -1
454 # is returned instead to pass the value to the caller.
456 # *Return value: integer reply, specifically:
458 # the cardinality (number of elements) of the set as an integer
460 # 0 if the operation succeeded -2 if the specified key does not hold a set value
463 write
"SCARD #{key} \r\n "
464 case i
= integer_reply
466 raise RedisError
, "key: #{key} contains a non set value"
473 # SISMEMBER key member
475 # Time complexity O(1)
476 # Return 1 if member is a member of the set stored at key, otherwise 0 is
477 # returned. On error a negative value is returned. Client libraries should
478 # raise an error when a negative value is returned instead to pass the value
481 # *Return value: integer reply, specifically:
483 # 1 if the element is a member of the set 0 if the element is not a member of
484 # the set OR if the key does not exist -2 if the key does not hold a set value
485 def set_member
?( key
, member
)
487 write
"SISMEMBER #{key} #{member.to_s.size} \r\n #{member} \r\n "
494 raise RedisError
, "key: #{key} contains a non set value"
499 # SINTER key1 key2 ... keyN
500 # Time complexity O(N*M) worst case where N is the cardinality of the smallest
501 # set and M the number of sets
502 # Return the members of a set resulting from the intersection of all the sets
503 # hold at the specified keys. Like in LRANGE the result is sent to the client
504 # as a multi-bulk reply (see the protocol specification for more information).
505 # If just a single key is specified, then this command produces the same
506 # result as SELEMENTS. Actually SELEMENTS is just syntax sugar for SINTERSECT.
508 # If at least one of the specified keys does not exist or does not hold a set
509 # value an error is returned.
511 # Return value: multi bulk reply
512 def set_intersect (* keys
)
514 write
"SINTER #{keys.join(' ')} \r\n "
515 Set
. new ( multi_bulk_reply
)
519 # SINTERSTORE dstkey key1 key2 ... keyN
521 # Time complexity O(N*M) worst case where N is the cardinality of the smallest set and M the number of sets
522 # This commnad works exactly like SINTER but instead of being returned the resulting set is sotred as dstkey.
524 # Return value: status code reply
525 def set_inter_store ( destkey
, * keys
)
527 write
"SINTERSTORE #{destkey} #{keys.join(' ')} \r\n "
534 # Time complexity O(N)
535 # Return all the members (elements) of the set value stored at key.
536 # This is just syntax glue for SINTERSECT.
539 write
"SMEMBERS #{key} \r\n "
540 Set
. new ( multi_bulk_reply
)
545 # SORT key [BY pattern] [GET|DEL|INCR|DECR pattern] [ASC|DESC] [LIMIT start count]
546 # Sort the elements contained in the List or Set value at key. By default sorting is
547 # numeric with elements being compared as double precision floating point numbers.
548 # This is the simplest form of SORT.
551 # Assuming mylist contains a list of numbers, the return value will be the list of
552 # numbers ordered from the smallest to the bigger number. In order to get the sorting
553 # in reverse order use DESC:
556 # ASC is also supported but it's the default so you don't really need it. If you
557 # want to sort lexicographically use ALPHA. Note that Redis is utf-8 aware
558 # assuming you set the right value for the LC_COLLATE environment variable.
560 # Sort is able to limit the number of results using the LIMIT option:
561 # SORT mylist LIMIT 0 10
562 # In the above example SORT will return only 10 elements, starting from the first one
563 # (star is zero-based). Almost all the sort options can be mixed together. For example:
564 # SORT mylist LIMIT 0 10 ALPHA DESC
565 # Will sort mylist lexicographically, in descending order, returning only the first
567 # Sometimes you want to sort elements using external keys as weights to compare
568 # instead to compare the actual List or Set elements. For example the list mylist
569 # may contain the elements 1, 2, 3, 4, that are just the unique IDs of objects
570 # stored at object_1, object_2, object_3 and object_4, while the keys weight_1,
571 # weight_2, weight_3 and weight_4 can contain weights we want to use to sort the
572 # list of objects identifiers. We can use the following command:
573 # SORT mylist BY weight_*
574 # the BY option takes a pattern (weight_* in our example) that is used in order to
575 # generate the key names of the weights used for sorting. Weight key names are obtained
576 # substituting the first occurrence of * with the actual value of the elements on the
577 # list (1,2,3,4 in our example).
578 # Still our previous example will return just the sorted IDs. Often it is needed to
579 # get the actual objects sorted (object_1, ..., object_4 in the example). We can do
580 # it with the following command:
581 # SORT mylist BY weight_* GET object_*
582 # Note that GET can be used multiple times in order to get more key for every
583 # element of the original List or Set sorted.
585 # redis.sort 'index', :by => 'weight_*',
586 # :order => 'DESC ALPHA',
589 def sort ( key
, opts
={})
591 cmd
<< " BY #{opts[:by]} " if opts
[ :by ]
592 cmd
<< " GET #{opts[:get]} " if opts
[ :get ]
593 cmd
<< " INCR #{opts[:incr]} " if opts
[ :incr ]
594 cmd
<< " DEL #{opts[:del]} " if opts
[ :del ]
595 cmd
<< " DECR #{opts[:decr]} " if opts
[ :decr ]
596 cmd
<< " #{opts[:order]} " if opts
[ :order ]
597 cmd
<< " LIMIT #{opts[:limit].join(' ')} " if opts
[ :limit ]
603 # ADMIN functions for redis
607 # Select the DB with having the specified zero-based numeric index.
608 # For default every new client connection is automatically selected to DB 0.
609 # Return value: status code reply
612 write
"SELECT #{index} \r\n "
619 # Move the specified key from the currently selected DB to the specified
620 # destination DB. Note that this command returns 1 only if the key was
621 # successfully moved, and 0 if the target key was already there or if
622 # the source key was not found at all, so it is possible to use MOVE
623 # as a locking primitive.
625 # *Return value: integer reply, specifically:
627 # 1 if the key was moved 0 if the key was not moved because already
628 # present on the target DB or was not found in the current DB. -3
629 # if the destination DB is the same as the source DB -4 if the database
630 # index if out of range
633 write
"MOVE #{index} \r\n "
640 raise RedisError
, "destination db same as source db"
642 raise RedisError
, "db index if out of range"
649 # Save the DB on disk. The server hangs while the saving is not completed,
650 # no connection is served in the meanwhile. An OK code is returned when
651 # the DB was fully stored in disk.
652 # Return value: status code reply
662 # Save the DB in background. The OK code is immediately returned. Redis
663 # forks, the parent continues to server the clients, the child saves
664 # the DB on disk then exit. A client my be able to check if the operation
665 # succeeded using the LASTSAVE command.
666 # Return value: status code reply
676 # Return the UNIX TIME of the last DB save executed with success. A client
677 # may check if a BGSAVE command succeeded reading the LASTSAVE value, then
678 # issuing a BGSAVE command and checking at regular intervals every N seconds
679 # if LASTSAVE changed.
681 # Return value: integer reply (UNIX timestamp)
698 def redis_unmarshal ( obj
)
706 def redis_marshal ( obj
)
716 socket
. close
unless socket
. closed
?
719 def timeout_retry ( time
, retries
, & block
)
720 timeout ( time
, & block
)
723 retry unless retries
< 0
727 connect
if ( !
@socket or @socket . closed
?)
732 @socket = TCPSocket
. new ( @opts [ :host ], @opts [ :port ])
737 def read ( length
, nodebug
= true )
739 res
= socket
. read ( length
)
740 puts
"read: #{res} " if @opts [ :debug ] && nodebug
751 puts
"write: #{data} " if @opts [ :debug ]
767 print
"read proto: " if @opts [ :debug ]
769 while ( char
= read ( 1 , false ))
770 print char
if @opts [ :debug ]
772 break if buff
[- 2 ..- 1 ] == CTRLF
774 puts
if @opts [ :debug ]
779 def status_code_reply
781 if res
. index ( ERRCODE
) == 0
782 raise RedisError
, res
790 if res
. index ( ERRCODE
) == 0
791 err
= read ( res
. to_i
. abs
)
793 raise RedisError
, err
795 val
= read ( res
. to_i
. abs
)
806 if res
. index ( ERRCODE
) == 0
807 err
= read ( res
. to_i
. abs
)
809 raise RedisError
, err
816 len
= Integer ( read_proto
)
828 def single_line_reply