├── client-libraries ├── erlang │ ├── .hgignore │ ├── .hg_archival.txt │ ├── include │ │ └── erldis.hrl │ ├── src │ │ ├── Makefile │ │ └── proto.erl │ ├── test │ │ ├── Makefile │ │ └── proto_tests.erl │ ├── Makefile │ ├── LICENSE │ └── support │ │ └── include.mk ├── clojure │ ├── .gitignore │ ├── benchmarks │ │ └── ruby.clj │ ├── examples │ │ └── demo.clj │ ├── LICENSE │ ├── README.markdown │ └── build.xml ├── ruby │ ├── .gitignore │ ├── spec │ │ └── spec_helper.rb │ ├── examples │ │ ├── basic.rb │ │ ├── incr-decr.rb │ │ ├── list.rb │ │ └── sets.rb │ ├── speed.rb │ ├── lib │ │ ├── pipeline.rb │ │ └── dist_redis.rb │ ├── profile.rb │ ├── benchmarking │ │ ├── suite.rb │ │ └── worker.rb │ ├── bin │ │ └── distredis │ ├── README.markdown │ ├── LICENSE │ ├── bench.rb │ ├── redis-rb.gemspec │ └── Rakefile ├── scala │ ├── .gitignore │ ├── src │ │ ├── main │ │ │ └── scala │ │ │ │ └── com │ │ │ │ └── redis │ │ │ │ ├── Connection.scala │ │ │ │ ├── Operations │ │ │ │ ├── SortOperations.scala │ │ │ │ └── KeySpaceOperations.scala │ │ │ │ ├── RedisClient.scala │ │ │ │ ├── RedisCluster.scala │ │ │ │ └── HashRing.scala │ │ └── test │ │ │ └── scala │ │ │ └── com │ │ │ └── redis │ │ │ ├── helpers │ │ │ └── RedisClientTestHelper.scala │ │ │ ├── RedisClientSpec.scala │ │ │ ├── operations │ │ │ ├── SortOperationsSpec.scala │ │ │ ├── KeySpaceOperationsSpec.scala │ │ │ ├── ListOperationsSpec.scala │ │ │ └── OperationsSpec.scala │ │ │ ├── RedisClusterSpec.scala │ │ │ └── SocketOperationsSpec.scala │ ├── project │ │ ├── build.properties │ │ └── build │ │ │ └── RedisClientProject.scala │ └── README.md ├── update-erlang-client.sh ├── perl │ ├── MANIFEST │ ├── t │ │ ├── 00-load.t │ │ ├── pod.t │ │ ├── 10-Redis-List.t │ │ ├── pod-coverage.t │ │ └── 20-Redis-Hash.t │ ├── Changes │ ├── Makefile.PL │ ├── scripts │ │ └── redis-benchmark.pl │ ├── README │ └── lib │ │ └── Redis │ │ ├── Hash.pm │ │ └── List.pm ├── cpp │ ├── fmacros.h │ ├── TODO │ ├── README.rst │ ├── Makefile │ └── anet.h ├── lua │ ├── README │ └── LICENSE ├── update-python-client.sh ├── update-lua-client.sh ├── update-perl-client.sh ├── update-scala-client.sh ├── update-cpp-client.sh ├── update-clojure-client.sh ├── update-ruby-client.sh ├── README └── tcl │ └── redis.tcl ├── BUGS ├── README ├── doc ├── redis.png ├── style.css ├── DesignPatterns.html ├── TemplateCommand.html ├── QuitCommand.html ├── FlushdbCommand.html ├── DbsizeCommand.html ├── FlushallCommand.html ├── RandomkeyCommand.html ├── SelectCommand.html ├── SaveCommand.html ├── SetCommand.html ├── GetCommand.html ├── BgsaveCommand.html ├── RenameCommand.html ├── LastsaveCommand.html ├── TtlCommand.html ├── SetnxCommand.html ├── DelCommand.html ├── RenamenxCommand.html ├── ShutdownCommand.html ├── SpopCommand.html ├── TypeCommand.html ├── ExistsCommand.html ├── SmembersCommand.html ├── AuthCommand.html ├── UnstableSource.html ├── LlenCommand.html ├── LsetCommand.html ├── MoveCommand.html ├── ScardCommand.html ├── SinterstoreCommand.html ├── SunionstoreCommand.html ├── RpushCommand.html ├── LpopCommand.html ├── SismemberCommand.html ├── SremCommand.html ├── SdiffstoreCommand.html ├── MgetCommand.html ├── SaddCommand.html ├── GetsetCommand.html ├── LindexCommand.html ├── IncrCommand.html ├── MonitorCommand.html ├── SunionCommand.html ├── SdiffCommand.html ├── LremCommand.html ├── SinterCommand.html ├── LrangeCommand.html ├── Credits.html ├── SmoveCommand.html ├── SlaveofCommand.html ├── index.html ├── InfoCommand.html ├── KeysCommand.html └── LtrimCommand.html ├── fmacros.h ├── .gitignore ├── BETATESTING.txt ├── pqsort.h ├── README.md ├── config.h ├── utils ├── redis-sha1.rb └── redis-copy.rb ├── COPYING ├── TODO ├── zmalloc.h ├── redis.h ├── Makefile └── anet.h /client-libraries/erlang/.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.beam -------------------------------------------------------------------------------- /BUGS: -------------------------------------------------------------------------------- 1 | Plese check http://code.google.com/p/redis/issues/list 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Check the 'doc' directory. doc/README.html is a good starting point :) 2 | -------------------------------------------------------------------------------- /doc/redis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zwjlpeng/Redis_Deep_Read/HEAD/doc/redis.png -------------------------------------------------------------------------------- /client-libraries/clojure/.gitignore: -------------------------------------------------------------------------------- 1 | classes 2 | \#* 3 | .\#* 4 | *.jar 5 | build.properties -------------------------------------------------------------------------------- /client-libraries/ruby/.gitignore: -------------------------------------------------------------------------------- 1 | nohup.out 2 | redis/* 3 | rdsrv 4 | pkg/* 5 | coverage/* 6 | .idea 7 | -------------------------------------------------------------------------------- /client-libraries/scala/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | lib_managed 3 | project/boot 4 | target 5 | target/ 6 | target/**/* 7 | -------------------------------------------------------------------------------- /client-libraries/update-erlang-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Sorry for now this must be done by hand... don't know mercurial enough" 3 | -------------------------------------------------------------------------------- /fmacros.h: -------------------------------------------------------------------------------- 1 | #ifndef _REDIS_FMACRO_H 2 | #define _REDIS_FMACRO_H 3 | 4 | #define _BSD_SOURCE 5 | #define _XOPEN_SOURCE 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /client-libraries/erlang/.hg_archival.txt: -------------------------------------------------------------------------------- 1 | repo: 9e1f35ed7fdc7b3da7f5ff66a71d1975b85e2ae5 2 | node: 85e28ca5597e22ff1dde18ed4625f41923128993 3 | -------------------------------------------------------------------------------- /client-libraries/erlang/include/erldis.hrl: -------------------------------------------------------------------------------- 1 | -record(redis, {socket,buffer=[],reply_caller,calls=0,remaining=0,pstate=empty,results=[]}). 2 | -------------------------------------------------------------------------------- /client-libraries/perl/MANIFEST: -------------------------------------------------------------------------------- 1 | Changes 2 | MANIFEST 3 | Makefile.PL 4 | README 5 | lib/Redis.pm 6 | t/00-load.t 7 | t/pod-coverage.t 8 | t/pod.t 9 | -------------------------------------------------------------------------------- /client-libraries/cpp/fmacros.h: -------------------------------------------------------------------------------- 1 | #ifndef _REDIS_FMACRO_H 2 | #define _REDIS_FMACRO_H 3 | 4 | #define _BSD_SOURCE 5 | #define _XOPEN_SOURCE 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /client-libraries/ruby/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | $TESTING=true 3 | $:.unshift File.join(File.dirname(__FILE__), '..', 'lib') 4 | require 'redis' 5 | -------------------------------------------------------------------------------- /client-libraries/lua/README: -------------------------------------------------------------------------------- 1 | redis-lua 2 | ------------------------------------------------------------------------------- 3 | 4 | A Lua client library for the redis key value storage system. -------------------------------------------------------------------------------- /client-libraries/erlang/src/Makefile: -------------------------------------------------------------------------------- 1 | include ../support/include.mk 2 | 3 | all: $(EBIN_FILES) 4 | 5 | debug: 6 | $(MAKE) DEBUG=-DDEBUG 7 | 8 | clean: 9 | rm -rf $(EBIN_FILES) erl_crash.dump 10 | -------------------------------------------------------------------------------- /client-libraries/perl/t/00-load.t: -------------------------------------------------------------------------------- 1 | #!perl -T 2 | 3 | use Test::More tests => 1; 4 | 5 | BEGIN { 6 | use_ok( 'Redis' ); 7 | } 8 | 9 | diag( "Testing Redis $Redis::VERSION, Perl $], $^X" ); 10 | -------------------------------------------------------------------------------- /client-libraries/scala/src/main/scala/com/redis/Connection.scala: -------------------------------------------------------------------------------- 1 | package com.redis 2 | 3 | /** 4 | * Redis client Connection 5 | * 6 | */ 7 | 8 | case class Connection(val host: String, val port: Int) extends SocketOperations 9 | -------------------------------------------------------------------------------- /client-libraries/update-python-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf temp 3 | mkdir temp 4 | cd temp 5 | git clone git://github.com/ludoo/redis.git 6 | cd .. 7 | rm -rf python 8 | mv temp/redis/client-libraries/python python 9 | rm -rf temp 10 | -------------------------------------------------------------------------------- /client-libraries/ruby/examples/basic.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'redis' 3 | 4 | r = Redis.new 5 | 6 | r.delete('foo') 7 | 8 | puts 9 | 10 | p'set foo to "bar"' 11 | r['foo'] = 'bar' 12 | 13 | puts 14 | 15 | p 'value of foo' 16 | p r['foo'] 17 | -------------------------------------------------------------------------------- /client-libraries/update-lua-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf temp 3 | mkdir temp 4 | cd temp 5 | git clone git://github.com/nrk/redis-lua.git 6 | cd redis-lua 7 | rm -rf .git 8 | cd .. 9 | cd .. 10 | rm -rf lua 11 | mv temp/redis-lua lua 12 | rm -rf temp 13 | -------------------------------------------------------------------------------- /client-libraries/scala/project/build.properties: -------------------------------------------------------------------------------- 1 | #Project properties 2 | #Wed Aug 19 07:54:05 ART 2009 3 | project.organization=com.redis 4 | project.name=RedisClient 5 | sbt.version=0.5.1 6 | project.version=1.0.1 7 | scala.version=2.7.5 8 | project.initialize=false 9 | -------------------------------------------------------------------------------- /client-libraries/update-perl-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf temp 3 | mkdir temp 4 | cd temp 5 | svn checkout svn://svn.rot13.org/Redis/ 6 | find . -name '.svn' -exec rm -rf {} \; 2> /dev/null 7 | cd .. 8 | rm -rf perl 9 | mv temp/Redis perl 10 | rm -rf temp 11 | -------------------------------------------------------------------------------- /client-libraries/update-scala-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf temp 3 | mkdir temp 4 | cd temp 5 | git clone git://github.com/acrosa/scala-redis.git 6 | cd scala-redis 7 | rm -rf .git 8 | cd .. 9 | cd .. 10 | rm -rf scala 11 | mv temp/scala-redis scala 12 | rm -rf temp 13 | -------------------------------------------------------------------------------- /client-libraries/update-cpp-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf temp 3 | mkdir temp 4 | cd temp 5 | git clone git://github.com/fictorial/redis-cpp-client.git 6 | cd redis-cpp-client 7 | rm -rf .git 8 | cd .. 9 | cd .. 10 | rm -rf cpp 11 | mv temp/redis-cpp-client cpp 12 | rm -rf temp 13 | -------------------------------------------------------------------------------- /client-libraries/update-clojure-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf temp 3 | mkdir temp 4 | cd temp 5 | git clone git://github.com/ragnard/redis-clojure.git 6 | cd redis-clojure 7 | rm -rf .git 8 | cd .. 9 | cd .. 10 | rm -rf clojure 11 | mv temp/redis-clojure clojure 12 | rm -rf temp 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | -------------------------------------------------------------------------------- /client-libraries/erlang/test/Makefile: -------------------------------------------------------------------------------- 1 | include ../support/include.mk 2 | 3 | all: $(EBIN_FILES) 4 | 5 | clean: 6 | rm -rf $(EBIN_FILES) erl_crash.dump 7 | 8 | test: $(MODULES) 9 | 10 | ./$(MODULES): 11 | @echo "Running tests for $@" 12 | erl -pa ../ebin -run $@ test -run init stop -noshell 13 | -------------------------------------------------------------------------------- /client-libraries/perl/t/pod.t: -------------------------------------------------------------------------------- 1 | #!perl -T 2 | 3 | use strict; 4 | use warnings; 5 | use Test::More; 6 | 7 | # Ensure a recent version of Test::Pod 8 | my $min_tp = 1.22; 9 | eval "use Test::Pod $min_tp"; 10 | plan skip_all => "Test::Pod $min_tp required for testing POD" if $@; 11 | 12 | all_pod_files_ok(); 13 | -------------------------------------------------------------------------------- /client-libraries/perl/Changes: -------------------------------------------------------------------------------- 1 | Revision history for Redis 2 | 3 | 0.01 Sun Mar 22 19:02:17 CET 2009 4 | First version, tracking git://github.com/antirez/redis 5 | 6 | 0.08 Tue Mar 24 22:38:59 CET 2009 7 | This version supports new protocol introduced in beta 8 8 | Version bump to be in-sync with Redis version 9 | -------------------------------------------------------------------------------- /client-libraries/update-ruby-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf temp 3 | mkdir temp 4 | cd temp 5 | git clone git://github.com/ezmobius/redis-rb.git 6 | #git clone git://github.com/jodosha/redis-rb.git 7 | cd redis-rb 8 | rm -rf .git 9 | cd .. 10 | cd .. 11 | rm -rf ruby 12 | mv temp/redis-rb ruby 13 | rm -rf temp 14 | -------------------------------------------------------------------------------- /BETATESTING.txt: -------------------------------------------------------------------------------- 1 | This is a stable release, for beta testing make sure to download the latest source code from Git: 2 | 3 | git clone git://github.com/antirez/redis.git 4 | 5 | It's also possibe to download the latest source code as a tarball: 6 | 7 | http://github.com/antirez/redis/tree/master 8 | 9 | (use the download button) 10 | -------------------------------------------------------------------------------- /client-libraries/ruby/examples/incr-decr.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'redis' 3 | 4 | r = Redis.new 5 | 6 | puts 7 | p 'incr' 8 | r.delete 'counter' 9 | 10 | p r.incr('counter') 11 | p r.incr('counter') 12 | p r.incr('counter') 13 | 14 | puts 15 | p 'decr' 16 | p r.decr('counter') 17 | p r.decr('counter') 18 | p r.decr('counter') 19 | -------------------------------------------------------------------------------- /client-libraries/erlang/test/proto_tests.erl: -------------------------------------------------------------------------------- 1 | -module(proto_tests). 2 | 3 | -include_lib("eunit/include/eunit.hrl"). 4 | 5 | parse_test() -> 6 | ok = proto:parse(empty, "+OK"), 7 | pong = proto:parse(empty, "+PONG"), 8 | false = proto:parse(empty, ":0"), 9 | true = proto:parse(empty, ":1"), 10 | {error, "1"} = proto:parse(empty, "-1"). 11 | -------------------------------------------------------------------------------- /doc/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Verdana'; 3 | width:800px; 4 | } 5 | 6 | a { 7 | text-decoration: none; 8 | } 9 | 10 | h1, h2, h3, h4, h5 { 11 | color: #333; 12 | } 13 | 14 | h1 { 15 | font-size: 20px; 16 | } 17 | 18 | .codeblock { 19 | color: darkgreen; 20 | padding:5px; 21 | } 22 | 23 | h1.wikiname { 24 | color: #f55000; 25 | } 26 | -------------------------------------------------------------------------------- /client-libraries/ruby/speed.rb: -------------------------------------------------------------------------------- 1 | require 'benchmark' 2 | require "#{File.dirname(__FILE__)}/lib/redis" 3 | 4 | r = Redis.new 5 | n = (ARGV.shift || 20000).to_i 6 | 7 | elapsed = Benchmark.realtime do 8 | # n sets, n gets 9 | n.times do |i| 10 | key = "foo#{i}" 11 | r[key] = key * 10 12 | r[key] 13 | end 14 | end 15 | 16 | puts '%.2f Kops' % (2 * n / 1000 / elapsed) 17 | -------------------------------------------------------------------------------- /client-libraries/ruby/lib/pipeline.rb: -------------------------------------------------------------------------------- 1 | require "redis" 2 | 3 | class Redis 4 | class Pipeline < Redis 5 | BUFFER_SIZE = 50_000 6 | 7 | def initialize(redis) 8 | @redis = redis 9 | @commands = [] 10 | end 11 | 12 | def call_command(command) 13 | @commands << command 14 | end 15 | 16 | def execute 17 | @redis.call_command(@commands) 18 | @commands.clear 19 | end 20 | 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /pqsort.h: -------------------------------------------------------------------------------- 1 | /* The following is the NetBSD libc qsort implementation modified in order to 2 | * support partial sorting of ranges for Redis. 3 | * 4 | * Copyright(C) 2009 Salvatore Sanfilippo. All rights reserved. 5 | * 6 | * See the pqsort.c file for the original copyright notice. */ 7 | 8 | #ifndef __PQSORT_H 9 | #define __PQSORT_H 10 | 11 | void 12 | pqsort(void *a, size_t n, size_t es, 13 | int (*cmp) (const void *, const void *), size_t lrange, size_t rrange); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /client-libraries/ruby/profile.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'ruby-prof' 3 | require "#{File.dirname(__FILE__)}/lib/redis" 4 | 5 | 6 | mode = ARGV.shift || 'process_time' 7 | n = (ARGV.shift || 200).to_i 8 | 9 | r = Redis.new 10 | RubyProf.measure_mode = RubyProf.const_get(mode.upcase) 11 | RubyProf.start 12 | 13 | n.times do |i| 14 | key = "foo#{i}" 15 | r[key] = key * 10 16 | r[key] 17 | end 18 | 19 | results = RubyProf.stop 20 | File.open("profile.#{mode}", 'w') do |out| 21 | RubyProf::CallTreePrinter.new(results).print(out) 22 | end 23 | -------------------------------------------------------------------------------- /client-libraries/scala/src/test/scala/com/redis/helpers/RedisClientTestHelper.scala: -------------------------------------------------------------------------------- 1 | import org.specs._ 2 | import com.redis._ 3 | import com.redis.operations._ 4 | 5 | import org.specs.mock.Mockito 6 | import org.mockito.Mock._ 7 | import org.mockito.Mockito._ 8 | import org.mockito.Mockito.doNothing 9 | 10 | class RedisTestClient(val connection: Connection) extends Operations with ListOperations with SetOperations with NodeOperations with KeySpaceOperations with SortOperations { 11 | var db: Int = 0 12 | def getConnection(key: String): Connection = connection 13 | } -------------------------------------------------------------------------------- /client-libraries/scala/project/build/RedisClientProject.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | 3 | class RedisClientProject(info: ProjectInfo) extends DefaultProject(info) with AutoCompilerPlugins 4 | { 5 | override def useDefaultConfigurations = true 6 | 7 | val scalatest = "org.scala-tools.testing" % "scalatest" % "0.9.5" % "test->default" 8 | val specs = "org.scala-tools.testing" % "specs" % "1.5.0" 9 | val mockito = "org.mockito" % "mockito-all" % "1.7" 10 | val junit = "junit" % "junit" % "4.5" 11 | val sxr = compilerPlugin("org.scala-tools.sxr" %% "sxr" % "0.2.1") 12 | } 13 | -------------------------------------------------------------------------------- /client-libraries/cpp/TODO: -------------------------------------------------------------------------------- 1 | general: 2 | - check for complete support for 0.100 (compiles; existing tests pass) 3 | 4 | command handlers: 5 | - support DEL as vararg 6 | - support MLLEN and MSCARD 7 | - support SDIFF 8 | - support SDIFFSTORE 9 | 10 | 11 | unit tests: 12 | - sort with limit 13 | - sort lexicographically 14 | - sort with pattern and weights 15 | 16 | extras: 17 | - benchmarking "test" app 18 | - consistent hashing? 19 | 20 | maybe/someday: 21 | - make all string literals constants so they can be easily changed 22 | - add conveniences that store a std::set in its entirety (same for std::list, std::vector) 23 | -------------------------------------------------------------------------------- /client-libraries/ruby/examples/list.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'redis' 3 | 4 | r = Redis.new 5 | 6 | r.delete 'logs' 7 | 8 | puts 9 | 10 | p "pushing log messages into a LIST" 11 | r.push_tail 'logs', 'some log message' 12 | r.push_tail 'logs', 'another log message' 13 | r.push_tail 'logs', 'yet another log message' 14 | r.push_tail 'logs', 'also another log message' 15 | 16 | puts 17 | p 'contents of logs LIST' 18 | 19 | p r.list_range('logs', 0, -1) 20 | 21 | puts 22 | p 'Trim logs LIST to last 2 elements(easy circular buffer)' 23 | 24 | r.list_trim('logs', -2, -1) 25 | 26 | p r.list_range('logs', 0, -1) 27 | -------------------------------------------------------------------------------- /client-libraries/perl/Makefile.PL: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use ExtUtils::MakeMaker; 4 | 5 | WriteMakefile( 6 | NAME => 'Redis', 7 | AUTHOR => 'Dobrica Pavlinusic ', 8 | VERSION_FROM => 'lib/Redis.pm', 9 | ABSTRACT_FROM => 'lib/Redis.pm', 10 | PL_FILES => {}, 11 | PREREQ_PM => { 12 | 'Test::More' => 0, 13 | 'IO::Socket::INET' => 0, 14 | 'Data::Dump' => 0, 15 | 'Carp' => 0, 16 | }, 17 | dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, 18 | clean => { FILES => 'Redis-*' }, 19 | ); 20 | -------------------------------------------------------------------------------- /client-libraries/perl/t/10-Redis-List.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use warnings; 4 | use strict; 5 | 6 | use Test::More tests => 8; 7 | use lib 'lib'; 8 | use Data::Dump qw/dump/; 9 | 10 | BEGIN { 11 | use_ok( 'Redis::List' ); 12 | } 13 | 14 | my @a; 15 | 16 | ok( my $o = tie( @a, 'Redis::List', 'test-redis-list' ), 'tie' ); 17 | 18 | isa_ok( $o, 'Redis::List' ); 19 | 20 | $o->CLEAR; 21 | 22 | ok( ! @a, 'empty list' ); 23 | 24 | ok( @a = ( 'foo', 'bar', 'baz' ), '=' ); 25 | is_deeply( [ @a ], [ 'foo', 'bar', 'baz' ] ); 26 | 27 | ok( push( @a, 'push' ), 'push' ); 28 | is_deeply( [ @a ], [ 'foo', 'bar', 'baz', 'push' ] ); 29 | 30 | #diag dump( @a ); 31 | -------------------------------------------------------------------------------- /client-libraries/perl/t/pod-coverage.t: -------------------------------------------------------------------------------- 1 | use strict; 2 | use warnings; 3 | use Test::More; 4 | 5 | # Ensure a recent version of Test::Pod::Coverage 6 | my $min_tpc = 1.08; 7 | eval "use Test::Pod::Coverage $min_tpc"; 8 | plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage" 9 | if $@; 10 | 11 | # Test::Pod::Coverage doesn't require a minimum Pod::Coverage version, 12 | # but older versions don't recognize some common documentation styles 13 | my $min_pc = 0.18; 14 | eval "use Pod::Coverage $min_pc"; 15 | plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage" 16 | if $@; 17 | 18 | all_pod_coverage_ok(); 19 | -------------------------------------------------------------------------------- /client-libraries/perl/t/20-Redis-Hash.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use warnings; 4 | use strict; 5 | 6 | use Test::More tests => 7; 7 | use lib 'lib'; 8 | use Data::Dump qw/dump/; 9 | 10 | BEGIN { 11 | use_ok( 'Redis::Hash' ); 12 | } 13 | 14 | ok( my $o = tie( my %h, 'Redis::Hash', 'test-redis-hash' ), 'tie' ); 15 | 16 | isa_ok( $o, 'Redis::Hash' ); 17 | 18 | $o->CLEAR(); 19 | 20 | ok( ! keys %h, 'empty' ); 21 | 22 | ok( %h = ( 'foo' => 42, 'bar' => 1, 'baz' => 99 ), '=' ); 23 | 24 | is_deeply( [ sort keys %h ], [ 'bar', 'baz', 'foo' ], 'keys' ); 25 | 26 | is_deeply( \%h, { bar => 1, baz => 99, foo => 42, }, 'structure' ); 27 | 28 | 29 | #diag dump( \%h ); 30 | 31 | -------------------------------------------------------------------------------- /client-libraries/clojure/benchmarks/ruby.clj: -------------------------------------------------------------------------------- 1 | (ns benchmarks.ruby 2 | (:require redis)) 3 | 4 | (dotimes [n 4] 5 | (redis/with-server 6 | {:db 15} 7 | (redis/set "foo" "The first line we sent to the server is some text") 8 | (time 9 | (dotimes [i 20000] 10 | (let [key (str "key" i)] 11 | (redis/set key "The first line we sent to the server is some text") 12 | (redis/get "foo")))))) 13 | 14 | 15 | ;(redis/with-server 16 | ; {} 17 | ; (redis/set "foo" "The first line we sent to the server is some text") 18 | ; (time 19 | ; (dotimes [i 20000] 20 | ; (let [key (str "push_trim" i)] 21 | ; (redis/lpush key i) 22 | ; (redis/ltrim key 0 30))))) 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /client-libraries/ruby/examples/sets.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'redis' 3 | 4 | r = Redis.new 5 | 6 | r.delete 'foo-tags' 7 | r.delete 'bar-tags' 8 | 9 | puts 10 | p "create a set of tags on foo-tags" 11 | 12 | r.set_add 'foo-tags', 'one' 13 | r.set_add 'foo-tags', 'two' 14 | r.set_add 'foo-tags', 'three' 15 | 16 | puts 17 | p "create a set of tags on bar-tags" 18 | 19 | r.set_add 'bar-tags', 'three' 20 | r.set_add 'bar-tags', 'four' 21 | r.set_add 'bar-tags', 'five' 22 | 23 | puts 24 | p 'foo-tags' 25 | 26 | p r.set_members('foo-tags') 27 | 28 | puts 29 | p 'bar-tags' 30 | 31 | p r.set_members('bar-tags') 32 | 33 | puts 34 | p 'intersection of foo-tags and bar-tags' 35 | 36 | p r.set_intersect('foo-tags', 'bar-tags') 37 | -------------------------------------------------------------------------------- /client-libraries/cpp/README.rst: -------------------------------------------------------------------------------- 1 | redis-cpp-client 2 | ================ 3 | 4 | * A C++ client for the Redis_ key-value database (which is hosted at github_). 5 | * This client has no external dependencies other than g++ (no Boost for instance). 6 | * It uses anet from antirez_ (redis' author), which is bundled. 7 | * This client is licensed under the same license as redis. 8 | * Tested on Linux and Mac OS X. 9 | 10 | * This is a work in progress. I will update this README when the client is "done". 11 | If I had to put a version number on it right now, I'd call it version 0.85 12 | 13 | .. _Redis: http://code.google.com/p/redis/ 14 | .. _github: http://github.com/antirez/redis/tree/master 15 | .. _antirez: https://github.com/antirez 16 | 17 | -------------------------------------------------------------------------------- /client-libraries/perl/scripts/redis-benchmark.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use warnings; 4 | use strict; 5 | use Benchmark qw/:all/; 6 | use lib 'lib'; 7 | use Redis; 8 | 9 | my $r = Redis->new; 10 | 11 | my $i = 0; 12 | 13 | timethese( 100000, { 14 | '00_ping' => sub { $r->ping }, 15 | '10_set' => sub { $r->set( 'foo', $i++ ) }, 16 | '11_set_r' => sub { $r->set( 'bench-' . rand(), rand() ) }, 17 | '20_get' => sub { $r->get( 'foo' ) }, 18 | '21_get_r' => sub { $r->get( 'bench-' . rand() ) }, 19 | '30_incr' => sub { $r->incr( 'counter' ) }, 20 | '30_incr_r' => sub { $r->incr( 'bench-' . rand() ) }, 21 | '40_lpush' => sub { $r->lpush( 'mylist', 'bar' ) }, 22 | '40_lpush' => sub { $r->lpush( 'mylist', 'bar' ) }, 23 | '50_lpop' => sub { $r->lpop( 'mylist' ) }, 24 | }); 25 | -------------------------------------------------------------------------------- /client-libraries/erlang/Makefile: -------------------------------------------------------------------------------- 1 | LIBDIR=`erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell` 2 | 3 | all: 4 | mkdir -p ebin/ 5 | (cd src;$(MAKE)) 6 | (cd test;$(MAKE)) 7 | 8 | clean: clean_tests 9 | (cd src;$(MAKE) clean) 10 | rm -rf erl_crash.dump *.beam 11 | 12 | clean_tests: 13 | (cd test;$(MAKE) clean) 14 | rm -rf erl_crash.dump *.beam 15 | 16 | test: clean 17 | mkdir -p ebin/ 18 | (cd src;$(MAKE)) 19 | (cd test;$(MAKE)) 20 | (cd test;$(MAKE) test) 21 | 22 | testrun: all 23 | mkdir -p ebin/ 24 | (cd test;$(MAKE) test) 25 | 26 | install: all 27 | mkdir -p ${LIBDIR}/erldis-0.0.1/{ebin,include} 28 | for i in ebin/*.beam; do install $$i $(LIBDIR)/erldis-0.0.1/$$i ; done 29 | for i in include/*.hrl; do install $$i $(LIBDIR)/erldis-0.0.1/$$i ; done 30 | -------------------------------------------------------------------------------- /client-libraries/ruby/benchmarking/suite.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | def run_in_background(command) 4 | fork { system command } 5 | end 6 | 7 | def with_all_segments(&block) 8 | 0.upto(9) do |segment_number| 9 | block_size = 100000 10 | start_index = segment_number * block_size 11 | end_index = start_index + block_size - 1 12 | block.call(start_index, end_index) 13 | end 14 | end 15 | 16 | #with_all_segments do |start_index, end_index| 17 | # puts "Initializing keys from #{start_index} to #{end_index}" 18 | # system "ruby worker.rb initialize #{start_index} #{end_index} 0" 19 | #end 20 | 21 | with_all_segments do |start_index, end_index| 22 | run_in_background "ruby worker.rb write #{start_index} #{end_index} 10" 23 | run_in_background "ruby worker.rb read #{start_index} #{end_index} 1" 24 | end -------------------------------------------------------------------------------- /client-libraries/scala/src/main/scala/com/redis/Operations/SortOperations.scala: -------------------------------------------------------------------------------- 1 | package com.redis.operations 2 | 3 | /** 4 | * Redis sort operations 5 | * 6 | */ 7 | 8 | trait SortOperations{ 9 | 10 | def getConnection(key: String): Connection 11 | 12 | // SORT 13 | // Sort a Set or a List accordingly to the specified parameters. 14 | def sort(args: Any): List[String] = args match { 15 | case (key: String, command: String) => doSort(key, command) 16 | case (key: String) => doSort(key, "") 17 | } 18 | 19 | def doSort(key: String, command: String): List[String] = { 20 | val connection = getConnection(key) 21 | if(command != "") { 22 | connection.write("SORT "+key+" "+command+"\r\n") 23 | } else { 24 | connection.write("SORT "+key+"\r\n") 25 | } 26 | connection.readList 27 | } 28 | } -------------------------------------------------------------------------------- /client-libraries/scala/src/test/scala/com/redis/RedisClientSpec.scala: -------------------------------------------------------------------------------- 1 | import org.specs._ 2 | import com.redis._ 3 | 4 | import org.specs.mock.Mockito 5 | import org.mockito.Mock._ 6 | import org.mockito.Mockito._ 7 | import org.mockito.Mockito.doNothing 8 | 9 | object RedisClientSpec extends Specification with Mockito { 10 | 11 | "Redis Client" should { 12 | var client: Redis = null 13 | 14 | "print formatted client status" in { 15 | client = new Redis("localhost", 121212) 16 | client.toString must be matching("localhost:121212 ") 17 | } 18 | 19 | "get the same connection when passing key para or not since it's a single node" in { 20 | client.getConnection("key") mustEqual client.getConnection 21 | } 22 | 23 | "use db zero as default" in { 24 | client.db mustEqual 0 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Redis 源码注释 2 | ====================== 3 | 4 | 1.Redis内存回收:LRU算法 5 | 6 | Redis中采用两种算法进行内存回收,引用计数算法以及LRU算法,在操作系统内存管理一节中,我们都学习过LRU算法(最近最久未使用算法),那么什么是LRU算法呢,LRU算法作为内存管理的一种有效算法,其含义是在内存有限的情况下,当内存容量不足时,为了保证程序的运行,这时就不得不淘汰内存中的一些对象,释放这些对象占用的空间,那么选择淘汰哪些对象呢... 7 | 8 | 2.Redis有序集内部实现原理分析 9 | 10 | Redis中支持的数据结构比Memcached要多的多啦,如基本的字符串、哈希表、列表、集合、可排序集,在这些基本数据结构上也提供了针对该数据结构的各种操作,这也是Redis之所以流行起来的一个重要原因,当然Redis能够流行起来的原因,远远不只这一个,如支持高并发的读写、数据的持久化、高效的内存管理及淘汰机制... 11 | 12 | 13 | 3.Redis有序集内部实现原理分析(二) 14 | 15 | 本篇博文紧随上篇Redis有序集内部实现原理分析,在这篇博文里凡出现源码的地方均以下述`src/version.h`中定义的Redis版本为主,在上篇博文Redis有序集内部实现原理分析中,我分析了Redis从什么时候开始支持有序集、跳表的原理、跳表的结构、跳表的查找/插入/删除的实现,理解了跳表的基本结构,理解Redis中有序集的实... 16 | 17 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H 2 | #define __CONFIG_H 3 | 4 | /* 5 | * 如果是apple机时要包含的头文件 6 | */ 7 | #ifdef __APPLE__ 8 | #include 9 | #endif 10 | 11 | /* test for malloc_size() */ 12 | #ifdef __APPLE__ 13 | #include 14 | //下面这个宏定义表示有malloc_size这个函数 15 | #define HAVE_MALLOC_SIZE 1 16 | //将redis_malloc_size宏定义为malloc_size函数 17 | #define redis_malloc_size(p) malloc_size(p) 18 | #endif 19 | 20 | /* define redis_fstat to fstat or fstat64() */ 21 | #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6) 22 | //MAC机下的stat函数原型 23 | #define redis_fstat fstat64 24 | #define redis_stat stat64 25 | #else 26 | //其他操作系统下对应的stat函数 27 | #define redis_fstat fstat 28 | #define redis_stat stat 29 | #endif 30 | 31 | /* test for backtrace() */ 32 | #if defined(__APPLE__) || defined(__linux__) 33 | //返回函数的调用栈,一般用于调试(在mac以及linux下才有) 34 | #define HAVE_BACKTRACE 1 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /client-libraries/cpp/Makefile: -------------------------------------------------------------------------------- 1 | # Redis C++ Client Library Makefile 2 | 3 | #CFLAGS?= -pedantic -O2 -Wall -W -DNDEBUG 4 | CFLAGS?= -pedantic -O0 -W -DDEBUG -g 5 | CC = g++ 6 | 7 | CLIENTOBJS = anet.o redisclient.o 8 | LIBNAME = libredisclient.a 9 | 10 | TESTAPP = test_client 11 | TESTAPPOBJS = test_client.o 12 | TESTAPPLIBS = $(LIBNAME) -lstdc++ 13 | 14 | all: $(LIBNAME) $(TESTAPP) 15 | 16 | $(LIBNAME): $(CLIENTOBJS) 17 | ar rcs $(LIBNAME) $(CLIENTOBJS) 18 | 19 | .c.o: 20 | $(CC) -c $(CFLAGS) $< 21 | 22 | .cpp.o: 23 | $(CC) -c $(CFLAGS) $< 24 | 25 | $(TESTAPP): $(LIBNAME) $(TESTAPPOBJS) 26 | $(CC) -o $(TESTAPP) $(TESTAPPOBJS) $(TESTAPPLIBS) 27 | 28 | test: $(TESTAPP) 29 | @./test_client 30 | 31 | check: test 32 | 33 | clean: 34 | rm -rf $(LIBNAME) *.o $(TESTAPP) 35 | 36 | dep: 37 | $(CC) -MM *.c *.cpp 38 | 39 | log: 40 | git log '--pretty=format:%ad %s' --date=short > Changelog 41 | 42 | anet.o: anet.c fmacros.h anet.h 43 | redisclient.o: redisclient.cpp redisclient.h anet.h 44 | 45 | -------------------------------------------------------------------------------- /client-libraries/ruby/bin/distredis: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | class RedisCluster 4 | 5 | def initialize(opts={}) 6 | opts = {:port => 6379, :host => 'localhost', :basedir => "#{Dir.pwd}/rdsrv" }.merge(opts) 7 | FileUtils.mkdir_p opts[:basedir] 8 | opts[:size].times do |i| 9 | port = opts[:port] + i 10 | FileUtils.mkdir_p "#{opts[:basedir]}/#{port}" 11 | File.open("#{opts[:basedir]}/#{port}.conf", 'w'){|f| f.write(make_config(port, "#{opts[:basedir]}/#{port}", "#{opts[:basedir]}/#{port}.log"))} 12 | system(%Q{#{File.join(File.expand_path(File.dirname(__FILE__)), "../redis/redis-server #{opts[:basedir]}/#{port}.conf &" )}}) 13 | end 14 | end 15 | 16 | def make_config(port=6379, data=port, logfile='stdout', loglevel='debug') 17 | config = %Q{ 18 | timeout 300 19 | save 900 1 20 | save 300 10 21 | save 60 10000 22 | dir #{data} 23 | loglevel #{loglevel} 24 | logfile #{logfile} 25 | databases 16 26 | port #{port} 27 | } 28 | end 29 | 30 | end 31 | 32 | 33 | RedisCluster.new :size => 4 -------------------------------------------------------------------------------- /client-libraries/clojure/examples/demo.clj: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; Simple demo of redis-clojure functionality 3 | ;; 4 | ;; Make sure redis-clojure.jar or the contents of the src/ directory 5 | ;; is on the classpath. 6 | ;; 7 | ;; Either: 8 | ;; (add-classpath "file:///path/to/redis-clojure.jar" 9 | ;; or: 10 | ;; (add-classpath "file:///path/to/redis/src-dir/") 11 | ;; 12 | 13 | (add-classpath "file:///Users/ragge/Projects/clojure/redis-clojure/redis-clojure.jar") 14 | 15 | (ns demo 16 | (:require redis)) 17 | 18 | 19 | (redis/with-server 20 | {:host "127.0.0.1" :port 6379 :db 0} 21 | (do 22 | (println "Sending ping") 23 | (println "Reply:" (redis/ping)) 24 | (println "Server info:") 25 | (let [info (redis/info)] 26 | (dorun 27 | (map (fn [entry] 28 | (println (str "- "(first entry) ": " (last entry)))) info))) 29 | (println "Setting key 'foo' to 'bar'") 30 | (println "Reply:" (redis/set "foo" "bar")) 31 | (println "Getting value of key 'foo'") 32 | (println "Reply:" (redis/get "foo")))) 33 | 34 | -------------------------------------------------------------------------------- /client-libraries/erlang/src/proto.erl: -------------------------------------------------------------------------------- 1 | -module(proto). 2 | 3 | -export([parse/2]). 4 | 5 | parse(empty, "+OK") -> 6 | ok; 7 | parse(empty, "+PONG") -> 8 | pong; 9 | parse(empty, ":0") -> 10 | false; 11 | parse(empty, ":1") -> 12 | true; 13 | parse(empty, "-" ++ Message) -> 14 | {error, Message}; 15 | parse(empty, "$-1") -> 16 | {read, nil}; 17 | parse(empty, "*-1") -> 18 | {hold, nil}; 19 | parse(empty, "$" ++ BulkSize) -> 20 | {read, list_to_integer(BulkSize)}; 21 | parse(read, "$" ++ BulkSize) -> 22 | {read, list_to_integer(BulkSize)}; 23 | parse(empty, "*" ++ MultiBulkSize) -> 24 | {hold, list_to_integer(MultiBulkSize)}; 25 | parse(empty, Message) -> 26 | convert(Message). 27 | 28 | convert(":" ++ Message) -> 29 | list_to_integer(Message); 30 | % in case the message is not OK or PONG it's a 31 | % real value that we don't know how to convert 32 | % to an atom, so just pass it as is and remove 33 | % the + 34 | convert("+" ++ Message) -> 35 | Message; 36 | convert(Message) -> 37 | Message. 38 | 39 | -------------------------------------------------------------------------------- /client-libraries/perl/README: -------------------------------------------------------------------------------- 1 | Redis 2 | 3 | Perl binding for Redis database which is in-memory hash store with 4 | support for scalars, arrays and sets and disk persistence. 5 | 6 | INSTALLATION 7 | 8 | To install this module, run the following commands: 9 | 10 | perl Makefile.PL 11 | make 12 | make test 13 | make install 14 | 15 | SUPPORT AND DOCUMENTATION 16 | 17 | After installing, you can find documentation for this module with the 18 | perldoc command. 19 | 20 | perldoc Redis 21 | 22 | You can also look for information at: 23 | 24 | RT, CPAN's request tracker 25 | http://rt.cpan.org/NoAuth/Bugs.html?Dist=Redis 26 | 27 | AnnoCPAN, Annotated CPAN documentation 28 | http://annocpan.org/dist/Redis 29 | 30 | CPAN Ratings 31 | http://cpanratings.perl.org/d/Redis 32 | 33 | Search CPAN 34 | http://search.cpan.org/dist/Redis 35 | 36 | 37 | COPYRIGHT AND LICENCE 38 | 39 | Copyright (C) 2009 Dobrica Pavlinusic 40 | 41 | This program is free software; you can redistribute it and/or modify it 42 | under the same terms as Perl itself. 43 | 44 | -------------------------------------------------------------------------------- /client-libraries/ruby/README.markdown: -------------------------------------------------------------------------------- 1 | # redis-rb 2 | 3 | A ruby client library for the redis key value storage system. 4 | 5 | ## Information about redis 6 | 7 | Redis is a key value store with some interesting features: 8 | 1. It's fast. 9 | 2. Keys are strings but values can have types of "NONE", "STRING", "LIST", or "SET". List's can be atomically push'd, pop'd, lpush'd, lpop'd and indexed. This allows you to store things like lists of comments under one key while retaining the ability to append comments without reading and putting back the whole list. 10 | 11 | See [redis on code.google.com](http://code.google.com/p/redis/wiki/README) for more information. 12 | 13 | ## Dependencies 14 | 15 | 1. rspec - 16 | sudo gem install rspec 17 | 18 | 2. redis - 19 | 20 | rake redis:install 21 | 22 | 2. dtach - 23 | 24 | rake dtach:install 25 | 26 | 3. git - git is the new black. 27 | 28 | ## Setup 29 | 30 | Use the tasks mentioned above (in Dependencies) to get your machine setup. 31 | 32 | ## Examples 33 | 34 | Check the examples/ directory. *Note* you need to have redis-server running first. -------------------------------------------------------------------------------- /client-libraries/ruby/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Ezra Zygmuntowicz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /client-libraries/scala/src/main/scala/com/redis/RedisClient.scala: -------------------------------------------------------------------------------- 1 | package com.redis 2 | 3 | import com.redis.operations._ 4 | 5 | /** 6 | * Redis client 7 | * 8 | */ 9 | 10 | class Redis(val host: String, val port: Int) extends Operations with ListOperations with SetOperations with NodeOperations with KeySpaceOperations with SortOperations { 11 | 12 | // auxiliary constructor 13 | def this() = this("localhost", 6379) 14 | 15 | // Points to the connection to a server instance 16 | val connection = Connection(host, port) 17 | var db: Int = 0 18 | 19 | // Connect and Disconnect to the Redis server 20 | def connect = connection.connect 21 | def disconnect = connection.disconnect 22 | def connected: Boolean = connection.connected 23 | 24 | // Establish the connection to the server instance on initialize 25 | connect 26 | 27 | // Get Redis Client connection. 28 | def getConnection(key: String) = getConnection 29 | def getConnection = connection 30 | 31 | // Outputs a formatted representation of the Redis server. 32 | override def toString = connection.host+":"+connection.port+" " 33 | } 34 | -------------------------------------------------------------------------------- /client-libraries/clojure/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Ragnar Dahlén (r.dahlen@gmail.com) 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /client-libraries/erlang/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 2 | adroll.com 3 | Valentino Volonghi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /client-libraries/lua/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 2 | Daniele Alessandri 3 | http://www.clorophilla.net/ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /client-libraries/scala/src/test/scala/com/redis/operations/SortOperationsSpec.scala: -------------------------------------------------------------------------------- 1 | import org.specs._ 2 | import com.redis._ 3 | 4 | import org.specs.mock.Mockito 5 | import org.mockito.Mock._ 6 | import org.mockito.Mockito._ 7 | 8 | object SortOperationsSpec extends Specification with Mockito { 9 | 10 | "Redis Client Sort Operations" should { 11 | 12 | var client: RedisTestClient = null 13 | var connection: Connection = null 14 | 15 | doBefore{ 16 | connection = mock[Connection] 17 | client = new RedisTestClient(connection) 18 | } 19 | 20 | "sort the contents of the specified key" in { 21 | val listResult: List[String] = List("one", "two", "three") 22 | connection.readList returns listResult 23 | client.sort("set", "ALPHA DESC") mustEqual listResult 24 | connection.write("SORT set ALPHA DESC\r\n") was called 25 | } 26 | 27 | "sort the contents of the specified key with default" in { 28 | val listResult: List[String] = List("one", "two", "three") 29 | connection.readList returns listResult 30 | client.sort("set") mustEqual listResult 31 | connection.write("SORT set\r\n") was called 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /client-libraries/ruby/bench.rb: -------------------------------------------------------------------------------- 1 | require 'benchmark' 2 | $:.push File.join(File.dirname(__FILE__), 'lib') 3 | require 'redis' 4 | 5 | times = 20000 6 | 7 | @r = Redis.new#(:debug => true) 8 | @r['foo'] = "The first line we sent to the server is some text" 9 | 10 | Benchmark.bmbm do |x| 11 | x.report("set") do 12 | 20000.times do |i| 13 | @r["set#{i}"] = "The first line we sent to the server is some text"; @r["foo#{i}"] 14 | end 15 | end 16 | 17 | x.report("set (pipelined)") do 18 | @r.pipelined do |pipeline| 19 | 20000.times do |i| 20 | pipeline["set_pipelined#{i}"] = "The first line we sent to the server is some text"; @r["foo#{i}"] 21 | end 22 | end 23 | end 24 | 25 | x.report("push+trim") do 26 | 20000.times do |i| 27 | @r.push_head "push_trim#{i}", i 28 | @r.list_trim "push_trim#{i}", 0, 30 29 | end 30 | end 31 | 32 | x.report("push+trim (pipelined)") do 33 | @r.pipelined do |pipeline| 34 | 20000.times do |i| 35 | pipeline.push_head "push_trim_pipelined#{i}", i 36 | pipeline.list_trim "push_trim_pipelined#{i}", 0, 30 37 | end 38 | end 39 | end 40 | end 41 | 42 | @r.keys('*').each do |k| 43 | @r.delete k 44 | end -------------------------------------------------------------------------------- /doc/DesignPatterns.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | DesignPatterns: Contents 20 |
21 | 22 |

DesignPatterns

23 | 24 |
25 | 26 |
27 | 28 |
29 | Use random keys instead of incremental keys in order to avoid a single-key that gets incremented by many servers. This can can't be distributed among servers. 30 | 31 |
32 | 33 |
34 |
35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /client-libraries/clojure/README.markdown: -------------------------------------------------------------------------------- 1 | # redis-clojure 2 | 3 | A Clojure client library for the 4 | [Redis](http://code.google.com/p/redis) key value storage system. 5 | 6 | ## Dependencies 7 | 8 | To use redis-clojure, you'll need: 9 | 10 | * The [Clojure](http://clojure.org) programming language 11 | * The [Clojure-Contrib](http://code.google.com/p/clojure-contrib) library (for running the tests) 12 | 13 | ## Building 14 | 15 | To build redis-clojure: 16 | 17 | ant -Dclojure.jar=/path/to/clojure.jar 18 | 19 | This will build `redis-clojure.jar`. 20 | 21 | ## Running tests 22 | 23 | To run tests: 24 | 25 | ant -Dclojure.jar=/path/to/clojure.jar -Dclojure-contrib.jar=/path/to/clojure-contrib.jar test 26 | 27 | *Note* you need to have `redis-server` running first. 28 | 29 | ## Using 30 | 31 | To use redis-clojure in your application, simply make sure either 32 | `redis-clojure.jar` or the contents of the `src/` directory is on your 33 | classpath. 34 | 35 | This can be accomplished like so: 36 | 37 | (add-classpath "file:///path/to/redis-clojure.jar") 38 | 39 | ## Examples 40 | 41 | Check the `examples/` directory. 42 | 43 | *Note* you need to have `redis-server` running first. 44 | 45 | ## Todo 46 | 47 | * Work on performance 48 | * Maybe implement pipelining 49 | 50 | -------------------------------------------------------------------------------- /client-libraries/scala/src/main/scala/com/redis/RedisCluster.scala: -------------------------------------------------------------------------------- 1 | package com.redis 2 | 3 | import com.redis.operations._ 4 | 5 | /** 6 | * Redis cluster 7 | * 8 | */ 9 | 10 | import scala.collection.mutable.ArrayBuffer 11 | 12 | class RedisCluster(val hosts: String*) extends Operations with ListOperations with SetOperations with HashRing with SortOperations { 13 | 14 | // Get Redis Client connection inside the HashRing. 15 | def getConnection(key: String) = { 16 | getNode(key).connection 17 | } 18 | 19 | // Default value used on MemCache client. 20 | private val NUMBER_OF_REPLICAS = 160 21 | val replicas = NUMBER_OF_REPLICAS 22 | 23 | // Outputs a formatted representation of the Redis server. 24 | override def toString = cluster.mkString(", ") 25 | 26 | // Connect the client and add it to the cluster. 27 | def connectClient(host: String): Boolean = { 28 | val h = host.split(":")(0) 29 | val p = host.split(":")(1) 30 | val client = new Redis(h.toString, p.toString.toInt) 31 | addNode(client) 32 | client.connected 33 | } 34 | 35 | // Connect all clients in the cluster. 36 | def connect = cluster.map(c => c.connect) 37 | 38 | // Initialize cluster. 39 | def initialize_cluster = hosts.map(connectClient(_)) 40 | 41 | initialize_cluster 42 | } 43 | -------------------------------------------------------------------------------- /utils/redis-sha1.rb: -------------------------------------------------------------------------------- 1 | # redis-sha1.rb - Copyright (C) 2009 Salvatore Sanfilippo 2 | # BSD license, See the COPYING file for more information. 3 | # 4 | # Performs the SHA1 sum of the whole datset. 5 | # This is useful to spot bugs in persistence related code and to make sure 6 | # Slaves and Masters are in SYNC. 7 | # 8 | # If you hack this code make sure to sort keys and set elements as this are 9 | # unsorted elements. Otherwise the sum may differ with equal dataset. 10 | 11 | require 'rubygems' 12 | require 'redis' 13 | require 'digest/sha1' 14 | 15 | def redisSha1(opts={}) 16 | sha1="" 17 | r = Redis.new(opts) 18 | r.keys('*').sort.each{|k| 19 | sha1 = Digest::SHA1.hexdigest(sha1+k) 20 | vtype = r.type?(k) 21 | if vtype == "string" 22 | sha1 = Digest::SHA1.hexdigest(sha1+r.get(k)) 23 | elsif vtype == "list" 24 | sha1 = Digest::SHA1.hexdigest(sha1+r.list_range(k,0,-1).join("\x01")) 25 | elsif vtype == "set" 26 | sha1 = Digest::SHA1.hexdigest(sha1+r.set_members(k).to_a.sort.join("\x02")) 27 | end 28 | } 29 | sha1 30 | end 31 | 32 | host = ARGV[0] || "127.0.0.1" 33 | port = ARGV[1] || "6379" 34 | puts "Performing SHA1 of Redis server #{host} #{port}" 35 | p "Dataset SHA1: #{redisSha1(:host => host, :port => port.to_i)}" 36 | -------------------------------------------------------------------------------- /client-libraries/ruby/redis-rb.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | Gem::Specification.new do |s| 4 | s.name = %q{redis} 5 | s.version = "0.1" 6 | 7 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 8 | s.authors = ["Ezra Zygmuntowicz", "Taylor Weibley", "Matthew Clark", "Brian McKinney", "Salvatore Sanfilippo", "Luca Guidi"] 9 | # s.autorequire = %q{redis-rb} 10 | s.date = %q{2009-06-23} 11 | s.description = %q{Ruby client library for redis key value storage server} 12 | s.email = %q{ez@engineyard.com} 13 | s.extra_rdoc_files = ["LICENSE"] 14 | s.files = ["LICENSE", "README.markdown", "Rakefile", "lib/dist_redis.rb", "lib/hash_ring.rb", "lib/pipeline.rb", "lib/redis.rb", "spec/redis_spec.rb", "spec/spec_helper.rb"] 15 | s.has_rdoc = true 16 | s.homepage = %q{http://github.com/ezmobius/redis-rb} 17 | s.require_paths = ["lib"] 18 | s.rubygems_version = %q{1.3.1} 19 | s.summary = %q{Ruby client library for redis key value storage server} 20 | 21 | if s.respond_to? :specification_version then 22 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION 23 | s.specification_version = 2 24 | 25 | if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then 26 | else 27 | end 28 | else 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /doc/TemplateCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | TemplateCommand: Contents
    Return value
    See also 20 |
21 | 22 |

TemplateCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 | 30 |

Return value

ReplyTypes

See also

31 |
  • []
32 |
33 | 34 |
35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /client-libraries/scala/README.md: -------------------------------------------------------------------------------- 1 | # Redis Scala client 2 | 3 | ## Key features of the library 4 | 5 | - Native Scala types Set and List responses. 6 | - Consisten Hashing on the client. 7 | - Support for Clustering of Redis nodes. 8 | 9 | ## Information about redis 10 | 11 | Redis is a key-value database. It is similar to memcached but the dataset is not volatile, and values can be strings, exactly like in memcached, but also lists and sets with atomic operations to push/pop elements. 12 | 13 | http://code.google.com/p/redis/ 14 | 15 | ### Key features of Redis 16 | 17 | - Fast in-memory store with asynchronous save to disk. 18 | - Key value get, set, delete, etc. 19 | - Atomic operations on sets and lists, union, intersection, trim, etc. 20 | 21 | ## Requirements 22 | 23 | - sbt (get it at http://code.google.com/p/simple-build-tool/) 24 | 25 | ## Usage 26 | 27 | Start your redis instance (usually redis-server will do it) 28 | 29 | $ cd scala-redis 30 | $ sbt 31 | > update 32 | > test (optional to run the tests) 33 | > console 34 | 35 | And you are ready to start issuing commands to the server(s) 36 | 37 | let's connect and get a key: 38 | 39 | scala> import com.redis._ 40 | scala> val r = new Redis("localhost", 6379) 41 | scala> val r.set("key", "some value") 42 | scala> val r.get("key") 43 | 44 | 45 | Alejandro Crosa <> 46 | 47 | -------------------------------------------------------------------------------- /doc/QuitCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | QuitCommand: Contents
  Quit
    Return value 20 |
21 | 22 |

QuitCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

Quit

Ask the server to silently close the connection.
30 |

Return value

None. The connection is closed as soon as the QUIT command is received. 31 | 32 |
33 | 34 |
35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /client-libraries/README: -------------------------------------------------------------------------------- 1 | Redis client libraries 2 | ---------------------- 3 | 4 | In this directory you'll find client libraries for different languages. 5 | This are the latest releases available at the time this Redis tar.gz for this 6 | release was created, and are good for most uses, but if you need more fresh 7 | code or recent bugfixes read more. 8 | 9 | How to get the lastest versions of client libraries source code 10 | --------------------------------------------------------------- 11 | 12 | Note that while the pure PHP, Tcl, Python and Ruby_2 (Ruby alternative lib) 13 | libraries are the most uptodate available libraries, all the other libraries 14 | have their own repositories where it's possible to grab the most recent version: 15 | 16 | Ruby lib source code: 17 | http://github.com/ezmobius/redis-rb/tree/master 18 | git://github.com/ezmobius/redis-rb.git 19 | 20 | Erlang lib source code: 21 | http://bitbucket.org/adroll/erldis/ 22 | 23 | Perl lib source code: 24 | (web) http://svn.rot13.org/index.cgi/Redis 25 | (svn) svn://svn.rot13.org/Redis/ 26 | 27 | Redis-php PHP C module: 28 | http://code.google.com/p/phpredis/ 29 | 30 | Lua lib source code: 31 | http://github.com/nrk/redis-lua/tree/master 32 | git://github.com/nrk/redis-lua.git 33 | 34 | Clojure lib source code: 35 | http://github.com/ragnard/redis-clojure/ 36 | git://github.com/ragnard/redis-clojure.git 37 | 38 | For all the rest check the Redis tarball or Git repository. 39 | -------------------------------------------------------------------------------- /client-libraries/scala/src/main/scala/com/redis/Operations/KeySpaceOperations.scala: -------------------------------------------------------------------------------- 1 | package com.redis.operations 2 | 3 | /** 4 | * Redis key space operations 5 | * 6 | */ 7 | 8 | trait KeySpaceOperations{ 9 | 10 | val connection: Connection 11 | var db: Int 12 | 13 | // KEYS 14 | // returns all the keys matching the glob-style pattern. 15 | def keys(pattern: String): Array[String] = { 16 | connection.write("KEYS "+pattern+"\r\n") 17 | connection.readResponse.toString.split(" ") 18 | } 19 | 20 | // RANDKEY 21 | // return a randomly selected key from the currently selected DB. 22 | def randomKey: String = { 23 | connection.write("RANDOMKEY\r\n") 24 | connection.readResponse.toString.split('+')(1) 25 | } 26 | 27 | // RENAME (oldkey, newkey) 28 | // atomically renames the key oldkey to newkey. 29 | def rename(oldkey: String, newkey: String): Boolean = { 30 | connection.write("RENAME "+oldkey+" "+newkey+"\r\n") 31 | connection.readBoolean 32 | } 33 | 34 | // RENAMENX (oldkey, newkey) 35 | // rename oldkey into newkey but fails if the destination key newkey already exists. 36 | def renamenx(oldkey: String, newkey: String): Boolean = { 37 | connection.write("RENAMENX "+oldkey+" "+newkey+"\r\n") 38 | connection.readBoolean 39 | } 40 | 41 | // DBSIZE 42 | // return the size of the db. 43 | def dbSize: Int = { 44 | connection.write("DBSIZE\r\n") 45 | connection.readInt 46 | } 47 | } -------------------------------------------------------------------------------- /client-libraries/perl/lib/Redis/Hash.pm: -------------------------------------------------------------------------------- 1 | package Redis::Hash; 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Tie::Hash; 7 | use base qw/Redis Tie::StdHash/; 8 | 9 | use Data::Dump qw/dump/; 10 | 11 | =head1 NAME 12 | 13 | Redis::Hash - tie perl hashes into Redis 14 | 15 | =head1 SYNOPSYS 16 | 17 | tie %name, 'Redis::Hash', 'prefix'; 18 | 19 | =cut 20 | 21 | # mandatory methods 22 | sub TIEHASH { 23 | my ($class,$name) = @_; 24 | my $self = Redis->new; 25 | $name .= ':' if $name; 26 | $self->{name} = $name || ''; 27 | bless $self => $class; 28 | } 29 | 30 | sub STORE { 31 | my ($self,$key,$value) = @_; 32 | $self->set( $self->{name} . $key, $value ); 33 | } 34 | 35 | sub FETCH { 36 | my ($self,$key) = @_; 37 | $self->get( $self->{name} . $key ); 38 | } 39 | 40 | sub FIRSTKEY { 41 | my $self = shift; 42 | $self->{keys} = [ $self->keys( $self->{name} . '*' ) ]; 43 | $self->NEXTKEY; 44 | } 45 | 46 | sub NEXTKEY { 47 | my $self = shift; 48 | my $key = shift @{ $self->{keys} } || return; 49 | my $name = $self->{name}; 50 | $key =~ s{^$name}{} || warn "can't strip $name from $key"; 51 | return $key; 52 | } 53 | 54 | sub EXISTS { 55 | my ($self,$key) = @_; 56 | $self->exists( $self->{name} . $key ); 57 | } 58 | 59 | sub DELETE { 60 | my ($self,$key) = @_; 61 | $self->del( $self->{name} . $key ); 62 | } 63 | 64 | sub CLEAR { 65 | my ($self) = @_; 66 | $self->del( $_ ) foreach ( $self->keys( $self->{name} . '*' ) ); 67 | $self->{keys} = []; 68 | } 69 | 70 | 1; 71 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2009, Salvatore Sanfilippo 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | * Neither the name of Redis nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /client-libraries/erlang/support/include.mk: -------------------------------------------------------------------------------- 1 | ## -*- makefile -*- 2 | 3 | ERL := erl 4 | ERLC := $(ERL)c 5 | 6 | INCLUDE_DIRS := ../include $(wildcard ../deps/*/include) 7 | EBIN_DIRS := $(wildcard ../deps/*/ebin) 8 | ERLC_FLAGS := -W $(INCLUDE_DIRS:../%=-I ../%) $(EBIN_DIRS:%=-pa %) 9 | 10 | ifndef no_debug_info 11 | ERLC_FLAGS += +debug_info 12 | endif 13 | 14 | ifdef debug 15 | ERLC_FLAGS += -Ddebug 16 | endif 17 | 18 | ifdef test 19 | ERLC_FLAGS += -DTEST 20 | endif 21 | 22 | EBIN_DIR := ../ebin 23 | DOC_DIR := ../doc 24 | EMULATOR := beam 25 | 26 | ERL_TEMPLATE := $(wildcard *.et) 27 | ERL_SOURCES := $(wildcard *.erl) 28 | ERL_HEADERS := $(wildcard *.hrl) $(wildcard ../include/*.hrl) 29 | ERL_OBJECTS := $(ERL_SOURCES:%.erl=$(EBIN_DIR)/%.beam) 30 | ERL_TEMPLATES := $(ERL_TEMPLATE:%.et=$(EBIN_DIR)/%.beam) 31 | ERL_OBJECTS_LOCAL := $(ERL_SOURCES:%.erl=./%.$(EMULATOR)) 32 | APP_FILES := $(wildcard *.app) 33 | EBIN_FILES = $(ERL_OBJECTS) $(APP_FILES:%.app=../ebin/%.app) $(ERL_TEMPLATES) 34 | MODULES = $(ERL_SOURCES:%.erl=%) 35 | 36 | ../ebin/%.app: %.app 37 | cp $< $@ 38 | 39 | $(EBIN_DIR)/%.$(EMULATOR): %.erl 40 | $(ERLC) $(ERLC_FLAGS) -o $(EBIN_DIR) $< 41 | 42 | $(EBIN_DIR)/%.$(EMULATOR): %.et 43 | $(ERL) -noshell -pa ../../elib/erltl/ebin/ -eval "erltl:compile(atom_to_list('$<'), [{outdir, \"../ebin\"}, report_errors, report_warnings, nowarn_unused_vars])." -s init stop 44 | 45 | ./%.$(EMULATOR): %.erl 46 | $(ERLC) $(ERLC_FLAGS) -o . $< 47 | 48 | $(DOC_DIR)/%.html: %.erl 49 | $(ERL) -noshell -run edoc file $< -run init stop 50 | mv *.html $(DOC_DIR) 51 | 52 | -------------------------------------------------------------------------------- /doc/FlushdbCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | FlushdbCommand: Contents
  FLUSHDB
    Return value
    See also 20 |
21 | 22 |

FlushdbCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

FLUSHDB

30 |
Delete all the keys of the currently selected DB. This command never fails.
31 |

Return value

Status code reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/DbsizeCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | DbsizeCommand: Contents
  DBSIZE
    Return value
    See also 20 |
21 | 22 |

DbsizeCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

DBSIZE

Return the number of keys in the currently selected database.
30 |

Return value

Integer reply

See also

31 | 32 |
33 | 34 |
35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /doc/FlushallCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | FlushallCommand: Contents
  FLUSHALL
    Return value
    See also 20 |
21 | 22 |

FlushallCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

FLUSHALL

30 |
Delete all the keys of all the existing databases, not just the currently selected one. This command never fails.
31 |

Return value

Status code reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /client-libraries/scala/src/test/scala/com/redis/operations/KeySpaceOperationsSpec.scala: -------------------------------------------------------------------------------- 1 | import org.specs._ 2 | import com.redis._ 3 | 4 | import org.specs.mock.Mockito 5 | import org.mockito.Mock._ 6 | import org.mockito.Mockito._ 7 | import org.mockito.Mockito.doNothing 8 | 9 | object KeySpaceOperationsSpec extends Specification with Mockito { 10 | 11 | "Redis Client Key Operations" should { 12 | var client: RedisTestClient = null 13 | var connection: Connection = null 14 | 15 | doBefore{ 16 | connection = mock[Connection] 17 | client = new RedisTestClient(connection) 18 | } 19 | 20 | "return all keys matching" in { 21 | connection.readResponse returns "akey anotherkey adiffkey" 22 | client.keys("a*") 23 | connection.write("KEYS a*\r\n") was called 24 | } 25 | 26 | "return a random key" in { 27 | connection.readResponse returns "+somerandonkey" 28 | client.randomKey mustEqual "somerandonkey" 29 | connection.write("RANDOMKEY\r\n") was called 30 | } 31 | 32 | "remame a key" in { 33 | connection.readBoolean returns true 34 | client.rename("a", "b") must beTrue 35 | connection.write("RENAME a b\r\n") was called 36 | } 37 | 38 | "rename a key only if destintation doesn't exist" in { 39 | connection.readBoolean returns false 40 | client.renamenx("a", "b") must beFalse 41 | connection.write("RENAMENX a b\r\n") was called 42 | } 43 | 44 | "tell the size of the db, # of keys" in { 45 | connection.readInt returns 4 46 | client.dbSize mustEqual 4 47 | connection.write("DBSIZE\r\n") was called 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /doc/RandomkeyCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | RandomkeyCommand: Contents
  RANDOMKEY
    Return value
    See also 20 |
21 | 22 |

RandomkeyCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

RANDOMKEY

30 | Time complexity: O(1)
Return a randomly selected key from the currently selected DB.
31 |

Return value

Singe line reply, specifically the randomly selected key or an empty string is the database is empty.

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/SelectCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SelectCommand: Contents
  SELECT _index_
    Return value
    See also 20 |
21 | 22 |

SelectCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SELECT _index_

30 |
Select the DB with having the specified zero-based numeric index.For default every new client connection is automatically selectedto DB 0.
31 |

Return value

Status code reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /client-libraries/perl/lib/Redis/List.pm: -------------------------------------------------------------------------------- 1 | package Redis::List; 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use base qw/Redis Tie::Array/; 7 | 8 | =head1 NAME 9 | 10 | Redis::List - tie perl arrays into Redis lists 11 | 12 | =head1 SYNOPSYS 13 | 14 | tie @a, 'Redis::List', 'name'; 15 | 16 | =cut 17 | 18 | # mandatory methods 19 | sub TIEARRAY { 20 | my ($class,$name) = @_; 21 | my $self = $class->new; 22 | $self->{name} = $name; 23 | bless $self => $class; 24 | } 25 | 26 | sub FETCH { 27 | my ($self,$index) = @_; 28 | $self->lindex( $self->{name}, $index ); 29 | } 30 | 31 | sub FETCHSIZE { 32 | my ($self) = @_; 33 | $self->llen( $self->{name} ); 34 | } 35 | 36 | sub STORE { 37 | my ($self,$index,$value) = @_; 38 | $self->lset( $self->{name}, $index, $value ); 39 | } 40 | 41 | sub STORESIZE { 42 | my ($self,$count) = @_; 43 | $self->ltrim( $self->{name}, 0, $count ); 44 | # if $count > $self->FETCHSIZE; 45 | } 46 | 47 | sub CLEAR { 48 | my ($self) = @_; 49 | $self->del( $self->{name} ); 50 | } 51 | 52 | sub PUSH { 53 | my $self = shift; 54 | $self->rpush( $self->{name}, $_ ) foreach @_; 55 | } 56 | 57 | sub SHIFT { 58 | my $self = shift; 59 | $self->lpop( $self->{name} ); 60 | } 61 | 62 | sub UNSHIFT { 63 | my $self = shift; 64 | $self->lpush( $self->{name}, $_ ) foreach @_; 65 | } 66 | 67 | sub SPLICE { 68 | my $self = shift; 69 | my $offset = shift; 70 | my $length = shift; 71 | $self->lrange( $self->{name}, $offset, $length ); 72 | # FIXME rest of @_ ? 73 | } 74 | 75 | sub EXTEND { 76 | my ($self,$count) = @_; 77 | $self->rpush( $self->{name}, '' ) foreach ( $self->FETCHSIZE .. ( $count - 1 ) ); 78 | } 79 | 80 | sub DESTROY { 81 | my $self = shift; 82 | $self->quit; 83 | } 84 | 85 | 1; 86 | -------------------------------------------------------------------------------- /doc/SaveCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SaveCommand: Contents
      SAVE
    Return value
    See also 20 |
21 | 22 |

SaveCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SAVE

30 |
Save the DB on disk. The server hangs while the saving is notcompleted, no connection is served in the meanwhile. An OK codeis returned when the DB was fully stored in disk.
31 |

Return value

Status code reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/SetCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SetCommand: Contents
  SET _key_ _value_
    Return value
    See also 20 |
21 | 22 |

SetCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SET _key_ _value_

30 | Time complexity: O(1)
Set the string value as value of the key.The string can't be longer than 1073741824 bytes (1 GB).
31 |

Return value

Status code reply

See also

32 |
  • SETNX is like SET but don't perform the operation if the target key already exists.
33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /client-libraries/scala/src/test/scala/com/redis/RedisClusterSpec.scala: -------------------------------------------------------------------------------- 1 | import org.specs._ 2 | import com.redis._ 3 | 4 | import org.specs.mock.Mockito 5 | import org.mockito.Mock._ 6 | import org.mockito.Mockito._ 7 | import org.mockito.Mockito.doNothing 8 | 9 | object RedisClusterSpec extends Specification with Mockito { 10 | 11 | "Redis Cluster" should { 12 | var cluster: RedisCluster = null 13 | var mockedRedis: Redis = null 14 | 15 | doBefore { 16 | cluster = new RedisCluster("localhost:11221", "localhost:99991") 17 | mockedRedis = mock[Redis] 18 | } 19 | 20 | "print formatted client status" in { 21 | cluster.toString must be matching("localhost:11221 , localhost:99991 ") 22 | } 23 | 24 | "get the connection for the specified key" in { 25 | cluster.getConnection("key") mustEqual Connection("localhost", 99991) 26 | cluster.getConnection("anotherkey") mustEqual Connection("localhost", 11221) 27 | } 28 | 29 | "use the default number of replicas" in { 30 | cluster.replicas mustEqual 160 31 | } 32 | 33 | "initialize cluster" in { 34 | val initializedCluster = cluster.initialize_cluster 35 | initializedCluster.size mustEqual 2 36 | initializedCluster(0) mustEqual false 37 | initializedCluster(1) mustEqual false 38 | } 39 | 40 | "connect all the redis instances" in { 41 | cluster.cluster(1) = mockedRedis 42 | 43 | cluster.cluster(1).connect returns true 44 | val connectResult = cluster.connect 45 | connectResult.size mustEqual 2 46 | connectResult(0) mustEqual false 47 | connectResult(1) mustEqual true 48 | cluster.cluster(1).connect was called 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /doc/GetCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | GetCommand: Contents
  GET _key_
    Return value
    See also 20 |
21 | 22 |

GetCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

GET _key_

30 | Time complexity: O(1)
Get the value of the specified key. If the keydoes not exist the special value 'nil' is returned.If the value stored at key is not a string an erroris returned because GET can only handle string values.
31 |

Return value

Bulk reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /client-libraries/ruby/benchmarking/worker.rb: -------------------------------------------------------------------------------- 1 | BENCHMARK_ROOT = File.dirname(__FILE__) 2 | REDIS_ROOT = File.join(BENCHMARK_ROOT, "..", "lib") 3 | 4 | $: << REDIS_ROOT 5 | require 'redis' 6 | require 'benchmark' 7 | 8 | def show_usage 9 | puts <<-EOL 10 | Usage: worker.rb [read:write] 11 | EOL 12 | end 13 | 14 | def shift_from_argv 15 | value = ARGV.shift 16 | unless value 17 | show_usage 18 | exit -1 19 | end 20 | value 21 | end 22 | 23 | operation = shift_from_argv.to_sym 24 | start_index = shift_from_argv.to_i 25 | end_index = shift_from_argv.to_i 26 | sleep_msec = shift_from_argv.to_i 27 | sleep_duration = sleep_msec/1000.0 28 | 29 | redis = Redis.new 30 | 31 | case operation 32 | when :initialize 33 | 34 | start_index.upto(end_index) do |i| 35 | redis[i] = 0 36 | end 37 | 38 | when :clear 39 | 40 | start_index.upto(end_index) do |i| 41 | redis.delete(i) 42 | end 43 | 44 | when :read, :write 45 | 46 | puts "Starting to #{operation} at segment #{end_index + 1}" 47 | 48 | loop do 49 | t1 = Time.now 50 | start_index.upto(end_index) do |i| 51 | case operation 52 | when :read 53 | redis.get(i) 54 | when :write 55 | redis.incr(i) 56 | else 57 | raise "Unknown operation: #{operation}" 58 | end 59 | sleep sleep_duration 60 | end 61 | t2 = Time.now 62 | 63 | requests_processed = end_index - start_index 64 | time = t2 - t1 65 | puts "#{t2.strftime("%H:%M")} [segment #{end_index + 1}] : Processed #{requests_processed} requests in #{time} seconds - #{(requests_processed/time).round} requests/sec" 66 | end 67 | 68 | else 69 | raise "Unknown operation: #{operation}" 70 | end 71 | 72 | -------------------------------------------------------------------------------- /client-libraries/ruby/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'rake/gempackagetask' 3 | require 'rubygems/specification' 4 | require 'date' 5 | require 'spec/rake/spectask' 6 | require 'tasks/redis.tasks' 7 | 8 | 9 | GEM = 'redis' 10 | GEM_NAME = 'redis' 11 | GEM_VERSION = '0.1' 12 | AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark', 'Brian McKinney', 'Salvatore Sanfilippo', 'Luca Guidi'] 13 | EMAIL = "ez@engineyard.com" 14 | HOMEPAGE = "http://github.com/ezmobius/redis-rb" 15 | SUMMARY = "Ruby client library for redis key value storage server" 16 | 17 | spec = Gem::Specification.new do |s| 18 | s.name = GEM 19 | s.version = GEM_VERSION 20 | s.platform = Gem::Platform::RUBY 21 | s.has_rdoc = true 22 | s.extra_rdoc_files = ["LICENSE"] 23 | s.summary = SUMMARY 24 | s.description = s.summary 25 | s.authors = AUTHORS 26 | s.email = EMAIL 27 | s.homepage = HOMEPAGE 28 | s.add_dependency "rspec" 29 | s.require_path = 'lib' 30 | s.autorequire = GEM 31 | s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,tasks,spec}/**/*") 32 | end 33 | 34 | task :default => :spec 35 | 36 | desc "Run specs" 37 | Spec::Rake::SpecTask.new do |t| 38 | t.spec_files = FileList['spec/**/*_spec.rb'] 39 | t.spec_opts = %w(-fs --color) 40 | end 41 | 42 | Rake::GemPackageTask.new(spec) do |pkg| 43 | pkg.gem_spec = spec 44 | end 45 | 46 | desc "install the gem locally" 47 | task :install => [:package] do 48 | sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}} 49 | end 50 | 51 | desc "create a gemspec file" 52 | task :make_spec do 53 | File.open("#{GEM}.gemspec", "w") do |file| 54 | file.puts spec.to_ruby 55 | end 56 | end 57 | 58 | desc "Run all examples with RCov" 59 | Spec::Rake::SpecTask.new(:rcov) do |t| 60 | t.spec_files = FileList['spec/**/*_spec.rb'] 61 | t.rcov = true 62 | end 63 | -------------------------------------------------------------------------------- /doc/BgsaveCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | BgsaveCommand: Contents
  BGSAVE
    Return value
    See also 20 |
21 | 22 |

BgsaveCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

BGSAVE

30 |
Save the DB in background. The OK code is immediately returned.Redis forks, the parent continues to server the clients, the childsaves the DB on disk then exit. A client my be able to check if theoperation succeeded using the LASTSAVE command.
31 |

Return value

Status code reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/RenameCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | RenameCommand: Contents
  RENAME _oldkey_ _newkey_
    Return value
    See also 20 |
21 | 22 |

RenameCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

RENAME _oldkey_ _newkey_

30 | Time complexity: O(1)
Atomically renames the key oldkey to newkey. If the source anddestination name are the same an error is returned. If newkeyalready exists it is overwritten.
31 |

Return value

Status code repy

See also

32 |
  • RENAMENX if you don't want overwrite the destionation key if it exists.
33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/LastsaveCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | LastsaveCommand: Contents
  LASTSAVE
    Return value
    See also 20 |
21 | 22 |

LastsaveCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

LASTSAVE

30 |
Return the UNIX TIME of the last DB save executed with success.A client may check if a BGSAVE command succeeded reading the LASTSAVEvalue, then issuing a BGSAVE command and checking at regular intervalsevery N seconds if LASTSAVE changed.
31 |

Return value

Integer reply, specifically an UNIX time stamp.

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /client-libraries/scala/src/main/scala/com/redis/HashRing.scala: -------------------------------------------------------------------------------- 1 | package com.redis 2 | 3 | /** 4 | * Hash Ring 5 | * 6 | */ 7 | 8 | import java.util.zip.CRC32 9 | import scala.collection.mutable.ArrayBuffer 10 | import scala.collection.mutable.Map 11 | 12 | trait HashRing { 13 | 14 | val replicas: Int 15 | 16 | var sortedKeys: List[Long] = List() 17 | var cluster = new ArrayBuffer[Redis] 18 | val ring = Map[Long, Redis]() 19 | 20 | // Adds the node to the hashRing 21 | // including a number of replicas. 22 | def addNode(node: Redis) = { 23 | cluster += node 24 | (1 to replicas).foreach{ replica => 25 | val key = calculateChecksum(node+":"+replica) 26 | ring += (key -> node) 27 | sortedKeys = sortedKeys ::: List(key) 28 | } 29 | sortedKeys = sortedKeys.sort(_ < _) 30 | } 31 | 32 | // get the node in the hash ring for this key 33 | def getNode(key: String) = getNodePos(key)._1 34 | 35 | def getNodePos(key: String): (Redis, Int) = { 36 | val crc = calculateChecksum(key) 37 | val idx = binarySearch(crc) 38 | (ring(sortedKeys(idx)), idx) 39 | } 40 | 41 | // TODO this should perform a Bynary search 42 | def binarySearch(value: Long): Int = { 43 | var upper = (sortedKeys.length -1) 44 | var lower = 0 45 | var idx = 0 46 | var comp: Long = 0 47 | 48 | while(lower <= upper){ 49 | idx = (lower + upper) / 2 50 | comp = sortedKeys(idx) 51 | 52 | if(comp == value) { return idx } 53 | if(comp < value) { upper = idx -1 } 54 | if(comp > value) { lower = idx +1 } 55 | } 56 | return upper 57 | } 58 | 59 | // Computes the CRC-32 of the given String 60 | def calculateChecksum(value: String): Long = { 61 | val checksum = new CRC32 62 | checksum.update(value.getBytes) 63 | checksum.getValue 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /doc/TtlCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | TtlCommand: Contents
  TTL _key_
    Return value
    See also 20 |
21 | 22 |

TtlCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

TTL _key_

The TTL command returns the remaining time to live in seconds of a key that has an EXPIRE set. This introspection capability allows a Redis client to check how many seconds a given key will continue to be part of the dataset. If the Key does not exists or does not have an associated expire, -1 is returned.
30 |

Return value

Integer reply

See also

31 | 32 |
33 | 34 |
35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /doc/SetnxCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SetnxCommand: Contents
  SETNX _key_ _value_
    Return value
    See also 20 |
21 | 22 |

SetnxCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SETNX _key_ _value_

30 | Time complexity: O(1)
SETNX works exactly like SET with the only difference thatif the key already exists no operation is performed.SETNX actually means "SET if Not eXists".
31 |

Return value

Integer reply, specifically:

32 | 1 if the key was set
33 | 0 if the key was not set
34 | 

See also

35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/DelCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | DelCommand: Contents
  DEL _key_
    Return value
    See also 20 |
21 | 22 |

DelCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

DEL _key_

30 | Time complexity: O(1)
Remove the specified key. If the key does not existno operation is performed. The command always returns success.
31 |

Return value

Integer reply, specifically:

32 | 1 if the key was removed
33 | 0 if the key does not exist
34 | 

See also

35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/RenamenxCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | RenamenxCommand: Contents
  RENAMENX _oldkey_ _newkey_
    Return value
    See also 20 |
21 | 22 |

RenamenxCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

RENAMENX _oldkey_ _newkey_

30 | Time complexity: O(1)
Rename oldkey into newkey but fails if the destination key newkey already exists.
31 |

Return value

Integer reply, specifically:

32 | 1 if the key was renamed
33 | 0 if the target key already exist
34 | 

See also

35 |
  • RENAME is like RENAMENX but overwrite existing destionation key.
36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/ShutdownCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | ShutdownCommand: Contents
  SHUTDOWN
    Return value
    See also 20 |
21 | 22 |

ShutdownCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SHUTDOWN

30 |
Stop all the clients, save the DB, then quit the server. This commandsmakes sure that the DB is switched off without the lost of any data.This is not guaranteed if the client uses simply "SAVE" and then"QUIT" because other clients may alter the DB data between the twocommands.
31 |

Return value

Status code reply on error. On success nothing is returned since the server quits and the connection is closed.

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/SpopCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SpopCommand: Contents
  SPOP _key_
    Return value
    See also 20 |
21 | 22 |

SpopCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SPOP _key_

30 | Time complexity O(1)
Pop a random element from a Set, and return it to the caller. If the key does not exist or if the key contains an empty Set a special 'nil' value is returned.
31 |

Return value

bulk reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/TypeCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | TypeCommand: Contents
  TYPE _key_
    Return value
    See also 20 |
21 | 22 |

TypeCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

TYPE _key_

30 | Time complexity: O(1)
Return the type of the value stored at key in form of astring. The type can be one of "none", "string", "list", "set"."none" is returned if the key does not exist.
31 |

Return value

Status code reply, specifically:

32 | "none" if the key does not exist
33 | "string" if the key contains a String value
34 | "list" if the key contains a List value
35 | "set" if the key contains a Set value
36 | 

See also

37 | 38 |
39 | 40 |
41 |
42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /doc/ExistsCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | ExistsCommand: Contents
  EXISTS _key_
    Return value
    See also 20 |
21 | 22 |

ExistsCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

EXISTS _key_

30 | Time complexity: O(1)
Test if the specified key exists. The command returns"0" if the key exists, otherwise "1" is returned.Note that even keys set with an empty string as value willreturn "1".
31 |

Return value

Integer reply, specifically:

32 | 1 if the key exists.
33 | 0 if the key does not exist.
34 | 

See also

35 |
  • SETNX is a SET if not EXISTS atomic operation.
  • SISMEMBER test if an element is a member of a Set.
36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/SmembersCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SmembersCommand: Contents
  SMEMBERS _key_
    Return value
    See also 20 |
21 | 22 |

SmembersCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SMEMBERS _key_

30 | Time complexity O(N)
Return all the members (elements) of the set value stored at key. Thisis just syntax glue for SINTERSECT.
31 |

Return value

Multi bulk reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/AuthCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | AuthCommand: Contents
  AUTH _password_
    Return value 20 |
21 | 22 |

AuthCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

AUTH _password_

Request for authentication in a password protected Redis server.A Redis server can be instructed to require a password before to allow clientsto issue commands. This is done using the requirepass directive in theRedis configuration file.
30 |
If the password given by the client is correct the server replies withan OK status code reply and starts accepting commands from the client.Otherwise an error is returned and the clients needs to try a new password.Note that for the high performance nature of Redis it is possible to trya lot of passwords in parallel in very short time, so make sure to generatea strong and very long password so that this attack is infeasible.
31 |

Return value

Status code reply 32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/UnstableSource.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | UnstableSource: Contents
  Get the latest Redis source code
    Unstable code
    Stable code 20 |
21 | 22 |

UnstableSource

23 | 24 |
25 | 26 |
27 | 28 |
29 |

Get the latest Redis source code

Unstable code

30 | The development version of Redis is hosted here at Github, have fun cloning the source code with Git. If you are not familar with Git just use the download button to get a tarball.

Stable code

31 | Warning: the development source code is only intended for people that want to develop Redis or absolutely need the latest features still not available on the stable releases. You may have a better experience with the latest stable tarball. 32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/LlenCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | LlenCommand: Contents
  LLEN _key_
    Return value
    See also 20 |
21 | 22 |

LlenCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

LLEN _key_

30 | Time complexity: O(1)
Return the length of the list stored at the specified key. If thekey does not exist zero is returned (the same behaviour as forempty lists). If the value stored at key is not a list an error is returned.
31 |

Return value

Integer reply, specifically:

32 | The length of the list.
33 | 

See also

34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /doc/LsetCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | LsetCommand: Contents
  LSET _key_ _index_ _value_
    Return value
    See also 20 |
21 | 22 |

LsetCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

LSET _key_ _index_ _value_

30 | Time complexity: O(N) (with N being the length of the list)
Set the list element at index (see LINDEX for information about the_index_ argument) with the new value. Out of range indexes willgenerate an error. Note that setting the first or last elements ofthe list is O(1).
31 |

Return value

Status code reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/MoveCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | MoveCommand: Contents
  MOVE _key_ _dbindex_
    Return value
    See also 20 |
21 | 22 |

MoveCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

MOVE _key_ _dbindex_

30 |
Move the specified key from the currently selected DB to the specifieddestination DB. Note that this command returns 1 only if the key wassuccessfully moved, and 0 if the target key was already there or if thesource key was not found at all, so it is possible to use MOVE as a lockingprimitive.
31 |

Return value

Integer reply, specifically:

32 | 1 if the key was moved
33 | 0 if the key was not moved because already present on the target DB or was not found in the current DB.
34 | 

See also

35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * Expiring algorithm should be adaptive, if there are a lot of keys with an expire set and many of this happen to be already expired it should be, proportionally, more aggressive. 2 | * Add a command to inspect the currently selected DB index 3 | * Consistent hashing implemented in all the client libraries having an user base 4 | * SORT: Don't copy the list into a vector when BY argument is constant. 5 | * SORT ... STORE keyname. Instead to return the SORTed data set it into key. 6 | * Profiling and optimization in order to limit the CPU usage at minimum 7 | * Write the hash table size of every db in the dump, so that Redis can resize the hash table just one time when loading a big DB. 8 | * Elapsed time in logs for SAVE when saving is going to take more than 2 seconds 9 | * LOCK / TRYLOCK / UNLOCK as described many times in the google group 10 | * Replication automated tests 11 | * some kind of sorted type, example: 12 | ZADD mykey foo 100 13 | ZADD mykey bar 50 14 | ZRANGE mykey 0 1 => bar foo 15 | This is able to take elements sorted because a binary tree is used to store 16 | the elements by 'score', with the actual value being the key. On the other 17 | side the type also takes an hash table with key->score mapping, so that when 18 | there is an update we lookup the current score and can traverse the tree. 19 | * BITMAP / BYTEARRAY type? 20 | * LRANGE 4 0 should return the same elements as LRANGE 0 4 but in reverse order (only if we get enough motivated requests about it) 21 | * zmalloc() should avoid to add a private header for archs where there is some other kind of libc-specific way to get the size of a malloced block. 22 | 23 | FUTURE HINTS 24 | 25 | - In memory compression: if in-memory values compression will be implemented, make sure to implement this so that addReply() is able to handle compressed objects, just creating an uncompressed version on the fly and adding this to the output queue instead of the original one. When insetad we need to look at the object string value (SORT BY for example), call a function that will turn the object into an uncompresed one. 26 | -------------------------------------------------------------------------------- /doc/ScardCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | ScardCommand: Contents
  SCARD _key_
    Return value
    See also 20 |
21 | 22 |

ScardCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SCARD _key_

30 | Time complexity O(1)
Return the set cardinality (number of elements). If the key does notexist 0 is returned, like for empty sets.
31 |

Return value

Integer reply, specifically:

32 | the cardinality (number of elements) of the set as an integer.
33 | 

See also

34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /doc/SinterstoreCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SinterstoreCommand: Contents
  SINTERSTORE _dstkey_ _key1_ _key2_ ... _keyN_
    Return value
    See also 20 |
21 | 22 |

SinterstoreCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SINTERSTORE _dstkey_ _key1_ _key2_ ... _keyN_

30 | Time complexity O(NM) worst case where N is the cardinality of the smallest set and M the number of sets_

This commnad works exactly like SINTER but instead of being returned the resulting set is sotred as _dstkey_.
31 |

Return value

Status code reply

See also

32 |
* SADD* SREM* SISMEMBER* SCARD* SMEMBERS* SINTER* SINTERSTORE* SMOVE
33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/SunionstoreCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SunionstoreCommand: Contents
  SUNIONSTORE _dstkey_ _key1_ _key2_ ... _keyN_
    Return value
    See also 20 |
21 | 22 |

SunionstoreCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SUNIONSTORE _dstkey_ _key1_ _key2_ ... _keyN_

30 | Time complexity O(N) where N is the total number of elements in all the provided sets
This commnad works exactly like SUNION but instead of being returned the resulting set is sotred as dstkey.
31 |

Return value

Status code reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/RpushCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | RpushCommand: Contents
      RPUSH _key_ _string_
      LPUSH _key_ _string_
    Return value
    See also 20 |
21 | 22 |

RpushCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

RPUSH _key_ _string_

30 |

LPUSH _key_ _string_

31 | Time complexity: O(1)
Add the string value to the head (RPUSH) or tail (LPUSH) of the liststored at key. If the key does not exist an empty list is created just beforethe append operation. If the key exists but is not a List an erroris returned.
32 |

Return value

Status code reply

See also

33 | 34 |
35 | 36 |
37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /doc/LpopCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | LpopCommand: Contents
  LPOP _key_
  RPOP _key_
    Return value
    See also 20 |
21 | 22 |

LpopCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

LPOP _key_

30 |

RPOP _key_

31 | Time complexity: O(1)
Atomically return and remove the first (LPOP) or last (RPOP) elementof the list. For example if the list contains the elements "a","b","c" LPOPwill return "a" and the list will become "b","c".
32 |
If the key does not exist or the list is already empty the specialvalue 'nil' is returned.
33 |

Return value

Bulk reply

See also

34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /doc/SismemberCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SismemberCommand: Contents
  SISMEMBER _key_ _member_
    Return value
    See also 20 |
21 | 22 |

SismemberCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SISMEMBER _key_ _member_

30 | Time complexity O(1)
Return 1 if member is a member of the set stored at key, otherwise0 is returned.
31 |

Return value

Integer reply, specifically:

32 | 1 if the element is a member of the set
33 | 0 if the element is not a member of the set OR if the key does not exist
34 | 

See also

35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/SremCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SremCommand: Contents
  SREM _key_ _member_
    Return value
    See also 20 |
21 | 22 |

SremCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SREM _key_ _member_

30 | Time complexity O(1)
Remove the specified member from the set value stored at key. If_member_ was not a member of the set no operation is performed. If keydoes not exist or does not hold a set value an error is returned.
31 |

Return value

Integer reply, specifically:

32 | 1 if the new element was removed
33 | 0 if the new element was not a member of the set
34 | 

See also

35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/SdiffstoreCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SdiffstoreCommand: Contents
  SDIFFSTORE _dstkey_ _key1_ _key2_ ... _keyN_
    Return value
    See also 20 |
21 | 22 |

SdiffstoreCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SDIFFSTORE _dstkey_ _key1_ _key2_ ... _keyN_

30 | Time complexity O(N) where N is the total number of elements in all the provided sets
This commnad works exactly like SDIFF but instead of being returned the resulting set is sotred in dstkey.
31 |

Return value

Status code reply

See also

32 | 33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /doc/MgetCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | MgetCommand: Contents
  MGET _key1_ _key2_ ... _keyN_
    Return value
    Example
    See also 20 |
21 | 22 |

MgetCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

MGET _key1_ _key2_ ... _keyN_

30 | Time complexity: O(1) for every key
Get the values of all the specified keys. If one or more keys dont existor is not of type String, a 'nil' value is returned instead of the valueof the specified key, but the operation never fails.
31 |

Return value

Multi bulk reply

Example

32 | $ ./redis-cli set foo 1000
33 | +OK
34 | $ ./redis-cli set bar 2000
35 | +OK
36 | $ ./redis-cli mget foo bar
37 | 1. 1000
38 | 2. 2000
39 | $ ./redis-cli mget foo bar nokey
40 | 1. 1000
41 | 2. 2000
42 | 3. (nil)
43 | $ 
44 | 

See also

45 | 46 |
47 | 48 |
49 |
50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /doc/SaddCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SaddCommand: Contents
  SADD _key_ _member_
    Return value
    See also 20 |
21 | 22 |

SaddCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SADD _key_ _member_

30 | Time complexity O(1)
Add the specified member to the set value stored at key. If memberis already a member of the set no operation is performed. If keydoes not exist a new set with the specified member as sole member iscrated. If the key exists but does not hold a set value an error isreturned.
31 |

Return value

Integer reply, specifically:

32 | 1 if the new element was added
33 | 0 if the new element was already a member of the set
34 | 

See also

35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/GetsetCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | GetsetCommand: Contents
  GETSET _key_ _value_
    Return value
    Design patterns
    See also 20 |
21 | 22 |

GetsetCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

GETSET _key_ _value_

30 | Time complexity: O(1)
GETSET is an atomic set this value and return the old value command.Set key to the string value and return the old value stored at key.The string can't be longer than 1073741824 bytes (1 GB).
31 |

Return value

Bulk reply

Design patterns

GETSET can be used together with INCR for counting with atomic reset whena given condition arises. For example a process may call INCR against thekey mycounter every time some event occurred, but from time totime we need to get the value of the counter and reset it to zero atomicallyusing GETSET mycounter 0.
32 |

See also

33 | 34 |
35 | 36 |
37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /doc/LindexCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | LindexCommand: Contents
  LINDEX _key_ _index_
    Return value
    See also 20 |
21 | 22 |

LindexCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

LINDEX _key_ _index_

30 | Time complexity: O(n) (with n being the length of the list)
Return the specified element of the list stored at the specifiedkey. 0 is the first element, 1 the second and so on. Negative indexesare supported, for example -1 is the last element, -2 the penultimateand so on.
31 |
If the value stored at key is not of list type an error is returned.If the index is out of range an empty string is returned.
32 |
Note that even if the average time complexity is O(n) asking forthe first or the last element of the list is O(1).
33 |

Return value

Bulk reply, specifically the requested element.

See also

34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /doc/IncrCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | IncrCommand: Contents
  INCR _key_
  INCRBY _key_ _integer_
  DECR _key_ _integer_
  DECRBY _key_ _integer_
    Return value
    See also 20 |
21 | 22 |

IncrCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

INCR _key_

30 |

INCRBY _key_ _integer_

31 |

DECR _key_ _integer_

32 |

DECRBY _key_ _integer_

33 | Time complexity: O(1)
Increment or decrement the number stored at key by one. If the key doesnot exist or contains a value of a wrong type, set the key to thevalue of "0" before to perform the increment or decrement operation.
34 |
INCRBY and DECRBY work just like INCR and DECR but instead toincrement/decrement by 1 the increment/decrement is integer.
35 |

Return value

Integer reply, this commands will reply with the new value of key after the increment or decrement.

See also

36 | 37 |
38 | 39 |
40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /doc/MonitorCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | MonitorCommand: Contents
  MONITOR
    Return value
    See also 20 |
21 | 22 |

MonitorCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

MONITOR

MONITOR is a debugging command that outputs the whole sequence of commandsreceived by the Redis server. is very handy in order to understandwhat is happening into the database. This command is used directlyvia telnet.
30 |
31 | % telnet 127.0.0.1 6379
32 | Trying 127.0.0.1...
33 | Connected to segnalo-local.com.
34 | Escape character is '^]'.
35 | MONITOR
36 | +OK
37 | monitor
38 | keys *
39 | dbsize
40 | set x 6
41 | foobar
42 | get x
43 | del x
44 | get x
45 | set key_x 5
46 | hello
47 | set key_y 5
48 | hello
49 | set key_z 5
50 | hello
51 | set foo_a 5
52 | hello
53 | 
The ability to see all the requests processed by the server is useful in orderto spot bugs in the application both when using Redis as a database and asa distributed caching system.
54 |
In order to end a monitoring session just issue a QUIT command by hand.
55 |

Return value

Non standard return value, just dumps the received commands in an infinite flow.

See also

56 | 57 |
58 | 59 |
60 |
61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /doc/SunionCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SunionCommand: Contents
  SUNION _key1_ _key2_ ... _keyN_
    Return value
    See also 20 |
21 | 22 |

SunionCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SUNION _key1_ _key2_ ... _keyN_

30 | Time complexity O(N) where N is the total number of elements in all the provided sets
Return the members of a set resulting from the union of all thesets hold at the specified keys. Like in LRANGE the result is sent tothe client as a multi-bulk reply (see the protocol specification formore information). If just a single key is specified, then this commandproduces the same result as SELEMENTS.
31 |
Non existing keys are considered like empty sets.
32 |

Return value

Multi bulk reply, specifically the list of common elements.

See also

33 | 34 |
35 | 36 |
37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /client-libraries/cpp/anet.h: -------------------------------------------------------------------------------- 1 | /* anet.c -- Basic TCP socket stuff made a bit less boring 2 | * 3 | * Copyright (c) 2006-2009, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef ANET_H 32 | #define ANET_H 33 | 34 | #define ANET_OK 0 35 | #define ANET_ERR -1 36 | #define ANET_ERR_LEN 256 37 | 38 | int anetTcpConnect(char *err, char *addr, int port); 39 | int anetTcpNonBlockConnect(char *err, char *addr, int port); 40 | int anetRead(int fd, char *buf, int count); 41 | int anetResolve(char *err, char *host, char *ipbuf); 42 | int anetTcpServer(char *err, int port, char *bindaddr); 43 | int anetAccept(char *err, int serversock, char *ip, int *port); 44 | int anetWrite(int fd, char *buf, int count); 45 | int anetNonBlock(char *err, int fd); 46 | int anetTcpNoDelay(char *err, int fd); 47 | int anetTcpKeepAlive(char *err, int fd); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /doc/SdiffCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SdiffCommand: Contents
  SDIFF _key1_ _key2_ ... _keyN_
    Return value
    See also 20 |
21 | 22 |

SdiffCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SDIFF _key1_ _key2_ ... _keyN_

30 | Time complexity O(N) with N being the total number of elements of all the sets
Return the members of a set resulting from the difference between the firstset provided and all the successive sets. Example:
31 |
32 | key1 = x,a,b,c
33 | key2 = c
34 | key3 = a,d
35 | SDIFF key1,key2,key3 => x,b
36 | 
Non existing keys are considered like empty sets.
37 |

Return value

Multi bulk reply, specifically the list of common elements.

See also

38 | 39 |
40 | 41 |
42 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /zmalloc.h: -------------------------------------------------------------------------------- 1 | /* zmalloc - total amount of allocated memory aware version of malloc() 2 | * 3 | * Copyright (c) 2006-2009, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | /* 32 | * redis通过自已的方式来部署与管理内存 33 | * redis下层采用的是C语言来编写的,因此 34 | * redis提供的内存分配其实也就是对C语言中 35 | * 基本的内存分配函数如malloc/free/calloc/realloc 36 | * 的封装 37 | */ 38 | 39 | #ifndef _ZMALLOC_H 40 | #define _ZMALLOC_H 41 | 42 | /* 43 | * 此函数用于分配指定大小的内存空间 44 | * 若分配失败的话则返回NULL 45 | * 分配成功的话,返回空间的首地址 46 | */ 47 | 48 | void *zmalloc(size_t size); 49 | 50 | /* 51 | * 此函数用于重新分配内存空间,若ptr指向地址 52 | * 处有size个空间的话,则ptr不变 53 | * 若不足size个空间的话,会重新分配内存空间 54 | * 返回新空间的首地址,将将原有数据拷贝到新 55 | * 空间,同时释放旧空间 56 | */ 57 | 58 | void *zrealloc(void *ptr, size_t size); 59 | 60 | /* 61 | * 用于释放ptr指向的内存空间 62 | */ 63 | 64 | void zfree(void *ptr); 65 | 66 | /* 67 | * 用于字符串的拷贝 68 | */ 69 | 70 | char *zstrdup(const char *s); 71 | 72 | /* 73 | * 获取实际分配的内存空间大小 74 | */ 75 | 76 | size_t zmalloc_used_memory(void); 77 | 78 | #endif /* _ZMALLOC_H */ 79 | -------------------------------------------------------------------------------- /doc/LremCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | LremCommand: Contents
  LREM _key_ _count_ _value_
    Return value
    See also 20 |
21 | 22 |

LremCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

LREM _key_ _count_ _value_

30 | Time complexity: O(N) (with N being the length of the list)
Remove the first count occurrences of the value element from the list.If count is zero all the elements are removed. If count is negativeelements are removed from tail to head, instead to go from head to tailthat is the normal behaviour. So for example LREM with count -2 and_hello_ as value to remove against the list (a,b,c,hello,x,hello,hello) willlave the list (a,b,c,hello,x). The number of removed elements is returnedas an integer, see below for more information about the returned value.Note that non existing keys are considered like empty lists by LREM, so LREMagainst non existing keys will always return 0.
31 |

Return value

Integer Reply, specifically:

32 | The number of removed elements if the operation succeeded
33 | 

See also

34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /redis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006-2009, Salvatore Sanfilippo 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * * Neither the name of Redis nor the names of its contributors may be used 14 | * to endorse or promote products derived from this software without 15 | * specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | * POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef __REDIS_H__ 31 | #define __REDIS_H__ 32 | 33 | enum 34 | { 35 | REG_GS = 0, 36 | # define REG_GS REG_GS 37 | REG_FS, 38 | # define REG_FS REG_FS 39 | REG_ES, 40 | # define REG_ES REG_ES 41 | REG_DS, 42 | # define REG_DS REG_DS 43 | REG_EDI, 44 | # define REG_EDI REG_EDI 45 | REG_ESI, 46 | # define REG_ESI REG_ESI 47 | REG_EBP, 48 | # define REG_EBP REG_EBP 49 | REG_ESP, 50 | # define REG_ESP REG_ESP 51 | REG_EBX, 52 | # define REG_EBX REG_EBX 53 | REG_EDX, 54 | # define REG_EDX REG_EDX 55 | REG_ECX, 56 | # define REG_ECX REG_ECX 57 | REG_EAX, 58 | # define REG_EAX REG_EAX 59 | REG_TRAPNO, 60 | # define REG_TRAPNO REG_TRAPNO 61 | REG_ERR, 62 | # define REG_ERR REG_ERR 63 | REG_EIP, 64 | # define REG_EIP REG_EIP 65 | REG_CS, 66 | # define REG_CS REG_CS 67 | REG_EFL, 68 | # define REG_EFL REG_EFL 69 | REG_UESP, 70 | # define REG_UESP REG_UESP 71 | REG_SS 72 | # define REG_SS REG_SS 73 | }; 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /doc/SinterCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SinterCommand: Contents
  SINTER _key1_ _key2_ ... _keyN_
    Return value
    See also 20 |
21 | 22 |

SinterCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SINTER _key1_ _key2_ ... _keyN_

30 | Time complexity O(NM) worst case where N is the cardinality of the smallest set and M the number of sets_

Return the members of a set resulting from the intersection of all thesets hold at the specified keys. Like in LRANGE the result is sent tothe client as a multi-bulk reply (see the protocol specification formore information). If just a single key is specified, then this commandproduces the same result as SMEMBERS. Actually SMEMBERS is just syntaxsugar for SINTERSECT.
31 |
Non existing keys are considered like empty sets, so if one of the keys ismissing an empty set is returned (since the intersection with an emptyset always is an empty set).
32 |

Return value

Multi bulk reply, specifically the list of common elements.

See also

33 |
* SADD* SREM* SISMEMBER* SCARD* SMEMBERS* SINTERSTORE* SUNION* SUNIONSTORE* SMOVE
34 |
35 | 36 |
37 |
38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /doc/LrangeCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | LrangeCommand: Contents
  LRANGE _key_ _start_ _end_
    Return value
    See also 20 |
21 | 22 |

LrangeCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

LRANGE _key_ _start_ _end_

30 | Time complexity: O(n) (with n being the length of the range)
Return the specified elements of the list stored at the specifiedkey. Start and end are zero-based indexes. 0 is the first elementof the list (the list head), 1 the next element and so on.
31 |
For example LRANGE foobar 0 2 will return the first three elementsof the list.
32 |
_start_ and end can also be negative numbers indicating offsetsfrom the end of the list. For example -1 is the last element ofthe list, -2 the penultimate element and so on.
33 |
Indexes out of range will not produce an error: if start is overthe end of the list, or start > end, an empty list is returned.If end is over the end of the list Redis will threat it just likethe last element of the list.
34 |

Return value

Multi bulk reply, specifically a list of elements in the specified range.

See also

35 | 36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /doc/Credits.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | Credits: Contents
  Credits 20 |
21 | 22 |

Credits

23 | 24 |
25 | 26 |
27 | 28 |
29 |

Credits

  • The Redis server was designed and written by Salvatore Sanfilippo (aka antirez)
  • Ezra Zygmuntowicz (aka ezmobius) - Ruby client lib initial version and hacking
  • Ludovico Magnocavallo (aka ludo) - Python clinet lib
  • Valentino Volonghi of Adroll - Erlang client lib
  • brettbender - found and fixed a bug in sds.c that caused the server to crash at least on 64 bit systems, and anyway to be buggy since we used the same vararg thing against vsprintf without to call va_start and va_end every time.
  • Dobrica Pavlinusic - Perl client lib
  • Brian Hammond - AUTH command implementation, C++ client lib
  • Daniele Alessandri - Lua client lib
  • Corey Stup - C99 cleanups
  • Taylor Weibley - Ruby client improvements
  • Bob Potter - Rearrange redisObject struct to reduce memory usage in 64bit environments
  • Luca Guidi and Brian McKinney - Ruby client improvements
  • Aman Gupta - SDIFF / SDIFFSTORE, other Set operations improvements, ability to disable clients timeout.
  • Diego Rosario Brogna - Code and ideas about dumping backtrace on sigsegv and similar error conditions.
30 | p.s. sorry to take this file in sync is hard in this early days. Please drop me an email if I forgot to add your name here! 31 | 32 |
33 | 34 |
35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /utils/redis-copy.rb: -------------------------------------------------------------------------------- 1 | # redis-sha1.rb - Copyright (C) 2009 Salvatore Sanfilippo 2 | # BSD license, See the COPYING file for more information. 3 | # 4 | # Performs the SHA1 sum of the whole datset. 5 | # This is useful to spot bugs in persistence related code and to make sure 6 | # Slaves and Masters are in SYNC. 7 | # 8 | # If you hack this code make sure to sort keys and set elements as this are 9 | # unsorted elements. Otherwise the sum may differ with equal dataset. 10 | 11 | require 'rubygems' 12 | require 'redis' 13 | require 'digest/sha1' 14 | 15 | def redisCopy(opts={}) 16 | sha1="" 17 | src = Redis.new(:host => opts[:srchost], :port => opts[:srcport]) 18 | dst = Redis.new(:host => opts[:dsthost], :port => opts[:dstport]) 19 | puts "Loading key names..." 20 | keys = src.keys('*') 21 | puts "Copying #{keys.length} keys..." 22 | c = 0 23 | keys.each{|k| 24 | vtype = src.type?(k) 25 | ttl = src.ttl(k).to_i if vtype != "none" 26 | 27 | if vtype == "string" 28 | dst[k] = src[k] 29 | elsif vtype == "list" 30 | list = src.lrange(k,0,-1) 31 | if list.length == 0 32 | # Empty list special case 33 | dst.lpush(k,"") 34 | dst.lpop(k) 35 | else 36 | list.each{|ele| 37 | dst.rpush(k,ele) 38 | } 39 | end 40 | elsif vtype == "set" 41 | set = src.smembers(k) 42 | if set.length == 0 43 | # Empty set special case 44 | dst.sadd(k,"") 45 | dst.srem(k,"") 46 | else 47 | set.each{|ele| 48 | dst.sadd(k,ele) 49 | } 50 | end 51 | elsif vtype == "none" 52 | puts "WARNING: key '#{k}' was removed in the meanwhile." 53 | end 54 | 55 | # Handle keys with an expire time set 56 | if ttl != -1 and vtype != "none" 57 | dst.expire(k,ttl) 58 | end 59 | 60 | c = c+1 61 | if (c % 1000) == 0 62 | puts "#{c}/#{keys.length} completed" 63 | end 64 | } 65 | puts "DONE!" 66 | end 67 | 68 | if ARGV.length != 4 69 | puts "Usage: redis-copy.rb " 70 | exit 1 71 | end 72 | puts "WARNING: it's up to you to FLUSHDB the destination host before to continue, press any key when ready." 73 | STDIN.gets 74 | srchost = ARGV[0] 75 | srcport = ARGV[1] 76 | dsthost = ARGV[2] 77 | dstport = ARGV[3] 78 | puts "Copying #{srchost}:#{srcport} into #{dsthost}:#{dstport}" 79 | redisCopy(:srchost => srchost, :srcport => srcport.to_i, 80 | :dsthost => dsthost, :dstport => dstport.to_i) 81 | -------------------------------------------------------------------------------- /doc/SmoveCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SmoveCommand: Contents
  SMOVE _srckey_ _dstkey_ _member_
    Return value
    See also 20 |
21 | 22 |

SmoveCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SMOVE _srckey_ _dstkey_ _member_

30 | Time complexity O(1)
Move the specifided member from the set at srckey to the set at dstkey.This operation is atomic, in every given moment the element will appear tobe in the source or destination set for accessing clients.
31 |
If the source set does not exist or does not contain the specified elementno operation is performed and zero is returned, otherwise the element isremoved from the source set and added to the destination set. On successone is returned, even if the element was already present in the destinationset.
32 |
An error is raised if the source or destination keys contain a non Set value.
33 |

Return value

Integer reply, specifically:

34 | 1 if the element was moved
35 | 0 if the element was not found on the first set and no operation was performed
36 | 

See also

37 | 38 |
39 | 40 |
41 |
42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /doc/SlaveofCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | SlaveofCommand: Contents
  SLAVEOF _host_ _port_
  SLAVEOF no one
    Return value
    See also 20 |
21 | 22 |

SlaveofCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

SLAVEOF _host_ _port_

30 |

SLAVEOF no one

The SLAVEOF command can change the replication settings of a slave on the fly.If a Redis server is arleady acting as slave, the command SLAVEOF NO ONEwill turn off the replicaiton turning the Redis server into a MASTER.In the proper form SLAVEOF hostname port will make the server a slave of thespecific server listening at the specified hostname and port.
31 |
If a server is already a slave of some master, SLAVEOF hostname port willstop the replication against the old server and start the synchrnonizationagainst the new one discarding the old dataset.
32 |
The form SLAVEOF no one will stop replication turning the server into aMASTER but will not discard the replication. So if the old master stop workingit is possible to turn the slave into a master and set the application touse the new master in read/write. Later when the other Redis server will befixed it can be configured in order to work as slave.
33 |

Return value

Status code reply

See also

34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | index: Contents
  Redis Documentation 20 |
21 | 22 |

index

23 | 24 |
25 | 26 |
27 | 28 |
29 |

Redis Documentation

Hello! The followings are pointers to different parts of the Redis Documentation.

30 |
31 | 32 |
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /client-libraries/scala/src/test/scala/com/redis/operations/ListOperationsSpec.scala: -------------------------------------------------------------------------------- 1 | import org.specs._ 2 | import com.redis._ 3 | 4 | import org.specs.mock.Mockito 5 | import org.mockito.Mock._ 6 | import org.mockito.Mockito._ 7 | import org.mockito.Mockito.doNothing 8 | 9 | object ListOperationsSpec extends Specification with Mockito { 10 | 11 | "Redis Client List Operations" should { 12 | var client: RedisTestClient = null 13 | var connection: Connection = null 14 | 15 | doBefore{ 16 | connection = mock[Connection] 17 | client = new RedisTestClient(connection) 18 | } 19 | 20 | "push to head" in { 21 | connection.readBoolean returns true 22 | client.pushHead("k", "v") must beTrue 23 | connection.write("LPUSH k 1\r\nv\r\n") was called 24 | } 25 | 26 | "push to tail" in { 27 | connection.readBoolean returns true 28 | client.pushTail("k", "v") must beTrue 29 | connection.write("RPUSH k 1\r\nv\r\n") was called 30 | } 31 | 32 | "pop from head" in { 33 | connection.readString returns "value" 34 | client.popHead("key") mustEqual "value" 35 | connection.write("LPOP key\r\n") was called 36 | } 37 | 38 | "pop from tail" in { 39 | connection.readString returns "value" 40 | client.popTail("key") mustEqual "value" 41 | connection.write("RPOP key\r\n") was called 42 | } 43 | 44 | "return list index" in { 45 | connection.readString returns "value" 46 | client.listIndex("k", 2) mustEqual "value" 47 | connection.write("LINDEX k 2\r\n") was called 48 | } 49 | 50 | "return set element at index" in { 51 | connection.readBoolean returns true 52 | client.listSet("k", 1, "value") mustEqual true 53 | connection.write("LSET k 1 5\r\nvalue\r\n") was called 54 | } 55 | 56 | "return list size" in { 57 | connection.readInt returns 3 58 | client.listLength("k") mustEqual 3 59 | connection.write("LLEN k\r\n") was called 60 | } 61 | 62 | "return list range" in { 63 | val listResult: List[String] = List("one", "two", "three", "four", "five") 64 | connection.readList returns listResult 65 | client.listRange("k", 2, 4) mustEqual listResult 66 | connection.write("LRANGE k 2 4\r\n") was called 67 | } 68 | 69 | "trim a list" in { 70 | connection.readBoolean returns true 71 | client.listTrim("k", 2, 4) mustEqual true 72 | connection.write("LTRIM k 2 4\r\n") was called 73 | } 74 | 75 | "remove occurrences of a value in the list" in { 76 | connection.readBoolean returns true 77 | client.listRem("k", 2, "value") mustEqual true 78 | connection.write("LREM k 2 5\r\nvalue\r\n") was called 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /doc/InfoCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | InfoCommand: Contents
  INFO
    Return value
    Notes
    See also 20 |
21 | 22 |

InfoCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

INFO

The info command returns different information and statistics about the server in an format that's simple to parse by computers and easy to red by huamns.
30 |

Return value

Bulk reply, specifically in the following format:

31 | edis_version:0.07
32 | connected_clients:1
33 | connected_slaves:0
34 | used_memory:3187
35 | changes_since_last_save:0
36 | last_save_time:1237655729
37 | total_connections_received:1
38 | total_commands_processed:1
39 | uptime_in_seconds:25
40 | uptime_in_days:0
41 | 
All the fields are in the form field:value

Notes

  • used_memory is returned in bytes, and is the total number of bytes allocated by the program using malloc.
  • uptime_in_days is redundant since the uptime in seconds contains already the full uptime information, this field is only mainly present for humans.
  • changes_since_last_save does not refer to the number of key changes, but to the number of operations that produced some kind of change in the dataset.
42 |

See also

43 | 44 |
45 | 46 |
47 |
48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Redis Makefile 2 | # Copyright (C) 2009 Salvatore Sanfilippo 3 | # This file is released under the BSD license, see the COPYING file 4 | #此条语句是Makefile中的条件赋值 5 | # -g表示产生调试信息 6 | # -rdynamic用来通知链接器将所有的符号添加到动态符号表中 7 | # -ggdb表未要让gcc为GDB生成专用的更为丰富的调试信息 8 | DEBUG?= -g -rdynamic -ggdb 9 | # -std=c99表示C语言的版本采用的是C99标准 10 | # -pedantic打开完全服从ANSI C标准所需的全部警告诊断;拒绝接受采用了被禁止的语法扩展的程序 11 | # -O2表示程序代码的优化级别 12 | # -Wall表示打开警告开关 13 | # -W不生成任何警告信息 14 | CFLAGS?= -std=c99 -pedantic -O2 -Wall -W 15 | # CC在Makefile中表示的是编译器,这里就是编译器的选项 16 | CCOPT= $(CFLAGS) 17 | # 这些OBJ基本上都是服务器端的 18 | OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o 19 | # 与性能测试相关的 20 | BENCHOBJ = ae.o anet.o benchmark.o sds.o adlist.o zmalloc.o 21 | # 这些OBJ基本上都是客户端的 22 | CLIOBJ = anet.o sds.o adlist.o redis-cli.o zmalloc.o 23 | # 服务器端 24 | PRGNAME = redis-server 25 | # 性能测试相关 26 | BENCHPRGNAME = redis-benchmark 27 | # 客户端 28 | CLIPRGNAME = redis-cli 29 | 30 | # 伪目标,make会将第一个出现的目标作为默认目标,就是只执行make不加目标名的时候,第一个目标名通常是all 31 | all: redis-server redis-benchmark redis-cli 32 | 33 | # Deps (use make dep to generate this) 34 | # 下面是各种依赖 35 | adlist.o: adlist.c adlist.h zmalloc.h 36 | ae.o: ae.c ae.h zmalloc.h 37 | anet.o: anet.c fmacros.h anet.h 38 | benchmark.o: benchmark.c fmacros.h ae.h anet.h sds.h adlist.h zmalloc.h 39 | dict.o: dict.c fmacros.h dict.h zmalloc.h 40 | lzf_c.o: lzf_c.c lzfP.h 41 | lzf_d.o: lzf_d.c lzfP.h 42 | pqsort.o: pqsort.c 43 | redis-cli.o: redis-cli.c fmacros.h anet.h sds.h adlist.h zmalloc.h 44 | redis.o: redis.c fmacros.h ae.h sds.h anet.h dict.h adlist.h zmalloc.h lzf.h pqsort.h config.h 45 | sds.o: sds.c sds.h zmalloc.h 46 | zmalloc.o: zmalloc.c config.h 47 | 48 | # $(OBJ)表示要生成redis-server需要依赖的文件 49 | redis-server: $(OBJ) 50 | $(CC) -o $(PRGNAME) $(CCOPT) $(DEBUG) $(OBJ) 51 | @echo "" 52 | @echo "Hint: To run the test-redis.tcl script is a good idea." 53 | @echo "Launch the redis server with ./redis-server, then in another" 54 | @echo "terminal window enter this directory and run 'make test'." 55 | @echo "" 56 | # 编译生成性能测试工具,$(BENCHOBJ)表示生成性能测试工具时依赖的文件 57 | redis-benchmark: $(BENCHOBJ) 58 | $(CC) -o $(BENCHPRGNAME) $(CCOPT) $(DEBUG) $(BENCHOBJ) 59 | # 编译生成redis客户端程序 60 | redis-cli: $(CLIOBJ) 61 | $(CC) -o $(CLIPRGNAME) $(CCOPT) $(DEBUG) $(CLIOBJ) 62 | # 其实和%o:%c等价,是Makefile里的旧格式 63 | # gcc -o test.o test.c 64 | # 在该规则的作用下,会变成gcc -c $(CCOPT) $(DEBUG) $(COMPILE_TIME) test.c 65 | # -c选项表示是只编译不链接 66 | .c.o: 67 | $(CC) -c $(CCOPT) $(DEBUG) $(COMPILE_TIME) $< 68 | # 删除生成的目标程序以及所有的中间目标文件 69 | clean: 70 | rm -rf $(PRGNAME) $(BENCHPRGNAME) $(CLIPRGNAME) *.o 71 | # -MM选项表示的是是列出源文件对其他文件的依赖关系 72 | dep: 73 | $(CC) -MM *.c 74 | # 开启对服务器端进行测试 75 | test: 76 | tclsh test-redis.tcl 77 | # 开启性能测试 78 | bench: 79 | ./redis-benchmark 80 | # 将工程的更新日志信息输出到本地的Changelog里 81 | log: 82 | git log '--pretty=format:%ad %s' --date=short > Changelog 83 | -------------------------------------------------------------------------------- /doc/KeysCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | KeysCommand: Contents
  KEYS _pattern_
    Return value
    See also 20 |
21 | 22 |

KeysCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

KEYS _pattern_

30 | Time complexity: O(n) (with n being the number of keys in the DB, and assuming keys and pattern of limited length)
Returns all the keys matching the glob-style pattern asspace separated strings. For example if you have in thedatabase the keys "foo" and "foobar" the command "KEYS foo*"will return "foo foobar".
31 |
Note that while the time complexity for this operation is O(n)the constant times are pretty low. For example Redis runningon an entry level laptop can scan a 1 million keys databasein 40 milliseconds. Still it's better to consider this one ofthe slow commands that may ruin the DB performance if not usedwith care.
32 | Glob style patterns examples: 33 |
  • h?llo will match hello hallo hhllo
  • hllo will match hllo heeeello 34 |
    * haello will match hello and hallo, but not hillo
    Use \ to escape special chars if you want to match them verbatim.

    Return value

    Bulk reply, specifically a string in the form of space separated list of keys. Note that most client libraries will return an Array of keys and not a single string with space separated keys (that is, split by " " is performed in the client library usually).

    See also

    35 |
    * RANDOMKEY to get the name of a randomly selected key in O(1).
36 |
37 | 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /anet.h: -------------------------------------------------------------------------------- 1 | /* anet.c -- Basic TCP socket stuff made a bit less boring 2 | * 3 | * Copyright (c) 2006-2009, Salvatore Sanfilippo 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | /** 32 | * redis里的套接字相关的操作 33 | */ 34 | #ifndef ANET_H 35 | #define ANET_H 36 | 37 | #define ANET_OK 0 38 | #define ANET_ERR -1 39 | #define ANET_ERR_LEN 256 40 | /** 41 | * 用于建立非阻塞型的网络套接字连接 42 | */ 43 | int anetTcpConnect(char *err, char *addr, int port); 44 | /** 45 | * 用于建立阻塞型的网络套接字连接 46 | */ 47 | int anetTcpNonBlockConnect(char *err, char *addr, int port); 48 | /** 49 | * 用于套接字的读 50 | */ 51 | int anetRead(int fd, char *buf, int count); 52 | /** 53 | * 用于套接字的写 54 | */ 55 | int anetResolve(char *err, char *host, char *ipbuf); 56 | /** 57 | * 建立网络套接字服务器方法 58 | * 是对bind()/socket()/listen等一系列操作的封装 59 | * 返回套接字的fd 60 | */ 61 | int anetTcpServer(char *err, int port, char *bindaddr); 62 | /** 63 | * 用于接收连接 64 | */ 65 | int anetAccept(char *err, int serversock, char *ip, int *port); 66 | /** 67 | * 用于套接字的写功能 68 | */ 69 | int anetWrite(int fd, char *buf, int count); 70 | /** 71 | * 将fd设置为非阻塞型 72 | */ 73 | int anetNonBlock(char *err, int fd); 74 | /** 75 | * 将TCP设为非延迟的,即屏蔽Nagle算法 76 | */ 77 | int anetTcpNoDelay(char *err, int fd); 78 | /** 79 | * 开启连机监测,避免对方塔机,网络中断是fd无限期的等待 80 | */ 81 | int anetTcpKeepAlive(char *err, int fd); 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /client-libraries/ruby/lib/dist_redis.rb: -------------------------------------------------------------------------------- 1 | require 'redis' 2 | require 'hash_ring' 3 | class DistRedis 4 | attr_reader :ring 5 | def initialize(opts={}) 6 | hosts = [] 7 | 8 | db = opts[:db] || nil 9 | timeout = opts[:timeout] || nil 10 | 11 | raise Error, "No hosts given" unless opts[:hosts] 12 | 13 | opts[:hosts].each do |h| 14 | host, port = h.split(':') 15 | hosts << Redis.new(:host => host, :port => port, :db => db, :timeout => timeout) 16 | end 17 | 18 | @ring = HashRing.new hosts 19 | end 20 | 21 | def node_for_key(key) 22 | key = $1 if key =~ /\{(.*)?\}/ 23 | @ring.get_node(key) 24 | end 25 | 26 | def add_server(server) 27 | server, port = server.split(':') 28 | @ring.add_node Redis.new(:host => server, :port => port) 29 | end 30 | 31 | def method_missing(sym, *args, &blk) 32 | if redis = node_for_key(args.first.to_s) 33 | redis.send sym, *args, &blk 34 | else 35 | super 36 | end 37 | end 38 | 39 | def keys(glob) 40 | @ring.nodes.map do |red| 41 | red.keys(glob) 42 | end 43 | end 44 | 45 | def save 46 | on_each_node :save 47 | end 48 | 49 | def bgsave 50 | on_each_node :bgsave 51 | end 52 | 53 | def quit 54 | on_each_node :quit 55 | end 56 | 57 | def flush_all 58 | on_each_node :flush_all 59 | end 60 | alias_method :flushall, :flush_all 61 | 62 | def flush_db 63 | on_each_node :flush_db 64 | end 65 | alias_method :flushdb, :flush_db 66 | 67 | def delete_cloud! 68 | @ring.nodes.each do |red| 69 | red.keys("*").each do |key| 70 | red.delete key 71 | end 72 | end 73 | end 74 | 75 | def on_each_node(command, *args) 76 | @ring.nodes.each do |red| 77 | red.send(command, *args) 78 | end 79 | end 80 | 81 | end 82 | 83 | 84 | if __FILE__ == $0 85 | 86 | r = DistRedis.new 'localhost:6379', 'localhost:6380', 'localhost:6381', 'localhost:6382' 87 | r['urmom'] = 'urmom' 88 | r['urdad'] = 'urdad' 89 | r['urmom1'] = 'urmom1' 90 | r['urdad1'] = 'urdad1' 91 | r['urmom2'] = 'urmom2' 92 | r['urdad2'] = 'urdad2' 93 | r['urmom3'] = 'urmom3' 94 | r['urdad3'] = 'urdad3' 95 | p r['urmom'] 96 | p r['urdad'] 97 | p r['urmom1'] 98 | p r['urdad1'] 99 | p r['urmom2'] 100 | p r['urdad2'] 101 | p r['urmom3'] 102 | p r['urdad3'] 103 | 104 | r.push_tail 'listor', 'foo1' 105 | r.push_tail 'listor', 'foo2' 106 | r.push_tail 'listor', 'foo3' 107 | r.push_tail 'listor', 'foo4' 108 | r.push_tail 'listor', 'foo5' 109 | 110 | p r.pop_tail('listor') 111 | p r.pop_tail('listor') 112 | p r.pop_tail('listor') 113 | p r.pop_tail('listor') 114 | p r.pop_tail('listor') 115 | 116 | puts "key distribution:" 117 | 118 | r.ring.nodes.each do |red| 119 | p [red.port, red.keys("*")] 120 | end 121 | r.delete_cloud! 122 | p r.keys('*') 123 | 124 | end 125 | -------------------------------------------------------------------------------- /doc/LtrimCommand.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 15 | 16 |
17 |
18 | 19 | LtrimCommand: Contents
  LTRIM _key_ _start_ _end_
    Return value
    See also 20 |
21 | 22 |

LtrimCommand

23 | 24 |
25 | 26 |
27 | 28 |
29 |

LTRIM _key_ _start_ _end_

30 | Time complexity: O(n) (with n being len of list - len of range)
Trim an existing list so that it will contain only the specifiedrange of elements specified. Start and end are zero-based indexes.0 is the first element of the list (the list head), 1 the next elementand so on.
31 |
For example LTRIM foobar 0 2 will modify the list stored at foobarkey so that only the first three elements of the list will remain.
32 |
_start_ and end can also be negative numbers indicating offsetsfrom the end of the list. For example -1 is the last element ofthe list, -2 the penultimate element and so on.
33 |
Indexes out of range will not produce an error: if start is overthe end of the list, or start > end, an empty list is left as value.If end over the end of the list Redis will threat it just likethe last element of the list.
34 |
Hint: the obvious use of LTRIM is together with LPUSH/RPUSH. For example:
35 |
36 |         LPUSH mylist <someelement>
37 |         LTRIM mylist 0 99
38 | 
The above two commands will push elements in the list taking care thatthe list will not grow without limits. This is very useful when usingRedis to store logs for example. It is important to note that when usedin this way LTRIM is an O(1) operation because in the average casejust one element is removed from the tail of the list.
39 |

Return value

Status code reply

See also

40 | 41 |
42 | 43 |
44 |
45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /client-libraries/clojure/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Redis client library for Clojure. 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /client-libraries/scala/src/test/scala/com/redis/SocketOperationsSpec.scala: -------------------------------------------------------------------------------- 1 | import org.specs._ 2 | import com.redis._ 3 | 4 | import java.io._ 5 | import java.net.Socket 6 | 7 | import org.specs.mock.Mockito 8 | import org.mockito.Mock._ 9 | import org.mockito.Mockito._ 10 | 11 | class SocketOperationTest(val host:String, val port: Int) extends SocketOperations 12 | 13 | object SocketOperationsSpec extends Specification with Mockito { 14 | 15 | "Socket Operations" should { 16 | var socketOperation: SocketOperationTest = null 17 | var socket: Socket = null 18 | var in: BufferedReader = null 19 | 20 | doBefore { 21 | socketOperation = new SocketOperationTest("localhost", 6379666) 22 | socket = mock[Socket] 23 | in = mock[BufferedReader] 24 | socketOperation.socket = socket 25 | socketOperation.in = in 26 | } 27 | 28 | def readOkFromInput = { when(in.readLine()).thenReturn(socketOperation.OK) } 29 | def readSingleFromInput = { when(in.readLine()).thenReturn(socketOperation.SINGLE) } 30 | def readBulkFromInput = { in.readLine() returns("$6\r\nfoobar\r\n") thenReturns("$6\r\nfoobar\r\n") } 31 | def readIntFromInput = { when(in.readLine()).thenReturn(socketOperation.INT+"666") } 32 | 33 | "tell if it's connected" in { 34 | socketOperation.connected mustEqual true 35 | socketOperation.socket = null 36 | socketOperation.connected mustEqual false 37 | } 38 | 39 | "return false when can't connect" in { 40 | socketOperation.connect mustEqual false 41 | } 42 | 43 | "return current data input stream" in { 44 | socketOperation.getInputStream mustEqual in 45 | } 46 | 47 | "read a line from socket" in { 48 | readOkFromInput 49 | socketOperation.in mustEqual in 50 | socketOperation.readline mustEqual socketOperation.OK 51 | } 52 | 53 | "read type response" in { 54 | readOkFromInput 55 | socketOperation.readtype mustEqual ("+", socketOperation.OK) 56 | } 57 | 58 | "when reading responses" in { 59 | 60 | "read OK" in { 61 | readOkFromInput 62 | socketOperation.readResponse mustEqual socketOperation.OK 63 | } 64 | 65 | "read single line" in { 66 | readSingleFromInput 67 | socketOperation.readResponse mustEqual socketOperation.SINGLE 68 | } 69 | 70 | "reconnect on error" in { 71 | socketOperation.readResponse mustEqual false 72 | socket.close was called 73 | socketOperation.connected mustEqual true 74 | } 75 | 76 | "read in bulk" in { 77 | // readBulkFromInput 78 | // this shouldn't be the response, it doesn't seem to work return and then returns. 79 | // Here's what should happen: '$6\r\n' on first readLine and then 'foobar\r\n' 80 | readBulkFromInput 81 | socketOperation.readtype mustEqual ("$", "$6\r\nfoobar\r\n") 82 | socketOperation.readResponse mustEqual "$6\r\nfoobar\r\n" 83 | socketOperation.bulkReply("$6\r\nfoobar\r\n") was called 84 | } 85 | 86 | "read integer" in { 87 | readIntFromInput 88 | socketOperation.readInt mustEqual 666 89 | } 90 | 91 | "read a boolean return value" in { 92 | readOkFromInput 93 | socketOperation.readBoolean mustEqual true 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /client-libraries/tcl/redis.tcl: -------------------------------------------------------------------------------- 1 | # Tcl clinet library - used by test-redis.tcl script for now 2 | # Copyright (C) 2009 Salvatore Sanfilippo 3 | # Released under the BSD license like Redis itself 4 | # 5 | # Example usage: 6 | # 7 | # set r [redis 127.0.0.1 6379] 8 | # $r lpush mylist foo 9 | # $r lpush mylist bar 10 | # $r lrange mylist 0 -1 11 | # $r close 12 | 13 | package provide redis 0.1 14 | 15 | namespace eval redis {} 16 | set ::redis::id 0 17 | array set ::redis::fd {} 18 | array set ::redis::bulkarg {} 19 | 20 | # Flag commands requiring last argument as a bulk write operation 21 | foreach redis_bulk_cmd { 22 | set setnx rpush lpush lset lrem sadd srem sismember echo getset smove 23 | } { 24 | set ::redis::bulkarg($redis_bulk_cmd) {} 25 | } 26 | unset redis_bulk_cmd 27 | 28 | proc redis {{server 127.0.0.1} {port 6379}} { 29 | set fd [socket $server $port] 30 | fconfigure $fd -translation binary 31 | set id [incr ::redis::id] 32 | set ::redis::fd($id) $fd 33 | interp alias {} ::redis::redisHandle$id {} ::redis::__dispatch__ $id 34 | } 35 | 36 | proc ::redis::__dispatch__ {id method args} { 37 | set fd $::redis::fd($id) 38 | if {[info command ::redis::__method__$method] eq {}} { 39 | set cmd "$method " 40 | if {[info exists ::redis::bulkarg($method)]} { 41 | append cmd [join [lrange $args 0 end-1]] 42 | append cmd " [string length [lindex $args end]]\r\n" 43 | append cmd [lindex $args end] 44 | } else { 45 | append cmd [join $args] 46 | } 47 | ::redis::redis_writenl $fd $cmd 48 | ::redis::redis_read_reply $fd 49 | } else { 50 | uplevel 1 [list ::redis::__method__$method $id $fd] $args 51 | } 52 | } 53 | 54 | proc ::redis::__method__close {id fd} { 55 | catch {close $fd} 56 | catch {unset ::redis::fd($id)} 57 | catch {interp alias {} ::redis::redisHandle$id {}} 58 | } 59 | 60 | proc ::redis::__method__channel {id fd} { 61 | return $fd 62 | } 63 | 64 | proc ::redis::redis_write {fd buf} { 65 | puts -nonewline $fd $buf 66 | } 67 | 68 | proc ::redis::redis_writenl {fd buf} { 69 | redis_write $fd $buf 70 | redis_write $fd "\r\n" 71 | flush $fd 72 | } 73 | 74 | proc ::redis::redis_readnl {fd len} { 75 | set buf [read $fd $len] 76 | read $fd 2 ; # discard CR LF 77 | return $buf 78 | } 79 | 80 | proc ::redis::redis_bulk_read {fd} { 81 | set count [redis_read_line $fd] 82 | if {$count == -1} return {} 83 | set buf [redis_readnl $fd $count] 84 | return $buf 85 | } 86 | 87 | proc ::redis::redis_multi_bulk_read fd { 88 | set count [redis_read_line $fd] 89 | if {$count == -1} return {} 90 | set l {} 91 | for {set i 0} {$i < $count} {incr i} { 92 | lappend l [redis_read_reply $fd] 93 | } 94 | return $l 95 | } 96 | 97 | proc ::redis::redis_read_line fd { 98 | string trim [gets $fd] 99 | } 100 | 101 | proc ::redis::redis_read_reply fd { 102 | set type [read $fd 1] 103 | switch -exact -- $type { 104 | : - 105 | + {redis_read_line $fd} 106 | - {return -code error [redis_read_line $fd]} 107 | $ {redis_bulk_read $fd} 108 | * {redis_multi_bulk_read $fd} 109 | default {return -code error "Bad protocol, $type as reply type byte"} 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /client-libraries/scala/src/test/scala/com/redis/operations/OperationsSpec.scala: -------------------------------------------------------------------------------- 1 | import org.specs._ 2 | import com.redis._ 3 | 4 | import org.specs.mock.Mockito 5 | import org.mockito.Mock._ 6 | import org.mockito.Mockito._ 7 | 8 | object OperationsSpec extends Specification with Mockito { 9 | 10 | "Redis Client Operations" should { 11 | 12 | var client: RedisTestClient = null 13 | var connection: Connection = null 14 | 15 | doBefore{ 16 | connection = mock[Connection] 17 | client = new RedisTestClient(connection) 18 | } 19 | 20 | "set a key" in { 21 | connection.readBoolean returns true 22 | client.set("a", "b") mustEqual true 23 | connection.write("SET a 1\r\nb\r\n") was called 24 | } 25 | 26 | "set a key with setKey" in { 27 | connection.readBoolean returns true 28 | client.setKey("a", "b") mustEqual true 29 | connection.write("SET a 1\r\nb\r\n") was called 30 | } 31 | 32 | "set a key with expiration" in { 33 | connection.readBoolean returns true 34 | client.set("a", "b", 4) mustEqual true 35 | connection.write("SET a 1\r\nb\r\n") was called 36 | connection.write("EXPIRE a 4\r\n") was called 37 | } 38 | 39 | "expire a key" in { 40 | connection.readBoolean returns true 41 | client.expire("a", 4) mustEqual true 42 | connection.write("EXPIRE a 4\r\n") was called 43 | } 44 | 45 | "get a key" in { 46 | connection.readResponse returns "b" 47 | client.get("a") mustEqual "b" 48 | connection.write("GET a\r\n") was called 49 | } 50 | 51 | "get and set a key" in { 52 | connection.readResponse returns "old" 53 | client.getSet("a", "new") mustEqual "old" 54 | connection.write("GETSET a 3\r\nnew\r\n") was called 55 | } 56 | 57 | "delete a key" in { 58 | connection.readBoolean returns true 59 | client.delete("a") mustEqual true 60 | connection.write("DEL a\r\n") was called 61 | } 62 | 63 | "tell if a key exists" in { 64 | connection.readBoolean returns true 65 | client.exists("a") mustEqual true 66 | connection.write("EXISTS a\r\n") was called 67 | } 68 | 69 | "tell if a key exists" in { 70 | connection.readBoolean returns true 71 | client.exists("a") mustEqual true 72 | connection.write("EXISTS a\r\n") was called 73 | } 74 | 75 | "increment a value" in { 76 | connection.readInt returns 1 77 | client.incr("a") mustEqual 1 78 | connection.write("INCR a\r\n") was called 79 | } 80 | 81 | "increment a value by N" in { 82 | connection.readInt returns 27 83 | client.incr("a", 23) mustEqual 27 84 | connection.write("INCRBY a 23\r\n") was called 85 | } 86 | 87 | "decrement a value" in { 88 | connection.readInt returns 0 89 | client.decr("a") mustEqual 0 90 | connection.write("DECR a\r\n") was called 91 | } 92 | 93 | "decrement a value by N" in { 94 | connection.readInt returns 25 95 | client.decr("a", 2) mustEqual 25 96 | connection.write("DECRBY a 2\r\n") was called 97 | } 98 | 99 | "return type of key" in { 100 | connection.readResponse returns "String" 101 | client.getType("a") mustEqual "String" 102 | connection.write("TYPE a\r\n") was called 103 | } 104 | } 105 | } 106 | --------------------------------------------------------------------------------