From 1259672feb4fcad189d413a341745990a844feda Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 3 Nov 2009 11:25:32 +0100 Subject: [PATCH] client libs removed from Redis git --- client-libraries/README | 38 - client-libraries/clojure/.gitignore | 5 - client-libraries/clojure/LICENSE | 22 - client-libraries/clojure/README.markdown | 49 - .../clojure/benchmarks/clojure.clj | 179 --- client-libraries/clojure/benchmarks/ruby.clj | 25 - client-libraries/clojure/build.xml | 91 -- client-libraries/clojure/examples/demo.clj | 33 - client-libraries/clojure/src/redis.clj | 129 -- .../clojure/src/redis/internal.clj | 263 ----- client-libraries/clojure/src/redis/tests.clj | 397 ------- .../clojure/src/redis/tests/internal.clj | 151 --- client-libraries/cpp/Makefile | 44 - client-libraries/cpp/README.rst | 16 - client-libraries/cpp/TODO | 22 - client-libraries/cpp/anet.c | 270 ----- client-libraries/cpp/anet.h | 49 - client-libraries/cpp/fmacros.h | 7 - client-libraries/cpp/redisclient.cpp | 894 -------------- client-libraries/cpp/redisclient.h | 488 -------- client-libraries/cpp/test_client.cpp | 629 ---------- client-libraries/erlang/.hg_archival.txt | 2 - client-libraries/erlang/.hgignore | 2 - client-libraries/erlang/LICENSE | 22 - client-libraries/erlang/Makefile | 29 - client-libraries/erlang/include/erldis.hrl | 1 - client-libraries/erlang/src/Makefile | 9 - client-libraries/erlang/src/client.erl | 250 ---- client-libraries/erlang/src/erldis.erl | 112 -- client-libraries/erlang/src/proto.erl | 38 - client-libraries/erlang/support/include.mk | 51 - client-libraries/erlang/test/Makefile | 12 - client-libraries/erlang/test/erldis_tests.erl | 91 -- client-libraries/erlang/test/proto_tests.erl | 10 - client-libraries/lua/LICENSE | 22 - client-libraries/lua/README | 4 - client-libraries/lua/redis.lua | 347 ------ client-libraries/perl/Changes | 8 - client-libraries/perl/MANIFEST | 8 - client-libraries/perl/Makefile.PL | 19 - client-libraries/perl/README | 43 - client-libraries/perl/lib/Redis.pm | 422 ------- client-libraries/perl/lib/Redis/Hash.pm | 70 -- client-libraries/perl/lib/Redis/List.pm | 85 -- .../perl/scripts/redis-benchmark.pl | 24 - client-libraries/perl/t/00-load.t | 9 - client-libraries/perl/t/01-Redis.t | 189 --- client-libraries/perl/t/10-Redis-List.t | 30 - client-libraries/perl/t/20-Redis-Hash.t | 30 - client-libraries/perl/t/pod-coverage.t | 18 - client-libraries/perl/t/pod.t | 12 - client-libraries/php/redis.php | 374 ------ client-libraries/php/tests.php | 87 -- client-libraries/python/redis.py | 1051 ----------------- client-libraries/ruby/.gitignore | 6 - client-libraries/ruby/LICENSE | 20 - client-libraries/ruby/README.markdown | 34 - client-libraries/ruby/Rakefile | 62 - client-libraries/ruby/bench.rb | 44 - client-libraries/ruby/benchmarking/suite.rb | 24 - client-libraries/ruby/benchmarking/worker.rb | 71 -- client-libraries/ruby/bin/distredis | 33 - client-libraries/ruby/examples/basic.rb | 16 - client-libraries/ruby/examples/incr-decr.rb | 18 - client-libraries/ruby/examples/list.rb | 26 - client-libraries/ruby/examples/sets.rb | 36 - client-libraries/ruby/lib/dist_redis.rb | 124 -- client-libraries/ruby/lib/hash_ring.rb | 128 -- client-libraries/ruby/lib/pipeline.rb | 22 - client-libraries/ruby/lib/redis.rb | 316 ----- client-libraries/ruby/profile.rb | 22 - client-libraries/ruby/redis-rb.gemspec | 30 - client-libraries/ruby/spec/redis_spec.rb | 478 -------- client-libraries/ruby/spec/spec_helper.rb | 4 - client-libraries/ruby/speed.rb | 16 - client-libraries/ruby/tasks/redis.tasks.rb | 125 -- client-libraries/scala/.gitignore | 6 - client-libraries/scala/README.md | 46 - .../scala/project/build.properties | 8 - .../project/build/RedisClientProject.scala | 12 - .../src/main/scala/com/redis/Connection.scala | 8 - .../src/main/scala/com/redis/HashRing.scala | 66 -- .../redis/Operations/KeySpaceOperations.scala | 47 - .../com/redis/Operations/ListOperations.scala | 94 -- .../com/redis/Operations/NodeOperations.scala | 121 -- .../com/redis/Operations/Operations.scala | 124 -- .../com/redis/Operations/SetOperations.scala | 115 -- .../com/redis/Operations/SortOperations.scala | 28 - .../main/scala/com/redis/RedisClient.scala | 33 - .../main/scala/com/redis/RedisCluster.scala | 42 - .../scala/com/redis/SocketOperations.scala | 167 --- .../scala/com/redis/RedisClientSpec.scala | 27 - .../scala/com/redis/RedisClusterSpec.scala | 51 - .../com/redis/SocketOperationsSpec.scala | 97 -- .../redis/helpers/RedisClientTestHelper.scala | 13 - .../operations/KeySpaceOperationsSpec.scala | 50 - .../redis/operations/ListOperationsSpec.scala | 81 -- .../redis/operations/NodeOperationsSpec.scala | 113 -- .../com/redis/operations/OperationsSpec.scala | 105 -- .../redis/operations/SetOperationsSpec.scala | 102 -- .../redis/operations/SortOperationsSpec.scala | 34 - client-libraries/tcl/redis.tcl | 131 -- client-libraries/update-clojure-client.sh | 12 - client-libraries/update-cpp-client.sh | 12 - client-libraries/update-erlang-client.sh | 2 - client-libraries/update-lua-client.sh | 12 - client-libraries/update-perl-client.sh | 10 - client-libraries/update-python-client.sh | 9 - client-libraries/update-ruby-client.sh | 13 - client-libraries/update-scala-client.sh | 12 - 110 files changed, 10740 deletions(-) delete mode 100644 client-libraries/README delete mode 100644 client-libraries/clojure/.gitignore delete mode 100644 client-libraries/clojure/LICENSE delete mode 100644 client-libraries/clojure/README.markdown delete mode 100644 client-libraries/clojure/benchmarks/clojure.clj delete mode 100644 client-libraries/clojure/benchmarks/ruby.clj delete mode 100644 client-libraries/clojure/build.xml delete mode 100644 client-libraries/clojure/examples/demo.clj delete mode 100644 client-libraries/clojure/src/redis.clj delete mode 100644 client-libraries/clojure/src/redis/internal.clj delete mode 100644 client-libraries/clojure/src/redis/tests.clj delete mode 100644 client-libraries/clojure/src/redis/tests/internal.clj delete mode 100644 client-libraries/cpp/Makefile delete mode 100644 client-libraries/cpp/README.rst delete mode 100644 client-libraries/cpp/TODO delete mode 100644 client-libraries/cpp/anet.c delete mode 100644 client-libraries/cpp/anet.h delete mode 100644 client-libraries/cpp/fmacros.h delete mode 100644 client-libraries/cpp/redisclient.cpp delete mode 100644 client-libraries/cpp/redisclient.h delete mode 100644 client-libraries/cpp/test_client.cpp delete mode 100644 client-libraries/erlang/.hg_archival.txt delete mode 100644 client-libraries/erlang/.hgignore delete mode 100644 client-libraries/erlang/LICENSE delete mode 100644 client-libraries/erlang/Makefile delete mode 100644 client-libraries/erlang/include/erldis.hrl delete mode 100644 client-libraries/erlang/src/Makefile delete mode 100644 client-libraries/erlang/src/client.erl delete mode 100644 client-libraries/erlang/src/erldis.erl delete mode 100644 client-libraries/erlang/src/proto.erl delete mode 100644 client-libraries/erlang/support/include.mk delete mode 100644 client-libraries/erlang/test/Makefile delete mode 100644 client-libraries/erlang/test/erldis_tests.erl delete mode 100644 client-libraries/erlang/test/proto_tests.erl delete mode 100644 client-libraries/lua/LICENSE delete mode 100644 client-libraries/lua/README delete mode 100644 client-libraries/lua/redis.lua delete mode 100644 client-libraries/perl/Changes delete mode 100644 client-libraries/perl/MANIFEST delete mode 100644 client-libraries/perl/Makefile.PL delete mode 100644 client-libraries/perl/README delete mode 100644 client-libraries/perl/lib/Redis.pm delete mode 100644 client-libraries/perl/lib/Redis/Hash.pm delete mode 100644 client-libraries/perl/lib/Redis/List.pm delete mode 100755 client-libraries/perl/scripts/redis-benchmark.pl delete mode 100644 client-libraries/perl/t/00-load.t delete mode 100755 client-libraries/perl/t/01-Redis.t delete mode 100755 client-libraries/perl/t/10-Redis-List.t delete mode 100755 client-libraries/perl/t/20-Redis-Hash.t delete mode 100644 client-libraries/perl/t/pod-coverage.t delete mode 100644 client-libraries/perl/t/pod.t delete mode 100644 client-libraries/php/redis.php delete mode 100644 client-libraries/php/tests.php delete mode 100644 client-libraries/python/redis.py delete mode 100644 client-libraries/ruby/.gitignore delete mode 100644 client-libraries/ruby/LICENSE delete mode 100644 client-libraries/ruby/README.markdown delete mode 100644 client-libraries/ruby/Rakefile delete mode 100644 client-libraries/ruby/bench.rb delete mode 100644 client-libraries/ruby/benchmarking/suite.rb delete mode 100644 client-libraries/ruby/benchmarking/worker.rb delete mode 100755 client-libraries/ruby/bin/distredis delete mode 100644 client-libraries/ruby/examples/basic.rb delete mode 100644 client-libraries/ruby/examples/incr-decr.rb delete mode 100644 client-libraries/ruby/examples/list.rb delete mode 100644 client-libraries/ruby/examples/sets.rb delete mode 100644 client-libraries/ruby/lib/dist_redis.rb delete mode 100644 client-libraries/ruby/lib/hash_ring.rb delete mode 100644 client-libraries/ruby/lib/pipeline.rb delete mode 100644 client-libraries/ruby/lib/redis.rb delete mode 100644 client-libraries/ruby/profile.rb delete mode 100644 client-libraries/ruby/redis-rb.gemspec delete mode 100644 client-libraries/ruby/spec/redis_spec.rb delete mode 100644 client-libraries/ruby/spec/spec_helper.rb delete mode 100644 client-libraries/ruby/speed.rb delete mode 100644 client-libraries/ruby/tasks/redis.tasks.rb delete mode 100644 client-libraries/scala/.gitignore delete mode 100644 client-libraries/scala/README.md delete mode 100644 client-libraries/scala/project/build.properties delete mode 100644 client-libraries/scala/project/build/RedisClientProject.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/Connection.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/HashRing.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/Operations/KeySpaceOperations.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/Operations/ListOperations.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/Operations/NodeOperations.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/Operations/Operations.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/Operations/SetOperations.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/Operations/SortOperations.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/RedisClient.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/RedisCluster.scala delete mode 100644 client-libraries/scala/src/main/scala/com/redis/SocketOperations.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/RedisClientSpec.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/RedisClusterSpec.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/SocketOperationsSpec.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/helpers/RedisClientTestHelper.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/operations/KeySpaceOperationsSpec.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/operations/ListOperationsSpec.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/operations/NodeOperationsSpec.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/operations/OperationsSpec.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/operations/SetOperationsSpec.scala delete mode 100644 client-libraries/scala/src/test/scala/com/redis/operations/SortOperationsSpec.scala delete mode 100644 client-libraries/tcl/redis.tcl delete mode 100755 client-libraries/update-clojure-client.sh delete mode 100755 client-libraries/update-cpp-client.sh delete mode 100755 client-libraries/update-erlang-client.sh delete mode 100755 client-libraries/update-lua-client.sh delete mode 100755 client-libraries/update-perl-client.sh delete mode 100755 client-libraries/update-python-client.sh delete mode 100755 client-libraries/update-ruby-client.sh delete mode 100755 client-libraries/update-scala-client.sh diff --git a/client-libraries/README b/client-libraries/README deleted file mode 100644 index 109e51bd..00000000 --- a/client-libraries/README +++ /dev/null @@ -1,38 +0,0 @@ -Redis client libraries ----------------------- - -In this directory you'll find client libraries for different languages. -This are the latest releases available at the time this Redis tar.gz for this -release was created, and are good for most uses, but if you need more fresh -code or recent bugfixes read more. - -How to get the lastest versions of client libraries source code ---------------------------------------------------------------- - -Note that while the pure PHP, Tcl, Python and Ruby_2 (Ruby alternative lib) -libraries are the most uptodate available libraries, all the other libraries -have their own repositories where it's possible to grab the most recent version: - -Ruby lib source code: -http://github.com/ezmobius/redis-rb/tree/master -git://github.com/ezmobius/redis-rb.git - -Erlang lib source code: -http://bitbucket.org/adroll/erldis/ - -Perl lib source code: -(web) http://svn.rot13.org/index.cgi/Redis -(svn) svn://svn.rot13.org/Redis/ - -Redis-php PHP C module: -http://code.google.com/p/phpredis/ - -Lua lib source code: -http://github.com/nrk/redis-lua/tree/master -git://github.com/nrk/redis-lua.git - -Clojure lib source code: -http://github.com/ragnard/redis-clojure/ -git://github.com/ragnard/redis-clojure.git - -For all the rest check the Redis tarball or Git repository. diff --git a/client-libraries/clojure/.gitignore b/client-libraries/clojure/.gitignore deleted file mode 100644 index 3c5a6529..00000000 --- a/client-libraries/clojure/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -classes -\#* -.\#* -*.jar -build.properties \ No newline at end of file diff --git a/client-libraries/clojure/LICENSE b/client-libraries/clojure/LICENSE deleted file mode 100644 index b71e93cd..00000000 --- a/client-libraries/clojure/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2009 Ragnar Dahlén (r.dahlen@gmail.com) - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/client-libraries/clojure/README.markdown b/client-libraries/clojure/README.markdown deleted file mode 100644 index 5b428c9a..00000000 --- a/client-libraries/clojure/README.markdown +++ /dev/null @@ -1,49 +0,0 @@ -# redis-clojure - -A Clojure client library for the -[Redis](http://code.google.com/p/redis) key value storage system. - -## Dependencies - -To use redis-clojure, you'll need: - -* The [Clojure](http://clojure.org) programming language -* The [Clojure-Contrib](http://code.google.com/p/clojure-contrib) library (for running the tests) - -## Building - -To build redis-clojure: - - ant -Dclojure.jar=/path/to/clojure.jar - -This will build `redis-clojure.jar`. - -## Running tests - -To run tests: - - ant -Dclojure.jar=/path/to/clojure.jar -Dclojure-contrib.jar=/path/to/clojure-contrib.jar test - -*Note* you need to have `redis-server` running first. - -## Using - -To use redis-clojure in your application, simply make sure either -`redis-clojure.jar` or the contents of the `src/` directory is on your -classpath. - -This can be accomplished like so: - - (add-classpath "file:///path/to/redis-clojure.jar") - -## Examples - -Check the `examples/` directory. - -*Note* you need to have `redis-server` running first. - -## Todo - -* Work on performance -* Maybe implement pipelining - diff --git a/client-libraries/clojure/benchmarks/clojure.clj b/client-libraries/clojure/benchmarks/clojure.clj deleted file mode 100644 index 13739f04..00000000 --- a/client-libraries/clojure/benchmarks/clojure.clj +++ /dev/null @@ -1,179 +0,0 @@ - - -(add-classpath "file:///Users/ragge/Projects/clojure/redis-clojure/redis-clojure.jar") - -(ns benchmarks.clojure - (:use clojure.contrib.pprint) - (:require redis)) - -(defstruct benchmark-options - :host - :port - :db - :clients - :requests - :key-size - :keyspace-size - :data-size) - - -(defstruct client - :id - :request-times - :requests-performed - :requests-per-second) - -(defstruct result - :options - :clients - :total-time - :requests) - - -(defmacro defbenchmark [name & body] - (let [benchmark-name (symbol (str name "-benchmark"))] - `(def ~(with-meta benchmark-name {:benchmark true}) - (fn ~benchmark-name - [client# options# result#] - (redis/with-server - {:host (options# :host) - :port (options# :port) - :db (options# :db)} - (let [requests# (:requests options#) - requests-done# (:requests result#)] - (loop [requests-performed# 0 request-times# []] - (if (>= @requests-done# requests#) - (assoc client# - :request-times request-times# - :requests-performed requests-performed#) - (do - (let [start# (System/nanoTime)] - ~@body - (let [end# (System/nanoTime) - elapsed# (/ (float (- end# start#)) 1000000.0)] - (dosync - (commute requests-done# inc)) - (recur (inc requests-performed#) - (conj request-times# elapsed#))))))))))))) - -(defbenchmark ping - (redis/ping)) - -(defbenchmark get - (redis/get (str "key-" (rand-int 1000)))) - -(defbenchmark set - (redis/set (str "key-" (rand-int 1000)) "abc")) - -(defbenchmark exists-set-and-get - (let [key (str "key-" (rand-int 100))] - (redis/exists key) - (redis/set key "blahongaa!") - (redis/get key))) - - -(def *default-options* (struct-map benchmark-options - :host "127.0.0.1" - :port 6379 - :db 15 - :clients 1 - :requests 10000)) - -(defn create-clients [options] - (for [id (range (:clients options))] - (agent (struct client id)))) - -(defn create-result [options clients] - (let [result (struct result options clients 0 (ref 0))] - result)) - - -(defn requests-by-ms [clients] - (let [all-times (apply concat (map #(:request-times (deref %)) clients)) - all-times-in-ms (map #(int (/ % 1)) all-times)] - (sort - (reduce - (fn [m time] - (if (m time) - (assoc m time (inc (m time))) - (assoc m time 1))) - {} all-times-in-ms)))) - -(defn report-request-times [clients requests] - (let [requests-dist (map #(let [perc (* 100 (/ (last %) requests))] - (conj % perc)) (requests-by-ms clients))] - (loop [items requests-dist - seen 0] - (if-not (empty? items) - (do - (let [item (first items) - seen (+ seen (last item))] - (println (format "%.2f%% < %d ms" (float seen) (inc (first item)))) - (recur (rest items) seen))))))) - -(defn report-client-rps [client] - (let [{:keys [id requests-performed request-times]} @client] - (when (< 0 requests-performed) - (let [total-time (apply + request-times) - requests-per-second (/ (float requests-performed) - total-time)] - (println total-time) - (println (format "Client %d: %f rps" id (float requests-per-second))))))) - -(defn report-result [result] - (let [{:keys [clients options]} result - name (:name result) - time (:total-time result) - time-in-seconds (/ time 1000) - requests (deref (:requests result)) - requests-per-second (/ requests time-in-seconds) - ] - (do - (println (format "====== %s =====\n" name)) - (println (format " %d requests completed in %f seconds\n" requests time-in-seconds)) - (println (format " %d parallel clients\n" (:clients options))) - (report-request-times clients requests) - ;(dorun (map report-client-rps clients)) - (println (format "%f requests per second\n\n" requests-per-second)) - ) - ) - ) - - - -(defn run-benchmark [fn options] - (let [clients (create-clients options) - result (create-result options clients) - start (System/nanoTime)] - (dorun - (map #(send-off % fn options result) clients)) - (apply await clients) - (let [elapsed (/ (double (- (System/nanoTime) start)) 1000000.0)] - (dorun - (map #(when (agent-errors %) - (pprint (agent-errors %))) clients)) - (assoc result - :name (str fn) - :options options - :clients clients - :total-time elapsed)))) - -(defn find-all-benchmarks [ns] - (filter #(:benchmark (meta %)) - (vals (ns-map ns)))) - -(defn run-and-report [fn options] - (let [result (run-benchmark fn options)] - (report-result result))) - -(defn run-all-benchmarks [ns] - (let [benchmarks (find-all-benchmarks ns)] - (dorun - (map #(run-and-report % *default-options*) benchmarks)))) - - -;(run-all-benchmarks) - -;(report-result (run-benchmark ping-benchmark *default-options*)) -;(run-benchmark get-benchmark *default-options*) - diff --git a/client-libraries/clojure/benchmarks/ruby.clj b/client-libraries/clojure/benchmarks/ruby.clj deleted file mode 100644 index c73c1a53..00000000 --- a/client-libraries/clojure/benchmarks/ruby.clj +++ /dev/null @@ -1,25 +0,0 @@ -(ns benchmarks.ruby - (:require redis)) - -(dotimes [n 4] - (redis/with-server - {:db 15} - (redis/set "foo" "The first line we sent to the server is some text") - (time - (dotimes [i 20000] - (let [key (str "key" i)] - (redis/set key "The first line we sent to the server is some text") - (redis/get "foo")))))) - - -;(redis/with-server -; {} -; (redis/set "foo" "The first line we sent to the server is some text") -; (time -; (dotimes [i 20000] -; (let [key (str "push_trim" i)] -; (redis/lpush key i) -; (redis/ltrim key 0 30))))) - - - diff --git a/client-libraries/clojure/build.xml b/client-libraries/clojure/build.xml deleted file mode 100644 index d25eba38..00000000 --- a/client-libraries/clojure/build.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - Redis client library for Clojure. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client-libraries/clojure/examples/demo.clj b/client-libraries/clojure/examples/demo.clj deleted file mode 100644 index d441e975..00000000 --- a/client-libraries/clojure/examples/demo.clj +++ /dev/null @@ -1,33 +0,0 @@ -;; -;; Simple demo of redis-clojure functionality -;; -;; Make sure redis-clojure.jar or the contents of the src/ directory -;; is on the classpath. -;; -;; Either: -;; (add-classpath "file:///path/to/redis-clojure.jar" -;; or: -;; (add-classpath "file:///path/to/redis/src-dir/") -;; - -(add-classpath "file:///Users/ragge/Projects/clojure/redis-clojure/redis-clojure.jar") - -(ns demo - (:require redis)) - - -(redis/with-server - {:host "127.0.0.1" :port 6379 :db 0} - (do - (println "Sending ping") - (println "Reply:" (redis/ping)) - (println "Server info:") - (let [info (redis/info)] - (dorun - (map (fn [entry] - (println (str "- "(first entry) ": " (last entry)))) info))) - (println "Setting key 'foo' to 'bar'") - (println "Reply:" (redis/set "foo" "bar")) - (println "Getting value of key 'foo'") - (println "Reply:" (redis/get "foo")))) - diff --git a/client-libraries/clojure/src/redis.clj b/client-libraries/clojure/src/redis.clj deleted file mode 100644 index cb5a4fae..00000000 --- a/client-libraries/clojure/src/redis.clj +++ /dev/null @@ -1,129 +0,0 @@ -;(add-classpath "file:///Users/ragge/Projects/clojure/redis-clojure/src/") - -(ns redis - (:refer-clojure :exclude [get set type keys sort]) - (:use redis.internal)) - -;(set! *warn-on-reflection* true) - -(defmacro with-server - "Evaluates body in the context of a new connection to a Redis server - then closes the connection. - - server-spec is a map with any of the following keys: - :host hostname (default \"127.0.0.1\") - :port port (default 6379) - :db database to use (default 0)" - [server-spec & body] - `(with-server* ~server-spec (fn [] - (do - (redis/select (:db *server*)) - ~@body)))) - - -;; -;; Reply conversion functions -;; -(defn int-to-bool - "Convert integer reply to a boolean value" - [int] - (= 1 int)) - -(defn string-to-keyword - "Convert a string reply to a keyword" - [string] - (keyword string)) - -(defn string-to-seq - "Convert a space separated string to a sequence of words" - [#^String string] - (if (empty? string) - nil - (re-seq #"\S+" string))) - -(defn string-to-map - "Convert strings with format 'key:value\r\n'+ to a map with {key - value} pairs" - [#^String string] - (let [lines (.split string "(\\r\\n|:)")] - (apply hash-map lines))) - -(defn int-to-date - "Return a Date representation of a UNIX timestamp" - [int] - (new java.util.Date (long int))) - -(defn seq-to-set - [sequence] - (clojure.core/set sequence)) - -;; -;; Commands -;; -(defcommands - ;; Connection handling - (auth [] :inline) - (quit [password] :inline) - (ping [] :inline) - ;; String commands - (set [key value] :bulk) - (get [key] :inline) - (getset [key value] :bulk) - (setnx [key value] :bulk int-to-bool) - (incr [key] :inline) - (incrby [key integer] :inline) - (decr [key] :inline) - (decrby [key integer] :inline) - (exists [key] :inline int-to-bool) - (mget [key & keys] :inline) - (del [key] :inline int-to-bool) - ;; Key space commands - (type [key] :inline string-to-keyword) - (keys [pattern] :inline string-to-seq) - (randomkey [] :inline) - (rename [oldkey newkey] :inline) - (renamenx [oldkey newkey] :inline int-to-bool) - (dbsize [] :inline) - (expire [key seconds] :inline int-to-bool) - (ttl [key] :inline) - ;; List commands - (rpush [key value] :bulk) - (lpush [key value] :bulk) - (llen [key] :inline) - (lrange [key start end] :inline) - (ltrim [key start end] :inline) - (lindex [key index] :inline) - (lset [key index value] :bulk) - (lrem [key count value] :bulk) - (lpop [key] :inline) - (rpop [key] :inline) - ;; Set commands - (sadd [key member] :bulk int-to-bool) - (srem [key member] :bulk int-to-bool) - (spop [key] :inline) - (smove [srckey destkey member] :bulk int-to-bool) - (scard [key] :inline) - (sismember [key member] :bulk int-to-bool) - (sinter [key & keys] :inline seq-to-set) - (sinterstore [destkey key & keys] :inline) - (sunion [key & keys] :inline seq-to-set) - (sunionstore [destkey key & keys] :inline) - (sdiff [key & keys] :inline seq-to-set) - (sdiffstore [destkey key & keys] :inline) - (smembers [key] :inline seq-to-set) - ;; Multiple database handling commands - (select [index] :inline) - (move [key dbindex] :inline) - (flushdb [] :inline) - (flushall [] :inline) - ;; Sorting - (sort [key & options] :sort) - ;; Persistence - (save [] :inline) - (bgsave [] :inline) - (lastsave [] :inline int-to-date) - (shutdown [] :inline) - ;; Remote control - (info [] :inline string-to-map) - ;;(monitor [] :inline)) -) diff --git a/client-libraries/clojure/src/redis/internal.clj b/client-libraries/clojure/src/redis/internal.clj deleted file mode 100644 index d8399bb8..00000000 --- a/client-libraries/clojure/src/redis/internal.clj +++ /dev/null @@ -1,263 +0,0 @@ -(ns redis.internal - (:import [java.io InputStream - OutputStream - Reader - InputStreamReader - BufferedReader] - [java.net Socket])) - - - -(def *cr* 0x0d) -(def *lf* 0x0a) -(defn- cr? [c] (= c *cr*)) -(defn- lf? [c] (= c *lf*)) - -(defn- uppercase [#^String s] (.toUpperCase s)) -(defn- trim [#^String s] (.trim s)) -(defn- parse-int [#^String s] (Integer/parseInt s)) -(defn- char-array [len] (make-array Character/TYPE len)) - -(def *default-host* "127.0.0.1") -(def *default-port* 6379) -(def *default-db* 0) -(def *default-timeout* 5) - - -(defstruct server :host :port :db :timeout :socket) - -(def *server* (struct-map server - :host *default-host* - :port *default-port* - :db *default-db* - :timeout *default-timeout* ;; not yet used - :socket nil)) - -(defn connect-to-server - "Create a Socket connected to server" - [server] - (let [{:keys [host port timeout]} server - socket (Socket. #^String host #^Integer port)] - (doto socket - (.setTcpNoDelay true) - (.setKeepAlive true)))) - -(defn with-server* - [server-spec func] - (let [server (merge *server* server-spec)] - (with-open [#^Socket socket (connect-to-server server)] - (binding [*server* (assoc server :socket socket)] - (func))))) - -(defn socket* [] - (or (:socket *server*) - (throw (Exception. "Not connected to a Redis server")))) - -(defn send-command - "Send a command string to server" - [#^String cmd] - (let [out (.getOutputStream (#^Socket socket*)) - bytes (.getBytes cmd)] - (.write out bytes))) - - -(defn read-crlf - "Read a CR+LF combination from Reader" - [#^Reader reader] - (let [cr (.read reader) - lf (.read reader)] - (when-not - (and (cr? cr) - (lf? lf)) - (throw (Exception. "Error reading CR/LF"))) - nil)) - -(defn read-line-crlf - "Read from reader until exactly a CR+LF combination is - found. Returns the line read without trailing CR+LF. - - This is used instead of Reader.readLine() method since it tries to - read either a CR, a LF or a CR+LF, which we don't want in this - case." - [#^Reader reader] - (loop [line [] - c (.read reader)] - (when (< c 0) - (throw (Exception. "Error reading line: EOF reached before CR/LF sequence"))) - (if (cr? c) - (let [next (.read reader)] - (if (lf? next) - (apply str line) - (throw (Exception. "Error reading line: Missing LF")))) - (recur (conj line (char c)) - (.read reader))))) - -;; -;; Reply dispatching -;; - - - -(defn reply-type - ([#^BufferedReader reader] - (char (.read reader)))) - -(defmulti parse-reply reply-type :default :unknown) - -(defn read-reply - ([] - (let [input-stream (.getInputStream (#^Socket socket*)) - reader (BufferedReader. (InputStreamReader. input-stream))] - (read-reply reader))) - ([#^BufferedReader reader] - (parse-reply reader))) - -(defmethod parse-reply :unknown - [#^BufferedReader reader] - (throw (Exception. (str "Unknown reply type:")))) - -(defmethod parse-reply \- - [#^BufferedReader reader] - (let [error (read-line-crlf reader)] - (throw (Exception. (str "Server error: " error))))) - -(defmethod parse-reply \+ - [#^BufferedReader reader] - (read-line-crlf reader)) - -(defmethod parse-reply \$ - [#^BufferedReader reader] - (let [line (read-line-crlf reader) - length (parse-int line)] - (if (< length 0) - nil - (let [#^chars cbuf (char-array length) - nread (.read reader cbuf 0 length)] - (if (not= nread length) - (throw (Exception. "Could not read correct number of bytes")) - (do - (read-crlf reader) ;; CRLF - (String. cbuf))))))) - -(defmethod parse-reply \* - [#^BufferedReader reader] - (let [line (read-line-crlf reader) - count (parse-int line)] - (if (< count 0) - nil - (loop [i count - replies []] - (if (zero? i) - replies - (recur (dec i) (conj replies (read-reply reader)))))))) - -(defmethod parse-reply \: - [#^BufferedReader reader] - (let [line (trim (read-line-crlf reader)) - int (parse-int line)] - int)) - - - -(defn str-join - "Join elements in sequence with separator" - [separator sequence] - (apply str (interpose separator sequence))) - - -(defn inline-command - "Create a string for an inline command" - [name & args] - (let [cmd (str-join " " (conj args name))] - (str cmd "\r\n"))) - -(defn bulk-command - "Create a string for an bulk command" - [name & args] - (let [data (str (last args)) - data-length (count (str data)) - args* (concat (butlast args) [data-length]) - cmd (apply inline-command name args*)] - (str cmd data "\r\n"))) - - -(defn- sort-command-args-to-string - [args] - (loop [arg-strings [] - args args] - (if (empty? args) - (str-join " " arg-strings) - (let [type (first args) - args (rest args)] - (condp = type - :by (let [pattern (first args)] - (recur (conj arg-strings "BY" pattern) - (rest args))) - :limit (let [start (first args) - end (second args)] - (recur (conj arg-strings "LIMIT" start end) - (drop 2 args))) - :get (let [pattern (first args)] - (recur (conj arg-strings "GET" pattern) - (rest args))) - :alpha (recur (conj arg-strings "ALPHA") args) - :asc (recur (conj arg-strings "ASC") args) - :desc (recur (conj arg-strings "DESC") args) - (throw (Exception. (str "Error parsing SORT arguments: Unknown argument: " type)))))))) - -(defn sort-command - [name & args] - (when-not (= name "SORT") - (throw (Exception. "Sort command name must be 'SORT'"))) - (let [key (first args) - arg-string (sort-command-args-to-string (rest args)) - cmd (str "SORT " key)] - (if (empty? arg-string) - (str cmd "\r\n") - (str cmd " " arg-string "\r\n")))) - - -(def command-fns {:inline 'inline-command - :bulk 'bulk-command - :sort 'sort-command}) - - -(defn parse-params - "Return a restructuring of params, which is of form: - [arg* (& more)?] - into - [(arg1 arg2 ..) more]" - [params] - (let [[args rest] (split-with #(not= % '&) params)] - [args (last rest)])) - -(defmacro defcommand - "Define a function for Redis command name with parameters - params. Type is one of :inline or :bulk, which determines how the - command string is constructued." - ([name params type] `(defcommand ~name ~params ~type (fn [reply#] reply#))) - ([name params type reply-fn] `(~name ~params ~type ~reply-fn) - (do - (let [command (uppercase (str name)) - command-fn (type command-fns) - [command-params - command-params-rest] (parse-params params)] - `(defn ~name - ~params - (let [request# (apply ~command-fn - ~command - ~@command-params - ~command-params-rest)] - (send-command request#) - (~reply-fn (read-reply))))) - - ))) - - -(defmacro defcommands - [& command-defs] - `(do ~@(map (fn [command-def] - `(defcommand ~@command-def)) command-defs))) - - - diff --git a/client-libraries/clojure/src/redis/tests.clj b/client-libraries/clojure/src/redis/tests.clj deleted file mode 100644 index 070b45be..00000000 --- a/client-libraries/clojure/src/redis/tests.clj +++ /dev/null @@ -1,397 +0,0 @@ -(ns redis.tests - (:refer-clojure :exclude [get set keys type sort]) - (:require redis) - (:use [clojure.contrib.test-is])) - - -(defn server-fixture [f] - (redis/with-server - {:host "127.0.0.1" - :port 6379 - :db 15} - ;; String value - (redis/set "foo" "bar") - ;; List with three items - (redis/rpush "list" "one") - (redis/rpush "list" "two") - (redis/rpush "list" "three") - ;; Set with three members - (redis/sadd "set" "one") - (redis/sadd "set" "two") - (redis/sadd "set" "three") - (f) - (redis/flushdb))) - -(use-fixtures :each server-fixture) - -(deftest ping - (is (= "PONG" (redis/ping)))) - -(deftest set - (redis/set "bar" "foo") - (is (= "foo" (redis/get "bar"))) - (redis/set "foo" "baz") - (is (= "baz" (redis/get "foo")))) - -(deftest get - (is (= nil (redis/get "bar"))) - (is (= "bar" (redis/get "foo")))) - -(deftest getset - (is (= nil (redis/getset "bar" "foo"))) - (is (= "foo" (redis/get "bar"))) - (is (= "bar" (redis/getset "foo" "baz"))) - (is (= "baz" (redis/get "foo")))) - -(deftest mget - (is (= [nil] (redis/mget "bar"))) - (redis/set "bar" "baz") - (redis/set "baz" "buz") - (is (= ["bar"] (redis/mget "foo"))) - (is (= ["bar" "baz"] (redis/mget "foo" "bar"))) - (is (= ["bar" "baz" "buz"] (redis/mget "foo" "bar" "baz"))) - (is (= ["bar" nil "buz"] (redis/mget "foo" "bra" "baz"))) - ) - -(deftest setnx - (is (= true (redis/setnx "bar" "foo"))) - (is (= "foo" (redis/get "bar"))) - (is (= false (redis/setnx "foo" "baz"))) - (is (= "bar" (redis/get "foo")))) - -(deftest incr - (is (= 1 (redis/incr "nonexistent"))) - (is (= 1 (redis/incr "foo"))) - (is (= 2 (redis/incr "foo")))) - -(deftest incrby - (is (= 42 (redis/incrby "nonexistent" 42))) - (is (= 0 (redis/incrby "foo" 0))) - (is (= 5 (redis/incrby "foo" 5)))) - -(deftest decr - (is (= -1 (redis/decr "nonexistent"))) - (is (= -1 (redis/decr "foo"))) - (is (= -2 (redis/decr "foo")))) - -(deftest decrby - (is (= -42 (redis/decrby "nonexistent" 42))) - (is (= 0 (redis/decrby "foo" 0))) - (is (= -5 (redis/decrby "foo" 5)))) - -(deftest exists - (is (= true (redis/exists "foo"))) - (is (= false (redis/exists "nonexistent")))) - -(deftest del - (is (= false (redis/del "nonexistent"))) - (is (= true (redis/del "foo"))) - (is (= nil (redis/get "foo")))) - -(deftest type - (is (= :none (redis/type "nonexistent"))) - (is (= :string (redis/type "foo"))) - (is (= :list (redis/type "list"))) - (is (= :set (redis/type "set")))) - -(deftest keys - (is (= nil (redis/keys "a*"))) - (is (= ["foo"] (redis/keys "f*"))) - (is (= ["foo"] (redis/keys "f?o"))) - (redis/set "fuu" "baz") - (is (= #{"foo" "fuu"} (clojure.core/set (redis/keys "f*"))))) - -(deftest randomkey - (redis/flushdb) - (redis/set "foo" "bar") - (is (= "foo" (redis/randomkey))) - (redis/flushdb) - (is (= "" (redis/randomkey)))) - -(deftest rename - (is (thrown? Exception (redis/rename "foo" "foo"))) - (is (thrown? Exception (redis/rename "nonexistent" "foo"))) - (redis/rename "foo" "bar") - (is (= "bar" (redis/get "bar"))) - (is (= nil (redis/get "foo"))) - (redis/set "foo" "bar") - (redis/set "bar" "baz") - (redis/rename "foo" "bar") - (is (= "bar" (redis/get "bar"))) - (is (= nil (redis/get "foo"))) - ) - -(deftest renamenx - (is (thrown? Exception (redis/renamenx "foo" "foo"))) - (is (thrown? Exception (redis/renamenx "nonexistent" "foo"))) - (is (= true (redis/renamenx "foo" "bar"))) - (is (= "bar" (redis/get "bar"))) - (is (= nil (redis/get "foo"))) - (redis/set "foo" "bar") - (redis/set "bar" "baz") - (is (= false (redis/renamenx "foo" "bar"))) - ) - -(deftest dbsize - (let [size-before (redis/dbsize)] - (redis/set "anewkey" "value") - (let [size-after (redis/dbsize)] - (is (= size-after - (+ 1 size-before)))))) - -(deftest expire - (is (= true (redis/expire "foo" 1))) - (Thread/sleep 2000) - (is (= false (redis/exists "foo"))) - (redis/set "foo" "bar") - (is (= true (redis/expire "foo" 20))) - (is (= false (redis/expire "foo" 10))) - (is (= false (redis/expire "nonexistent" 42))) - ) - -(deftest ttl - (is (= -1 (redis/ttl "nonexistent"))) - (is (= -1 (redis/ttl "foo"))) - (redis/expire "foo" 42) - (is (< 40 (redis/ttl "foo")))) - - -;; -;; List commands -;; -(deftest rpush - (is (thrown? Exception (redis/rpush "foo"))) - (redis/rpush "newlist" "one") - (is (= 1 (redis/llen "newlist"))) - (is (= "one" (redis/lindex "newlist" 0))) - (redis/del "newlist") - (redis/rpush "list" "item") - (is (= "item" (redis/rpop "list")))) - -(deftest lpush - (is (thrown? Exception (redis/lpush "foo"))) - (redis/lpush "newlist" "item") - (is (= 1 (redis/llen "newlist"))) - (is (= "item" (redis/lindex "newlist" 0))) - (redis/lpush "list" "item") - (is (= "item" (redis/lpop "list")))) - -(deftest llen - (is (thrown? Exception (redis/llen "foo"))) - (is (= 0 (redis/llen "newlist"))) - (is (= 3 (redis/llen "list")))) - -(deftest lrange - (is (thrown? Exception (redis/lrange "foo" 0 1))) - (is (= nil (redis/lrange "newlist" 0 42))) - (is (= ["one"] (redis/lrange "list" 0 0))) - (is (= ["three"] (redis/lrange "list" -1 -1))) - (is (= ["one" "two"] (redis/lrange "list" 0 1))) - (is (= ["one" "two" "three"] (redis/lrange "list" 0 2))) - (is (= ["one" "two" "three"] (redis/lrange "list" 0 42))) - (is (= [] (redis/lrange "list" 42 0))) -) - -;; TBD -(deftest ltrim - (is (thrown? Exception (redis/ltrim "foo" 0 0)))) - -(deftest lindex - (is (thrown? Exception (redis/lindex "foo" 0))) - (is (= nil (redis/lindex "list" 42))) - (is (= nil (redis/lindex "list" -4))) - (is (= "one" (redis/lindex "list" 0))) - (is (= "three" (redis/lindex "list" 2))) - (is (= "three" (redis/lindex "list" -1)))) - -(deftest lset - (is (thrown? Exception (redis/lset "foo" 0 "bar"))) - (is (thrown? Exception (redis/lset "list" 42 "value"))) - (redis/lset "list" 0 "test") - (is (= "test" (redis/lindex "list" 0))) - (redis/lset "list" 2 "test2") - (is (= "test2" (redis/lindex "list" 2))) - (redis/lset "list" -1 "test3") - (is (= "test3" (redis/lindex "list" 2)))) - -(deftest lrem - (is (thrown? Exception (redis/lrem "foo" 0 "bar"))) - (is (= 0 (redis/lrem "newlist" 0 ""))) - (is (= 1 (redis/lrem "list" 1 "two"))) - (is (= 1 (redis/lrem "list" 42 "three"))) - (is (= 1 (redis/llen "list")))) - - -(deftest lpop - (is (thrown? Exception (redis/lpop "foo"))) - (is (= nil (redis/lpop "newlist"))) - (is (= "one" (redis/lpop "list"))) - (is (= 2 (redis/llen "list")))) - -(deftest rpop - (is (thrown? Exception (redis/rpop "foo"))) - (is (= nil (redis/rpop "newlist"))) - (is (= "three" (redis/rpop "list"))) - (is (= 2 (redis/llen "list")))) - -;; -;; Set commands -;; -(deftest sadd - (is (thrown? Exception (redis/sadd "foo" "bar"))) - (is (= true (redis/sadd "newset" "member"))) - (is (= true (redis/sismember "newset" "member"))) - (is (= false (redis/sadd "set" "two"))) - (is (= true (redis/sadd "set" "four"))) - (is (= true (redis/sismember "set" "four")))) - -(deftest srem - (is (thrown? Exception (redis/srem "foo" "bar"))) - (is (= false (redis/srem "newset" "member"))) - (is (= true (redis/srem "set" "two"))) - (is (= false (redis/sismember "set" "two"))) - (is (= false (redis/srem "set" "blahonga")))) - -(deftest spop - (is (thrown? Exception (redis/spop "foo" "bar"))) - (is (= nil (redis/spop "newset"))) - (is (contains? #{"one" "two" "three"} (redis/spop "set")))) - -(deftest smove - (is (thrown? Exception (redis/smove "foo" "set" "one"))) - (is (thrown? Exception (redis/smove "set" "foo" "one"))) - (redis/sadd "set1" "two") - (is (= false (redis/smove "set" "set1" "four"))) - (is (= #{"two"} (redis/smembers "set1"))) - (is (= true (redis/smove "set" "set1" "one"))) - (is (= #{"one" "two"} (redis/smembers "set1")))) - -(deftest scard - (is (thrown? Exception (redis/scard "foo"))) - (is (= 3 (redis/scard "set")))) - -(deftest sismember - (is (thrown? Exception (redis/sismember "foo" "bar"))) - (is (= false (redis/sismember "set" "blahonga"))) - (is (= true (redis/sismember "set" "two")))) - -(deftest sinter - (is (thrown? Exception (redis/sinter "foo" "set"))) - (is (= #{} (redis/sinter "nonexistent"))) - (redis/sadd "set1" "one") - (redis/sadd "set1" "four") - (is (= #{"one" "two" "three"} (redis/sinter "set"))) - (is (= #{"one"} (redis/sinter "set" "set1"))) - (is (= #{} (redis/sinter "set" "set1" "nonexistent")))) - -(deftest sinterstore - (redis/sinterstore "foo" "set") - (is (= #{"one" "two" "three"} (redis/smembers "foo"))) - (redis/sadd "set1" "one") - (redis/sadd "set1" "four") - (redis/sinterstore "newset" "set" "set1") - (is (= #{"one"} (redis/smembers "newset")))) - -(deftest sunion - (is (thrown? Exception (redis/sunion "foo" "set"))) - (is (= #{} (redis/sunion "nonexistent"))) - (redis/sadd "set1" "one") - (redis/sadd "set1" "four") - (is (= #{"one" "two" "three"} (redis/sunion "set"))) - (is (= #{"one" "two" "three" "four"} (redis/sunion "set" "set1"))) - (is (= #{"one" "two" "three" "four"} (redis/sunion "set" "set1" "nonexistent")))) - -(deftest sunionstore - (redis/sunionstore "foo" "set") - (is (= #{"one" "two" "three"} (redis/smembers "foo"))) - (redis/sadd "set1" "one") - (redis/sadd "set1" "four") - (redis/sunionstore "newset" "set" "set1") - (is (= #{"one" "two" "three" "four"} (redis/smembers "newset")))) - -(deftest sdiff - (is (thrown? Exception (redis/sdiff "foo" "set"))) - (is (= #{} (redis/sdiff "nonexistent"))) - (redis/sadd "set1" "one") - (redis/sadd "set1" "four") - (is (= #{"one" "two" "three"} (redis/sdiff "set"))) - (is (= #{"two" "three"} (redis/sdiff "set" "set1"))) - (is (= #{"two" "three"} (redis/sdiff "set" "set1" "nonexistent")))) - -(deftest sdiffstore - (redis/sdiffstore "foo" "set") - (is (= #{"one" "two" "three"} (redis/smembers "foo"))) - (redis/sadd "set1" "one") - (redis/sadd "set1" "four") - (redis/sdiffstore "newset" "set" "set1") - (is (= #{"two" "three"} (redis/smembers "newset")))) - -(deftest smembers - (is (thrown? Exception (redis/smembers "foo"))) - (is (= #{"one" "two" "three"} (redis/smembers "set")))) - - -;; -;; Sorting -;; -(deftest sort - (redis/lpush "ids" 1) - (redis/lpush "ids" 4) - (redis/lpush "ids" 2) - (redis/lpush "ids" 3) - (redis/set "object_1" "one") - (redis/set "object_2" "two") - (redis/set "object_3" "three") - (redis/set "object_4" "four") - (redis/set "name_1" "Derek") - (redis/set "name_2" "Charlie") - (redis/set "name_3" "Bob") - (redis/set "name_4" "Alice") - - (is (= ["one" "two" "three"] - (redis/sort "list"))) - (is (= ["one" "three" "two"] - (redis/sort "list" :alpha))) - (is (= ["1" "2" "3" "4"] - (redis/sort "ids"))) - (is (= ["1" "2" "3" "4"] - (redis/sort "ids" :asc))) - (is (= ["4" "3" "2" "1"] - (redis/sort "ids" :desc))) - (is (= ["1" "2"] - (redis/sort "ids" :asc :limit 0 2))) - (is (= ["4" "3"] - (redis/sort "ids" :desc :limit 0 2))) - (is (= ["4" "3" "2" "1"] - (redis/sort "ids" :by "name_*" :alpha))) - (is (= ["one" "two" "three" "four"] - (redis/sort "ids" :get "object_*"))) - (is (= ["one" "two"] - (redis/sort "ids" :by "name_*" :alpha :limit 0 2 :desc :get "object_*")))) - - - -;; -;; Multiple database handling commands -;; -(deftest select - (redis/select 0) - (is (= nil (redis/get "akeythat_probably_doesnotexsistindb0")))) - -(deftest flushdb - (redis/flushdb) - (is (= 0 (redis/dbsize)))) - -;; -;; Persistence commands -;; -(deftest save - (redis/save)) - -(deftest bgsave - (redis/bgsave)) - -(deftest lastsave - (let [ages-ago (new java.util.Date (long 1))] - (is (.before ages-ago (redis/lastsave))))) - diff --git a/client-libraries/clojure/src/redis/tests/internal.clj b/client-libraries/clojure/src/redis/tests/internal.clj deleted file mode 100644 index 9f1422e9..00000000 --- a/client-libraries/clojure/src/redis/tests/internal.clj +++ /dev/null @@ -1,151 +0,0 @@ -(ns redis.tests.internal - (:require [redis.internal :as redis]) - (:use [clojure.contrib.test-is]) - (:import [java.io StringReader BufferedReader])) - - -;; -;; Helpers -;; - -(defn- wrap-in-reader - [#^String s] - (let [reader (BufferedReader. (StringReader. s))] - reader)) - -(defn- read-reply - [#^String s] - (redis/read-reply (wrap-in-reader s))) - - -;; -;; Command generation -;; -(deftest inline-command - (is (= "FOO\r\n" - (redis/inline-command "FOO"))) - (is (= "FOO bar\r\n" - (redis/inline-command "FOO" "bar"))) - (is (= "FOO bar baz\r\n" - (redis/inline-command "FOO" "bar" "baz")))) - -(deftest bulk-command - (is (= "FOO 3\r\nbar\r\n" - (redis/bulk-command "FOO" "bar"))) - (is (= "SET foo 3\r\nbar\r\n" - (redis/bulk-command "SET" "foo" "bar"))) - (is (= "SET foo bar 3\r\nbaz\r\n" - (redis/bulk-command "SET" "foo" "bar" "baz")))) - -(deftest sort-command - (is (= "SORT key\r\n" - (redis/sort-command "SORT" "key"))) - (is (= "SORT key BY pattern\r\n" - (redis/sort-command "SORT" "key" :by "pattern"))) - (is (= "SORT key LIMIT 0 10\r\n" - (redis/sort-command "SORT" "key" :limit 0 10))) - (is (= "SORT key ASC\r\n" - (redis/sort-command "SORT" "key" :asc))) - (is (= "SORT key DESC\r\n" - (redis/sort-command "SORT" "key" :desc))) - (is (= "SORT key ALPHA\r\n" - (redis/sort-command "SORT" "key" :alpha))) - (is (= "SORT key GET object_* GET object2_*\r\n" - (redis/sort-command "SORT" "key" :get "object_*" :get "object2_*"))) - (is (= "SORT key BY weight_* LIMIT 0 10 GET object_* ALPHA DESC\r\n" - (redis/sort-command "SORT" "key" - :by "weight_*" - :limit 0 10 - :get "object_*" - :alpha - :desc)))) - - -;; -;; Reply parsing -;; -(deftest read-crlf - (is (thrown? Exception - (redis/read-crlf (wrap-in-reader "\n")))) - (is (thrown? Exception - (redis/read-crlf (wrap-in-reader "")))) - (is (thrown? Exception - (redis/read-crlf (wrap-in-reader "\r1")))) - (is (= nil - (redis/read-crlf (wrap-in-reader "\r\n"))))) - -;; (deftest read-newline-crlf -;; (is (thrown? Exception -;; (redis/read-line-crlf (wrap-in-reader ""))))) - -;; -;; Reply parsing -;; -(deftest reply - (is (thrown? Exception - (read-reply ""))) - (is (thrown? Exception - (read-reply "\r\n")))) - - -(deftest error-reply - (is (thrown? - Exception - (read-reply "-\r\n"))) - (is (thrown-with-msg? - Exception #".*Test" - (read-reply "-Test\r\n")))) - -(deftest simple-reply - (is (thrown? Exception - (read-reply "+"))) - (is (= "" - (read-reply "+\r\n"))) - (is (= "foobar" - (read-reply "+foobar\r\n")))) - -(deftest integer-reply - (is (thrown? Exception - (read-reply ":\r\n"))) - (is (= 0 - (read-reply ":0\r\n"))) - (is (= 42 - (read-reply ":42\r\n"))) - (is (= 42 - (read-reply ": 42 \r\n"))) - (is (= 429348754 - (read-reply ":429348754\r\n")))) - -(deftest bulk-reply - (is (thrown? Exception - (read-reply "$\r\n"))) - (is (thrown? Exception - (read-reply "$2\r\n1\r\n"))) - (is (thrown? Exception - (read-reply "$3\r\n1\r\n"))) - (is (= nil - (read-reply "$-1\r\n"))) - (is (= "foobar" - (read-reply "$6\r\nfoobar\r\n"))) - (is (= "foo\r\nbar" - (read-reply "$8\r\nfoo\r\nbar\r\n")))) - -(deftest multi-bulk-reply - (is (thrown? Exception - (read-reply "*1\r\n"))) - (is (thrown? Exception - (read-reply "*4\r\n:0\r\n:0\r\n:0\r\n"))) - (is (= nil - (read-reply "*-1\r\n"))) - (is (= [1] - (read-reply "*1\r\n:1\r\n"))) - (is (= ["foo" "bar"] - (read-reply "*2\r\n+foo\r\n+bar\r\n"))) - (is (= [1 "foo" "foo\r\nbar"] - (read-reply "*3\r\n:1\r\n+foo\r\n$8\r\nfoo\r\nbar\r\n")))) - - - - - - diff --git a/client-libraries/cpp/Makefile b/client-libraries/cpp/Makefile deleted file mode 100644 index c4e0416f..00000000 --- a/client-libraries/cpp/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# Redis C++ Client Library Makefile - -#CFLAGS?= -pedantic -O2 -Wall -W -DNDEBUG -CFLAGS?= -pedantic -O0 -W -DDEBUG -g -CC = g++ - -CLIENTOBJS = anet.o redisclient.o -LIBNAME = libredisclient.a - -TESTAPP = test_client -TESTAPPOBJS = test_client.o -TESTAPPLIBS = $(LIBNAME) -lstdc++ - -all: $(LIBNAME) $(TESTAPP) - -$(LIBNAME): $(CLIENTOBJS) - ar rcs $(LIBNAME) $(CLIENTOBJS) - -.c.o: - $(CC) -c $(CFLAGS) $< - -.cpp.o: - $(CC) -c $(CFLAGS) $< - -$(TESTAPP): $(LIBNAME) $(TESTAPPOBJS) - $(CC) -o $(TESTAPP) $(TESTAPPOBJS) $(TESTAPPLIBS) - -test: $(TESTAPP) - @./test_client - -check: test - -clean: - rm -rf $(LIBNAME) *.o $(TESTAPP) - -dep: - $(CC) -MM *.c *.cpp - -log: - git log '--pretty=format:%ad %s' --date=short > Changelog - -anet.o: anet.c fmacros.h anet.h -redisclient.o: redisclient.cpp redisclient.h anet.h - diff --git a/client-libraries/cpp/README.rst b/client-libraries/cpp/README.rst deleted file mode 100644 index 36603068..00000000 --- a/client-libraries/cpp/README.rst +++ /dev/null @@ -1,16 +0,0 @@ -redis-cpp-client -================ - -* A C++ client for the Redis_ key-value database (which is hosted at github_). -* This client has no external dependencies other than g++ (no Boost for instance). -* It uses anet from antirez_ (redis' author), which is bundled. -* This client is licensed under the same license as redis. -* Tested on Linux and Mac OS X. - -* This is a work in progress. I will update this README when the client is "done". - If I had to put a version number on it right now, I'd call it version 0.85 - -.. _Redis: http://code.google.com/p/redis/ -.. _github: http://github.com/antirez/redis/tree/master -.. _antirez: https://github.com/antirez - diff --git a/client-libraries/cpp/TODO b/client-libraries/cpp/TODO deleted file mode 100644 index cc541cdb..00000000 --- a/client-libraries/cpp/TODO +++ /dev/null @@ -1,22 +0,0 @@ -general: -- check for complete support for 0.100 (compiles; existing tests pass) - -command handlers: -- support DEL as vararg -- support MLLEN and MSCARD -- support SDIFF -- support SDIFFSTORE - - -unit tests: -- sort with limit -- sort lexicographically -- sort with pattern and weights - -extras: -- benchmarking "test" app -- consistent hashing? - -maybe/someday: -- make all string literals constants so they can be easily changed -- add conveniences that store a std::set in its entirety (same for std::list, std::vector) diff --git a/client-libraries/cpp/anet.c b/client-libraries/cpp/anet.c deleted file mode 100644 index 893f42c8..00000000 --- a/client-libraries/cpp/anet.c +++ /dev/null @@ -1,270 +0,0 @@ -/* anet.c -- Basic TCP socket stuff made a bit less boring - * - * Copyright (c) 2006-2009, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * 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. - * * 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. - * - * 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. - */ - -#include "fmacros.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "anet.h" - -static void anetSetError(char *err, const char *fmt, ...) -{ - va_list ap; - - if (!err) return; - va_start(ap, fmt); - vsnprintf(err, ANET_ERR_LEN, fmt, ap); - va_end(ap); -} - -int anetNonBlock(char *err, int fd) -{ - int flags; - - /* Set the socket nonblocking. - * Note that fcntl(2) for F_GETFL and F_SETFL can't be - * interrupted by a signal. */ - if ((flags = fcntl(fd, F_GETFL)) == -1) { - anetSetError(err, "fcntl(F_GETFL): %s\n", strerror(errno)); - return ANET_ERR; - } - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { - anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s\n", strerror(errno)); - return ANET_ERR; - } - return ANET_OK; -} - -int anetTcpNoDelay(char *err, int fd) -{ - int yes = 1; - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) - { - anetSetError(err, "setsockopt TCP_NODELAY: %s\n", strerror(errno)); - return ANET_ERR; - } - return ANET_OK; -} - -int anetSetSendBuffer(char *err, int fd, int buffsize) -{ - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1) - { - anetSetError(err, "setsockopt SO_SNDBUF: %s\n", strerror(errno)); - return ANET_ERR; - } - return ANET_OK; -} - -int anetTcpKeepAlive(char *err, int fd) -{ - int yes = 1; - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) == -1) { - anetSetError(err, "setsockopt SO_KEEPALIVE: %s\n", strerror(errno)); - return ANET_ERR; - } - return ANET_OK; -} - -int anetResolve(char *err, char *host, char *ipbuf) -{ - struct sockaddr_in sa; - - sa.sin_family = AF_INET; - if (inet_aton(host, &sa.sin_addr) == 0) { - struct hostent *he; - - he = gethostbyname(host); - if (he == NULL) { - anetSetError(err, "can't resolve: %s\n", host); - return ANET_ERR; - } - memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr)); - } - strcpy(ipbuf,inet_ntoa(sa.sin_addr)); - return ANET_OK; -} - -#define ANET_CONNECT_NONE 0 -#define ANET_CONNECT_NONBLOCK 1 -static int anetTcpGenericConnect(char *err, char *addr, int port, int flags) -{ - int s, on = 1; - struct sockaddr_in sa; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - anetSetError(err, "creating socket: %s\n", strerror(errno)); - return ANET_ERR; - } - /* Make sure connection-intensive things like the redis benckmark - * will be able to close/open sockets a zillion of times */ - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - if (inet_aton(addr, &sa.sin_addr) == 0) { - struct hostent *he; - - he = gethostbyname(addr); - if (he == NULL) { - anetSetError(err, "can't resolve: %s\n", addr); - close(s); - return ANET_ERR; - } - memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr)); - } - if (flags & ANET_CONNECT_NONBLOCK) { - if (anetNonBlock(err,s) != ANET_OK) - return ANET_ERR; - } - if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) { - if (errno == EINPROGRESS && - flags & ANET_CONNECT_NONBLOCK) - return s; - - anetSetError(err, "connect: %s\n", strerror(errno)); - close(s); - return ANET_ERR; - } - return s; -} - -int anetTcpConnect(char *err, char *addr, int port) -{ - return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE); -} - -int anetTcpNonBlockConnect(char *err, char *addr, int port) -{ - return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK); -} - -/* Like read(2) but make sure 'count' is read before to return - * (unless error or EOF condition is encountered) */ -int anetRead(int fd, char *buf, int count) -{ - int nread, totlen = 0; - while(totlen != count) { - nread = read(fd,buf,count-totlen); - if (nread == 0) return totlen; - if (nread == -1) return -1; - totlen += nread; - buf += nread; - } - return totlen; -} - -/* Like write(2) but make sure 'count' is read before to return - * (unless error is encountered) */ -int anetWrite(int fd, char *buf, int count) -{ - int nwritten, totlen = 0; - while(totlen != count) { - nwritten = write(fd,buf,count-totlen); - if (nwritten == 0) return totlen; - if (nwritten == -1) return -1; - totlen += nwritten; - buf += nwritten; - } - return totlen; -} - -int anetTcpServer(char *err, int port, char *bindaddr) -{ - int s, on = 1; - struct sockaddr_in sa; - - if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - anetSetError(err, "socket: %s\n", strerror(errno)); - return ANET_ERR; - } - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { - anetSetError(err, "setsockopt SO_REUSEADDR: %s\n", strerror(errno)); - close(s); - return ANET_ERR; - } - memset(&sa,0,sizeof(sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); - sa.sin_addr.s_addr = htonl(INADDR_ANY); - if (bindaddr) { - if (inet_aton(bindaddr, &sa.sin_addr) == 0) { - anetSetError(err, "Invalid bind address\n"); - close(s); - return ANET_ERR; - } - } - if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) { - anetSetError(err, "bind: %s\n", strerror(errno)); - close(s); - return ANET_ERR; - } - if (listen(s, 32) == -1) { - anetSetError(err, "listen: %s\n", strerror(errno)); - close(s); - return ANET_ERR; - } - return s; -} - -int anetAccept(char *err, int serversock, char *ip, int *port) -{ - int fd; - struct sockaddr_in sa; - unsigned int saLen; - - while(1) { - saLen = sizeof(sa); - fd = accept(serversock, (struct sockaddr*)&sa, &saLen); - if (fd == -1) { - if (errno == EINTR) - continue; - else { - anetSetError(err, "accept: %s\n", strerror(errno)); - return ANET_ERR; - } - } - break; - } - if (ip) strcpy(ip,inet_ntoa(sa.sin_addr)); - if (port) *port = ntohs(sa.sin_port); - return fd; -} diff --git a/client-libraries/cpp/anet.h b/client-libraries/cpp/anet.h deleted file mode 100644 index b1e9a567..00000000 --- a/client-libraries/cpp/anet.h +++ /dev/null @@ -1,49 +0,0 @@ -/* anet.c -- Basic TCP socket stuff made a bit less boring - * - * Copyright (c) 2006-2009, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * 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. - * * 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. - * - * 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. - */ - -#ifndef ANET_H -#define ANET_H - -#define ANET_OK 0 -#define ANET_ERR -1 -#define ANET_ERR_LEN 256 - -int anetTcpConnect(char *err, char *addr, int port); -int anetTcpNonBlockConnect(char *err, char *addr, int port); -int anetRead(int fd, char *buf, int count); -int anetResolve(char *err, char *host, char *ipbuf); -int anetTcpServer(char *err, int port, char *bindaddr); -int anetAccept(char *err, int serversock, char *ip, int *port); -int anetWrite(int fd, char *buf, int count); -int anetNonBlock(char *err, int fd); -int anetTcpNoDelay(char *err, int fd); -int anetTcpKeepAlive(char *err, int fd); - -#endif diff --git a/client-libraries/cpp/fmacros.h b/client-libraries/cpp/fmacros.h deleted file mode 100644 index 7c9b91ae..00000000 --- a/client-libraries/cpp/fmacros.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _REDIS_FMACRO_H -#define _REDIS_FMACRO_H - -#define _BSD_SOURCE -#define _XOPEN_SOURCE - -#endif diff --git a/client-libraries/cpp/redisclient.cpp b/client-libraries/cpp/redisclient.cpp deleted file mode 100644 index 5e3468cc..00000000 --- a/client-libraries/cpp/redisclient.cpp +++ /dev/null @@ -1,894 +0,0 @@ -/* redisclient.cpp -- a C++ client library for redis. - * - * Copyright (c) 2009, Brian Hammond - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * 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. - * * 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. - * - * 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. - */ - -#include "redisclient.h" -#include "anet.h" - -#include - -#ifndef NDEBUG -#include -#include -#include -#endif - -#include -#include - -#include -#include - -using namespace std; - -namespace -{ - const string whitespace(" \f\n\r\t\v"); - const string CRLF("\r\n"); - - // Modifies in-place. - - inline string & rtrim(string & str, const string & ws = whitespace) - { - string::size_type pos = str.find_last_not_of(ws); - str.erase(pos + 1); - return str; - } - - vector::size_type split(const string & str, char delim, vector & elems) - { - stringstream ss(str); - string item; - vector::size_type n = 0; - while (getline(ss, item, delim)) - { - elems.push_back(item); - ++n; - } - return n; - } - - inline void split_lines(const string & str, vector & elems) - { - split(str, '\n', elems); - for (vector::iterator it = elems.begin(); it != elems.end(); ++it) - rtrim(*it); - } - -#ifndef NDEBUG - - void output_proto_debug(const string & data, bool is_received = true) - { - string escaped_data(data); - size_t pos; - while ((pos = escaped_data.find("\n")) != string::npos) - escaped_data.replace(pos, 1, "\\n"); - while ((pos = escaped_data.find("\r")) != string::npos) - escaped_data.replace(pos, 1, "\\r"); - - cerr - << time(NULL) << ": " - << (is_received ? "RECV '" : "SEND '") - << escaped_data - << "'" - << endl; - } - -#endif - - class makecmd - { - public: - explicit makecmd(const string & initial, bool finalize = false) - { - buffer_ << initial; - if (!finalize) - buffer_ << " "; - } - - template - makecmd & operator<<(T const & datum) - { - buffer_ << datum; - return *this; - } - - template - makecmd & operator<<(const vector & data) - { - size_t n = data.size(); - for (size_t i = 0; i < n; ++i) - { - buffer_ << data[i]; - if (i < n - 1) - buffer_ << " "; - } - return *this; - } - - operator std::string () - { - buffer_ << CRLF; - return buffer_.str(); - } - - private: - ostringstream buffer_; - }; - - // Reads N bytes from given blocking socket. - - string read_n(int socket, ssize_t n) - { - char * buffer = new char[n + 1]; - buffer[n] = '\0'; - - char * bp = buffer; - ssize_t bytes_read = 0; - - while (bytes_read != n) - { - ssize_t bytes_received = 0; - do bytes_received = recv(socket, bp, n - (bp - buffer), 0); - while (bytes_received < 0 && errno == EINTR); - - if (bytes_received == 0) - throw redis::connection_error("connection was closed"); - - bytes_read += bytes_received; - bp += bytes_received; - } - - string str(buffer); - delete [] buffer; - return str; - } - - // Reads a single line of character data from the given blocking socket. - // Returns the line that was read, not including EOL delimiter(s). Both LF - // ('\n') and CRLF ("\r\n") delimiters are supported. If there was an I/O - // error reading from the socket, connection_error is raised. If max_size - // bytes are read before finding an EOL delimiter, a blank string is - // returned. - - string read_line(int socket, ssize_t max_size = 2048) - { - assert(socket > 0); - assert(max_size > 0); - - ostringstream oss; - - enum { buffer_size = 64 }; - char buffer[buffer_size]; - memset(buffer, 0, buffer_size); - - ssize_t total_bytes_read = 0; - bool found_delimiter = false; - - while (total_bytes_read < max_size && !found_delimiter) - { - // Peek at what's available. - - ssize_t bytes_received = 0; - do bytes_received = recv(socket, buffer, buffer_size, MSG_PEEK); - while (bytes_received < 0 && errno == EINTR); - - if (bytes_received == 0) - throw redis::connection_error("connection was closed"); - - // Some data is available; Length might be < buffer_size. - // Look for newline in whatever was read though. - - char * eol = static_cast(memchr(buffer, '\n', bytes_received)); - - // If found, write data from the buffer to the output string. - // Else, write the entire buffer and continue reading more data. - - ssize_t to_read = bytes_received; - - if (eol) - { - to_read = eol - buffer + 1; - oss.write(buffer, to_read); - found_delimiter = true; - } - else - oss.write(buffer, bytes_received); - - // Now read from the socket to remove the peeked data from the socket's - // read buffer. This will not block since we've peeked already and know - // there's data waiting. It might fail if we were interrupted however. - - do bytes_received = recv(socket, buffer, to_read, 0); - while (bytes_received < 0 && errno == EINTR); - } - - // Construct final line string. Remove trailing CRLF-based whitespace. - - string line = oss.str(); - return rtrim(line, CRLF); - } - - template - T value_from_string(const string & data) - { - T value; - - istringstream iss(data); - iss >> value; - if (iss.fail()) - throw redis::value_error("invalid number"); - - return value; - } - - const string status_reply_ok("OK"); - const string prefix_status_reply_error("-ERR "); - const char prefix_status_reply_value = '+'; - const char prefix_single_bulk_reply = '$'; - const char prefix_multi_bulk_reply = '*'; - const char prefix_int_reply = ':'; - - const string server_info_key_version = "redis_version"; - const string server_info_key_bgsave_in_progress = "bgsave_in_progress"; - const string server_info_key_connected_clients = "connected_clients"; - const string server_info_key_connected_slaves = "connected_slaves"; - const string server_info_key_used_memory = "used_memory"; - const string server_info_key_changes_since_last_save = "changes_since_last_save"; - const string server_info_key_last_save_time = "last_save_time"; - const string server_info_key_total_connections_received = "total_connections_received"; - const string server_info_key_total_commands_processed = "total_commands_processed"; - const string server_info_key_uptime_in_seconds = "uptime_in_seconds"; - const string server_info_key_uptime_in_days = "uptime_in_days"; - const string server_info_key_role = "role"; - - const string server_info_value_role_master = "master"; - const string server_info_value_role_slave = "slave"; -} - -namespace redis -{ - redis_error::redis_error(const string & err) : err_(err) - { - } - - redis_error::operator std::string () - { - return err_; - } - - redis_error::operator const std::string () const - { - return err_; - } - - connection_error::connection_error(const string & err) : redis_error(err) - { - } - - protocol_error::protocol_error(const string & err) : redis_error(err) - { - } - - key_error::key_error(const string & err) : redis_error(err) - { - } - - value_error::value_error(const string & err) : redis_error(err) - { - } - - client::string_type client::missing_value("**nonexistent-key**"); - - client::client(const string_type & host, unsigned int port) - { - char err[ANET_ERR_LEN]; - socket_ = anetTcpConnect(err, const_cast(host.c_str()), port); - if (socket_ == ANET_ERR) - throw connection_error(err); - anetTcpNoDelay(NULL, socket_); - } - - client::~client() - { - if (socket_ != ANET_ERR) - close(socket_); - } - - void client::auth(const client::string_type & pass) - { - send_(makecmd("AUTH") << pass); - recv_ok_reply_(); - } - - void client::set(const client::string_type & key, - const client::string_type & value) - { - send_(makecmd("SET") << key << ' ' << value.size() << CRLF << value); - recv_ok_reply_(); - } - - client::string_type client::get(const client::string_type & key) - { - send_(makecmd("GET") << key); - return recv_bulk_reply_(); - } - - client::string_type client::getset(const client::string_type & key, - const client::string_type & value) - { - send_(makecmd("GETSET") << key << ' ' << value.size() << CRLF << value); - return recv_bulk_reply_(); - } - - void client::mget(const client::string_vector & keys, string_vector & out) - { - send_(makecmd("MGET") << keys); - recv_multi_bulk_reply_(out); - } - - bool client::setnx(const client::string_type & key, - const client::string_type & value) - { - send_(makecmd("SETNX") << key << ' ' << value.size() << CRLF << value); - return recv_int_reply_() == 1; - } - - client::int_type client::incr(const client::string_type & key) - { - send_(makecmd("INCR") << key); - return recv_int_reply_(); - } - - client::int_type client::incrby(const client::string_type & key, - client::int_type by) - { - send_(makecmd("INCRBY") << key << ' ' << by); - return recv_int_reply_(); - } - - client::int_type client::decr(const client::string_type & key) - { - send_(makecmd("DECR") << key); - return recv_int_reply_(); - } - - client::int_type client::decrby(const client::string_type & key, - client::int_type by) - { - send_(makecmd("DECRBY") << key << ' ' << by); - return recv_int_reply_(); - } - - bool client::exists(const client::string_type & key) - { - send_(makecmd("EXISTS") << key); - return recv_int_reply_() == 1; - } - - void client::del(const client::string_type & key) - { - send_(makecmd("DEL") << key); - recv_int_ok_reply_(); - } - - client::datatype client::type(const client::string_type & key) - { - send_(makecmd("TYPE") << key); - string response = recv_single_line_reply_(); - - if (response == "none") return datatype_none; - if (response == "string") return datatype_string; - if (response == "list") return datatype_list; - if (response == "set") return datatype_set; - - return datatype_none; - } - - client::int_type client::keys(const client::string_type & pattern, - client::string_vector & out) - { - send_(makecmd("KEYS") << pattern); - string resp = recv_bulk_reply_(); - return split(resp, ' ', out); - } - - client::string_type client::randomkey() - { - send_(makecmd("RANDOMKEY", true)); - return recv_single_line_reply_(); - } - - void client::rename(const client::string_type & old_name, - const client::string_type & new_name) - { - send_(makecmd("RENAME") << old_name << ' ' << new_name); - recv_ok_reply_(); - } - - bool client::renamenx(const client::string_type & old_name, - const client::string_type & new_name) - { - send_(makecmd("RENAMENX") << old_name << ' ' << new_name); - return recv_int_reply_() == 1; - } - - client::int_type client::dbsize() - { - send_(makecmd("DBSIZE")); - return recv_int_reply_(); - } - - void client::expire(const string_type & key, unsigned int secs) - { - send_(makecmd("EXPIRE") << key << ' ' << secs); - recv_int_ok_reply_(); - } - - void client::rpush(const client::string_type & key, - const client::string_type & value) - { - send_(makecmd("RPUSH") << key << ' ' << value.length() << CRLF << value); - recv_ok_reply_(); - } - - void client::lpush(const client::string_type & key, - const client::string_type & value) - { - send_(makecmd("LPUSH") << key << ' ' << value.length() << CRLF << value); - recv_ok_reply_(); - } - - client::int_type client::llen(const client::string_type & key) - { - send_(makecmd("LLEN") << key); - return recv_int_reply_(); - } - - client::int_type client::lrange(const client::string_type & key, - client::int_type start, - client::int_type end, - client::string_vector & out) - { - send_(makecmd("LRANGE") << key << ' ' << start << ' ' << end); - return recv_multi_bulk_reply_(out); - } - - void client::ltrim(const client::string_type & key, - client::int_type start, - client::int_type end) - { - send_(makecmd("LTRIM") << key << ' ' << start << ' ' << end); - recv_ok_reply_(); - } - - client::string_type client::lindex(const client::string_type & key, - client::int_type index) - { - send_(makecmd("LINDEX") << key << ' ' << index); - return recv_bulk_reply_(); - } - - void client::lset(const client::string_type & key, - client::int_type index, - const client::string_type & value) - { - send_(makecmd("LSET") << key << ' ' << index << ' ' << value.length() << CRLF << value); - recv_ok_reply_(); - } - - client::int_type client::lrem(const client::string_type & key, - client::int_type count, - const client::string_type & value) - { - send_(makecmd("LREM") << key << ' ' << count << ' ' << value.length() << CRLF << value); - return recv_int_reply_(); - } - - client::string_type client::lpop(const client::string_type & key) - { - send_(makecmd("LPOP") << key); - return recv_bulk_reply_(); - } - - client::string_type client::rpop(const client::string_type & key) - { - send_(makecmd("RPOP") << key); - return recv_bulk_reply_(); - } - - void client::sadd(const client::string_type & key, - const client::string_type & value) - { - send_(makecmd("SADD") << key << ' ' << value.length() << CRLF << value); - recv_int_ok_reply_(); - } - - void client::srem(const client::string_type & key, - const client::string_type & value) - { - send_(makecmd("SREM") << key << ' ' << value.length() << CRLF << value); - recv_int_ok_reply_(); - } - - void client::smove(const client::string_type & srckey, - const client::string_type & dstkey, - const client::string_type & value) - { - send_(makecmd("SMOVE") << srckey << ' ' << dstkey << ' ' << value.length() << CRLF << value); - recv_int_ok_reply_(); - } - - client::int_type client::scard(const client::string_type & key) - { - send_(makecmd("SCARD") << key); - return recv_int_reply_(); - } - - bool client::sismember(const client::string_type & key, - const client::string_type & value) - { - send_(makecmd("SISMEMBER") << key << ' ' << value.length() << CRLF << value); - return recv_int_reply_() == 1; - } - - client::int_type client::sinter(const client::string_vector & keys, client::string_set & out) - { - send_(makecmd("SINTER") << keys); - return recv_multi_bulk_reply_(out); - } - - client::int_type client::sinterstore(const client::string_type & dstkey, - const client::string_vector & keys) - { - send_(makecmd("SINTERSTORE") << dstkey << ' ' << keys); - return recv_int_reply_(); - } - - client::int_type client::sunion(const client::string_vector & keys, - client::string_set & out) - { - send_(makecmd("SUNION") << keys); - return recv_multi_bulk_reply_(out); - } - - client::int_type client::sunionstore(const client::string_type & dstkey, - const client::string_vector & keys) - { - send_(makecmd("SUNIONSTORE") << dstkey << ' ' << keys); - return recv_int_reply_(); - } - - client::int_type client::smembers(const client::string_type & key, - client::string_set & out) - { - send_(makecmd("SMEMBERS") << key); - return recv_multi_bulk_reply_(out); - } - - void client::select(client::int_type dbindex) - { - send_(makecmd("SELECT") << dbindex); - recv_ok_reply_(); - } - - void client::move(const client::string_type & key, - client::int_type dbindex) - { - send_(makecmd("MOVE") << key << ' ' << dbindex); - recv_int_ok_reply_(); - } - - void client::flushdb() - { - send_(makecmd("FLUSHDB", true)); - recv_ok_reply_(); - } - - void client::flushall() - { - send_(makecmd("FLUSHALL", true)); - recv_ok_reply_(); - } - - client::int_type client::sort(const client::string_type & key, - client::string_vector & out, - client::sort_order order, - bool lexicographically) - { - send_(makecmd("SORT") << key - << (order == sort_order_ascending ? " ASC" : " DESC") - << (lexicographically ? " ALPHA" : "")); - - return recv_multi_bulk_reply_(out); - } - - client::int_type client::sort(const client::string_type & key, - client::string_vector & out, - client::int_type limit_start, - client::int_type limit_end, - client::sort_order order, - bool lexicographically) - { - send_(makecmd("SORT") << key - << " LIMIT " << limit_start << ' ' << limit_end - << (order == sort_order_ascending ? " ASC" : " DESC") - << (lexicographically ? " ALPHA" : "")); - - return recv_multi_bulk_reply_(out); - } - - client::int_type client::sort(const client::string_type & key, - client::string_vector & out, - const client::string_type & by_pattern, - client::int_type limit_start, - client::int_type limit_end, - const client::string_vector & get_patterns, - client::sort_order order, - bool lexicographically) - { - makecmd m("SORT"); - - m << key - << " BY " << by_pattern - << " LIMIT " << limit_start << ' ' << limit_end; - - client::string_vector::const_iterator it = get_patterns.begin(); - for ( ; it != get_patterns.end(); ++it) - m << " GET " << *it; - - m << (order == sort_order_ascending ? " ASC" : " DESC") - << (lexicographically ? " ALPHA" : ""); - - send_(m); - - return recv_multi_bulk_reply_(out); - } - - void client::save() - { - send_(makecmd("SAVE", true)); - recv_ok_reply_(); - } - - void client::bgsave() - { - send_(makecmd("BGSAVE", true)); - recv_ok_reply_(); - } - - time_t client::lastsave() - { - send_(makecmd("LASTSAVE", true)); - return recv_int_reply_(); - } - - void client::shutdown() - { - send_(makecmd("SHUTDOWN", true)); - - // we expected to get a connection_error as redis closes the connection on shutdown command. - - try - { - recv_ok_reply_(); - } - catch (connection_error & e) - { - } - } - - void client::info(server_info & out) - { - send_(makecmd("INFO", true)); - string response = recv_bulk_reply_(); - - if (response.empty()) - throw protocol_error("empty"); - - string_vector lines; - split_lines(response, lines); - if (lines.empty()) - throw protocol_error("empty line for info"); - - for (string_vector::const_iterator it = lines.begin(); - it != lines.end(); ++it) - { - const string & line = *it; - string_vector line_parts; - split(line, ':', line_parts); - if (line_parts.size() != 2) - throw protocol_error("unexpected line format for info"); - - const string & key = line_parts[0]; - const string & val = line_parts[1]; - - if (key == server_info_key_version) - out.version = val; - else if (key == server_info_key_bgsave_in_progress) - out.bgsave_in_progress = value_from_string(val) == 1; - else if (key == server_info_key_connected_clients) - out.connected_clients = value_from_string(val); - else if (key == server_info_key_connected_slaves) - out.connected_slaves = value_from_string(val); - else if (key == server_info_key_used_memory) - out.used_memory = value_from_string(val); - else if (key == server_info_key_changes_since_last_save) - out.changes_since_last_save = value_from_string(val); - else if (key == server_info_key_last_save_time) - out.last_save_time = value_from_string(val); - else if (key == server_info_key_total_connections_received) - out.total_connections_received = value_from_string(val); - else if (key == server_info_key_total_commands_processed) - out.total_commands_processed = value_from_string(val); - else if (key == server_info_key_uptime_in_seconds) - out.uptime_in_seconds = value_from_string(val); - else if (key == server_info_key_uptime_in_days) - out.uptime_in_days = value_from_string(val); - else if (key == server_info_key_role) - out.role = val == server_info_value_role_master ? role_master : role_slave; - else - throw protocol_error(string("unexpected info key '") + key + "'"); - } - } - - // - // Private methods - // - - void client::send_(const string & msg) - { -#ifndef NDEBUG - output_proto_debug(msg, false); -#endif - - if (anetWrite(socket_, const_cast(msg.data()), msg.size()) == -1) - throw connection_error(strerror(errno)); - } - - string client::recv_single_line_reply_() - { - string line = read_line(socket_); - -#ifndef NDEBUG - output_proto_debug(line); -#endif - - if (line.empty()) - throw protocol_error("empty single line reply"); - - if (line.find(prefix_status_reply_error) == 0) - { - string error_msg = line.substr(prefix_status_reply_error.length()); - if (error_msg.empty()) - error_msg = "unknown error"; - throw protocol_error(error_msg); - } - - if (line[0] != prefix_status_reply_value) - throw protocol_error("unexpected prefix for status reply"); - - return line.substr(1); - } - - void client::recv_ok_reply_() - { - if (recv_single_line_reply_() != status_reply_ok) - throw protocol_error("expected OK response"); - } - - client::int_type client::recv_bulk_reply_(char prefix) - { - string line = read_line(socket_); - -#ifndef NDEBUG - output_proto_debug(line); -#endif - - if (line[0] != prefix) - throw protocol_error("unexpected prefix for bulk reply"); - - return value_from_string(line.substr(1)); - } - - string client::recv_bulk_reply_() - { - int_type length = recv_bulk_reply_(prefix_single_bulk_reply); - - if (length == -1) - return client::missing_value; - - int_type real_length = length + 2; // CRLF - - string data = read_n(socket_, real_length); - -#ifndef NDEBUG - output_proto_debug(data.substr(0, data.length()-2)); -#endif - - if (data.empty()) - throw protocol_error("invalid bulk reply data; empty"); - - if (data.length() != static_cast(real_length)) - throw protocol_error("invalid bulk reply data; data of unexpected length"); - - data.erase(data.size() - 2); - - return data; - } - - client::int_type client::recv_multi_bulk_reply_(string_vector & out) - { - int_type length = recv_bulk_reply_(prefix_multi_bulk_reply); - - if (length == -1) - throw key_error("no such key"); - - for (int_type i = 0; i < length; ++i) - out.push_back(recv_bulk_reply_()); - - return length; - } - - client::int_type client::recv_multi_bulk_reply_(string_set & out) - { - int_type length = recv_bulk_reply_(prefix_multi_bulk_reply); - - if (length == -1) - throw key_error("no such key"); - - for (int_type i = 0; i < length; ++i) - out.insert(recv_bulk_reply_()); - - return length; - } - - client::int_type client::recv_int_reply_() - { - string line = read_line(socket_); - -#ifndef NDEBUG - output_proto_debug(line); -#endif - - if (line.empty()) - throw protocol_error("invalid integer reply; empty"); - - if (line[0] != prefix_int_reply) - throw protocol_error("unexpected prefix for integer reply"); - - return value_from_string(line.substr(1)); - } - - void client::recv_int_ok_reply_() - { - if (recv_int_reply_() != 1) - throw protocol_error("expecting int reply of 1"); - } -} diff --git a/client-libraries/cpp/redisclient.h b/client-libraries/cpp/redisclient.h deleted file mode 100644 index b51da8f9..00000000 --- a/client-libraries/cpp/redisclient.h +++ /dev/null @@ -1,488 +0,0 @@ -/* redisclient.h -- a C++ client library for redis. - * - * Copyright (c) 2009, Brian Hammond - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * 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. - * * 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. - * - * 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. - */ - -#ifndef REDISCLIENT_H -#define REDISCLIENT_H - -#include -#include -#include -#include -#include - -namespace redis -{ - enum server_role - { - role_master, - role_slave - }; - - struct server_info - { - std::string version; - bool bgsave_in_progress; - unsigned long connected_clients; - unsigned long connected_slaves; - unsigned long used_memory; - unsigned long changes_since_last_save; - unsigned long last_save_time; - unsigned long total_connections_received; - unsigned long total_commands_processed; - unsigned long uptime_in_seconds; - unsigned long uptime_in_days; - server_role role; - }; - - // Generic error that is thrown when communicating with the redis server. - - class redis_error - { - public: - redis_error(const std::string & err); - operator std::string (); - operator const std::string () const; - private: - std::string err_; - }; - - // Some socket-level I/O or general connection error. - - class connection_error : public redis_error - { - public: - connection_error(const std::string & err); - }; - - // Redis gave us a reply we were not expecting. - // Possibly an internal error (here or in redis, probably here). - - class protocol_error : public redis_error - { - public: - protocol_error(const std::string & err); - }; - - // A key that you expected to exist does not in fact exist. - - class key_error : public redis_error - { - public: - key_error(const std::string & err); - }; - - // A value of an expected type or other semantics was found to be invalid. - - class value_error : public redis_error - { - public: - value_error(const std::string & err); - }; - - // You should construct a 'client' object per connection to a redis-server. - // - // Please read the online redis command reference: - // http://code.google.com/p/redis/wiki/CommandReference - // - // No provisions for customizing the allocator on the string/bulk value type - // (std::string) are provided. If needed, you can always change the - // string_type typedef in your local version. - - class client - { - public: - typedef std::string string_type; - typedef std::vector string_vector; - typedef std::set string_set; - - typedef long int_type; - - explicit client(const string_type & host = "localhost", - unsigned int port = 6379); - - ~client(); - - // - // Connection handling - // - - void auth(const string_type & pass); - - // - // Commands operating on string values - // - // Note that empty string values do not denote nonexistent keys but well, - // empty values! If a nonexistent key is queried, the value returned will - // be missing_value, including when string_vector objects are returned. - // - - static string_type missing_value; - - // set a key to a string value - - void set(const string_type & key, const string_type & value); - - // return the string value of the key - - string_type get(const string_type & key); - - // set a key to a string returning the old value of the key - - string_type getset(const string_type & key, const string_type & value); - - // multi-get, return the strings values of the keys - - void mget(const string_vector & keys, string_vector & out); - - // set a key to a string value if the key does not exist. returns true if - // the key was set, else false. This does not throw since you are ok with - // this failing if the dst key already exists. - - bool setnx(const string_type & key, const string_type & value); - - // increment the integer value of key - // returns new value - - int_type incr(const string_type & key); - - // increment the integer value of key by integer - // returns new value - - int_type incrby(const string_type & key, int_type by); - - // decrement the integer value of key - // returns new value - - int_type decr(const string_type & key); - - // decrement the integer value of key by integer - // returns new value - - int_type decrby(const string_type & key, int_type by); - - // test if a key exists - - bool exists(const string_type & key); - - // delete a key - // throws if doesn't exist - - void del(const string_type & key); - - enum datatype - { - datatype_none, // key doesn't exist - datatype_string, - datatype_list, - datatype_set - }; - - // return the type of the value stored at key - - datatype type(const string_type & key); - - // - // Commands operating on the key space - // - - // find all the keys matching a given pattern - // returns numbers of keys appended to 'out' - - int_type keys(const string_type & pattern, string_vector & out); - - // return a random key from the key space - // returns empty string if db is empty - - string_type randomkey(); - - // rename the old key in the new one, destroying the new key if - // it already exists - - void rename(const string_type & old_name, const string_type & new_name); - - // rename the old key in the new one, if the new key does not already - // exist. This does not throw since you are ok with this failing if the - // new_name key already exists. - - bool renamenx(const string_type & old_name, const string_type & new_name); - - // return the number of keys in the current db - - int_type dbsize(); - - // set a time to live in seconds on a key. - // fails if there's already a timeout on the key. - - // NB: there's currently no generic way to remove a timeout on a key - - void expire(const string_type & key, unsigned int secs); - - // - // Commands operating on lists - // - - // Append an element to the tail of the list value at key - - void rpush(const string_type & key, const string_type & value); - - // Append an element to the head of the list value at key - - void lpush(const string_type & key, const string_type & value); - - // Return the length of the list value at key - // Returns 0 if the list does not exist; see 'exists' - - int_type llen(const string_type & key); - - // Fetch a range of elements from the list at key - // end can be negative for reverse offsets - // Returns number of elements appended to 'out' - - int_type lrange(const string_type & key, - int_type start, - int_type end, - string_vector & out); - - // Fetches the entire list at key. - - int_type get_list(const string_type & key, string_vector & out) - { - return lrange(key, 0, -1, out); - } - - // Trim the list at key to the specified range of elements - - void ltrim(const string_type & key, int_type start, int_type end); - - // Return the element at index position from the list at key - - string_type lindex(const string_type & key, int_type); - - // set a new value as the element at index position of the list at key - - void lset(const string_type & key, - int_type index, - const string_type &); - - // If count is zero all the elements are removed. If count is negative - // elements are removed from tail to head, instead to go from head to tail - // that 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) - // will lave the list (a,b,c,hello,x). Returns the number of removed - // elements if the operation succeeded. - // - // Note: this will not throw if the number of elements removed != count - // since you might want to remove at most count elements by don't care if - // < count elements are removed. See lrem_exact(). - - int_type lrem(const string_type & key, - int_type count, - const string_type & value); - - // An extension of 'lrem' that wants to remove exactly 'count' elements. - // Throws value_error if 'count' elements are not found & removed from the - // list at 'key'. - - void lrem_exact(const string_type & key, - int_type count, - const string_type & value) - { - if (lrem(key, count, value) != count) - throw value_error("failed to remove exactly N elements from list"); - } - - // Return and remove (atomically) the first element of the list at key - - string_type lpop(const string_type & key); - - // Return and remove (atomically) the last element of the list at key - - string_type rpop(const string_type & key); - - // - // Commands operating on sets - // - - // Add the specified member to the set value at key - // returns true if added, or false if already a member of the set. - - void sadd(const string_type & key, const string_type & value); - - // Remove the specified member from the set value at key - // returns true if removed or false if value is not a member of the set. - - void srem(const string_type & key, const string_type & value); - - // Move the specified member from one set to another atomically - // returns true if element was moved, else false (e.g. not found) - - void smove(const string_type & srckey, - const string_type & dstkey, - const string_type & value); - - // Return the number of elements (the cardinality) of the set at key - - int_type scard(const string_type & key); - - // Test if the specified value is a member of the set at key - // Returns false if key doesn't exist or value is not a member of the set at key - - bool sismember(const string_type & key, const string_type & value); - - // Return the intersection between the sets stored at key1, key2, ..., keyN - - int_type sinter(const string_vector & keys, string_set & out); - - // Compute the intersection between the sets stored at key1, key2, ..., - // keyN, and store the resulting set at dstkey - // Returns the number of items in the intersection - - int_type sinterstore(const string_type & dstkey, const string_vector & keys); - - // Return the union between the sets stored at key1, key2, ..., keyN - - int_type sunion(const string_vector & keys, string_set & out); - - // Compute the union between the sets stored at key1, key2, ..., keyN, - // and store the resulting set at dstkey - // Returns the number of items in the intersection - - int_type sunionstore(const string_type & dstkey, const string_vector & keys); - - // Return all the members of the set value at key - - int_type smembers(const string_type & key, string_set & out); - - // - // Multiple databases handling commands - // - - // Select the DB having the specified index - - void select(int_type dbindex); - - // Move the key from the currently selected DB to the DB having as index - // dbindex. Throws if key was already in the db at dbindex or not found in - // currently selected db. - - void move(const string_type & key, int_type dbindex); - - // Remove all the keys of the currently selected DB - - void flushdb(); - - // Remove all the keys from all the databases - - void flushall(); - - // - // Sorting - // Just go read http://code.google.com/p/redis/wiki/SortCommand - // - - enum sort_order - { - sort_order_ascending, - sort_order_descending - }; - - int_type sort(const string_type & key, - string_vector & out, - sort_order order = sort_order_ascending, - bool lexicographically = false); - - int_type sort(const string_type & key, - string_vector & out, - int_type limit_start, - int_type limit_end, - sort_order order = sort_order_ascending, - bool lexicographically = false); - - int_type sort(const string_type & key, - string_vector & out, - const string_type & by_pattern, - int_type limit_start, - int_type limit_end, - const string_vector & get_patterns, - sort_order order = sort_order_ascending, - bool lexicographically = false); - - // - // Persistence control commands - // - - // Synchronously save the DB on disk - - void save(); - - // Asynchronously save the DB on disk - - void bgsave(); - - // Return the UNIX time stamp of the last successfully saving of the - // dataset on disk - - time_t lastsave(); - - // Synchronously save the DB on disk, then shutdown the server. This - // object's connection to the server will be lost on success. Otherwise, - // redis_error is raised. Thus, on success, you should delete or otherwise - // no longer use the object. - - void shutdown(); - - // - // Remote server control commands - // - - // Provide information and statistics about the server - - void info(server_info & out); - - private: - client(const client &); - client & operator=(const client &); - - void send_(const std::string &); - void recv_ok_reply_(); - void recv_int_ok_reply_(); - std::string recv_single_line_reply_(); - int_type recv_bulk_reply_(char prefix); - std::string recv_bulk_reply_(); - int_type recv_multi_bulk_reply_(string_vector & out); - int_type recv_multi_bulk_reply_(string_set & out); - int_type recv_int_reply_(); - - private: - int socket_; - }; -} - -#endif diff --git a/client-libraries/cpp/test_client.cpp b/client-libraries/cpp/test_client.cpp deleted file mode 100644 index 53ef5117..00000000 --- a/client-libraries/cpp/test_client.cpp +++ /dev/null @@ -1,629 +0,0 @@ -#include "redisclient.h" - -#include - -using namespace std; - -#define ASSERT_EQUAL(x,y) assert_equal(x, y, __LINE__) -#define ASSERT_NOT_EQUAL(x,y) assert_not_equal(x, y, __LINE__) -#define ASSERT_GT(x,y) assert_gt(x, y, __LINE__) - -template -void assert_equal(const T & actual, const T & expected, int lineno) -{ -#ifndef NDEBUG - cerr << "assert_equal('" << expected << "', '" << actual << "')" << endl; -#endif - - if (expected != actual) - { - cerr << "expected '" << expected << "' got '" << actual << "'" << endl - << "failing test called from line " << lineno << endl; - - exit(1); - } - -#ifndef NDEBUG - cerr << "... OK" << endl; -#endif -} - -template -void assert_not_equal(const T & a, const T & b, int lineno) -{ - if (a == b) - { - cerr << "expected inequality" << endl - << "failing test called from line " << lineno << endl; - - exit(1); - } -} - -template -void assert_gt(const T & a, const T & b, int lineno) -{ -#ifndef NDEBUG - cerr << "assert_gt('" << a << "', '" << b << "')" << endl; -#endif - - if (a <= b) - { - cerr << "expected '" << a << "' > '" << b << "'" << endl - << "failing test called from line " << lineno << endl; - - exit(1); - } - -#ifndef NDEBUG - cerr << "... OK" << endl; -#endif -} - -void test(const string & name) -{ -#ifndef NDEBUG - cerr << "------------------------------" << endl - << "starting test: " << name << endl; -#endif -} - -int main(int argc, char ** argv) -{ - try - { - redis::client c; - - // Test on high number databases - - c.select(14); - c.flushdb(); - - c.select(15); - c.flushdb(); - - string foo("foo"), bar("bar"), baz("baz"), buz("buz"), goo("goo"); - - test("auth"); - { - // TODO ... needs a conf for redis-server - } - - test("info"); - { - // doesn't throw? then, has valid numbers and known info-keys. - redis::server_info info; - c.info(info); - } - - test("set, get"); - { - c.set(foo, bar); - ASSERT_EQUAL(c.get(foo), bar); - } - - test("getset"); - { - ASSERT_EQUAL(c.getset(foo, baz), bar); - ASSERT_EQUAL(c.get(foo), baz); - } - - test("mget"); - { - string x_val("hello"), y_val("world"); - c.set("x", x_val); - c.set("y", y_val); - redis::client::string_vector keys; - keys.push_back("x"); - keys.push_back("y"); - redis::client::string_vector vals; - c.mget(keys, vals); - ASSERT_EQUAL(vals.size(), size_t(2)); - ASSERT_EQUAL(vals[0], x_val); - ASSERT_EQUAL(vals[1], y_val); - } - - test("setnx"); - { - ASSERT_EQUAL(c.setnx(foo, bar), false); - ASSERT_EQUAL(c.setnx(buz, baz), true); - ASSERT_EQUAL(c.get(buz), baz); - } - - test("incr"); - { - ASSERT_EQUAL(c.incr("goo"), 1L);test("nonexistent (0) -> 1"); - ASSERT_EQUAL(c.incr("goo"), 2L);test("1->2"); - } - - test("decr"); - { - ASSERT_EQUAL(c.decr("goo"), 1L);test("2->1"); - ASSERT_EQUAL(c.decr("goo"), 0L);test("1->0"); - } - - test("incrby"); - { - ASSERT_EQUAL(c.incrby("goo", 3), 3L);test("0->3"); - ASSERT_EQUAL(c.incrby("goo", 2), 5L);test("3->5"); - } - - test("exists"); - { - ASSERT_EQUAL(c.exists("goo"), true); - } - - test("del"); - { - c.del("goo"); - ASSERT_EQUAL(c.exists("goo"), false); - } - - test("type (basic)"); - { - ASSERT_EQUAL(c.type(goo), redis::client::datatype_none);test("we deleted it"); - c.set(goo, "redis"); - ASSERT_EQUAL(c.type(goo), redis::client::datatype_string); - } - - test("keys"); - { - redis::client::string_vector keys; - ASSERT_EQUAL(c.keys("*oo", keys), 2L); - ASSERT_EQUAL(keys.size(), 2UL); - ASSERT_EQUAL(keys[0], foo); - ASSERT_EQUAL(keys[1], goo); - } - - test("randomkey"); - { - ASSERT_GT(c.randomkey().size(), 0UL); - } - - test("rename"); - { - ASSERT_EQUAL(c.exists("foo"), true); - ASSERT_EQUAL(c.exists("doo"), false); - c.rename("foo", "doo"); - ASSERT_EQUAL(c.exists("foo"), false); - ASSERT_EQUAL(c.exists("doo"), true); - } - - test("renamenx"); - { - ASSERT_EQUAL(c.exists("doo"), true); - ASSERT_EQUAL(c.exists("foo"), false); - ASSERT_EQUAL(c.renamenx("doo", "foo"), true); - ASSERT_EQUAL(c.exists("doo"), false); - ASSERT_EQUAL(c.exists("foo"), true); - ASSERT_EQUAL(c.renamenx("goo", "foo"), false); - ASSERT_EQUAL(c.exists("foo"), true); - ASSERT_EQUAL(c.exists("goo"), true); - } - - test("dbsize"); - { - ASSERT_GT(c.dbsize(), 0L); - } - - test("expire"); - { - c.expire("goo", 1); -#ifndef NDEBUG - cerr << "please wait a few seconds.." << endl; -#endif - sleep(2); - ASSERT_EQUAL(c.exists("goo"), false); - } - - test("rpush"); - { - ASSERT_EQUAL(c.exists("list1"), false); - c.rpush("list1", "val1"); - ASSERT_EQUAL(c.llen("list1"), 1L); - ASSERT_EQUAL(c.type("list1"), redis::client::datatype_list); - c.rpush("list1", "val2"); - ASSERT_EQUAL(c.llen("list1"), 2L); - ASSERT_EQUAL(c.lindex("list1", 0), string("val1")); - ASSERT_EQUAL(c.lindex("list1", 1), string("val2")); - } - - test("lpush"); - { - c.del("list1"); - ASSERT_EQUAL(c.exists("list1"), false); - c.lpush("list1", "val1"); - ASSERT_EQUAL(c.type("list1"), redis::client::datatype_list); - ASSERT_EQUAL(c.llen("list1"), 1L); - c.lpush("list1", "val2"); - ASSERT_EQUAL(c.llen("list1"), 2L); - ASSERT_EQUAL(c.lindex("list1", 0), string("val2")); - ASSERT_EQUAL(c.lindex("list1", 1), string("val1")); - } - - test("llen"); - { - c.del("list1"); - ASSERT_EQUAL(c.exists("list1"), false); - ASSERT_EQUAL(c.llen("list1"), 0L); - c.lpush("list1", "x"); - ASSERT_EQUAL(c.llen("list1"), 1L); - c.lpush("list1", "y"); - ASSERT_EQUAL(c.llen("list1"), 2L); - } - - test("lrange"); - { - ASSERT_EQUAL(c.exists("list1"), true); - ASSERT_EQUAL(c.llen("list1"), 2L); - redis::client::string_vector vals; - ASSERT_EQUAL(c.lrange("list1", 0, -1, vals), 2L); - ASSERT_EQUAL(vals.size(), 2UL); - ASSERT_EQUAL(vals[0], string("y")); - ASSERT_EQUAL(vals[1], string("x")); - } - - test("lrange with subset of full list"); - { - ASSERT_EQUAL(c.exists("list1"), true); - ASSERT_EQUAL(c.llen("list1"), 2L); - redis::client::string_vector vals; - ASSERT_EQUAL(c.lrange("list1", 0, 1, vals), 2L); // inclusive, so entire list - ASSERT_EQUAL(vals.size(), 2UL); - ASSERT_EQUAL(vals[0], string("y")); - ASSERT_EQUAL(vals[1], string("x")); - - redis::client::string_vector vals2; - ASSERT_EQUAL(c.lrange("list1", 0, 0, vals2), 1L); // inclusive, so first item - ASSERT_EQUAL(vals2.size(), 1UL); - ASSERT_EQUAL(vals2[0], string("y")); - - redis::client::string_vector vals3; - ASSERT_EQUAL(c.lrange("list1", -1, -1, vals3), 1L); // inclusive, so first item - ASSERT_EQUAL(vals3.size(), 1UL); - ASSERT_EQUAL(vals3[0], string("x")); - } - - test("get_list"); - { - ASSERT_EQUAL(c.exists("list1"), true); - ASSERT_EQUAL(c.llen("list1"), 2L); - redis::client::string_vector vals; - ASSERT_EQUAL(c.get_list("list1", vals), 2L); - ASSERT_EQUAL(vals.size(), 2UL); - ASSERT_EQUAL(vals[0], string("y")); - ASSERT_EQUAL(vals[1], string("x")); - } - - test("ltrim"); - { - ASSERT_EQUAL(c.exists("list1"), true); - ASSERT_EQUAL(c.llen("list1"), 2L); - c.ltrim("list1", 0, 0); - ASSERT_EQUAL(c.exists("list1"), true); - ASSERT_EQUAL(c.llen("list1"), 1L); - redis::client::string_vector vals; - ASSERT_EQUAL(c.get_list("list1", vals), 1L); - ASSERT_EQUAL(vals[0], string("y")); - } - - test("lindex"); - { - ASSERT_EQUAL(c.lindex("list1", 0), string("y")); - c.rpush("list1", "x"); - ASSERT_EQUAL(c.llen("list1"), 2L); - ASSERT_EQUAL(c.lindex("list1", -1), string("x")); - ASSERT_EQUAL(c.lindex("list1", 1), string("x")); - } - - test("lset"); - { - c.lset("list1", 1, "z"); - ASSERT_EQUAL(c.lindex("list1", 1), string("z")); - ASSERT_EQUAL(c.llen("list1"), 2L); - } - - test("lrem"); - { - c.lrem("list1", 1, "z"); - ASSERT_EQUAL(c.llen("list1"), 1L); - ASSERT_EQUAL(c.lindex("list1", 0), string("y")); - - // list1 = [ y ] - ASSERT_EQUAL(c.lrem("list1", 0, "q"), 0L); - - c.rpush("list1", "z"); - c.rpush("list1", "z"); - c.rpush("list1", "z"); - c.rpush("list1", "a"); - // list1 = [ y, z, z, z, a ] - ASSERT_EQUAL(c.lrem("list1", 2, "z"), 2L); - // list1 = [ y, z, a ] - ASSERT_EQUAL(c.llen("list1"), 3L); - ASSERT_EQUAL(c.lindex("list1", 0), string("y")); - ASSERT_EQUAL(c.lindex("list1", 1), string("z")); - ASSERT_EQUAL(c.lindex("list1", 2), string("a")); - - c.rpush("list1", "z"); - // list1 = [ y, z, a, z ] - ASSERT_EQUAL(c.lrem("list1", -1, "z"), 1L); // <0 => rm R to L - // list1 = [ y, z, a ] - ASSERT_EQUAL(c.llen("list1"), 3L); - ASSERT_EQUAL(c.lindex("list1", 0), string("y")); - ASSERT_EQUAL(c.lindex("list1", 1), string("z")); - ASSERT_EQUAL(c.lindex("list1", 2), string("a")); - - // list1 = [ y, z, a ] - // try to remove 5 'a's but there's only 1 ... no problem. - ASSERT_EQUAL(c.lrem("list1", 5, "a"), 1L); - // list1 = [ y, z ] - ASSERT_EQUAL(c.llen("list1"), 2L); - ASSERT_EQUAL(c.lindex("list1", 0), string("y")); - ASSERT_EQUAL(c.lindex("list1", 1), string("z")); - } - - test("lrem_exact"); - { - // list1 = [ y, z ] - - // try to remove 5 'z's but there's only 1 ... now it's a problem. - - bool threw = false; - - try - { - c.lrem_exact("list1", 5, "z"); - } - catch (redis::value_error & e) - { - threw = true; - } - - ASSERT_EQUAL(threw, true); - - // This DOES remove the one 'z' though - // list1 = [ y ] - - ASSERT_EQUAL(c.llen("list1"), 1L); - ASSERT_EQUAL(c.lindex("list1", 0), string("y")); - } - - test("lpop"); - { - ASSERT_EQUAL(c.lpop("list1"), string("y")); - // list1 = [] - ASSERT_EQUAL(c.lpop("list1"), redis::client::missing_value); - } - - test("rpop"); - { - c.rpush("list1", "hello"); - c.rpush("list1", "world"); - ASSERT_EQUAL(c.rpop("list1"), string("world")); - ASSERT_EQUAL(c.rpop("list1"), string("hello")); - ASSERT_EQUAL(c.lpop("list1"), redis::client::missing_value); - } - - test("sadd"); - { - c.sadd("set1", "sval1"); - ASSERT_EQUAL(c.exists("set1"), true); - ASSERT_EQUAL(c.type("set1"), redis::client::datatype_set); - ASSERT_EQUAL(c.sismember("set1", "sval1"), true); - } - - test("srem"); - { - c.srem("set1", "sval1"); - ASSERT_EQUAL(c.exists("set1"), true); - ASSERT_EQUAL(c.type("set1"), redis::client::datatype_set); - ASSERT_EQUAL(c.sismember("set1", "sval1"), false); - } - - test("smove"); - { - c.sadd("set1", "hi"); - // set1 = { hi } - ASSERT_EQUAL(c.exists("set2"), false); - c.smove("set1", "set2", "hi"); - ASSERT_EQUAL(c.sismember("set1", "hi"), false); - ASSERT_EQUAL(c.sismember("set2", "hi"), true); - } - - test("scard"); - { - ASSERT_EQUAL(c.scard("set1"), 0L); - ASSERT_EQUAL(c.scard("set2"), 1L); - } - - test("sismember"); - { - // see above - } - - test("smembers"); - { - c.sadd("set2", "bye"); - redis::client::string_set members; - ASSERT_EQUAL(c.smembers("set2", members), 2L); - ASSERT_EQUAL(members.size(), 2UL); - ASSERT_NOT_EQUAL(members.find("hi"), members.end()); - ASSERT_NOT_EQUAL(members.find("bye"), members.end()); - } - - test("sinter"); - { - c.sadd("set3", "bye"); - c.sadd("set3", "bye2"); - redis::client::string_vector keys; - keys.push_back("set2"); - keys.push_back("set3"); - redis::client::string_set intersection; - ASSERT_EQUAL(c.sinter(keys, intersection), 1L); - ASSERT_EQUAL(intersection.size(), 1UL); - ASSERT_NOT_EQUAL(intersection.find("bye"), intersection.end()); - } - - test("sinterstore"); - { - c.sadd("seta", "1"); - c.sadd("seta", "2"); - c.sadd("seta", "3"); - - c.sadd("setb", "2"); - c.sadd("setb", "3"); - c.sadd("setb", "4"); - - redis::client::string_vector keys; - keys.push_back("seta"); - keys.push_back("setb"); - - ASSERT_EQUAL(c.sinterstore("setc", keys), 2L); - - redis::client::string_set members; - ASSERT_EQUAL(c.smembers("setc", members), 2L); - ASSERT_EQUAL(members.size(), 2UL); - ASSERT_NOT_EQUAL(members.find("2"), members.end()); - ASSERT_NOT_EQUAL(members.find("3"), members.end()); - } - - test("sunion"); - { - c.sadd("setd", "1"); - c.sadd("sete", "2"); - redis::client::string_vector keys; - keys.push_back("setd"); - keys.push_back("sete"); - redis::client::string_set a_union; - ASSERT_EQUAL(c.sunion(keys, a_union), 2L); - ASSERT_EQUAL(a_union.size(), 2UL); - ASSERT_NOT_EQUAL(a_union.find("1"), a_union.end()); - ASSERT_NOT_EQUAL(a_union.find("2"), a_union.end()); - } - - test("sunionstore"); - { - c.sadd("setf", "1"); - c.sadd("setg", "2"); - - redis::client::string_vector keys; - keys.push_back("setf"); - keys.push_back("setg"); - - ASSERT_EQUAL(c.sunionstore("seth", keys), 2L); - - redis::client::string_set members; - ASSERT_EQUAL(c.smembers("seth", members), 2L); - ASSERT_EQUAL(members.size(), 2UL); - ASSERT_NOT_EQUAL(members.find("1"), members.end()); - ASSERT_NOT_EQUAL(members.find("2"), members.end()); - } - - test("move"); - { - c.select(14); - ASSERT_EQUAL(c.exists("ttt"), false); - c.select(15); - c.set("ttt", "uuu"); - c.move("ttt", 14); - c.select(14); - ASSERT_EQUAL(c.exists("ttt"), true); - c.select(15); - ASSERT_EQUAL(c.exists("ttt"), false); - } - - test("move should fail since key exists already"); - { - c.select(14); - c.set("ttt", "xxx"); - c.select(15); - c.set("ttt", "uuu"); - - bool threw = false; - - try - { - c.move("ttt", 14); - } - catch (redis::protocol_error & e) - { - threw = true; - } - - ASSERT_EQUAL(threw, true); - - c.select(14); - ASSERT_EQUAL(c.exists("ttt"), true); - c.select(15); - ASSERT_EQUAL(c.exists("ttt"), true); - } - - test("sort ascending"); - { - c.sadd("sort1", "3"); - c.sadd("sort1", "2"); - c.sadd("sort1", "1"); - - redis::client::string_vector sorted; - ASSERT_EQUAL(c.sort("sort1", sorted), 3L); - ASSERT_EQUAL(sorted.size(), 3UL); - ASSERT_EQUAL(sorted[0], string("1")); - ASSERT_EQUAL(sorted[1], string("2")); - ASSERT_EQUAL(sorted[2], string("3")); - } - - test("sort descending"); - { - redis::client::string_vector sorted; - ASSERT_EQUAL(c.sort("sort1", sorted, redis::client::sort_order_descending), 3L); - ASSERT_EQUAL(sorted.size(), 3UL); - ASSERT_EQUAL(sorted[0], string("3")); - ASSERT_EQUAL(sorted[1], string("2")); - ASSERT_EQUAL(sorted[2], string("1")); - } - - test("sort with limit"); - { - // TODO - } - - test("sort lexicographically"); - { - // TODO - } - - test("sort with pattern and weights"); - { - // TODO - } - - test("save"); - { - c.save(); - } - - test("bgsave"); - { - c.bgsave(); - } - - test("lastsave"); - { - ASSERT_GT(c.lastsave(), 0L); - } - - test("shutdown"); - { -// You can test this if you really want to ... -// c.shutdown(); - } - } - catch (redis::redis_error & e) - { - cerr << "got exception: " << string(e) << endl << "FAIL" << endl; - return 1; - } - - cout << endl << "testing completed successfully" << endl; - return 0; -} diff --git a/client-libraries/erlang/.hg_archival.txt b/client-libraries/erlang/.hg_archival.txt deleted file mode 100644 index 70656b77..00000000 --- a/client-libraries/erlang/.hg_archival.txt +++ /dev/null @@ -1,2 +0,0 @@ -repo: 9e1f35ed7fdc7b3da7f5ff66a71d1975b85e2ae5 -node: 85e28ca5597e22ff1dde18ed4625f41923128993 diff --git a/client-libraries/erlang/.hgignore b/client-libraries/erlang/.hgignore deleted file mode 100644 index 6822f5cd..00000000 --- a/client-libraries/erlang/.hgignore +++ /dev/null @@ -1,2 +0,0 @@ -syntax: glob -*.beam \ No newline at end of file diff --git a/client-libraries/erlang/LICENSE b/client-libraries/erlang/LICENSE deleted file mode 100644 index af3d5c8f..00000000 --- a/client-libraries/erlang/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2009 -adroll.com -Valentino Volonghi - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/client-libraries/erlang/Makefile b/client-libraries/erlang/Makefile deleted file mode 100644 index 7c7a7436..00000000 --- a/client-libraries/erlang/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -LIBDIR=`erl -eval 'io:format("~s~n", [code:lib_dir()])' -s init stop -noshell` - -all: - mkdir -p ebin/ - (cd src;$(MAKE)) - (cd test;$(MAKE)) - -clean: clean_tests - (cd src;$(MAKE) clean) - rm -rf erl_crash.dump *.beam - -clean_tests: - (cd test;$(MAKE) clean) - rm -rf erl_crash.dump *.beam - -test: clean - mkdir -p ebin/ - (cd src;$(MAKE)) - (cd test;$(MAKE)) - (cd test;$(MAKE) test) - -testrun: all - mkdir -p ebin/ - (cd test;$(MAKE) test) - -install: all - mkdir -p ${LIBDIR}/erldis-0.0.1/{ebin,include} - for i in ebin/*.beam; do install $$i $(LIBDIR)/erldis-0.0.1/$$i ; done - for i in include/*.hrl; do install $$i $(LIBDIR)/erldis-0.0.1/$$i ; done diff --git a/client-libraries/erlang/include/erldis.hrl b/client-libraries/erlang/include/erldis.hrl deleted file mode 100644 index 7ef43b85..00000000 --- a/client-libraries/erlang/include/erldis.hrl +++ /dev/null @@ -1 +0,0 @@ --record(redis, {socket,buffer=[],reply_caller,calls=0,remaining=0,pstate=empty,results=[]}). diff --git a/client-libraries/erlang/src/Makefile b/client-libraries/erlang/src/Makefile deleted file mode 100644 index c56f980b..00000000 --- a/client-libraries/erlang/src/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../support/include.mk - -all: $(EBIN_FILES) - -debug: - $(MAKE) DEBUG=-DDEBUG - -clean: - rm -rf $(EBIN_FILES) erl_crash.dump diff --git a/client-libraries/erlang/src/client.erl b/client-libraries/erlang/src/client.erl deleted file mode 100644 index 734a9d3e..00000000 --- a/client-libraries/erlang/src/client.erl +++ /dev/null @@ -1,250 +0,0 @@ --module(client). --behavior(gen_server). - --export([start/1, start/2, connect/1, connect/2, asend/2, send/3, send/2, - disconnect/1, ssend/3, str/1, format/1, sformat/1, ssend/2, - get_all_results/1]). --export([init/1, handle_call/3, handle_cast/2, - handle_info/2, terminate/2, code_change/3]). - --include("erldis.hrl"). - --define(EOL, "\r\n"). - - -%% Helpers -str(X) when is_list(X) -> - X; -str(X) when is_atom(X) -> - atom_to_list(X); -str(X) when is_binary(X) -> - binary_to_list(X); -str(X) when is_integer(X) -> - integer_to_list(X); -str(X) when is_float(X) -> - float_to_list(X). - -format([], Result) -> - string:join(lists:reverse(Result), ?EOL); -format([Line|Rest], Result) -> - JoinedLine = string:join([str(X) || X <- Line], " "), - format(Rest, [JoinedLine|Result]). - -format(Lines) -> - format(Lines, []). -sformat(Line) -> - format([Line], []). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -%% Exported API -start(Host) -> - connect(Host). -start(Host, Port) -> - connect(Host, Port). - -connect(Host) -> - connect(Host, 6379). -connect(Host, Port) -> - gen_server:start_link(?MODULE, [Host, Port], []). - -% This is the simple send with a single row of commands -ssend(Client, Cmd) -> ssend(Client, Cmd, []). -ssend(Client, Cmd, Args) -> - gen_server:cast(Client, {send, sformat([Cmd|Args])}). - -% This is the complete send with multiple rows -send(Client, Cmd) -> send(Client, Cmd, []). -send(Client, Cmd, Args) -> - gen_server:cast(Client, {send, - string:join([str(Cmd), format(Args)], " ")}). - -% asynchronous send, we don't care about the result. -asend(Client, Cmd) -> - gen_server:cast(Client, {asend, Cmd}). -disconnect(Client) -> - gen_server:call(Client, disconnect). - -get_all_results(Client) -> - gen_server:call(Client, get_all_results). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - -%% gen_server callbacks -init([Host, Port]) -> - process_flag(trap_exit, true), - ConnectOptions = [list, {active, once}, {packet, line}, {nodelay, true}], - case gen_tcp:connect(Host, Port, ConnectOptions) of - {error, Why} -> - {error, {socket_error, Why}}; - {ok, Socket} -> - {ok, #redis{socket=Socket, calls=0}} - end. - -handle_call({send, Cmd}, From, State) -> - gen_tcp:send(State#redis.socket, [Cmd|?EOL]), - {noreply, State#redis{reply_caller=fun(V) -> gen_server:reply(From, lists:nth(1, V)) end, - remaining=1}}; - -handle_call(disconnect, _From, State) -> - {stop, normal, ok, State}; -handle_call(get_all_results, From, State) -> - case State#redis.calls of - 0 -> - % answers came earlier than we could start listening... - % Very unlikely but totally possible. - {reply, lists:reverse(State#redis.results), State#redis{results=[], calls=0}}; - _ -> - % We are here earlier than results came, so just make - % ourselves wait until stuff is ready. - {noreply, State#redis{reply_caller=fun(V) -> gen_server:reply(From, V) end}} - end; -handle_call(_, _From, State) -> {noreply, State}. - - -handle_cast({asend, Cmd}, State) -> - gen_tcp:send(State#redis.socket, [Cmd|?EOL]), - {noreply, State}; -handle_cast({send, Cmd}, State=#redis{remaining=Remaining, calls=Calls}) -> - % how we should do here: if remaining is already != 0 then we'll - % let handle_info take care of keeping track how many remaining things - % there are. If instead it's 0 we are the first call so let's just - % do it. - gen_tcp:send(State#redis.socket, [Cmd|?EOL]), - case Remaining of - 0 -> - {noreply, State#redis{remaining=1, calls=1}}; - _ -> - {noreply, State#redis{calls=Calls+1}} - end; -handle_cast(_Msg, State) -> {noreply, State}. - - -trim2({ok, S}) -> - string:substr(S, 1, length(S)-2); -trim2(S) -> - trim2({ok, S}). - -% This function helps with pipelining by creating a pubsub system with -% the caller. The caller could submit multiple requests and not listen -% until later when all or some of them have been answered, at that -% point 2 conditions can be true: -% 1) We still need to process more things in this response chain -% 2) We are finished. -% -% And these 2 are together with the following 2: -% 1) We called get_all_results before the end of the responses. -% 2) We called get_all_results after the end of the responses. -% -% If there's stuff missing in the chain we just push results, this also -% happens when there's nothing more to process BUT we haven't requested -% results yet. -% In case we have requested results: if requests are not yet ready we -% just push them, otherwise we finally answer all of them. -save_or_reply(Result, State=#redis{calls=Calls, results=Results, reply_caller=ReplyCaller}) -> - case Calls of - 0 -> - % We don't reverse results here because if all the requests - % come in and then we submit another one, if we reverse - % they will be scrambled in the results field of the record. - % instead if we wait just before we reply they will be - % in the right order. - FullResults = [Result|Results], - NewState = case ReplyCaller of - undefined -> - State#redis{results=FullResults}; - _ -> - ReplyCaller(lists:reverse(FullResults)), - State#redis{results=[]} - end, - NewState#redis{remaining=0, pstate=empty, - reply_caller=undefined, buffer=[], - calls=0}; - _ -> - State#redis{results=[Result|Results], remaining=1, pstate=empty, buffer=[], calls=Calls} - - end. - -handle_info({tcp, Socket, Data}, State=#redis{calls=Calls}) -> - Trimmed = trim2(Data), - NewState = case {State#redis.remaining-1, proto:parse(State#redis.pstate, Trimmed)} of - % This line contained an error code. Next line will hold - % The error message that we will parse. - {0, error} -> - State#redis{remaining=1, pstate=error}; - - % The stateful parser just started and tells us the number - % of results that we will have to parse for those calls - % where more than one result is expected. The next - % line will start with the first item to read. - {0, {hold, Remaining}} -> - case Remaining of - nil -> - save_or_reply(nil, State#redis{calls=Calls-1}); - _ -> - % Reset the remaining value to the number of results that we need to parse. - State#redis{remaining=Remaining, pstate=read} - end; - - % We either had only one thing to read or we are at the - % end of the stuff that we need to read. either way - % just pack up the buffer and send. - {0, {read, NBytes}} -> - CurrentValue = case NBytes of - nil -> - nil; - _ -> - inet:setopts(Socket, [{packet, 0}]), % go into raw mode to read bytes - CV = trim2(gen_tcp:recv(Socket, NBytes+2)), % also consume the \r\n - inet:setopts(Socket, [{packet, line}]), % go back to line mode - CV - end, - OldBuffer = State#redis.buffer, - case OldBuffer of - [] -> - save_or_reply(CurrentValue, State#redis{calls=Calls-1}); - _ -> - save_or_reply(lists:reverse([CurrentValue|OldBuffer]), State#redis{calls=Calls-1}) - end; - - % The stateful parser tells us to read some bytes - {N, {read, NBytes}} -> - % annoying repetition... I should reuse this code. - CurrentValue = case NBytes of - nil -> - nil; - _ -> - inet:setopts(Socket, [{packet, 0}]), % go into raw mode to read bytes - CV = trim2(gen_tcp:recv(Socket, NBytes+2)), % also consume the \r\n - inet:setopts(Socket, [{packet, line}]), % go back to line mode - CV - end, - OldBuffer = State#redis.buffer, - State#redis{remaining=N, buffer=[CurrentValue|OldBuffer], pstate=read}; - - - % Simple return values contained in a single line - {0, Value} -> - save_or_reply(Value, State#redis{calls=Calls-1}) - - end, - inet:setopts(Socket, [{active, once}]), - {noreply, NewState}; -handle_info(_Info, State) -> {noreply, State}. - - -terminate(_Reason, State) -> - case State#redis.socket of - undefined -> - pass; - Socket -> - gen_tcp:close(Socket) - end, - ok. - - -code_change(_OldVsn, State, _Extra) -> {ok, State}. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - diff --git a/client-libraries/erlang/src/erldis.erl b/client-libraries/erlang/src/erldis.erl deleted file mode 100644 index 80d78eae..00000000 --- a/client-libraries/erlang/src/erldis.erl +++ /dev/null @@ -1,112 +0,0 @@ --module(erldis). - --compile(export_all). --define(EOL, "\r\n"). - -%% helpers -flatten({error, Message}) -> - {error, Message}; -flatten(List) when is_list(List)-> - lists:flatten(List). - -%% exposed API -connect(Host) -> - client:connect(Host). - -quit(Client) -> - client:asend(Client, "QUIT"), - client:disconnect(Client). - -%% Commands operating on string values -internal_set_like(Client, Command, Key, Value) -> - client:send(Client, Command, [[Key, length(Value)], - [Value]]). - -get_all_results(Client) -> client:get_all_results(Client). - -auth(Client, Password) -> client:ssend(Client, auth, [Password]). - -set(Client, Key, Value) -> internal_set_like(Client, set, Key, Value). -get(Client, Key) -> client:ssend(Client, get, [Key]). -getset(Client, Key, Value) -> internal_set_like(Client, getset, Key, Value). -mget(Client, Keys) -> client:ssend(Client, mget, Keys). -setnx(Client, Key, Value) -> internal_set_like(Client, setnx, Key, Value). -incr(Client, Key) -> client:ssend(Client, incr, [Key]). -incrby(Client, Key, By) -> client:ssend(Client, incrby, [Key, By]). -decr(Client, Key) -> client:ssend(Client, decr, [Key]). -decrby(Client, Key, By) -> client:ssend(Client, decrby, [Key, By]). - - - -%% Commands operating on every value -exists(Client, Key) -> client:ssend(Client, exists, [Key]). -del(Client, Key) -> client:ssend(Client, del, [Key]). -type(Client, Key) -> client:ssend(Client, type, [Key]). -keys(Client, Pattern) -> client:ssend(Client, keys, [Pattern]). -randomkey(Client, Key) -> client:ssend(Client, randomkey, [Key]). -rename(Client, OldKey, NewKey) -> client:ssend(Client, rename, [OldKey, NewKey]). -renamenx(Client, OldKey, NewKey) -> client:ssend(Client, renamenx, [OldKey, NewKey]). -dbsize(Client) -> client:ssend(Client, dbsize). -expire(Client, Key, Seconds) -> client:ssend(Client, expire, [Key, Seconds]). -ttl(Client, Key) -> client:ssend(Client, ttl, [Key]). - - - -%% Commands operating on lists -rpush(Client, Key, Value) -> internal_set_like(Client, rpush, Key, Value). -lpush(Client, Key, Value) -> internal_set_like(Client, lpush, Key, Value). -llen(Client, Key) -> client:ssend(Client, llen, [Key]). -lrange(Client, Key, Start, End) -> client:ssend(Client, lrange, [Key, Start, End]). -ltrim(Client, Key, Start, End) -> client:ssend(Client, ltrim, [Key, Start, End]). -lindex(Client, Key, Index) -> client:ssend(Client, lindex, [Key, Index]). -lset(Client, Key, Index, Value) -> - client:send(Client, lset, [[Key, Index, length(Value)], - [Value]]). -lrem(Client, Key, Number, Value) -> - client:send(Client, lrem, [[Key, Number, length(Value)], - [Value]]). -lpop(Client, Key) -> client:ssend(Client, lpop, [Key]). -rpop(Client, Key) -> client:ssend(Client, rpop, [Key]). - - - -%% Commands operating on sets -sadd(Client, Key, Value) -> internal_set_like(Client, sadd, Key, Value). -srem(Client, Key, Value) -> internal_set_like(Client, srem, Key, Value). -smove(Client, SrcKey, DstKey, Member) -> client:send(Client, smove, [[SrcKey, DstKey, length(Member)], - [Member]]). -scard(Client, Key) -> client:ssend(Client, scard, [Key]). -sismember(Client, Key, Value) -> internal_set_like(Client, sismember, Key, Value). -sintersect(Client, Keys) -> client:ssend(Client, sinter, Keys). -sinter(Client, Keys) -> sintersect(Client, Keys). -sinterstore(Client, DstKey, Keys) -> client:ssend(Client, sinterstore, [DstKey|Keys]). -sunion(Client, Keys) -> client:ssend(Client, sunion, Keys). -sunionstore(Client, DstKey, Keys) -> client:ssend(Client, sunionstore, [DstKey|Keys]). -sdiff(Client, Keys) -> client:ssend(Client, sdiff, Keys). -sdiffstore(Client, DstKey, Keys) -> client:ssend(Client, sdiffstore, [DstKey|Keys]). -smembers(Client, Key) -> client:ssend(Client, smembers, [Key]). - - -%% Multiple DB commands -select(Client, Index) -> client:ssend(Client, select, [Index]). -move(Client, Key, DBIndex) -> client:ssend(Client, move, [Key, DBIndex]). -flushdb(Client) -> client:ssend(Client, flushdb). -flushall(Client) -> client:ssend(Client, flushall). - - -%% Commands operating on both lists and sets -sort(Client, Key) -> client:ssend(Client, sort, [Key]). -sort(Client, Key, Extra) -> client:ssend(Client, sort, [Key, Extra]). - - -%% Persistence control commands -save(Client) -> client:ssend(Client, save). -bgsave(Client) -> client:ssend(Client, bgsave). -lastsave(Client) -> client:ssend(Client, lastsave). -shutdown(Client) -> client:asend(Client, shutdown). - - -%% Remote server control commands -info(Client) -> client:ssend(Client, info). -slaveof(Client, Host, Port) -> client:ssend(Client, slaveof, [Host, Port]). -slaveof(Client) -> client:ssend(Client, slaveof, ["no one"]). diff --git a/client-libraries/erlang/src/proto.erl b/client-libraries/erlang/src/proto.erl deleted file mode 100644 index 1de6da8c..00000000 --- a/client-libraries/erlang/src/proto.erl +++ /dev/null @@ -1,38 +0,0 @@ --module(proto). - --export([parse/2]). - -parse(empty, "+OK") -> - ok; -parse(empty, "+PONG") -> - pong; -parse(empty, ":0") -> - false; -parse(empty, ":1") -> - true; -parse(empty, "-" ++ Message) -> - {error, Message}; -parse(empty, "$-1") -> - {read, nil}; -parse(empty, "*-1") -> - {hold, nil}; -parse(empty, "$" ++ BulkSize) -> - {read, list_to_integer(BulkSize)}; -parse(read, "$" ++ BulkSize) -> - {read, list_to_integer(BulkSize)}; -parse(empty, "*" ++ MultiBulkSize) -> - {hold, list_to_integer(MultiBulkSize)}; -parse(empty, Message) -> - convert(Message). - -convert(":" ++ Message) -> - list_to_integer(Message); -% in case the message is not OK or PONG it's a -% real value that we don't know how to convert -% to an atom, so just pass it as is and remove -% the + -convert("+" ++ Message) -> - Message; -convert(Message) -> - Message. - diff --git a/client-libraries/erlang/support/include.mk b/client-libraries/erlang/support/include.mk deleted file mode 100644 index f289aed0..00000000 --- a/client-libraries/erlang/support/include.mk +++ /dev/null @@ -1,51 +0,0 @@ -## -*- makefile -*- - -ERL := erl -ERLC := $(ERL)c - -INCLUDE_DIRS := ../include $(wildcard ../deps/*/include) -EBIN_DIRS := $(wildcard ../deps/*/ebin) -ERLC_FLAGS := -W $(INCLUDE_DIRS:../%=-I ../%) $(EBIN_DIRS:%=-pa %) - -ifndef no_debug_info - ERLC_FLAGS += +debug_info -endif - -ifdef debug - ERLC_FLAGS += -Ddebug -endif - -ifdef test - ERLC_FLAGS += -DTEST -endif - -EBIN_DIR := ../ebin -DOC_DIR := ../doc -EMULATOR := beam - -ERL_TEMPLATE := $(wildcard *.et) -ERL_SOURCES := $(wildcard *.erl) -ERL_HEADERS := $(wildcard *.hrl) $(wildcard ../include/*.hrl) -ERL_OBJECTS := $(ERL_SOURCES:%.erl=$(EBIN_DIR)/%.beam) -ERL_TEMPLATES := $(ERL_TEMPLATE:%.et=$(EBIN_DIR)/%.beam) -ERL_OBJECTS_LOCAL := $(ERL_SOURCES:%.erl=./%.$(EMULATOR)) -APP_FILES := $(wildcard *.app) -EBIN_FILES = $(ERL_OBJECTS) $(APP_FILES:%.app=../ebin/%.app) $(ERL_TEMPLATES) -MODULES = $(ERL_SOURCES:%.erl=%) - -../ebin/%.app: %.app - cp $< $@ - -$(EBIN_DIR)/%.$(EMULATOR): %.erl - $(ERLC) $(ERLC_FLAGS) -o $(EBIN_DIR) $< - -$(EBIN_DIR)/%.$(EMULATOR): %.et - $(ERL) -noshell -pa ../../elib/erltl/ebin/ -eval "erltl:compile(atom_to_list('$<'), [{outdir, \"../ebin\"}, report_errors, report_warnings, nowarn_unused_vars])." -s init stop - -./%.$(EMULATOR): %.erl - $(ERLC) $(ERLC_FLAGS) -o . $< - -$(DOC_DIR)/%.html: %.erl - $(ERL) -noshell -run edoc file $< -run init stop - mv *.html $(DOC_DIR) - diff --git a/client-libraries/erlang/test/Makefile b/client-libraries/erlang/test/Makefile deleted file mode 100644 index b87cc9b0..00000000 --- a/client-libraries/erlang/test/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../support/include.mk - -all: $(EBIN_FILES) - -clean: - rm -rf $(EBIN_FILES) erl_crash.dump - -test: $(MODULES) - -./$(MODULES): - @echo "Running tests for $@" - erl -pa ../ebin -run $@ test -run init stop -noshell diff --git a/client-libraries/erlang/test/erldis_tests.erl b/client-libraries/erlang/test/erldis_tests.erl deleted file mode 100644 index 4ebdd24a..00000000 --- a/client-libraries/erlang/test/erldis_tests.erl +++ /dev/null @@ -1,91 +0,0 @@ --module(erldis_tests). - --include_lib("eunit/include/eunit.hrl"). --include("erldis.hrl"). - -quit_test() -> - {ok, Client} = erldis:connect("localhost"), - ok = erldis:quit(Client), - false = is_process_alive(Client). - -utils_test() -> - ?assertEqual(client:str(1), "1"), - ?assertEqual(client:str(atom), "atom"), - ?assertEqual(client:format([[1, 2, 3]]), "1 2 3"), - ?assertEqual(client:format([[1,2,3], [4,5,6]]), "1 2 3\r\n4 5 6"). - -basic_test() -> - {ok, Client} = erldis:connect("localhost"), - erldis:flushall(Client), - erldis:get(Client, "pippo"), - erldis:set(Client, "hello", "kitty!"), - erldis:setnx(Client, "foo", "bar"), - erldis:setnx(Client, "foo", "bar"), - [ok, nil, ok, true, false] = erldis:get_all_results(Client), - - erldis:exists(Client, "hello"), - erldis:exists(Client, "foo"), - erldis:get(Client, "foo"), - erldis:mget(Client, ["hello", "foo"]), - erldis:del(Client, "hello"), - erldis:del(Client, "foo"), - erldis:exists(Client, "hello"), - erldis:exists(Client, "foo"), - [true, true, "bar", ["kitty!", "bar"], true, true, false, false] = erldis:get_all_results(Client), - - erldis:set(Client, "pippo", "pluto"), - erldis:sadd(Client, "pippo", "paperino"), - % foo doesn't exist, the result will be nil - erldis:lrange(Client, "foo", 1, 2), - erldis:lrange(Client, "pippo", 1, 2), - [ok, - {error, "ERR Operation against a key holding the wrong kind of value"}, - nil, - {error, "ERR Operation against a key holding the wrong kind of value"} - ] = erldis:get_all_results(Client), - erldis:del(Client, "pippo"), - [true] = erldis:get_all_results(Client), - - erldis:rpush(Client, "a_list", "1"), - erldis:rpush(Client, "a_list", "2"), - erldis:rpush(Client, "a_list", "3"), - erldis:rpush(Client, "a_list", "1"), - erldis:lrem(Client, "a_list", 1, "1"), - erldis:lrange(Client, "a_list", 0, 2), - [ok, ok, ok, ok, true, ["2", "3", "1"]] = erldis:get_all_results(Client), - - erldis:sort(Client, "a_list"), - erldis:sort(Client, "a_list", "DESC"), - erldis:lrange(Client, "a_list", 0, 2), - erldis:sort(Client, "a_list", "LIMIT 0 2 ASC"), - [["1", "2", "3"], ["3", "2", "1"], ["2", "3", "1"], - ["1", "2"]] = erldis:get_all_results(Client), - - ok = erldis:quit(Client). - - - -% inline_tests(Client) -> -% [?_assertMatch(ok, erldis:set(Client, "hello", "kitty!")), -% ?_assertMatch(false, erldis:setnx(Client, "hello", "kitty!")), -% ?_assertMatch(true, erldis:exists(Client, "hello")), -% ?_assertMatch(true, erldis:del(Client, "hello")), -% ?_assertMatch(false, erldis:exists(Client, "hello")), -% -% ?_assertMatch(true, erldis:setnx(Client, "hello", "kitty!")), -% ?_assertMatch(true, erldis:exists(Client, "hello")), -% ?_assertMatch("kitty!", erldis:get(Client, "hello")), -% ?_assertMatch(true, erldis:del(Client, "hello")), -% -% -% ?_assertMatch(1, erldis:incr(Client, "pippo")) -% ,?_assertMatch(2, erldis:incr(Client, "pippo")) -% ,?_assertMatch(1, erldis:decr(Client, "pippo")) -% ,?_assertMatch(0, erldis:decr(Client, "pippo")) -% ,?_assertMatch(-1, erldis:decr(Client, "pippo")) -% -% ,?_assertMatch(6, erldis:incrby(Client, "pippo", 7)) -% ,?_assertMatch(2, erldis:decrby(Client, "pippo", 4)) -% ,?_assertMatch(-2, erldis:decrby(Client, "pippo", 4)) -% ,?_assertMatch(true, erldis:del(Client, "pippo")) -% ]. diff --git a/client-libraries/erlang/test/proto_tests.erl b/client-libraries/erlang/test/proto_tests.erl deleted file mode 100644 index a07f9313..00000000 --- a/client-libraries/erlang/test/proto_tests.erl +++ /dev/null @@ -1,10 +0,0 @@ --module(proto_tests). - --include_lib("eunit/include/eunit.hrl"). - -parse_test() -> - ok = proto:parse(empty, "+OK"), - pong = proto:parse(empty, "+PONG"), - false = proto:parse(empty, ":0"), - true = proto:parse(empty, ":1"), - {error, "1"} = proto:parse(empty, "-1"). diff --git a/client-libraries/lua/LICENSE b/client-libraries/lua/LICENSE deleted file mode 100644 index 2da03271..00000000 --- a/client-libraries/lua/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2009 -Daniele Alessandri -http://www.clorophilla.net/ - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/client-libraries/lua/README b/client-libraries/lua/README deleted file mode 100644 index 98a55348..00000000 --- a/client-libraries/lua/README +++ /dev/null @@ -1,4 +0,0 @@ -redis-lua -------------------------------------------------------------------------------- - -A Lua client library for the redis key value storage system. \ No newline at end of file diff --git a/client-libraries/lua/redis.lua b/client-libraries/lua/redis.lua deleted file mode 100644 index 1e85ffd8..00000000 --- a/client-libraries/lua/redis.lua +++ /dev/null @@ -1,347 +0,0 @@ -local _G = _G -local require, error, type, print = require, error, type, print -local table, pairs, tostring, tonumber = table, pairs, tostring, tonumber - -module('Redis') - -local socket = require('socket') -- requires LuaSocket as a dependency - -local redis_commands = {} -local network, request, response, utils = {}, {}, {}, {}, {} - -local protocol = { newline = '\r\n', ok = 'OK', err = 'ERR', null = 'nil' } - -local function toboolean(value) return value == 1 end - -local function load_methods(proto, methods) - local redis = _G.setmetatable ({}, _G.getmetatable(proto)) - for i, v in pairs(proto) do redis[i] = v end - - for i, v in pairs(methods) do redis[i] = v end - return redis -end - --- ############################################################################ - -function network.write(client, buffer) - local _, err = client.socket:send(buffer) - if err then error(err) end -end - -function network.read(client, len) - if len == nil then len = '*l' end - local line, err = client.socket:receive(len) - if not err then return line else error('Connection error: ' .. err) end -end - --- ############################################################################ - -function response.read(client) - local res = network.read(client) - local prefix = res:sub(1, -#res) - local response_handler = protocol.prefixes[prefix] - - if not response_handler then - error("Unknown response prefix: " .. prefix) - else - return response_handler(client, res) - end -end - -function response.status(client, data) - local sub = data:sub(2) - if sub == protocol.ok then return true else return sub end -end - -function response.error(client, data) - local err_line = data:sub(2) - - if err_line:sub(1, 3) == protocol.err then - error("Redis error: " .. err_line:sub(5)) - else - error("Redis error: " .. err_line) - end -end - -function response.bulk(client, data) - local str = data:sub(2) - local len = tonumber(str) - - if not len then - error('Cannot parse ' .. str .. ' as data length.') - else - if len == -1 then return nil end - local next_chunk = network.read(client, len + 2) - return next_chunk:sub(1, -3); - end -end - -function response.multibulk(client, data) - local str = data:sub(2) - - -- TODO: add a check if the returned value is indeed a number - local list_count = tonumber(str) - - if list_count == -1 then - return nil - else - local list = {} - - if list_count > 0 then - for i = 1, list_count do - table.insert(list, i, response.bulk(client, network.read(client))) - end - end - - return list - end -end - -function response.integer(client, data) - local res = data:sub(2) - local number = tonumber(res) - - if not number then - if res == protocol.null then - return nil - else - error('Cannot parse ' .. res .. ' as numeric response.') - end - end - - return number -end - -protocol.prefixes = { - ['+'] = response.status, - ['-'] = response.error, - ['$'] = response.bulk, - ['*'] = response.multibulk, - [':'] = response.integer, -} - --- ############################################################################ - -function request.raw(client, buffer) - -- TODO: optimize - local bufferType = type(buffer) - - if bufferType == 'string' then - network.write(client, buffer) - elseif bufferType == 'table' then - network.write(client, table.concat(buffer)) - else - error('Argument error: ' .. bufferType) - end - - return response.read(client) -end - -function request.inline(client, command, ...) - if arg.n == 0 then - network.write(client, command .. protocol.newline) - else - local arguments = arg - arguments.n = nil - - if #arguments > 0 then - arguments = table.concat(arguments, ' ') - else - arguments = '' - end - - network.write(client, command .. ' ' .. arguments .. protocol.newline) - end - - return response.read(client) -end - -function request.bulk(client, command, ...) - local arguments = arg - local data = tostring(table.remove(arguments)) - arguments.n = nil - - -- TODO: optimize - if #arguments > 0 then - arguments = table.concat(arguments, ' ') - else - arguments = '' - end - - return request.raw(client, { - command, ' ', arguments, ' ', #data, protocol.newline, data, protocol.newline - }) -end - --- ############################################################################ - -local function custom(command, send, parse) - return function(self, ...) - local reply = send(self, command, ...) - if parse then - return parse(reply, command, ...) - else - return reply - end - end -end - -local function bulk(command, reader) - return custom(command, request.bulk, reader) -end - -local function inline(command, reader) - return custom(command, request.inline, reader) -end - --- ############################################################################ - -function connect(host, port) - local client_socket = socket.connect(host, port) - if not client_socket then - error('Could not connect to ' .. host .. ':' .. port) - end - - local redis_client = { - socket = client_socket, - raw_cmd = function(self, buffer) - return request.raw(self, buffer .. protocol.newline) - end, - } - - return load_methods(redis_client, redis_commands) -end - --- ############################################################################ - -redis_commands = { - -- miscellaneous commands - ping = inline('PING', - function(response) - if response == 'PONG' then return true else return false end - end - ), - echo = bulk('ECHO'), - -- TODO: the server returns an empty -ERR on authentication failure - auth = inline('AUTH'), - - -- connection handling - quit = custom('QUIT', - function(client, command) - -- let's fire and forget! the connection is closed as soon - -- as the QUIT command is received by the server. - network.write(client, command .. protocol.newline) - end - ), - - -- commands operating on string values - set = bulk('SET'), - set_preserve = bulk('SETNX', toboolean), - get = inline('GET'), - get_multiple = inline('MGET'), - get_set = bulk('GETSET'), - increment = inline('INCR'), - increment_by = inline('INCRBY'), - decrement = inline('DECR'), - decrement_by = inline('DECRBY'), - exists = inline('EXISTS', toboolean), - delete = inline('DEL', toboolean), - type = inline('TYPE'), - - -- commands operating on the key space - keys = inline('KEYS', - function(response) - local keys = {} - response:gsub('%w+', function(key) - table.insert(keys, key) - end) - return keys - end - ), - random_key = inline('RANDOMKEY'), - rename = inline('RENAME'), - rename_preserve = inline('RENAMENX'), - expire = inline('EXPIRE', toboolean), - database_size = inline('DBSIZE'), - time_to_live = inline('TTL'), - - -- commands operating on lists - push_tail = bulk('RPUSH'), - push_head = bulk('LPUSH'), - list_length = inline('LLEN'), - list_range = inline('LRANGE'), - list_trim = inline('LTRIM'), - list_index = inline('LINDEX'), - list_set = bulk('LSET'), - list_remove = bulk('LREM'), - pop_first = inline('LPOP'), - pop_last = inline('RPOP'), - - -- commands operating on sets - set_add = bulk('SADD'), - set_remove = bulk('SREM'), - set_move = bulk('SMOVE'), - set_cardinality = inline('SCARD'), - set_is_member = inline('SISMEMBER'), - set_intersection = inline('SINTER'), - set_intersection_store = inline('SINTERSTORE'), - set_union = inline('SUNION'), - set_union_store = inline('SUNIONSTORE'), - set_diff = inline('SDIFF'), - set_diff_store = inline('SDIFFSTORE'), - set_members = inline('SMEMBERS'), - - -- multiple databases handling commands - select_database = inline('SELECT'), - move_key = inline('MOVE'), - flush_database = inline('FLUSHDB'), - flush_databases = inline('FLUSHALL'), - - -- sorting - --[[ - TODO: should we pass sort parameters as a table? e.g: - params = { - by = 'weight_*', - get = 'object_*', - limit = { 0, 10 }, - sort = { 'desc', 'alpha' } - } - --]] - sort = custom('SORT', - function(client, command, params) - -- TODO: here we will put the logic needed to serialize the params - -- table to be sent as the argument of the SORT command. - return request.inline(client, command, params) - end - ), - - -- persistence control commands - save = inline('SAVE'), - background_save = inline('BGSAVE'), - last_save = inline('LASTSAVE'), - shutdown = custom('SHUTDOWN', - function(client, command) - -- let's fire and forget! the connection is closed as soon - -- as the SHUTDOWN command is received by the server. - network.write(client, command .. protocol.newline) - end - ), - - -- remote server control commands - info = inline('INFO', - function(response) - local info = {} - response:gsub('([^\r\n]*)\r\n', function(kv) - local k,v = kv:match(('([^:]*):([^:]*)'):rep(1)) - info[k] = v - end) - return info - end - ), - slave_of = inline('SLAVEOF'), - slave_of_no_one = custom('SLAVEOF', - function(client, command) - return request.inline(client, command, 'NO ONE') - end - ), -} diff --git a/client-libraries/perl/Changes b/client-libraries/perl/Changes deleted file mode 100644 index 876e71d5..00000000 --- a/client-libraries/perl/Changes +++ /dev/null @@ -1,8 +0,0 @@ -Revision history for Redis - -0.01 Sun Mar 22 19:02:17 CET 2009 - First version, tracking git://github.com/antirez/redis - -0.08 Tue Mar 24 22:38:59 CET 2009 - This version supports new protocol introduced in beta 8 - Version bump to be in-sync with Redis version diff --git a/client-libraries/perl/MANIFEST b/client-libraries/perl/MANIFEST deleted file mode 100644 index 80bd1119..00000000 --- a/client-libraries/perl/MANIFEST +++ /dev/null @@ -1,8 +0,0 @@ -Changes -MANIFEST -Makefile.PL -README -lib/Redis.pm -t/00-load.t -t/pod-coverage.t -t/pod.t diff --git a/client-libraries/perl/Makefile.PL b/client-libraries/perl/Makefile.PL deleted file mode 100644 index fb2edf52..00000000 --- a/client-libraries/perl/Makefile.PL +++ /dev/null @@ -1,19 +0,0 @@ -use strict; -use warnings; -use ExtUtils::MakeMaker; - -WriteMakefile( - NAME => 'Redis', - AUTHOR => 'Dobrica Pavlinusic ', - VERSION_FROM => 'lib/Redis.pm', - ABSTRACT_FROM => 'lib/Redis.pm', - PL_FILES => {}, - PREREQ_PM => { - 'Test::More' => 0, - 'IO::Socket::INET' => 0, - 'Data::Dump' => 0, - 'Carp' => 0, - }, - dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, - clean => { FILES => 'Redis-*' }, -); diff --git a/client-libraries/perl/README b/client-libraries/perl/README deleted file mode 100644 index a386e912..00000000 --- a/client-libraries/perl/README +++ /dev/null @@ -1,43 +0,0 @@ -Redis - -Perl binding for Redis database which is in-memory hash store with -support for scalars, arrays and sets and disk persistence. - -INSTALLATION - -To install this module, run the following commands: - - perl Makefile.PL - make - make test - make install - -SUPPORT AND DOCUMENTATION - -After installing, you can find documentation for this module with the -perldoc command. - - perldoc Redis - -You can also look for information at: - - RT, CPAN's request tracker - http://rt.cpan.org/NoAuth/Bugs.html?Dist=Redis - - AnnoCPAN, Annotated CPAN documentation - http://annocpan.org/dist/Redis - - CPAN Ratings - http://cpanratings.perl.org/d/Redis - - Search CPAN - http://search.cpan.org/dist/Redis - - -COPYRIGHT AND LICENCE - -Copyright (C) 2009 Dobrica Pavlinusic - -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. - diff --git a/client-libraries/perl/lib/Redis.pm b/client-libraries/perl/lib/Redis.pm deleted file mode 100644 index 6a6d2789..00000000 --- a/client-libraries/perl/lib/Redis.pm +++ /dev/null @@ -1,422 +0,0 @@ -package Redis; - -use warnings; -use strict; - -use IO::Socket::INET; -use Data::Dump qw/dump/; -use Carp qw/confess/; - -=head1 NAME - -Redis - perl binding for Redis database - -=cut - -our $VERSION = '0.08'; - - -=head1 DESCRIPTION - -Pure perl bindings for L - -This version support git version 0.08 of Redis available at - -L - -This documentation -lists commands which are exercised in test suite, but -additinal commands will work correctly since protocol -specifies enough information to support almost all commands -with same peace of code with a little help of C. - -=head1 FUNCTIONS - -=head2 new - - my $r = Redis->new; - -=cut - -our $debug = $ENV{REDIS} || 0; - -our $sock; -my $server = '127.0.0.1:6379'; - -sub new { - my $class = shift; - my $self = {}; - bless($self, $class); - - warn "# opening socket to $server"; - - $sock ||= IO::Socket::INET->new( - PeerAddr => $server, - Proto => 'tcp', - ) || die $!; - - $self; -} - -my $bulk_command = { - set => 1, setnx => 1, - rpush => 1, lpush => 1, - lset => 1, lrem => 1, - sadd => 1, srem => 1, - sismember => 1, - echo => 1, -}; - -# we don't want DESTROY to fallback into AUTOLOAD -sub DESTROY {} - -our $AUTOLOAD; -sub AUTOLOAD { - my $self = shift; - - my $command = $AUTOLOAD; - $command =~ s/.*://; - - warn "## $command ",dump(@_) if $debug; - - my $send; - - if ( defined $bulk_command->{$command} ) { - my $value = pop; - $value = '' if ! defined $value; - $send - = uc($command) - . ' ' - . join(' ', @_) - . ' ' - . length( $value ) - . "\r\n$value\r\n" - ; - } else { - $send - = uc($command) - . ' ' - . join(' ', @_) - . "\r\n" - ; - } - - warn ">> $send" if $debug; - print $sock $send; - - if ( $command eq 'quit' ) { - close( $sock ) || die "can't close socket: $!"; - return 1; - } - - my $result = <$sock> || die "can't read socket: $!"; - warn "<< $result" if $debug; - my $type = substr($result,0,1); - $result = substr($result,1,-2); - - if ( $command eq 'info' ) { - my $hash; - foreach my $l ( split(/\r\n/, __sock_read_bulk($result) ) ) { - my ($n,$v) = split(/:/, $l, 2); - $hash->{$n} = $v; - } - return $hash; - } elsif ( $command eq 'keys' ) { - my $keys = __sock_read_bulk($result); - return split(/\s/, $keys) if $keys; - return; - } - - if ( $type eq '-' ) { - confess $result; - } elsif ( $type eq '+' ) { - return $result; - } elsif ( $type eq '$' ) { - return __sock_read_bulk($result); - } elsif ( $type eq '*' ) { - return __sock_read_multi_bulk($result); - } elsif ( $type eq ':' ) { - return $result; # FIXME check if int? - } else { - confess "unknown type: $type", __sock_read_line(); - } -} - -sub __sock_read_bulk { - my $len = shift; - return undef if $len < 0; - - my $v; - if ( $len > 0 ) { - read($sock, $v, $len) || die $!; - warn "<< ",dump($v),$/ if $debug; - } - my $crlf; - read($sock, $crlf, 2); # skip cr/lf - return $v; -} - -sub __sock_read_multi_bulk { - my $size = shift; - return undef if $size < 0; - - $size--; - - my @list = ( 0 .. $size ); - foreach ( 0 .. $size ) { - $list[ $_ ] = __sock_read_bulk( substr(<$sock>,1,-2) ); - } - - warn "## list = ", dump( @list ) if $debug; - return @list; -} - -1; - -__END__ - -=head1 Connection Handling - -=head2 quit - - $r->quit; - -=head2 ping - - $r->ping || die "no server?"; - -=head1 Commands operating on string values - -=head2 set - - $r->set( foo => 'bar' ); - - $r->setnx( foo => 42 ); - -=head2 get - - my $value = $r->get( 'foo' ); - -=head2 mget - - my @values = $r->mget( 'foo', 'bar', 'baz' ); - -=head2 incr - - $r->incr('counter'); - - $r->incrby('tripplets', 3); - -=head2 decr - - $r->decr('counter'); - - $r->decrby('tripplets', 3); - -=head2 exists - - $r->exists( 'key' ) && print "got key!"; - -=head2 del - - $r->del( 'key' ) || warn "key doesn't exist"; - -=head2 type - - $r->type( 'key' ); # = string - -=head1 Commands operating on the key space - -=head2 keys - - my @keys = $r->keys( '*glob_pattern*' ); - -=head2 randomkey - - my $key = $r->randomkey; - -=head2 rename - - my $ok = $r->rename( 'old-key', 'new-key', $new ); - -=head2 dbsize - - my $nr_keys = $r->dbsize; - -=head1 Commands operating on lists - -See also L for tie interface. - -=head2 rpush - - $r->rpush( $key, $value ); - -=head2 lpush - - $r->lpush( $key, $value ); - -=head2 llen - - $r->llen( $key ); - -=head2 lrange - - my @list = $r->lrange( $key, $start, $end ); - -=head2 ltrim - - my $ok = $r->ltrim( $key, $start, $end ); - -=head2 lindex - - $r->lindex( $key, $index ); - -=head2 lset - - $r->lset( $key, $index, $value ); - -=head2 lrem - - my $modified_count = $r->lrem( $key, $count, $value ); - -=head2 lpop - - my $value = $r->lpop( $key ); - -=head2 rpop - - my $value = $r->rpop( $key ); - -=head1 Commands operating on sets - -=head2 sadd - - $r->sadd( $key, $member ); - -=head2 srem - - $r->srem( $key, $member ); - -=head2 scard - - my $elements = $r->scard( $key ); - -=head2 sismember - - $r->sismember( $key, $member ); - -=head2 sinter - - $r->sinter( $key1, $key2, ... ); - -=head2 sinterstore - - my $ok = $r->sinterstore( $dstkey, $key1, $key2, ... ); - -=head1 Multiple databases handling commands - -=head2 select - - $r->select( $dbindex ); # 0 for new clients - -=head2 move - - $r->move( $key, $dbindex ); - -=head2 flushdb - - $r->flushdb; - -=head2 flushall - - $r->flushall; - -=head1 Sorting - -=head2 sort - - $r->sort("key BY pattern LIMIT start end GET pattern ASC|DESC ALPHA'); - -=head1 Persistence control commands - -=head2 save - - $r->save; - -=head2 bgsave - - $r->bgsave; - -=head2 lastsave - - $r->lastsave; - -=head2 shutdown - - $r->shutdown; - -=head1 Remote server control commands - -=head2 info - - my $info_hash = $r->info; - -=head1 AUTHOR - -Dobrica Pavlinusic, C<< >> - -=head1 BUGS - -Please report any bugs or feature requests to C, or through -the web interface at L. I will be notified, and then you'll -automatically be notified of progress on your bug as I make changes. - - - - -=head1 SUPPORT - -You can find documentation for this module with the perldoc command. - - perldoc Redis - perldoc Redis::List - perldoc Redis::Hash - - -You can also look for information at: - -=over 4 - -=item * RT: CPAN's request tracker - -L - -=item * AnnoCPAN: Annotated CPAN documentation - -L - -=item * CPAN Ratings - -L - -=item * Search CPAN - -L - -=back - - -=head1 ACKNOWLEDGEMENTS - - -=head1 COPYRIGHT & LICENSE - -Copyright 2009 Dobrica Pavlinusic, all rights reserved. - -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. - - -=cut - -1; # End of Redis diff --git a/client-libraries/perl/lib/Redis/Hash.pm b/client-libraries/perl/lib/Redis/Hash.pm deleted file mode 100644 index e5f8f703..00000000 --- a/client-libraries/perl/lib/Redis/Hash.pm +++ /dev/null @@ -1,70 +0,0 @@ -package Redis::Hash; - -use strict; -use warnings; - -use Tie::Hash; -use base qw/Redis Tie::StdHash/; - -use Data::Dump qw/dump/; - -=head1 NAME - -Redis::Hash - tie perl hashes into Redis - -=head1 SYNOPSYS - - tie %name, 'Redis::Hash', 'prefix'; - -=cut - -# mandatory methods -sub TIEHASH { - my ($class,$name) = @_; - my $self = Redis->new; - $name .= ':' if $name; - $self->{name} = $name || ''; - bless $self => $class; -} - -sub STORE { - my ($self,$key,$value) = @_; - $self->set( $self->{name} . $key, $value ); -} - -sub FETCH { - my ($self,$key) = @_; - $self->get( $self->{name} . $key ); -} - -sub FIRSTKEY { - my $self = shift; - $self->{keys} = [ $self->keys( $self->{name} . '*' ) ]; - $self->NEXTKEY; -} - -sub NEXTKEY { - my $self = shift; - my $key = shift @{ $self->{keys} } || return; - my $name = $self->{name}; - $key =~ s{^$name}{} || warn "can't strip $name from $key"; - return $key; -} - -sub EXISTS { - my ($self,$key) = @_; - $self->exists( $self->{name} . $key ); -} - -sub DELETE { - my ($self,$key) = @_; - $self->del( $self->{name} . $key ); -} - -sub CLEAR { - my ($self) = @_; - $self->del( $_ ) foreach ( $self->keys( $self->{name} . '*' ) ); - $self->{keys} = []; -} - -1; diff --git a/client-libraries/perl/lib/Redis/List.pm b/client-libraries/perl/lib/Redis/List.pm deleted file mode 100644 index 6bbc093c..00000000 --- a/client-libraries/perl/lib/Redis/List.pm +++ /dev/null @@ -1,85 +0,0 @@ -package Redis::List; - -use strict; -use warnings; - -use base qw/Redis Tie::Array/; - -=head1 NAME - -Redis::List - tie perl arrays into Redis lists - -=head1 SYNOPSYS - - tie @a, 'Redis::List', 'name'; - -=cut - -# mandatory methods -sub TIEARRAY { - my ($class,$name) = @_; - my $self = $class->new; - $self->{name} = $name; - bless $self => $class; -} - -sub FETCH { - my ($self,$index) = @_; - $self->lindex( $self->{name}, $index ); -} - -sub FETCHSIZE { - my ($self) = @_; - $self->llen( $self->{name} ); -} - -sub STORE { - my ($self,$index,$value) = @_; - $self->lset( $self->{name}, $index, $value ); -} - -sub STORESIZE { - my ($self,$count) = @_; - $self->ltrim( $self->{name}, 0, $count ); -# if $count > $self->FETCHSIZE; -} - -sub CLEAR { - my ($self) = @_; - $self->del( $self->{name} ); -} - -sub PUSH { - my $self = shift; - $self->rpush( $self->{name}, $_ ) foreach @_; -} - -sub SHIFT { - my $self = shift; - $self->lpop( $self->{name} ); -} - -sub UNSHIFT { - my $self = shift; - $self->lpush( $self->{name}, $_ ) foreach @_; -} - -sub SPLICE { - my $self = shift; - my $offset = shift; - my $length = shift; - $self->lrange( $self->{name}, $offset, $length ); - # FIXME rest of @_ ? -} - -sub EXTEND { - my ($self,$count) = @_; - $self->rpush( $self->{name}, '' ) foreach ( $self->FETCHSIZE .. ( $count - 1 ) ); -} - -sub DESTROY { - my $self = shift; - $self->quit; -} - -1; diff --git a/client-libraries/perl/scripts/redis-benchmark.pl b/client-libraries/perl/scripts/redis-benchmark.pl deleted file mode 100755 index 74759b06..00000000 --- a/client-libraries/perl/scripts/redis-benchmark.pl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; -use Benchmark qw/:all/; -use lib 'lib'; -use Redis; - -my $r = Redis->new; - -my $i = 0; - -timethese( 100000, { - '00_ping' => sub { $r->ping }, - '10_set' => sub { $r->set( 'foo', $i++ ) }, - '11_set_r' => sub { $r->set( 'bench-' . rand(), rand() ) }, - '20_get' => sub { $r->get( 'foo' ) }, - '21_get_r' => sub { $r->get( 'bench-' . rand() ) }, - '30_incr' => sub { $r->incr( 'counter' ) }, - '30_incr_r' => sub { $r->incr( 'bench-' . rand() ) }, - '40_lpush' => sub { $r->lpush( 'mylist', 'bar' ) }, - '40_lpush' => sub { $r->lpush( 'mylist', 'bar' ) }, - '50_lpop' => sub { $r->lpop( 'mylist' ) }, -}); diff --git a/client-libraries/perl/t/00-load.t b/client-libraries/perl/t/00-load.t deleted file mode 100644 index d8a28caf..00000000 --- a/client-libraries/perl/t/00-load.t +++ /dev/null @@ -1,9 +0,0 @@ -#!perl -T - -use Test::More tests => 1; - -BEGIN { - use_ok( 'Redis' ); -} - -diag( "Testing Redis $Redis::VERSION, Perl $], $^X" ); diff --git a/client-libraries/perl/t/01-Redis.t b/client-libraries/perl/t/01-Redis.t deleted file mode 100755 index 90247e93..00000000 --- a/client-libraries/perl/t/01-Redis.t +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; - -use Test::More tests => 106; -use Data::Dump qw/dump/; - -use lib 'lib'; - -BEGIN { - use_ok( 'Redis' ); -} - -ok( my $o = Redis->new(), 'new' ); - -ok( $o->ping, 'ping' ); - - -diag "Commands operating on string values"; - -ok( $o->set( foo => 'bar' ), 'set foo => bar' ); - -ok( ! $o->setnx( foo => 'bar' ), 'setnx foo => bar fails' ); - -cmp_ok( $o->get( 'foo' ), 'eq', 'bar', 'get foo = bar' ); - -ok( $o->set( foo => 'baz' ), 'set foo => baz' ); - -cmp_ok( $o->get( 'foo' ), 'eq', 'baz', 'get foo = baz' ); - -ok( $o->set( 'test-undef' => 42 ), 'set test-undef' ); -ok( $o->set( 'test-undef' => undef ), 'set undef' ); -ok( ! defined $o->get( 'test-undef' ), 'get undef' ); -ok( $o->exists( 'test-undef' ), 'exists undef' ); - -$o->del('non-existant'); - -ok( ! $o->exists( 'non-existant' ), 'exists non-existant' ); -ok( ! $o->get( 'non-existant' ), 'get non-existant' ); - -ok( $o->set('key-next' => 0), 'key-next = 0' ); - -my $key_next = 3; - -ok( $o->set('key-left' => $key_next), 'key-left' ); - -is_deeply( [ $o->mget( 'foo', 'key-next', 'key-left' ) ], [ 'baz', 0, 3 ], 'mget' ); - -my @keys; - -foreach my $id ( 0 .. $key_next ) { - my $key = 'key-' . $id; - push @keys, $key; - ok( $o->set( $key => $id ), "set $key" ); - ok( $o->exists( $key ), "exists $key" ); - cmp_ok( $o->get( $key ), 'eq', $id, "get $key" ); - cmp_ok( $o->incr( 'key-next' ), '==', $id + 1, 'incr' ); - cmp_ok( $o->decr( 'key-left' ), '==', $key_next - $id - 1, 'decr' ); -} - -cmp_ok( $o->get( 'key-next' ), '==', $key_next + 1, 'key-next' ); - -ok( $o->set('test-incrby', 0), 'test-incrby' ); -ok( $o->set('test-decrby', 0), 'test-decry' ); -foreach ( 1 .. 3 ) { - cmp_ok( $o->incrby('test-incrby', 3), '==', $_ * 3, 'incrby 3' ); - cmp_ok( $o->decrby('test-decrby', 7), '==', -( $_ * 7 ), 'decrby 7' ); -} - -ok( $o->del( $_ ), "del $_" ) foreach map { "key-$_" } ( 'next', 'left' ); -ok( ! $o->del('non-existing' ), 'del non-existing' ); - -cmp_ok( $o->type('foo'), 'eq', 'string', 'type' ); - -cmp_ok( $o->keys('key-*'), '==', $key_next + 1, 'key-*' ); -is_deeply( [ $o->keys('key-*') ], [ @keys ], 'keys' ); - -ok( my $key = $o->randomkey, 'randomkey' ); - -ok( $o->rename( 'test-incrby', 'test-renamed' ), 'rename' ); -ok( $o->exists( 'test-renamed' ), 'exists test-renamed' ); - -eval { $o->rename( 'test-decrby', 'test-renamed', 1 ) }; -ok( $@, 'rename to existing key' ); - -ok( my $nr_keys = $o->dbsize, 'dbsize' ); - - -diag "Commands operating on lists"; - -my $list = 'test-list'; - -$o->del($list) && diag "cleanup $list from last run"; - -ok( $o->rpush( $list => "r$_" ), 'rpush' ) foreach ( 1 .. 3 ); - -ok( $o->lpush( $list => "l$_" ), 'lpush' ) foreach ( 1 .. 2 ); - -cmp_ok( $o->type($list), 'eq', 'list', 'type' ); -cmp_ok( $o->llen($list), '==', 5, 'llen' ); - -is_deeply( [ $o->lrange( $list, 0, 1 ) ], [ 'l2', 'l1' ], 'lrange' ); - -ok( $o->ltrim( $list, 1, 2 ), 'ltrim' ); -cmp_ok( $o->llen($list), '==', 2, 'llen after ltrim' ); - -cmp_ok( $o->lindex( $list, 0 ), 'eq', 'l1', 'lindex' ); -cmp_ok( $o->lindex( $list, 1 ), 'eq', 'r1', 'lindex' ); - -ok( $o->lset( $list, 0, 'foo' ), 'lset' ); -cmp_ok( $o->lindex( $list, 0 ), 'eq', 'foo', 'verified' ); - -ok( $o->lrem( $list, 1, 'foo' ), 'lrem' ); -cmp_ok( $o->llen( $list ), '==', 1, 'llen after lrem' ); - -cmp_ok( $o->lpop( $list ), 'eq', 'r1', 'lpop' ); - -ok( ! $o->rpop( $list ), 'rpop' ); - - -diag "Commands operating on sets"; - -my $set = 'test-set'; -$o->del($set); - -ok( $o->sadd( $set, 'foo' ), 'sadd' ); -ok( ! $o->sadd( $set, 'foo' ), 'sadd' ); -cmp_ok( $o->scard( $set ), '==', 1, 'scard' ); -ok( $o->sismember( $set, 'foo' ), 'sismember' ); - -cmp_ok( $o->type( $set ), 'eq', 'set', 'type is set' ); - -ok( $o->srem( $set, 'foo' ), 'srem' ); -ok( ! $o->srem( $set, 'foo' ), 'srem again' ); -cmp_ok( $o->scard( $set ), '==', 0, 'scard' ); - -$o->sadd( 'test-set1', $_ ) foreach ( 'foo', 'bar', 'baz' ); -$o->sadd( 'test-set2', $_ ) foreach ( 'foo', 'baz', 'xxx' ); - -my $inter = [ 'baz', 'foo' ]; - -is_deeply( [ $o->sinter( 'test-set1', 'test-set2' ) ], $inter, 'siter' ); - -ok( $o->sinterstore( 'test-set-inter', 'test-set1', 'test-set2' ), 'sinterstore' ); - -cmp_ok( $o->scard( 'test-set-inter' ), '==', $#$inter + 1, 'cardinality of intersection' ); - - -diag "Multiple databases handling commands"; - -ok( $o->select( 1 ), 'select' ); -ok( $o->select( 0 ), 'select' ); - -ok( $o->move( 'foo', 1 ), 'move' ); -ok( ! $o->exists( 'foo' ), 'gone' ); - -ok( $o->select( 1 ), 'select' ); -ok( $o->exists( 'foo' ), 'exists' ); - -ok( $o->flushdb, 'flushdb' ); -cmp_ok( $o->dbsize, '==', 0, 'empty' ); - - -diag "Sorting"; - -ok( $o->lpush( 'test-sort', $_ ), "put $_" ) foreach ( 1 .. 4 ); -cmp_ok( $o->llen( 'test-sort' ), '==', 4, 'llen' ); - -is_deeply( [ $o->sort( 'test-sort' ) ], [ 1,2,3,4 ], 'sort' ); -is_deeply( [ $o->sort( 'test-sort DESC' ) ], [ 4,3,2,1 ], 'sort DESC' ); - - -diag "Persistence control commands"; - -ok( $o->save, 'save' ); -ok( $o->bgsave, 'bgsave' ); -ok( $o->lastsave, 'lastsave' ); -#ok( $o->shutdown, 'shutdown' ); -diag "shutdown not tested"; - -diag "Remote server control commands"; - -ok( my $info = $o->info, 'info' ); -diag dump( $info ); - -diag "Connection handling"; - -ok( $o->quit, 'quit' ); diff --git a/client-libraries/perl/t/10-Redis-List.t b/client-libraries/perl/t/10-Redis-List.t deleted file mode 100755 index 1ebdd757..00000000 --- a/client-libraries/perl/t/10-Redis-List.t +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; - -use Test::More tests => 8; -use lib 'lib'; -use Data::Dump qw/dump/; - -BEGIN { - use_ok( 'Redis::List' ); -} - -my @a; - -ok( my $o = tie( @a, 'Redis::List', 'test-redis-list' ), 'tie' ); - -isa_ok( $o, 'Redis::List' ); - -$o->CLEAR; - -ok( ! @a, 'empty list' ); - -ok( @a = ( 'foo', 'bar', 'baz' ), '=' ); -is_deeply( [ @a ], [ 'foo', 'bar', 'baz' ] ); - -ok( push( @a, 'push' ), 'push' ); -is_deeply( [ @a ], [ 'foo', 'bar', 'baz', 'push' ] ); - -#diag dump( @a ); diff --git a/client-libraries/perl/t/20-Redis-Hash.t b/client-libraries/perl/t/20-Redis-Hash.t deleted file mode 100755 index 7bd9dafc..00000000 --- a/client-libraries/perl/t/20-Redis-Hash.t +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl - -use warnings; -use strict; - -use Test::More tests => 7; -use lib 'lib'; -use Data::Dump qw/dump/; - -BEGIN { - use_ok( 'Redis::Hash' ); -} - -ok( my $o = tie( my %h, 'Redis::Hash', 'test-redis-hash' ), 'tie' ); - -isa_ok( $o, 'Redis::Hash' ); - -$o->CLEAR(); - -ok( ! keys %h, 'empty' ); - -ok( %h = ( 'foo' => 42, 'bar' => 1, 'baz' => 99 ), '=' ); - -is_deeply( [ sort keys %h ], [ 'bar', 'baz', 'foo' ], 'keys' ); - -is_deeply( \%h, { bar => 1, baz => 99, foo => 42, }, 'structure' ); - - -#diag dump( \%h ); - diff --git a/client-libraries/perl/t/pod-coverage.t b/client-libraries/perl/t/pod-coverage.t deleted file mode 100644 index fc40a57c..00000000 --- a/client-libraries/perl/t/pod-coverage.t +++ /dev/null @@ -1,18 +0,0 @@ -use strict; -use warnings; -use Test::More; - -# Ensure a recent version of Test::Pod::Coverage -my $min_tpc = 1.08; -eval "use Test::Pod::Coverage $min_tpc"; -plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage" - if $@; - -# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version, -# but older versions don't recognize some common documentation styles -my $min_pc = 0.18; -eval "use Pod::Coverage $min_pc"; -plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage" - if $@; - -all_pod_coverage_ok(); diff --git a/client-libraries/perl/t/pod.t b/client-libraries/perl/t/pod.t deleted file mode 100644 index ee8b18ad..00000000 --- a/client-libraries/perl/t/pod.t +++ /dev/null @@ -1,12 +0,0 @@ -#!perl -T - -use strict; -use warnings; -use Test::More; - -# Ensure a recent version of Test::Pod -my $min_tp = 1.22; -eval "use Test::Pod $min_tp"; -plan skip_all => "Test::Pod $min_tp required for testing POD" if $@; - -all_pod_files_ok(); diff --git a/client-libraries/php/redis.php b/client-libraries/php/redis.php deleted file mode 100644 index 6a0d21be..00000000 --- a/client-libraries/php/redis.php +++ /dev/null @@ -1,374 +0,0 @@ -host = $host; - $this->port = $port; - } - - public function connect() { - if ($this->_sock) return; - if ($sock = fsockopen($this->host, $this->port, $errno, $errstr)) { - $this->_sock = $sock; - return; - } - $msg = "Cannot open socket to {$this->host}:{$this->port}"; - if ($errno || $errmsg) - $msg .= "," . ($errno ? " error $errno" : "") . - ($errmsg ? " $errmsg" : ""); - trigger_error("$msg.", E_USER_ERROR); - } - - public function disconnect() { - if ($this->_sock) @fclose($this->_sock); - $this->_sock = null; - } - - public function ping() { - $this->connect(); - $this->write("PING\r\n"); - return $this->get_response(); - } - - public function do_echo($s) { - $this->connect(); - $this->write("ECHO " . strlen($s) . "\r\n$s\r\n"); - return $this->get_response(); - } - - public function set($name, $value, $preserve=false) { - $this->connect(); - $this->write( - ($preserve ? 'SETNX' : 'SET') . - " $name " . strlen($value) . "\r\n$value\r\n" - ); - return $this->get_response(); - } - - public function get($name) { - $this->connect(); - $this->write("GET $name\r\n"); - return $this->get_response(); - } - - public function mget($keys) { - $this->connect(); - $this->write("MGET ".implode(" ",$keys)."\r\n"); - return $this->get_response(); - } - - public function incr($name, $amount=1) { - $this->connect(); - if ($amount == 1) - $this->write("INCR $name\r\n"); - else - $this->write("INCRBY $name $amount\r\n"); - return $this->get_response(); - } - - public function decr($name, $amount=1) { - $this->connect(); - if ($amount == 1) - $this->write("DECR $name\r\n"); - else - $this->write("DECRBY $name $amount\r\n"); - return $this->get_response(); - } - - public function exists($name) { - $this->connect(); - $this->write("EXISTS $name\r\n"); - return $this->get_response(); - } - - public function delete($name) { - $this->connect(); - $this->write("DEL $name\r\n"); - return $this->get_response(); - } - - public function keys($pattern) { - $this->connect(); - $this->write("KEYS $pattern\r\n"); - return explode(' ', $this->get_response()); - } - - public function randomkey() { - $this->connect(); - $this->write("RANDOMKEY\r\n"); - return $this->get_response(); - } - - public function rename($src, $dst) { - $this->connect(); - $this->write("RENAME $src $dst\r\n"); - return $this->get_response(); - } - - public function renamenx($src, $dst) { - $this->connect(); - $this->write("RENAMENX $src $dst\r\n"); - return $this->get_response(); - } - - public function expire($name, $time) { - $this->connect(); - $this->write("EXPIRE $name $time\r\n"); - return $this->get_response(); - } - - public function push($name, $value, $tail=true) { - // default is to append the element to the list - $this->connect(); - $this->write( - ($tail ? 'RPUSH' : 'LPUSH') . - " $name " . strlen($value) . "\r\n$value\r\n" - ); - return $this->get_response(); - } - - public function lpush($name, $value) { - return $this->push($name, $value, false); - } - - public function rpush($name, $value) { - return $this->push($name, $value, true); - } - - public function ltrim($name, $start, $end) { - $this->connect(); - $this->write("LTRIM $name $start $end\r\n"); - return $this->get_response(); - } - - public function lindex($name, $index) { - $this->connect(); - $this->write("LINDEX $name $index\r\n"); - return $this->get_response(); - } - - public function pop($name, $tail=true) { - $this->connect(); - $this->write( - ($tail ? 'RPOP' : 'LPOP') . - " $name\r\n" - ); - return $this->get_response(); - } - - public function lpop($name, $value) { - return $this->pop($name, $value, false); - } - - public function rpop($name, $value) { - return $this->pop($name, $value, true); - } - - public function llen($name) { - $this->connect(); - $this->write("LLEN $name\r\n"); - return $this->get_response(); - } - - public function lrange($name, $start, $end) { - $this->connect(); - $this->write("LRANGE $name $start $end\r\n"); - return $this->get_response(); - } - - public function sort($name, $query=false) { - $this->connect(); - $this->write($query == false ? "SORT $name\r\n" : "SORT $name $query\r\n"); - return $this->get_response(); - } - - public function lset($name, $value, $index) { - $this->connect(); - $this->write("LSET $name $index " . strlen($value) . "\r\n$value\r\n"); - return $this->get_response(); - } - - public function sadd($name, $value) { - $this->connect(); - $this->write("SADD $name " . strlen($value) . "\r\n$value\r\n"); - return $this->get_response(); - } - - public function srem($name, $value) { - $this->connect(); - $this->write("SREM $name " . strlen($value) . "\r\n$value\r\n"); - return $this->get_response(); - } - - public function sismember($name, $value) { - $this->connect(); - $this->write("SISMEMBER $name " . strlen($value) . "\r\n$value\r\n"); - return $this->get_response(); - } - - public function sinter($sets) { - $this->connect(); - $this->write('SINTER ' . implode(' ', $sets) . "\r\n"); - return $this->get_response(); - } - - public function smembers($name) { - $this->connect(); - $this->write("SMEMBERS $name\r\n"); - return $this->get_response(); - } - - public function scard($name) { - $this->connect(); - $this->write("SCARD $name\r\n"); - return $this->get_response(); - } - - public function select_db($name) { - $this->connect(); - $this->write("SELECT $name\r\n"); - return $this->get_response(); - } - - public function move($name, $db) { - $this->connect(); - $this->write("MOVE $name $db\r\n"); - return $this->get_response(); - } - - public function save($background=false) { - $this->connect(); - $this->write(($background ? "BGSAVE\r\n" : "SAVE\r\n")); - return $this->get_response(); - } - - public function bgsave($background=false) { - return $this->save(true); - } - - public function lastsave() { - $this->connect(); - $this->write("LASTSAVE\r\n"); - return $this->get_response(); - } - - public function flushdb($all=false) { - $this->connect(); - $this->write($all ? "FLUSHALL\r\n" : "FLUSHDB\r\n"); - return $this->get_response(); - } - - public function flushall() { - return $this->flush(true); - } - - public function info() { - $this->connect(); - $this->write("INFO\r\n"); - $info = array(); - $data =& $this->get_response(); - foreach (explode("\r\n", $data) as $l) { - if (!$l) - continue; - list($k, $v) = explode(':', $l, 2); - $_v = strpos($v, '.') !== false ? (float)$v : (int)$v; - $info[$k] = (string)$_v == $v ? $_v : $v; - } - return $info; - } - - private function write($s) { - while ($s) { - $i = fwrite($this->_sock, $s); - if ($i == 0) // || $i == strlen($s)) - break; - $s = substr($s, $i); - } - } - - private function read($len=1024) { - if ($s = fgets($this->_sock)) - return $s; - $this->disconnect(); - trigger_error("Cannot read from socket.", E_USER_ERROR); - } - - private function get_response() { - $data = trim($this->read()); - $c = $data[0]; - $data = substr($data, 1); - switch ($c) { - case '-': - trigger_error($data, E_USER_ERROR); - break; - case '+': - return $data; - case ':': - $i = strpos($data, '.') !== false ? (int)$data : (float)$data; - if ((string)$i != $data) - trigger_error("Cannot convert data '$c$data' to integer", E_USER_ERROR); - return $i; - case '$': - return $this->get_bulk_reply($c . $data); - case '*': - $num = (int)$data; - if ((string)$num != $data) - trigger_error("Cannot convert multi-response header '$data' to integer", E_USER_ERROR); - $result = array(); - for ($i=0; $i<$num; $i++) - $result[] =& $this->get_response(); - return $result; - default: - trigger_error("Invalid reply type byte: '$c'"); - } - } - - private function get_bulk_reply($data=null) { - if ($data === null) - $data = trim($this->read()); - if ($data == '$-1') - return null; - $c = $data[0]; - $data = substr($data, 1); - $bulklen = (int)$data; - if ((string)$bulklen != $data) - trigger_error("Cannot convert bulk read header '$c$data' to integer", E_USER_ERROR); - if ($c != '$') - trigger_error("Unkown response prefix for '$c$data'", E_USER_ERROR); - $buffer = ''; - while ($bulklen) { - $data = fread($this->_sock,$bulklen); - $bulklen -= strlen($data); - $buffer .= $data; - } - $crlf = fread($this->_sock,2); - return $buffer; - } -} - -/* -$r = new Redis(); -var_dump($r->set("foo","bar")); -var_dump($r->get("foo")); -var_dump($r->info()); -*/ - -?> diff --git a/client-libraries/php/tests.php b/client-libraries/php/tests.php deleted file mode 100644 index d7bf74cf..00000000 --- a/client-libraries/php/tests.php +++ /dev/null @@ -1,87 +0,0 @@ -connect(); -$r->select_db(9); -$r->flushdb(); -echo "
\n";
-echo $r->ping() . "\n";
-echo $r->do_echo('ECHO test') . "\n";
-echo "SET aaa " . $r->set('aaa', 'bbb') . "\n";
-echo "SETNX aaa " . $r->set('aaa', 'ccc', true) . "\n";
-echo "GET aaa " . $r->get('aaa') . "\n";
-echo "INCR aaa " . $r->incr('aaa') . "\n";
-echo "GET aaa " . $r->get('aaa') . "\n";
-echo "INCRBY aaa 3 " . $r->incr('aaa', 2) . "\n";
-echo "GET aaa " . $r->get('aaa') . "\n";
-echo "DECR aaa " . $r->decr('aaa') . "\n";
-echo "GET aaa " . $r->get('aaa') . "\n";
-echo "DECRBY aaa 2 " . $r->decr('aaa', 2) . "\n";
-echo "GET aaa " . $r->get('aaa') . "\n";
-echo "EXISTS aaa " . $r->exists('aaa') . "\n";
-echo "EXISTS fsfjslfjkls " . $r->exists('fsfjslfjkls') . "\n";
-echo "DELETE aaa " . $r->delete('aaa') . "\n";
-echo "EXISTS aaa " . $r->exists('aaa') . "\n";
-echo 'SET a1 a2 a3' . $r->set('a1', 'a') . $r->set('a2', 'b') . $r->set('a3', 'c') . "\n";
-echo 'KEYS a* ' . print_r($r->keys('a*'), true) . "\n";
-echo 'RANDOMKEY ' . $r->randomkey('a*') . "\n";
-echo 'RENAME a1 a0 ' . $r->rename('a1', 'a0') . "\n";
-echo 'RENAMENX a0 a2 ' . $r->renamenx('a0', 'a2') . "\n";
-echo 'RENAMENX a0 a1 ' . $r->renamenx('a0', 'a1') . "\n";
-
-echo 'LPUSH a0 aaa ' . $r->push('a0', 'aaa') . "\n";
-echo 'LPUSH a0 bbb ' . $r->push('a0', 'bbb') . "\n";
-echo 'RPUSH a0 ccc ' . $r->push('a0', 'ccc', false) . "\n";
-echo 'LLEN a0 ' . $r->llen('a0') . "\n";
-echo 'LRANGE sdkjhfskdjfh 0 100 ' . print_r($r->lrange('sdkjhfskdjfh', 0, 100), true) . "\n";
-echo 'LRANGE a0 0 0 ' . print_r($r->lrange('a0', 0, 0), true) . "\n";
-echo 'LRANGE a0 0 100 ' . print_r($r->lrange('a0', 0, 100), true) . "\n";
-echo 'LTRIM a0 0 1 ' . $r->ltrim('a0', 0, 1) . "\n";
-echo 'LRANGE a0 0 100 ' . print_r($r->lrange('a0', 0, 100), true) . "\n";
-echo 'LINDEX a0 0 ' . $r->lindex('a0', 0) . "\n";
-echo 'LPUSH a0 bbb ' . $r->push('a0', 'bbb') . "\n";
-echo 'LRANGE a0 0 100 ' . print_r($r->lrange('a0', 0, 100), true) . "\n";
-echo 'RPOP a0 ' . $r->pop('a0') . "\n";
-echo 'LPOP a0 ' . $r->pop('a0', false) . "\n";
-echo 'LSET a0 ccc 0 ' . $r->lset('a0', 'ccc', 0) . "\n";
-echo 'LRANGE a0 0 100 ' . print_r($r->lrange('a0', 0, 100), true) . "\n";
-
-echo 'SADD s0 aaa ' . $r->sadd('s0', 'aaa') . "\n";
-echo 'SADD s0 aaa ' . $r->sadd('s0', 'aaa') . "\n";
-echo 'SADD s0 bbb ' . $r->sadd('s0', 'bbb') . "\n";
-echo 'SREM s0 bbb ' . $r->srem('s0', 'bbb') . "\n";
-echo 'SISMEMBER s0 aaa ' . $r->sismember('s0', 'aaa') . "\n";
-echo 'SISMEMBER s0 bbb ' . $r->sismember('s0', 'bbb') . "\n";
-echo 'SADD s0 bbb ' . $r->sadd('s0', 'bbb') . "\n";
-echo 'SADD s1 bbb ' . $r->sadd('s1', 'bbb') . "\n";
-echo 'SADD s1 aaa ' . $r->sadd('s1', 'aaa') . "\n";
-echo 'SINTER s0 s1 ' . print_r($r->sinter(array('s0', 's1')), true) . "\n";
-echo 'SREM s0 bbb ' . $r->srem('s0', 'bbb') . "\n";
-echo 'SINTER s0 s1 ' . print_r($r->sinter(array('s0', 's1')), true) . "\n";
-echo 'SMEMBERS s1 ' . print_r($r->smembers('s1'), true) . "\n";
-
-echo 'SELECT 8 ' . $r->select_db(8) . "\n";
-echo 'EXISTS s1 ' . $r->exists('s1') . "\n";
-if ($r->exists('s1'))
-    echo 'SMEMBERS s1 ' . print_r($r->smembers('s1'), true) . "\n";
-echo 'SELECT 9 ' . $r->select_db(9) . "\n";
-echo 'SMEMBERS s1 ' . print_r($r->smembers('s1'), true) . "\n";
-echo 'MOVE s1 8 ' . $r->move('s1', 8) . "\n";
-echo 'EXISTS s1 ' . $r->exists('s1') . "\n";
-if ($r->exists('s1'))
-    echo 'SMEMBERS s1 ' . print_r($r->smembers('s1'), true) . "\n";
-echo 'SELECT 8 ' . $r->select_db(8) . "\n";
-echo 'SMEMBERS s1 ' . print_r($r->smembers('s1'), true) . "\n";
-echo 'SELECT 9 ' . $r->select_db(9) . "\n";
-
-echo 'SAVE ' . $r->save() . "\n";
-echo 'BGSAVE ' . $r->save(true) . "\n";
-echo 'LASTSAVE ' . $r->lastsave() . "\n";
-
-echo 'INFO ' . print_r($r->info()) . "\n";
-echo "
\n"; -?> diff --git a/client-libraries/python/redis.py b/client-libraries/python/redis.py deleted file mode 100644 index 9618901e..00000000 --- a/client-libraries/python/redis.py +++ /dev/null @@ -1,1051 +0,0 @@ -#!/usr/bin/env python - -""" redis.py - A client for the Redis daemon. - -History: - - - 20090603 fix missing errno import, add sunion and sunionstore commands, - generalize shebang (Jochen Kupperschmidt) - -""" - -__author__ = "Ludovico Magnocavallo " -__copyright__ = "Copyright 2009, Ludovico Magnocavallo" -__license__ = "MIT" -__version__ = "0.5" -__revision__ = "$LastChangedRevision: 175 $"[22:-2] -__date__ = "$LastChangedDate: 2009-03-17 16:15:55 +0100 (Mar, 17 Mar 2009) $"[18:-2] - - -# TODO: Redis._get_multi_response - - -import socket -import decimal -import errno - - -BUFSIZE = 4096 - - -class RedisError(Exception): pass -class ConnectionError(RedisError): pass -class ResponseError(RedisError): pass -class InvalidResponse(RedisError): pass -class InvalidData(RedisError): pass - - -class Redis(object): - """The main Redis client. - """ - - def __init__(self, host=None, port=None, timeout=None, db=None, nodelay=None, charset='utf8', errors='strict'): - self.host = host or 'localhost' - self.port = port or 6379 - if timeout: - socket.setdefaulttimeout(timeout) - self.nodelay = nodelay - self.charset = charset - self.errors = errors - self._sock = None - self._fp = None - self.db = db - - def _encode(self, s): - if isinstance(s, str): - return s - if isinstance(s, unicode): - try: - return s.encode(self.charset, self.errors) - except UnicodeEncodeError, e: - raise InvalidData("Error encoding unicode value '%s': %s" % (value.encode(self.charset, 'replace'), e)) - return str(s) - - def _write(self, s): - """ - >>> r = Redis(db=9) - >>> r.connect() - >>> r._sock.close() - >>> try: - ... r._write('pippo') - ... except ConnectionError, e: - ... print e - Error 9 while writing to socket. Bad file descriptor. - >>> - >>> - """ - try: - self._sock.sendall(s) - except socket.error, e: - if e.args[0] == 32: - # broken pipe - self.disconnect() - raise ConnectionError("Error %s while writing to socket. %s." % tuple(e.args)) - - def _read(self): - try: - return self._fp.readline() - except socket.error, e: - if e.args and e.args[0] == errno.EAGAIN: - return - self.disconnect() - raise ConnectionError("Error %s while reading from socket. %s." % tuple(e.args)) - if not data: - self.disconnect() - raise ConnectionError("Socket connection closed when reading.") - return data - - def ping(self): - """ - >>> r = Redis(db=9) - >>> r.ping() - 'PONG' - >>> - """ - self.connect() - self._write('PING\r\n') - return self.get_response() - - def set(self, name, value, preserve=False, getset=False): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'pippo') - 'OK' - >>> r.set('a', u'pippo \u3235') - 'OK' - >>> r.get('a') - u'pippo \u3235' - >>> r.set('b', 105.2) - 'OK' - >>> r.set('b', 'xxx', preserve=True) - 0 - >>> r.get('b') - Decimal("105.2") - >>> - """ - self.connect() - # the following will raise an error for unicode values that can't be encoded to ascii - # we could probably add an 'encoding' arg to init, but then what do we do with get()? - # convert back to unicode? and what about ints, or pickled values? - if getset: command = 'GETSET' - elif preserve: command = 'SETNX' - else: command = 'SET' - value = self._encode(value) - self._write('%s %s %s\r\n%s\r\n' % ( - command, name, len(value), value - )) - return self.get_response() - - def get(self, name): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', ' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '), r.set('d', '\\r\\n') - ('OK', 'OK', 'OK', 'OK') - >>> r.get('a') - u'pippo' - >>> r.get('b') - 15 - >>> r.get('d') - u'\\r\\n' - >>> r.get('b') - 15 - >>> r.get('c') - u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n ' - >>> r.get('c') - u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n ' - >>> r.get('ajhsd') - >>> - """ - self.connect() - self._write('GET %s\r\n' % name) - return self.get_response() - - def getset(self, name, value): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'pippo') - 'OK' - >>> r.getset('a', 2) - u'pippo' - >>> - """ - return self.set(name, value, getset=True) - - def mget(self, *args): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'), r.set('d', '\\r\\n') - ('OK', 'OK', 'OK', 'OK') - >>> r.mget('a', 'b', 'c', 'd') - [u'pippo', 15, u'\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n', u'\\r\\n'] - >>> - """ - self.connect() - self._write('MGET %s\r\n' % ' '.join(args)) - return self.get_response() - - def incr(self, name, amount=1): - """ - >>> r = Redis(db=9) - >>> r.delete('a') - 1 - >>> r.incr('a') - 1 - >>> r.incr('a') - 2 - >>> r.incr('a', 2) - 4 - >>> - """ - self.connect() - if amount == 1: - self._write('INCR %s\r\n' % name) - else: - self._write('INCRBY %s %s\r\n' % (name, amount)) - return self.get_response() - - def decr(self, name, amount=1): - """ - >>> r = Redis(db=9) - >>> if r.get('a'): - ... r.delete('a') - ... else: - ... print 1 - 1 - >>> r.decr('a') - -1 - >>> r.decr('a') - -2 - >>> r.decr('a', 5) - -7 - >>> - """ - self.connect() - if amount == 1: - self._write('DECR %s\r\n' % name) - else: - self._write('DECRBY %s %s\r\n' % (name, amount)) - return self.get_response() - - def exists(self, name): - """ - >>> r = Redis(db=9) - >>> r.exists('dsjhfksjdhfkdsjfh') - 0 - >>> r.set('a', 'a') - 'OK' - >>> r.exists('a') - 1 - >>> - """ - self.connect() - self._write('EXISTS %s\r\n' % name) - return self.get_response() - - def delete(self, name): - """ - >>> r = Redis(db=9) - >>> r.delete('dsjhfksjdhfkdsjfh') - 0 - >>> r.set('a', 'a') - 'OK' - >>> r.delete('a') - 1 - >>> r.exists('a') - 0 - >>> r.delete('a') - 0 - >>> - """ - self.connect() - self._write('DEL %s\r\n' % name) - return self.get_response() - - def get_type(self, name): - """ - >>> r = Redis(db=9) - >>> r.set('a', 3) - 'OK' - >>> r.get_type('a') - 'string' - >>> r.get_type('zzz') - >>> - """ - self.connect() - self._write('TYPE %s\r\n' % name) - res = self.get_response() - return None if res == 'none' else res - - def keys(self, pattern): - """ - >>> r = Redis(db=9) - >>> r.flush() - 'OK' - >>> r.set('a', 'a') - 'OK' - >>> r.keys('a*') - [u'a'] - >>> r.set('a2', 'a') - 'OK' - >>> r.keys('a*') - [u'a', u'a2'] - >>> r.delete('a2') - 1 - >>> r.keys('sjdfhskjh*') - [] - >>> - """ - self.connect() - self._write('KEYS %s\r\n' % pattern) - return self.get_response().split() - - def randomkey(self): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'a') - 'OK' - >>> isinstance(r.randomkey(), str) - True - >>> - """ - #raise NotImplementedError("Implemented but buggy, do not use.") - self.connect() - self._write('RANDOMKEY\r\n') - return self.get_response() - - def rename(self, src, dst, preserve=False): - """ - >>> r = Redis(db=9) - >>> try: - ... r.rename('a', 'a') - ... except ResponseError, e: - ... print e - source and destination objects are the same - >>> r.rename('a', 'b') - 'OK' - >>> try: - ... r.rename('a', 'b') - ... except ResponseError, e: - ... print e - no such key - >>> r.set('a', 1) - 'OK' - >>> r.rename('b', 'a', preserve=True) - 0 - >>> - """ - self.connect() - if preserve: - self._write('RENAMENX %s %s\r\n' % (src, dst)) - return self.get_response() - else: - self._write('RENAME %s %s\r\n' % (src, dst)) - return self.get_response() #.strip() - - def dbsize(self): - """ - >>> r = Redis(db=9) - >>> type(r.dbsize()) - - >>> - """ - self.connect() - self._write('DBSIZE\r\n') - return self.get_response() - - def ttl(self, name): - """ - >>> r = Redis(db=9) - >>> r.ttl('a') - -1 - >>> r.expire('a', 10) - 1 - >>> r.ttl('a') - 10 - >>> r.expire('a', 0) - 0 - >>> - """ - self.connect() - self._write('TTL %s\r\n' % name) - return self.get_response() - - def expire(self, name, time): - """ - >>> r = Redis(db=9) - >>> r.set('a', 1) - 'OK' - >>> r.expire('a', 1) - 1 - >>> r.expire('zzzzz', 1) - 0 - >>> - """ - self.connect() - self._write('EXPIRE %s %s\r\n' % (name, time)) - return self.get_response() - - def push(self, name, value, tail=False): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.push('l', 'a') - 'OK' - >>> r.set('a', 'a') - 'OK' - >>> try: - ... r.push('a', 'a') - ... except ResponseError, e: - ... print e - Operation against a key holding the wrong kind of value - >>> - """ - self.connect() - value = self._encode(value) - self._write('%s %s %s\r\n%s\r\n' % ( - 'LPUSH' if tail else 'RPUSH', name, len(value), value - )) - return self.get_response() - - def llen(self, name): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.push('l', 'a') - 'OK' - >>> r.llen('l') - 1 - >>> r.push('l', 'a') - 'OK' - >>> r.llen('l') - 2 - >>> - """ - self.connect() - self._write('LLEN %s\r\n' % name) - return self.get_response() - - def lrange(self, name, start, end): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.lrange('l', 0, 1) - [] - >>> r.push('l', 'aaa') - 'OK' - >>> r.lrange('l', 0, 1) - [u'aaa'] - >>> r.push('l', 'bbb') - 'OK' - >>> r.lrange('l', 0, 0) - [u'aaa'] - >>> r.lrange('l', 0, 1) - [u'aaa', u'bbb'] - >>> r.lrange('l', -1, 0) - [] - >>> r.lrange('l', -1, -1) - [u'bbb'] - >>> - """ - self.connect() - self._write('LRANGE %s %s %s\r\n' % (name, start, end)) - return self.get_response() - - def ltrim(self, name, start, end): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> try: - ... r.ltrim('l', 0, 1) - ... except ResponseError, e: - ... print e - no such key - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.push('l', 'ccc') - 'OK' - >>> r.ltrim('l', 0, 1) - 'OK' - >>> r.llen('l') - 2 - >>> r.ltrim('l', 99, 95) - 'OK' - >>> r.llen('l') - 0 - >>> - """ - self.connect() - self._write('LTRIM %s %s %s\r\n' % (name, start, end)) - return self.get_response() - - def lindex(self, name, index): - """ - >>> r = Redis(db=9) - >>> res = r.delete('l') - >>> r.lindex('l', 0) - >>> r.push('l', 'aaa') - 'OK' - >>> r.lindex('l', 0) - u'aaa' - >>> r.lindex('l', 2) - >>> r.push('l', 'ccc') - 'OK' - >>> r.lindex('l', 1) - u'ccc' - >>> r.lindex('l', -1) - u'ccc' - >>> - """ - self.connect() - self._write('LINDEX %s %s\r\n' % (name, index)) - return self.get_response() - - def pop(self, name, tail=False): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.pop('l') - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.pop('l') - u'aaa' - >>> r.pop('l') - u'bbb' - >>> r.pop('l') - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.pop('l', tail=True) - u'bbb' - >>> r.pop('l') - u'aaa' - >>> r.pop('l') - >>> - """ - self.connect() - self._write('%s %s\r\n' % ('RPOP' if tail else 'LPOP', name)) - return self.get_response() - - def lset(self, name, index, value): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> try: - ... r.lset('l', 0, 'a') - ... except ResponseError, e: - ... print e - no such key - >>> r.push('l', 'aaa') - 'OK' - >>> try: - ... r.lset('l', 1, 'a') - ... except ResponseError, e: - ... print e - index out of range - >>> r.lset('l', 0, 'bbb') - 'OK' - >>> r.lrange('l', 0, 1) - [u'bbb'] - >>> - """ - self.connect() - value = self._encode(value) - self._write('LSET %s %s %s\r\n%s\r\n' % ( - name, index, len(value), value - )) - return self.get_response() - - def lrem(self, name, value, num=0): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.push('l', 'aaa') - 'OK' - >>> r.lrem('l', 'aaa') - 2 - >>> r.lrange('l', 0, 10) - [u'bbb'] - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'aaa') - 'OK' - >>> r.lrem('l', 'aaa', 1) - 1 - >>> r.lrem('l', 'aaa', 1) - 1 - >>> r.lrem('l', 'aaa', 1) - 0 - >>> - """ - self.connect() - value = self._encode(value) - self._write('LREM %s %s %s\r\n%s\r\n' % ( - name, num, len(value), value - )) - return self.get_response() - - def sort(self, name, by=None, get=None, start=None, num=None, desc=False, alpha=False): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.push('l', 'ccc') - 'OK' - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'ddd') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.sort('l', alpha=True) - [u'aaa', u'bbb', u'ccc', u'ddd'] - >>> r.delete('l') - 1 - >>> for i in range(1, 5): - ... res = r.push('l', 1.0 / i) - >>> r.sort('l') - [Decimal("0.25"), Decimal("0.333333333333"), Decimal("0.5"), Decimal("1.0")] - >>> r.sort('l', desc=True) - [Decimal("1.0"), Decimal("0.5"), Decimal("0.333333333333"), Decimal("0.25")] - >>> r.sort('l', desc=True, start=2, num=1) - [Decimal("0.333333333333")] - >>> r.set('weight_0.5', 10) - 'OK' - >>> r.sort('l', desc=True, by='weight_*') - [Decimal("0.5"), Decimal("1.0"), Decimal("0.333333333333"), Decimal("0.25")] - >>> for i in r.sort('l', desc=True): - ... res = r.set('test_%s' % i, 100 - float(i)) - >>> r.sort('l', desc=True, get='test_*') - [Decimal("99.0"), Decimal("99.5"), Decimal("99.6666666667"), Decimal("99.75")] - >>> r.sort('l', desc=True, by='weight_*', get='test_*') - [Decimal("99.5"), Decimal("99.0"), Decimal("99.6666666667"), Decimal("99.75")] - >>> r.sort('l', desc=True, by='weight_*', get='missing_*') - [None, None, None, None] - >>> - """ - stmt = ['SORT', name] - if by: - stmt.append("BY %s" % by) - if start and num: - stmt.append("LIMIT %s %s" % (start, num)) - if get is None: - pass - elif isinstance(get, basestring): - stmt.append("GET %s" % get) - elif isinstance(get, list) or isinstance(get, tuple): - for g in get: - stmt.append("GET %s" % g) - else: - raise RedisError("Invalid parameter 'get' for Redis sort") - if desc: - stmt.append("DESC") - if alpha: - stmt.append("ALPHA") - self.connect() - self._write(' '.join(stmt + ["\r\n"])) - return self.get_response() - - def sadd(self, name, value): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s') - >>> r.sadd('s', 'a') - 1 - >>> r.sadd('s', 'b') - 1 - >>> - """ - self.connect() - value = self._encode(value) - self._write('SADD %s %s\r\n%s\r\n' % ( - name, len(value), value - )) - return self.get_response() - - def srem(self, name, value): - """ - >>> r = Redis(db=9) - >>> r.delete('s') - 1 - >>> r.srem('s', 'aaa') - 0 - >>> r.sadd('s', 'b') - 1 - >>> r.srem('s', 'b') - 1 - >>> r.sismember('s', 'b') - 0 - >>> - """ - self.connect() - value = self._encode(value) - self._write('SREM %s %s\r\n%s\r\n' % ( - name, len(value), value - )) - return self.get_response() - - def sismember(self, name, value): - """ - >>> r = Redis(db=9) - >>> r.delete('s') - 1 - >>> r.sismember('s', 'b') - 0 - >>> r.sadd('s', 'a') - 1 - >>> r.sismember('s', 'b') - 0 - >>> r.sismember('s', 'a') - 1 - >>> - """ - self.connect() - value = self._encode(value) - self._write('SISMEMBER %s %s\r\n%s\r\n' % ( - name, len(value), value - )) - return self.get_response() - - def sinter(self, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'a') - 1 - >>> r.sadd('s3', 'b') - 1 - >>> try: - ... r.sinter() - ... except ResponseError, e: - ... print e - wrong number of arguments - >>> try: - ... r.sinter('l') - ... except ResponseError, e: - ... print e - Operation against a key holding the wrong kind of value - >>> r.sinter('s1', 's2', 's3') - set([]) - >>> r.sinter('s1', 's2') - set([u'a']) - >>> - """ - self.connect() - self._write('SINTER %s\r\n' % ' '.join(args)) - return set(self.get_response()) - - def sinterstore(self, dest, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'a') - 1 - >>> r.sadd('s3', 'b') - 1 - >>> r.sinterstore('s_s', 's1', 's2', 's3') - 0 - >>> r.sinterstore('s_s', 's1', 's2') - 1 - >>> r.smembers('s_s') - set([u'a']) - >>> - """ - self.connect() - self._write('SINTERSTORE %s %s\r\n' % (dest, ' '.join(args))) - return self.get_response() - - def smembers(self, name): - """ - >>> r = Redis(db=9) - >>> r.delete('s') - 1 - >>> r.sadd('s', 'a') - 1 - >>> r.sadd('s', 'b') - 1 - >>> try: - ... r.smembers('l') - ... except ResponseError, e: - ... print e - Operation against a key holding the wrong kind of value - >>> r.smembers('s') - set([u'a', u'b']) - >>> - """ - self.connect() - self._write('SMEMBERS %s\r\n' % name) - return set(self.get_response()) - - def sunion(self, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'a') - 1 - >>> r.sadd('s3', 'b') - 1 - >>> r.sunion('s1', 's2', 's3') - set([u'a', u'b']) - >>> r.sadd('s2', 'c') - 1 - >>> r.sunion('s1', 's2', 's3') - set([u'a', u'c', u'b']) - >>> - """ - self.connect() - self._write('SUNION %s\r\n' % ' '.join(args)) - return set(self.get_response()) - - def sunionstore(self, dest, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'a') - 1 - >>> r.sadd('s3', 'b') - 1 - >>> r.sunionstore('s4', 's1', 's2', 's3') - 2 - >>> r.smembers('s4') - set([u'a', u'b']) - >>> - """ - self.connect() - self._write('SUNIONSTORE %s %s\r\n' % (dest, ' '.join(args))) - return self.get_response() - - def select(self, db): - """ - >>> r = Redis(db=9) - >>> r.delete('a') - 1 - >>> r.select(10) - 'OK' - >>> r.set('a', 1) - 'OK' - >>> r.select(9) - 'OK' - >>> r.get('a') - >>> - """ - self.connect() - self._write('SELECT %s\r\n' % db) - return self.get_response() - - def move(self, name, db): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'a') - 'OK' - >>> r.select(10) - 'OK' - >>> if r.get('a'): - ... r.delete('a') - ... else: - ... print 1 - 1 - >>> r.select(9) - 'OK' - >>> r.move('a', 10) - 1 - >>> r.get('a') - >>> r.select(10) - 'OK' - >>> r.get('a') - u'a' - >>> r.select(9) - 'OK' - >>> - """ - self.connect() - self._write('MOVE %s %s\r\n' % (name, db)) - return self.get_response() - - def save(self, background=False): - """ - >>> r = Redis(db=9) - >>> r.save() - 'OK' - >>> try: - ... resp = r.save(background=True) - ... except ResponseError, e: - ... assert str(e) == 'background save already in progress', str(e) - ... else: - ... assert resp == 'OK' - >>> - """ - self.connect() - if background: - self._write('BGSAVE\r\n') - else: - self._write('SAVE\r\n') - return self.get_response() - - def lastsave(self): - """ - >>> import time - >>> r = Redis(db=9) - >>> t = int(time.time()) - >>> r.save() - 'OK' - >>> r.lastsave() >= t - True - >>> - """ - self.connect() - self._write('LASTSAVE\r\n') - return self.get_response() - - def flush(self, all_dbs=False): - """ - >>> r = Redis(db=9) - >>> r.flush() - 'OK' - >>> # r.flush(all_dbs=True) - >>> - """ - self.connect() - self._write('%s\r\n' % ('FLUSHALL' if all_dbs else 'FLUSHDB')) - return self.get_response() - - def info(self): - """ - >>> r = Redis(db=9) - >>> info = r.info() - >>> info and isinstance(info, dict) - True - >>> isinstance(info.get('connected_clients'), int) - True - >>> - """ - self.connect() - self._write('INFO\r\n') - info = dict() - for l in self.get_response().split('\r\n'): - if not l: - continue - k, v = l.split(':', 1) - info[k] = int(v) if v.isdigit() else v - return info - - def auth(self, passwd): - self.connect() - self._write('AUTH %s\r\n' % passwd) - return self.get_response() - - def get_response(self): - data = self._read().strip() - if not data: - self.disconnect() - raise ConnectionError("Socket closed on remote end") - c = data[0] - if c == '-': - raise ResponseError(data[5:] if data[:5] == '-ERR ' else data[1:]) - if c == '+': - return data[1:] - if c == '*': - try: - num = int(data[1:]) - except (TypeError, ValueError): - raise InvalidResponse("Cannot convert multi-response header '%s' to integer" % data) - result = list() - for i in range(num): - result.append(self._get_value()) - return result - return self._get_value(data) - - def _get_value(self, data=None): - data = data or self._read().strip() - if data == '$-1': - return None - try: - c, i = data[0], (int(data[1:]) if data.find('.') == -1 else float(data[1:])) - except ValueError: - raise InvalidResponse("Cannot convert data '%s' to integer" % data) - if c == ':': - return i - if c != '$': - raise InvalidResponse("Unkown response prefix for '%s'" % data) - buf = [] - while True: - data = self._read() - i -= len(data) - buf.append(data) - if i < 0: - break - data = ''.join(buf)[:-2] - try: - return int(data) if data.find('.') == -1 else decimal.Decimal(data) - except (ValueError, decimal.InvalidOperation): - return data.decode(self.charset) - - def disconnect(self): - if isinstance(self._sock, socket.socket): - try: - self._sock.close() - except socket.error: - pass - self._sock = None - self._fp = None - - def connect(self): - """ - >>> r = Redis(db=9) - >>> r.connect() - >>> isinstance(r._sock, socket.socket) - True - >>> r.disconnect() - >>> - """ - if isinstance(self._sock, socket.socket): - return - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((self.host, self.port)) - except socket.error, e: - raise ConnectionError("Error %s connecting to %s:%s. %s." % (e.args[0], self.host, self.port, e.args[1])) - else: - self._sock = sock - self._fp = self._sock.makefile('r') - if self.db: - self.select(self.db) - if self.nodelay is not None: - self._sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, self.nodelay) - - -if __name__ == '__main__': - import doctest - doctest.testmod() - diff --git a/client-libraries/ruby/.gitignore b/client-libraries/ruby/.gitignore deleted file mode 100644 index f3b05636..00000000 --- a/client-libraries/ruby/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -nohup.out -redis/* -rdsrv -pkg/* -coverage/* -.idea diff --git a/client-libraries/ruby/LICENSE b/client-libraries/ruby/LICENSE deleted file mode 100644 index 5e648fa9..00000000 --- a/client-libraries/ruby/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2009 Ezra Zygmuntowicz - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/client-libraries/ruby/README.markdown b/client-libraries/ruby/README.markdown deleted file mode 100644 index b36633d6..00000000 --- a/client-libraries/ruby/README.markdown +++ /dev/null @@ -1,34 +0,0 @@ -# redis-rb - -A ruby client library for the redis key value storage system. - -## Information about redis - -Redis is a key value store with some interesting features: -1. It's fast. -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. - -See [redis on code.google.com](http://code.google.com/p/redis/wiki/README) for more information. - -## Dependencies - -1. rspec - - sudo gem install rspec - -2. redis - - - rake redis:install - -2. dtach - - - rake dtach:install - -3. git - git is the new black. - -## Setup - -Use the tasks mentioned above (in Dependencies) to get your machine setup. - -## Examples - -Check the examples/ directory. *Note* you need to have redis-server running first. \ No newline at end of file diff --git a/client-libraries/ruby/Rakefile b/client-libraries/ruby/Rakefile deleted file mode 100644 index e659d18a..00000000 --- a/client-libraries/ruby/Rakefile +++ /dev/null @@ -1,62 +0,0 @@ -require 'rubygems' -require 'rake/gempackagetask' -require 'rubygems/specification' -require 'date' -require 'spec/rake/spectask' -require 'tasks/redis.tasks' - - -GEM = 'redis' -GEM_NAME = 'redis' -GEM_VERSION = '0.1' -AUTHORS = ['Ezra Zygmuntowicz', 'Taylor Weibley', 'Matthew Clark', 'Brian McKinney', 'Salvatore Sanfilippo', 'Luca Guidi'] -EMAIL = "ez@engineyard.com" -HOMEPAGE = "http://github.com/ezmobius/redis-rb" -SUMMARY = "Ruby client library for redis key value storage server" - -spec = Gem::Specification.new do |s| - s.name = GEM - s.version = GEM_VERSION - s.platform = Gem::Platform::RUBY - s.has_rdoc = true - s.extra_rdoc_files = ["LICENSE"] - s.summary = SUMMARY - s.description = s.summary - s.authors = AUTHORS - s.email = EMAIL - s.homepage = HOMEPAGE - s.add_dependency "rspec" - s.require_path = 'lib' - s.autorequire = GEM - s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{lib,tasks,spec}/**/*") -end - -task :default => :spec - -desc "Run specs" -Spec::Rake::SpecTask.new do |t| - t.spec_files = FileList['spec/**/*_spec.rb'] - t.spec_opts = %w(-fs --color) -end - -Rake::GemPackageTask.new(spec) do |pkg| - pkg.gem_spec = spec -end - -desc "install the gem locally" -task :install => [:package] do - sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}} -end - -desc "create a gemspec file" -task :make_spec do - File.open("#{GEM}.gemspec", "w") do |file| - file.puts spec.to_ruby - end -end - -desc "Run all examples with RCov" -Spec::Rake::SpecTask.new(:rcov) do |t| - t.spec_files = FileList['spec/**/*_spec.rb'] - t.rcov = true -end diff --git a/client-libraries/ruby/bench.rb b/client-libraries/ruby/bench.rb deleted file mode 100644 index 82898d0c..00000000 --- a/client-libraries/ruby/bench.rb +++ /dev/null @@ -1,44 +0,0 @@ -require 'benchmark' -$:.push File.join(File.dirname(__FILE__), 'lib') -require 'redis' - -times = 20000 - -@r = Redis.new#(:debug => true) -@r['foo'] = "The first line we sent to the server is some text" - -Benchmark.bmbm do |x| - x.report("set") do - 20000.times do |i| - @r["set#{i}"] = "The first line we sent to the server is some text"; @r["foo#{i}"] - end - end - - x.report("set (pipelined)") do - @r.pipelined do |pipeline| - 20000.times do |i| - pipeline["set_pipelined#{i}"] = "The first line we sent to the server is some text"; @r["foo#{i}"] - end - end - end - - x.report("push+trim") do - 20000.times do |i| - @r.push_head "push_trim#{i}", i - @r.list_trim "push_trim#{i}", 0, 30 - end - end - - x.report("push+trim (pipelined)") do - @r.pipelined do |pipeline| - 20000.times do |i| - pipeline.push_head "push_trim_pipelined#{i}", i - pipeline.list_trim "push_trim_pipelined#{i}", 0, 30 - end - end - end -end - -@r.keys('*').each do |k| - @r.delete k -end \ No newline at end of file diff --git a/client-libraries/ruby/benchmarking/suite.rb b/client-libraries/ruby/benchmarking/suite.rb deleted file mode 100644 index f03694b0..00000000 --- a/client-libraries/ruby/benchmarking/suite.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'fileutils' - -def run_in_background(command) - fork { system command } -end - -def with_all_segments(&block) - 0.upto(9) do |segment_number| - block_size = 100000 - start_index = segment_number * block_size - end_index = start_index + block_size - 1 - block.call(start_index, end_index) - end -end - -#with_all_segments do |start_index, end_index| -# puts "Initializing keys from #{start_index} to #{end_index}" -# system "ruby worker.rb initialize #{start_index} #{end_index} 0" -#end - -with_all_segments do |start_index, end_index| - run_in_background "ruby worker.rb write #{start_index} #{end_index} 10" - run_in_background "ruby worker.rb read #{start_index} #{end_index} 1" -end \ No newline at end of file diff --git a/client-libraries/ruby/benchmarking/worker.rb b/client-libraries/ruby/benchmarking/worker.rb deleted file mode 100644 index 836d03b0..00000000 --- a/client-libraries/ruby/benchmarking/worker.rb +++ /dev/null @@ -1,71 +0,0 @@ -BENCHMARK_ROOT = File.dirname(__FILE__) -REDIS_ROOT = File.join(BENCHMARK_ROOT, "..", "lib") - -$: << REDIS_ROOT -require 'redis' -require 'benchmark' - -def show_usage - puts <<-EOL - Usage: worker.rb [read:write] - EOL -end - -def shift_from_argv - value = ARGV.shift - unless value - show_usage - exit -1 - end - value -end - -operation = shift_from_argv.to_sym -start_index = shift_from_argv.to_i -end_index = shift_from_argv.to_i -sleep_msec = shift_from_argv.to_i -sleep_duration = sleep_msec/1000.0 - -redis = Redis.new - -case operation - when :initialize - - start_index.upto(end_index) do |i| - redis[i] = 0 - end - - when :clear - - start_index.upto(end_index) do |i| - redis.delete(i) - end - - when :read, :write - - puts "Starting to #{operation} at segment #{end_index + 1}" - - loop do - t1 = Time.now - start_index.upto(end_index) do |i| - case operation - when :read - redis.get(i) - when :write - redis.incr(i) - else - raise "Unknown operation: #{operation}" - end - sleep sleep_duration - end - t2 = Time.now - - requests_processed = end_index - start_index - time = t2 - t1 - puts "#{t2.strftime("%H:%M")} [segment #{end_index + 1}] : Processed #{requests_processed} requests in #{time} seconds - #{(requests_processed/time).round} requests/sec" - end - - else - raise "Unknown operation: #{operation}" -end - diff --git a/client-libraries/ruby/bin/distredis b/client-libraries/ruby/bin/distredis deleted file mode 100755 index d5702079..00000000 --- a/client-libraries/ruby/bin/distredis +++ /dev/null @@ -1,33 +0,0 @@ -require 'fileutils' - -class RedisCluster - - def initialize(opts={}) - opts = {:port => 6379, :host => 'localhost', :basedir => "#{Dir.pwd}/rdsrv" }.merge(opts) - FileUtils.mkdir_p opts[:basedir] - opts[:size].times do |i| - port = opts[:port] + i - FileUtils.mkdir_p "#{opts[:basedir]}/#{port}" - File.open("#{opts[:basedir]}/#{port}.conf", 'w'){|f| f.write(make_config(port, "#{opts[:basedir]}/#{port}", "#{opts[:basedir]}/#{port}.log"))} - system(%Q{#{File.join(File.expand_path(File.dirname(__FILE__)), "../redis/redis-server #{opts[:basedir]}/#{port}.conf &" )}}) - end - end - - def make_config(port=6379, data=port, logfile='stdout', loglevel='debug') - config = %Q{ -timeout 300 -save 900 1 -save 300 10 -save 60 10000 -dir #{data} -loglevel #{loglevel} -logfile #{logfile} -databases 16 -port #{port} - } - end - -end - - -RedisCluster.new :size => 4 \ No newline at end of file diff --git a/client-libraries/ruby/examples/basic.rb b/client-libraries/ruby/examples/basic.rb deleted file mode 100644 index 022796db..00000000 --- a/client-libraries/ruby/examples/basic.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'rubygems' -require 'redis' - -r = Redis.new - -r.delete('foo') - -puts - -p'set foo to "bar"' -r['foo'] = 'bar' - -puts - -p 'value of foo' -p r['foo'] diff --git a/client-libraries/ruby/examples/incr-decr.rb b/client-libraries/ruby/examples/incr-decr.rb deleted file mode 100644 index e951969a..00000000 --- a/client-libraries/ruby/examples/incr-decr.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'rubygems' -require 'redis' - -r = Redis.new - -puts -p 'incr' -r.delete 'counter' - -p r.incr('counter') -p r.incr('counter') -p r.incr('counter') - -puts -p 'decr' -p r.decr('counter') -p r.decr('counter') -p r.decr('counter') diff --git a/client-libraries/ruby/examples/list.rb b/client-libraries/ruby/examples/list.rb deleted file mode 100644 index 8f186c15..00000000 --- a/client-libraries/ruby/examples/list.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'rubygems' -require 'redis' - -r = Redis.new - -r.delete 'logs' - -puts - -p "pushing log messages into a LIST" -r.push_tail 'logs', 'some log message' -r.push_tail 'logs', 'another log message' -r.push_tail 'logs', 'yet another log message' -r.push_tail 'logs', 'also another log message' - -puts -p 'contents of logs LIST' - -p r.list_range('logs', 0, -1) - -puts -p 'Trim logs LIST to last 2 elements(easy circular buffer)' - -r.list_trim('logs', -2, -1) - -p r.list_range('logs', 0, -1) diff --git a/client-libraries/ruby/examples/sets.rb b/client-libraries/ruby/examples/sets.rb deleted file mode 100644 index 1ba4e30c..00000000 --- a/client-libraries/ruby/examples/sets.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'rubygems' -require 'redis' - -r = Redis.new - -r.delete 'foo-tags' -r.delete 'bar-tags' - -puts -p "create a set of tags on foo-tags" - -r.set_add 'foo-tags', 'one' -r.set_add 'foo-tags', 'two' -r.set_add 'foo-tags', 'three' - -puts -p "create a set of tags on bar-tags" - -r.set_add 'bar-tags', 'three' -r.set_add 'bar-tags', 'four' -r.set_add 'bar-tags', 'five' - -puts -p 'foo-tags' - -p r.set_members('foo-tags') - -puts -p 'bar-tags' - -p r.set_members('bar-tags') - -puts -p 'intersection of foo-tags and bar-tags' - -p r.set_intersect('foo-tags', 'bar-tags') diff --git a/client-libraries/ruby/lib/dist_redis.rb b/client-libraries/ruby/lib/dist_redis.rb deleted file mode 100644 index d92c956e..00000000 --- a/client-libraries/ruby/lib/dist_redis.rb +++ /dev/null @@ -1,124 +0,0 @@ -require 'redis' -require 'hash_ring' -class DistRedis - attr_reader :ring - def initialize(opts={}) - hosts = [] - - db = opts[:db] || nil - timeout = opts[:timeout] || nil - - raise Error, "No hosts given" unless opts[:hosts] - - opts[:hosts].each do |h| - host, port = h.split(':') - hosts << Redis.new(:host => host, :port => port, :db => db, :timeout => timeout) - end - - @ring = HashRing.new hosts - end - - def node_for_key(key) - key = $1 if key =~ /\{(.*)?\}/ - @ring.get_node(key) - end - - def add_server(server) - server, port = server.split(':') - @ring.add_node Redis.new(:host => server, :port => port) - end - - def method_missing(sym, *args, &blk) - if redis = node_for_key(args.first.to_s) - redis.send sym, *args, &blk - else - super - end - end - - def keys(glob) - @ring.nodes.map do |red| - red.keys(glob) - end - end - - def save - on_each_node :save - end - - def bgsave - on_each_node :bgsave - end - - def quit - on_each_node :quit - end - - def flush_all - on_each_node :flush_all - end - alias_method :flushall, :flush_all - - def flush_db - on_each_node :flush_db - end - alias_method :flushdb, :flush_db - - def delete_cloud! - @ring.nodes.each do |red| - red.keys("*").each do |key| - red.delete key - end - end - end - - def on_each_node(command, *args) - @ring.nodes.each do |red| - red.send(command, *args) - end - end - -end - - -if __FILE__ == $0 - -r = DistRedis.new 'localhost:6379', 'localhost:6380', 'localhost:6381', 'localhost:6382' - r['urmom'] = 'urmom' - r['urdad'] = 'urdad' - r['urmom1'] = 'urmom1' - r['urdad1'] = 'urdad1' - r['urmom2'] = 'urmom2' - r['urdad2'] = 'urdad2' - r['urmom3'] = 'urmom3' - r['urdad3'] = 'urdad3' - p r['urmom'] - p r['urdad'] - p r['urmom1'] - p r['urdad1'] - p r['urmom2'] - p r['urdad2'] - p r['urmom3'] - p r['urdad3'] - - r.push_tail 'listor', 'foo1' - r.push_tail 'listor', 'foo2' - r.push_tail 'listor', 'foo3' - r.push_tail 'listor', 'foo4' - r.push_tail 'listor', 'foo5' - - p r.pop_tail('listor') - p r.pop_tail('listor') - p r.pop_tail('listor') - p r.pop_tail('listor') - p r.pop_tail('listor') - - puts "key distribution:" - - r.ring.nodes.each do |red| - p [red.port, red.keys("*")] - end - r.delete_cloud! - p r.keys('*') - -end diff --git a/client-libraries/ruby/lib/hash_ring.rb b/client-libraries/ruby/lib/hash_ring.rb deleted file mode 100644 index ec488636..00000000 --- a/client-libraries/ruby/lib/hash_ring.rb +++ /dev/null @@ -1,128 +0,0 @@ -require 'zlib' - -class HashRing - - POINTS_PER_SERVER = 160 # this is the default in libmemcached - - attr_reader :ring, :sorted_keys, :replicas, :nodes - - # nodes is a list of objects that have a proper to_s representation. - # replicas indicates how many virtual points should be used pr. node, - # replicas are required to improve the distribution. - def initialize(nodes=[], replicas=POINTS_PER_SERVER) - @replicas = replicas - @ring = {} - @nodes = [] - @sorted_keys = [] - nodes.each do |node| - add_node(node) - end - end - - # Adds a `node` to the hash ring (including a number of replicas). - def add_node(node) - @nodes << node - @replicas.times do |i| - key = Zlib.crc32("#{node}:#{i}") - @ring[key] = node - @sorted_keys << key - end - @sorted_keys.sort! - end - - def remove_node(node) - @nodes.reject!{|n| n.to_s == node.to_s} - @replicas.times do |i| - key = Zlib.crc32("#{node}:#{i}") - @ring.delete(key) - @sorted_keys.reject! {|k| k == key} - end - end - - # get the node in the hash ring for this key - def get_node(key) - get_node_pos(key)[0] - end - - def get_node_pos(key) - return [nil,nil] if @ring.size == 0 - crc = Zlib.crc32(key) - idx = HashRing.binary_search(@sorted_keys, crc) - return [@ring[@sorted_keys[idx]], idx] - end - - def iter_nodes(key) - return [nil,nil] if @ring.size == 0 - node, pos = get_node_pos(key) - @sorted_keys[pos..-1].each do |k| - yield @ring[k] - end - end - - class << self - - # gem install RubyInline to use this code - # Native extension to perform the binary search within the hashring. - # There's a pure ruby version below so this is purely optional - # for performance. In testing 20k gets and sets, the native - # binary search shaved about 12% off the runtime (9sec -> 8sec). - begin - require 'inline' - inline do |builder| - builder.c <<-EOM - int binary_search(VALUE ary, unsigned int r) { - int upper = RARRAY_LEN(ary) - 1; - int lower = 0; - int idx = 0; - - while (lower <= upper) { - idx = (lower + upper) / 2; - - VALUE continuumValue = RARRAY_PTR(ary)[idx]; - unsigned int l = NUM2UINT(continuumValue); - if (l == r) { - return idx; - } - else if (l > r) { - upper = idx - 1; - } - else { - lower = idx + 1; - } - } - return upper; - } - EOM - end - rescue Exception => e - # Find the closest index in HashRing with value <= the given value - def binary_search(ary, value, &block) - upper = ary.size - 1 - lower = 0 - idx = 0 - - while(lower <= upper) do - idx = (lower + upper) / 2 - comp = ary[idx] <=> value - - if comp == 0 - return idx - elsif comp > 0 - upper = idx - 1 - else - lower = idx + 1 - end - end - return upper - end - - end - end - -end - -# ring = HashRing.new ['server1', 'server2', 'server3'] -# p ring -# # -# p ring.get_node "kjhjkjlkjlkkh" -# \ No newline at end of file diff --git a/client-libraries/ruby/lib/pipeline.rb b/client-libraries/ruby/lib/pipeline.rb deleted file mode 100644 index acab5acc..00000000 --- a/client-libraries/ruby/lib/pipeline.rb +++ /dev/null @@ -1,22 +0,0 @@ -require "redis" - -class Redis - class Pipeline < Redis - BUFFER_SIZE = 50_000 - - def initialize(redis) - @redis = redis - @commands = [] - end - - def call_command(command) - @commands << command - end - - def execute - @redis.call_command(@commands) - @commands.clear - end - - end -end diff --git a/client-libraries/ruby/lib/redis.rb b/client-libraries/ruby/lib/redis.rb deleted file mode 100644 index bbe5343e..00000000 --- a/client-libraries/ruby/lib/redis.rb +++ /dev/null @@ -1,316 +0,0 @@ -require 'socket' -require File.join(File.dirname(__FILE__),'pipeline') - -begin - if RUBY_VERSION >= '1.9' - require 'timeout' - RedisTimer = Timeout - else - require 'system_timer' - RedisTimer = SystemTimer - end -rescue LoadError - RedisTimer = nil -end - -class Redis - OK = "OK".freeze - MINUS = "-".freeze - PLUS = "+".freeze - COLON = ":".freeze - DOLLAR = "$".freeze - ASTERISK = "*".freeze - - BULK_COMMANDS = { - "set" => true, - "setnx" => true, - "rpush" => true, - "lpush" => true, - "lset" => true, - "lrem" => true, - "sadd" => true, - "srem" => true, - "sismember" => true, - "echo" => true, - "getset" => true, - "smove" => true - } - - BOOLEAN_PROCESSOR = lambda{|r| r == 1 } - - REPLY_PROCESSOR = { - "exists" => BOOLEAN_PROCESSOR, - "sismember" => BOOLEAN_PROCESSOR, - "sadd" => BOOLEAN_PROCESSOR, - "srem" => BOOLEAN_PROCESSOR, - "smove" => BOOLEAN_PROCESSOR, - "move" => BOOLEAN_PROCESSOR, - "setnx" => BOOLEAN_PROCESSOR, - "del" => BOOLEAN_PROCESSOR, - "renamenx" => BOOLEAN_PROCESSOR, - "expire" => BOOLEAN_PROCESSOR, - "keys" => lambda{|r| r.split(" ")}, - "info" => lambda{|r| - info = {} - r.each_line {|kv| - k,v = kv.split(":",2).map{|x| x.chomp} - info[k.to_sym] = v - } - info - } - } - - ALIASES = { - "flush_db" => "flushdb", - "flush_all" => "flushall", - "last_save" => "lastsave", - "key?" => "exists", - "delete" => "del", - "randkey" => "randomkey", - "list_length" => "llen", - "push_tail" => "rpush", - "push_head" => "lpush", - "pop_tail" => "rpop", - "pop_head" => "lpop", - "list_set" => "lset", - "list_range" => "lrange", - "list_trim" => "ltrim", - "list_index" => "lindex", - "list_rm" => "lrem", - "set_add" => "sadd", - "set_delete" => "srem", - "set_count" => "scard", - "set_member?" => "sismember", - "set_members" => "smembers", - "set_intersect" => "sinter", - "set_intersect_store" => "sinterstore", - "set_inter_store" => "sinterstore", - "set_union" => "sunion", - "set_union_store" => "sunionstore", - "set_diff" => "sdiff", - "set_diff_store" => "sdiffstore", - "set_move" => "smove", - "set_unless_exists" => "setnx", - "rename_unless_exists" => "renamenx", - "type?" => "type" - } - - DISABLED_COMMANDS = { - "monitor" => true, - "sync" => true - } - - def initialize(options = {}) - @host = options[:host] || '127.0.0.1' - @port = (options[:port] || 6379).to_i - @db = (options[:db] || 0).to_i - @timeout = (options[:timeout] || 5).to_i - @password = options[:password] - @logger = options[:logger] - - @logger.info { self.to_s } if @logger - connect_to_server - end - - def to_s - "Redis Client connected to #{server} against DB #{@db}" - end - - def server - "#{@host}:#{@port}" - end - - def connect_to_server - @sock = connect_to(@host, @port, @timeout == 0 ? nil : @timeout) - call_command(["auth",@password]) if @password - call_command(["select",@db]) unless @db == 0 - end - - def connect_to(host, port, timeout=nil) - # We support connect() timeout only if system_timer is availabe - # or if we are running against Ruby >= 1.9 - # Timeout reading from the socket instead will be supported anyway. - if @timeout != 0 and RedisTimer - begin - sock = TCPSocket.new(host, port) - rescue Timeout::Error - @sock = nil - raise Timeout::Error, "Timeout connecting to the server" - end - else - sock = TCPSocket.new(host, port) - end - sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 - - # If the timeout is set we set the low level socket options in order - # to make sure a blocking read will return after the specified number - # of seconds. This hack is from memcached ruby client. - if timeout - secs = Integer(timeout) - usecs = Integer((timeout - secs) * 1_000_000) - optval = [secs, usecs].pack("l_2") - sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval - sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval - end - sock - end - - def method_missing(*argv) - call_command(argv) - end - - def call_command(argv) - @logger.debug { argv.inspect } if @logger - - # this wrapper to raw_call_command handle reconnection on socket - # error. We try to reconnect just one time, otherwise let the error - # araise. - connect_to_server if !@sock - - begin - raw_call_command(argv.dup) - rescue Errno::ECONNRESET, Errno::EPIPE - @sock.close - @sock = nil - connect_to_server - raw_call_command(argv.dup) - end - end - - def raw_call_command(argvp) - pipeline = argvp[0].is_a?(Array) - - unless pipeline - argvv = [argvp] - else - argvv = argvp - end - - command = '' - - argvv.each do |argv| - bulk = nil - argv[0] = argv[0].to_s.downcase - argv[0] = ALIASES[argv[0]] if ALIASES[argv[0]] - raise "#{argv[0]} command is disabled" if DISABLED_COMMANDS[argv[0]] - if BULK_COMMANDS[argv[0]] and argv.length > 1 - bulk = argv[-1].to_s - argv[-1] = bulk.respond_to?(:bytesize) ? bulk.bytesize : bulk.size - end - command << "#{argv.join(' ')}\r\n" - command << "#{bulk}\r\n" if bulk - end - - @sock.write(command) - - results = argvv.map do |argv| - processor = REPLY_PROCESSOR[argv[0]] - processor ? processor.call(read_reply) : read_reply - end - - return pipeline ? results : results[0] - end - - def select(*args) - raise "SELECT not allowed, use the :db option when creating the object" - end - - def [](key) - self.get(key) - end - - def []=(key,value) - set(key,value) - end - - def set(key, value, expiry=nil) - s = call_command([:set, key, value]) == OK - expire(key, expiry) if s && expiry - s - end - - def sort(key, options = {}) - cmd = ["SORT"] - cmd << key - cmd << "BY #{options[:by]}" if options[:by] - cmd << "GET #{[options[:get]].flatten * ' GET '}" if options[:get] - cmd << "#{options[:order]}" if options[:order] - cmd << "LIMIT #{options[:limit].join(' ')}" if options[:limit] - call_command(cmd) - end - - def incr(key, increment = nil) - call_command(increment ? ["incrby",key,increment] : ["incr",key]) - end - - def decr(key,decrement = nil) - call_command(decrement ? ["decrby",key,decrement] : ["decr",key]) - end - - # Similar to memcache.rb's #get_multi, returns a hash mapping - # keys to values. - def mapped_mget(*keys) - mget(*keys).inject({}) do |hash, value| - key = keys.shift - value.nil? ? hash : hash.merge(key => value) - end - end - - # Ruby defines a now deprecated type method so we need to override it here - # since it will never hit method_missing - def type(key) - call_command(['type', key]) - end - - def quit - call_command(['quit']) - rescue Errno::ECONNRESET - end - - def pipelined(&block) - pipeline = Pipeline.new self - yield pipeline - pipeline.execute - end - - def read_reply - # We read the first byte using read() mainly because gets() is - # immune to raw socket timeouts. - begin - rtype = @sock.read(1) - rescue Errno::EAGAIN - # We want to make sure it reconnects on the next command after the - # timeout. Otherwise the server may reply in the meantime leaving - # the protocol in a desync status. - @sock = nil - raise Errno::EAGAIN, "Timeout reading from the socket" - end - - raise Errno::ECONNRESET,"Connection lost" if !rtype - line = @sock.gets - case rtype - when MINUS - raise MINUS + line.strip - when PLUS - line.strip - when COLON - line.to_i - when DOLLAR - bulklen = line.to_i - return nil if bulklen == -1 - data = @sock.read(bulklen) - @sock.read(2) # CRLF - data - when ASTERISK - objects = line.to_i - return nil if bulklen == -1 - res = [] - objects.times { - res << read_reply - } - res - else - raise "Protocol error, got '#{rtype}' as initial reply byte" - end - end -end diff --git a/client-libraries/ruby/profile.rb b/client-libraries/ruby/profile.rb deleted file mode 100644 index e5dc8c03..00000000 --- a/client-libraries/ruby/profile.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'rubygems' -require 'ruby-prof' -require "#{File.dirname(__FILE__)}/lib/redis" - - -mode = ARGV.shift || 'process_time' -n = (ARGV.shift || 200).to_i - -r = Redis.new -RubyProf.measure_mode = RubyProf.const_get(mode.upcase) -RubyProf.start - -n.times do |i| - key = "foo#{i}" - r[key] = key * 10 - r[key] -end - -results = RubyProf.stop -File.open("profile.#{mode}", 'w') do |out| - RubyProf::CallTreePrinter.new(results).print(out) -end diff --git a/client-libraries/ruby/redis-rb.gemspec b/client-libraries/ruby/redis-rb.gemspec deleted file mode 100644 index 04de472c..00000000 --- a/client-libraries/ruby/redis-rb.gemspec +++ /dev/null @@ -1,30 +0,0 @@ -# -*- encoding: utf-8 -*- - -Gem::Specification.new do |s| - s.name = %q{redis} - s.version = "0.1" - - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.authors = ["Ezra Zygmuntowicz", "Taylor Weibley", "Matthew Clark", "Brian McKinney", "Salvatore Sanfilippo", "Luca Guidi"] - # s.autorequire = %q{redis-rb} - s.date = %q{2009-06-23} - s.description = %q{Ruby client library for redis key value storage server} - s.email = %q{ez@engineyard.com} - s.extra_rdoc_files = ["LICENSE"] - 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"] - s.has_rdoc = true - s.homepage = %q{http://github.com/ezmobius/redis-rb} - s.require_paths = ["lib"] - s.rubygems_version = %q{1.3.1} - s.summary = %q{Ruby client library for redis key value storage server} - - if s.respond_to? :specification_version then - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION - s.specification_version = 2 - - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then - else - end - else - end -end diff --git a/client-libraries/ruby/spec/redis_spec.rb b/client-libraries/ruby/spec/redis_spec.rb deleted file mode 100644 index 0da249e1..00000000 --- a/client-libraries/ruby/spec/redis_spec.rb +++ /dev/null @@ -1,478 +0,0 @@ -require File.dirname(__FILE__) + '/spec_helper' -require 'logger' - -class Foo - attr_accessor :bar - def initialize(bar) - @bar = bar - end - - def ==(other) - @bar == other.bar - end -end - -describe "redis" do - before(:all) do - # use database 15 for testing so we dont accidentally step on you real data - @r = Redis.new :db => 15 - end - - before(:each) do - @r['foo'] = 'bar' - end - - after(:each) do - @r.keys('*').each {|k| @r.del k} - end - - after(:all) do - @r.quit - end - - it "should be able connect without a timeout" do - lambda { Redis.new :timeout => 0 }.should_not raise_error - end - - it "should be able to provide a logger" do - log = StringIO.new - r = Redis.new :db => 15, :logger => Logger.new(log) - r.ping - log.string.should include("ping") - end - - it "should be able to PING" do - @r.ping.should == 'PONG' - end - - it "should be able to GET a key" do - @r['foo'].should == 'bar' - end - - it "should be able to SET a key" do - @r['foo'] = 'nik' - @r['foo'].should == 'nik' - end - - it "should properly handle trailing newline characters" do - @r['foo'] = "bar\n" - @r['foo'].should == "bar\n" - end - - it "should store and retrieve all possible characters at the beginning and the end of a string" do - (0..255).each do |char_idx| - string = "#{char_idx.chr}---#{char_idx.chr}" - @r['foo'] = string - @r['foo'].should == string - end - end - - it "should be able to SET a key with an expiry" do - @r.set('foo', 'bar', 1) - @r['foo'].should == 'bar' - sleep 2 - @r['foo'].should == nil - end - - it "should be able to return a TTL for a key" do - @r.set('foo', 'bar', 1) - @r.ttl('foo').should == 1 - end - - it "should be able to SETNX" do - @r['foo'] = 'nik' - @r['foo'].should == 'nik' - @r.setnx 'foo', 'bar' - @r['foo'].should == 'nik' - end - # - it "should be able to GETSET" do - @r.getset('foo', 'baz').should == 'bar' - @r['foo'].should == 'baz' - end - # - it "should be able to INCR a key" do - @r.del('counter') - @r.incr('counter').should == 1 - @r.incr('counter').should == 2 - @r.incr('counter').should == 3 - end - # - it "should be able to INCRBY a key" do - @r.del('counter') - @r.incrby('counter', 1).should == 1 - @r.incrby('counter', 2).should == 3 - @r.incrby('counter', 3).should == 6 - end - # - it "should be able to DECR a key" do - @r.del('counter') - @r.incr('counter').should == 1 - @r.incr('counter').should == 2 - @r.incr('counter').should == 3 - @r.decr('counter').should == 2 - @r.decr('counter', 2).should == 0 - end - # - it "should be able to RANDKEY" do - @r.randkey.should_not be_nil - end - # - it "should be able to RENAME a key" do - @r.del 'foo' - @r.del'bar' - @r['foo'] = 'hi' - @r.rename 'foo', 'bar' - @r['bar'].should == 'hi' - end - # - it "should be able to RENAMENX a key" do - @r.del 'foo' - @r.del 'bar' - @r['foo'] = 'hi' - @r['bar'] = 'ohai' - @r.renamenx 'foo', 'bar' - @r['bar'].should == 'ohai' - end - # - it "should be able to get DBSIZE of the database" do - @r.delete 'foo' - dbsize_without_foo = @r.dbsize - @r['foo'] = 0 - dbsize_with_foo = @r.dbsize - - dbsize_with_foo.should == dbsize_without_foo + 1 - end - # - it "should be able to EXPIRE a key" do - @r['foo'] = 'bar' - @r.expire 'foo', 1 - @r['foo'].should == "bar" - sleep 2 - @r['foo'].should == nil - end - # - it "should be able to EXISTS" do - @r['foo'] = 'nik' - @r.exists('foo').should be_true - @r.del 'foo' - @r.exists('foo').should be_false - end - # - it "should be able to KEYS" do - @r.keys("f*").each { |key| @r.del key } - @r['f'] = 'nik' - @r['fo'] = 'nak' - @r['foo'] = 'qux' - @r.keys("f*").sort.should == ['f','fo', 'foo'].sort - end - # - it "should be able to return a random key (RANDOMKEY)" do - 3.times { @r.exists(@r.randomkey).should be_true } - end - # - it "should be able to check the TYPE of a key" do - @r['foo'] = 'nik' - @r.type('foo').should == "string" - @r.del 'foo' - @r.type('foo').should == "none" - end - # - it "should be able to push to the head of a list (LPUSH)" do - @r.lpush "list", 'hello' - @r.lpush "list", 42 - @r.type('list').should == "list" - @r.llen('list').should == 2 - @r.lpop('list').should == '42' - end - # - it "should be able to push to the tail of a list (RPUSH)" do - @r.rpush "list", 'hello' - @r.type('list').should == "list" - @r.llen('list').should == 1 - end - # - it "should be able to pop the tail of a list (RPOP)" do - @r.rpush "list", 'hello' - @r.rpush"list", 'goodbye' - @r.type('list').should == "list" - @r.llen('list').should == 2 - @r.rpop('list').should == 'goodbye' - end - # - it "should be able to pop the head of a list (LPOP)" do - @r.rpush "list", 'hello' - @r.rpush "list", 'goodbye' - @r.type('list').should == "list" - @r.llen('list').should == 2 - @r.lpop('list').should == 'hello' - end - # - it "should be able to get the length of a list (LLEN)" do - @r.rpush "list", 'hello' - @r.rpush "list", 'goodbye' - @r.type('list').should == "list" - @r.llen('list').should == 2 - end - # - it "should be able to get a range of values from a list (LRANGE)" do - @r.rpush "list", 'hello' - @r.rpush "list", 'goodbye' - @r.rpush "list", '1' - @r.rpush "list", '2' - @r.rpush "list", '3' - @r.type('list').should == "list" - @r.llen('list').should == 5 - @r.lrange('list', 2, -1).should == ['1', '2', '3'] - end - # - it "should be able to trim a list (LTRIM)" do - @r.rpush "list", 'hello' - @r.rpush "list", 'goodbye' - @r.rpush "list", '1' - @r.rpush "list", '2' - @r.rpush "list", '3' - @r.type('list').should == "list" - @r.llen('list').should == 5 - @r.ltrim 'list', 0, 1 - @r.llen('list').should == 2 - @r.lrange('list', 0, -1).should == ['hello', 'goodbye'] - end - # - it "should be able to get a value by indexing into a list (LINDEX)" do - @r.rpush "list", 'hello' - @r.rpush "list", 'goodbye' - @r.type('list').should == "list" - @r.llen('list').should == 2 - @r.lindex('list', 1).should == 'goodbye' - end - # - it "should be able to set a value by indexing into a list (LSET)" do - @r.rpush "list", 'hello' - @r.rpush "list", 'hello' - @r.type('list').should == "list" - @r.llen('list').should == 2 - @r.lset('list', 1, 'goodbye').should == 'OK' - @r.lindex('list', 1).should == 'goodbye' - end - # - it "should be able to remove values from a list (LREM)" do - @r.rpush "list", 'hello' - @r.rpush "list", 'goodbye' - @r.type('list').should == "list" - @r.llen('list').should == 2 - @r.lrem('list', 1, 'hello').should == 1 - @r.lrange('list', 0, -1).should == ['goodbye'] - end - # - it "should be able add members to a set (SADD)" do - @r.sadd "set", 'key1' - @r.sadd "set", 'key2' - @r.type('set').should == "set" - @r.scard('set').should == 2 - @r.smembers('set').sort.should == ['key1', 'key2'].sort - end - # - it "should be able delete members to a set (SREM)" do - @r.sadd "set", 'key1' - @r.sadd "set", 'key2' - @r.type('set').should == "set" - @r.scard('set').should == 2 - @r.smembers('set').sort.should == ['key1', 'key2'].sort - @r.srem('set', 'key1') - @r.scard('set').should == 1 - @r.smembers('set').should == ['key2'] - end - # - it "should be able count the members of a set (SCARD)" do - @r.sadd "set", 'key1' - @r.sadd "set", 'key2' - @r.type('set').should == "set" - @r.scard('set').should == 2 - end - # - it "should be able test for set membership (SISMEMBER)" do - @r.sadd "set", 'key1' - @r.sadd "set", 'key2' - @r.type('set').should == "set" - @r.scard('set').should == 2 - @r.sismember('set', 'key1').should be_true - @r.sismember('set', 'key2').should be_true - @r.sismember('set', 'notthere').should be_false - end - # - it "should be able to do set intersection (SINTER)" do - @r.sadd "set", 'key1' - @r.sadd "set", 'key2' - @r.sadd "set2", 'key2' - @r.sinter('set', 'set2').should == ['key2'] - end - # - it "should be able to do set intersection and store the results in a key (SINTERSTORE)" do - @r.sadd "set", 'key1' - @r.sadd "set", 'key2' - @r.sadd "set2", 'key2' - @r.sinterstore('newone', 'set', 'set2').should == 1 - @r.smembers('newone').should == ['key2'] - end - # - it "should be able to do set union (SUNION)" do - @r.sadd "set", 'key1' - @r.sadd "set", 'key2' - @r.sadd "set2", 'key2' - @r.sadd "set2", 'key3' - @r.sunion('set', 'set2').sort.should == ['key1','key2','key3'].sort - end - # - it "should be able to do set union and store the results in a key (SUNIONSTORE)" do - @r.sadd "set", 'key1' - @r.sadd "set", 'key2' - @r.sadd "set2", 'key2' - @r.sadd "set2", 'key3' - @r.sunionstore('newone', 'set', 'set2').should == 3 - @r.smembers('newone').sort.should == ['key1','key2','key3'].sort - end - # - it "should be able to do set difference (SDIFF)" do - @r.sadd "set", 'a' - @r.sadd "set", 'b' - @r.sadd "set2", 'b' - @r.sadd "set2", 'c' - @r.sdiff('set', 'set2').should == ['a'] - end - # - it "should be able to do set difference and store the results in a key (SDIFFSTORE)" do - @r.sadd "set", 'a' - @r.sadd "set", 'b' - @r.sadd "set2", 'b' - @r.sadd "set2", 'c' - @r.sdiffstore('newone', 'set', 'set2') - @r.smembers('newone').should == ['a'] - end - # - it "should be able move elements from one set to another (SMOVE)" do - @r.sadd 'set1', 'a' - @r.sadd 'set1', 'b' - @r.sadd 'set2', 'x' - @r.smove('set1', 'set2', 'a').should be_true - @r.sismember('set2', 'a').should be_true - @r.delete('set1') - end - # - it "should be able to do crazy SORT queries" do - # The 'Dogs' is capitialized on purpose - @r['dog_1'] = 'louie' - @r.rpush 'Dogs', 1 - @r['dog_2'] = 'lucy' - @r.rpush 'Dogs', 2 - @r['dog_3'] = 'max' - @r.rpush 'Dogs', 3 - @r['dog_4'] = 'taj' - @r.rpush 'Dogs', 4 - @r.sort('Dogs', :get => 'dog_*', :limit => [0,1]).should == ['louie'] - @r.sort('Dogs', :get => 'dog_*', :limit => [0,1], :order => 'desc alpha').should == ['taj'] - end - - it "should be able to handle array of :get using SORT" do - @r['dog:1:name'] = 'louie' - @r['dog:1:breed'] = 'mutt' - @r.rpush 'dogs', 1 - @r['dog:2:name'] = 'lucy' - @r['dog:2:breed'] = 'poodle' - @r.rpush 'dogs', 2 - @r['dog:3:name'] = 'max' - @r['dog:3:breed'] = 'hound' - @r.rpush 'dogs', 3 - @r['dog:4:name'] = 'taj' - @r['dog:4:breed'] = 'terrier' - @r.rpush 'dogs', 4 - @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1]).should == ['louie', 'mutt'] - @r.sort('dogs', :get => ['dog:*:name', 'dog:*:breed'], :limit => [0,1], :order => 'desc alpha').should == ['taj', 'terrier'] - end - # - it "should provide info (INFO)" do - [:last_save_time, :redis_version, :total_connections_received, :connected_clients, :total_commands_processed, :connected_slaves, :uptime_in_seconds, :used_memory, :uptime_in_days, :changes_since_last_save].each do |x| - @r.info.keys.should include(x) - end - end - # - it "should be able to flush the database (FLUSHDB)" do - @r['key1'] = 'keyone' - @r['key2'] = 'keytwo' - @r.keys('*').sort.should == ['foo', 'key1', 'key2'].sort #foo from before - @r.flushdb - @r.keys('*').should == [] - end - # - it "should raise exception when manually try to change the database" do - lambda { @r.select(0) }.should raise_error - end - # - it "should be able to provide the last save time (LASTSAVE)" do - savetime = @r.lastsave - Time.at(savetime).class.should == Time - Time.at(savetime).should <= Time.now - end - - it "should be able to MGET keys" do - @r['foo'] = 1000 - @r['bar'] = 2000 - @r.mget('foo', 'bar').should == ['1000', '2000'] - @r.mget('foo', 'bar', 'baz').should == ['1000', '2000', nil] - end - - it "should be able to mapped MGET keys" do - @r['foo'] = 1000 - @r['bar'] = 2000 - @r.mapped_mget('foo', 'bar').should == { 'foo' => '1000', 'bar' => '2000'} - @r.mapped_mget('foo', 'baz', 'bar').should == { 'foo' => '1000', 'bar' => '2000'} - end - - it "should bgsave" do - @r.bgsave.should == 'OK' - end - - it "should be able to ECHO" do - @r.echo("message in a bottle\n").should == "message in a bottle\n" - end - - it "should raise error when invoke MONITOR" do - lambda { @r.monitor }.should raise_error - end - - it "should raise error when invoke SYNC" do - lambda { @r.sync }.should raise_error - end - - it "should handle multiple servers" do - require 'dist_redis' - @r = DistRedis.new(:hosts=> ['localhost:6379', '127.0.0.1:6379'], :db => 15) - - 100.times do |idx| - @r[idx] = "foo#{idx}" - end - - 100.times do |idx| - @r[idx].should == "foo#{idx}" - end - end - - it "should be able to pipeline writes" do - @r.pipelined do |pipeline| - pipeline.lpush 'list', "hello" - pipeline.lpush 'list', 42 - end - - @r.type('list').should == "list" - @r.llen('list').should == 2 - @r.lpop('list').should == '42' - end - - it "should AUTH when connecting with a password" do - r = Redis.new(:password => 'secret') - r.stub!(:connect_to) - r.should_receive(:call_command).with(['auth', 'secret']) - r.connect_to_server - end - -end diff --git a/client-libraries/ruby/spec/spec_helper.rb b/client-libraries/ruby/spec/spec_helper.rb deleted file mode 100644 index da70fe70..00000000 --- a/client-libraries/ruby/spec/spec_helper.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'rubygems' -$TESTING=true -$:.unshift File.join(File.dirname(__FILE__), '..', 'lib') -require 'redis' diff --git a/client-libraries/ruby/speed.rb b/client-libraries/ruby/speed.rb deleted file mode 100644 index 51e58110..00000000 --- a/client-libraries/ruby/speed.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'benchmark' -require "#{File.dirname(__FILE__)}/lib/redis" - -r = Redis.new -n = (ARGV.shift || 20000).to_i - -elapsed = Benchmark.realtime do - # n sets, n gets - n.times do |i| - key = "foo#{i}" - r[key] = key * 10 - r[key] - end -end - -puts '%.2f Kops' % (2 * n / 1000 / elapsed) diff --git a/client-libraries/ruby/tasks/redis.tasks.rb b/client-libraries/ruby/tasks/redis.tasks.rb deleted file mode 100644 index ed317d38..00000000 --- a/client-libraries/ruby/tasks/redis.tasks.rb +++ /dev/null @@ -1,125 +0,0 @@ -# Inspired by rabbitmq.rake the Redbox project at http://github.com/rick/redbox/tree/master -require 'fileutils' -require 'open-uri' - -class RedisRunner - - def self.redisdir - "/tmp/redis/" - end - - def self.redisconfdir - '/etc/redis.conf' - end - - def self.dtach_socket - '/tmp/redis.dtach' - end - - # Just check for existance of dtach socket - def self.running? - File.exists? dtach_socket - end - - def self.start - puts 'Detach with Ctrl+\ Re-attach with rake redis:attach' - sleep 3 - exec "dtach -A #{dtach_socket} redis-server #{redisconfdir}" - end - - def self.attach - exec "dtach -a #{dtach_socket}" - end - - def self.stop - sh 'echo "SHUTDOWN" | nc localhost 6379' - end - -end - -namespace :redis do - - desc 'About redis' - task :about do - puts "\nSee http://code.google.com/p/redis/ for information about redis.\n\n" - end - - desc 'Start redis' - task :start do - RedisRunner.start - end - - desc 'Stop redis' - task :stop do - RedisRunner.stop - end - - desc 'Restart redis' - task :restart do - RedisRunner.stop - RedisRunner.start - end - - desc 'Attach to redis dtach socket' - task :attach do - RedisRunner.attach - end - - desc 'Install the lastest verison of Redis from Github (requires git, duh)' - task :install => [:about, :download, :make] do - %w(redis-benchmark redis-cli redis-server).each do |bin| - sh "sudo cp /tmp/redis/#{bin} /usr/bin/" - end - - puts "Installed redis-benchmark, redis-cli and redis-server to /usr/bin/" - - unless File.exists?('/etc/redis.conf') - sh 'sudo cp /tmp/redis/redis.conf /etc/' - puts "Installed redis.conf to /etc/ \n You should look at this file!" - end - end - - task :make do - sh "cd #{RedisRunner.redisdir} && make clean" - sh "cd #{RedisRunner.redisdir} && make" - end - - desc "Download package" - task :download do - sh 'rm -rf /tmp/redis/' if File.exists?("#{RedisRunner.redisdir}/.svn") - sh 'git clone git://github.com/antirez/redis.git /tmp/redis' unless File.exists?(RedisRunner.redisdir) - sh "cd #{RedisRunner.redisdir} && git pull" if File.exists?("#{RedisRunner.redisdir}/.git") - end - -end - -namespace :dtach do - - desc 'About dtach' - task :about do - puts "\nSee http://dtach.sourceforge.net/ for information about dtach.\n\n" - end - - desc 'Install dtach 0.8 from source' - task :install => [:about] do - - Dir.chdir('/tmp/') - unless File.exists?('/tmp/dtach-0.8.tar.gz') - require 'net/http' - - url = 'http://downloads.sourceforge.net/project/dtach/dtach/0.8/dtach-0.8.tar.gz' - open('/tmp/dtach-0.8.tar.gz', 'wb') do |file| file.write(open(url).read) end - end - - unless File.directory?('/tmp/dtach-0.8') - system('tar xzf dtach-0.8.tar.gz') - end - - Dir.chdir('/tmp/dtach-0.8/') - sh 'cd /tmp/dtach-0.8/ && ./configure && make' - sh 'sudo cp /tmp/dtach-0.8/dtach /usr/bin/' - - puts 'Dtach successfully installed to /usr/bin.' - end -end - diff --git a/client-libraries/scala/.gitignore b/client-libraries/scala/.gitignore deleted file mode 100644 index f38e2ab9..00000000 --- a/client-libraries/scala/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.DS_Store -lib_managed -project/boot -target -target/ -target/**/* diff --git a/client-libraries/scala/README.md b/client-libraries/scala/README.md deleted file mode 100644 index afb28bf1..00000000 --- a/client-libraries/scala/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Redis Scala client - -## Key features of the library - -- Native Scala types Set and List responses. -- Consisten Hashing on the client. -- Support for Clustering of Redis nodes. - -## Information about redis - -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. - -http://code.google.com/p/redis/ - -### Key features of Redis - -- Fast in-memory store with asynchronous save to disk. -- Key value get, set, delete, etc. -- Atomic operations on sets and lists, union, intersection, trim, etc. - -## Requirements - -- sbt (get it at http://code.google.com/p/simple-build-tool/) - -## Usage - -Start your redis instance (usually redis-server will do it) - - $ cd scala-redis - $ sbt - > update - > test (optional to run the tests) - > console - -And you are ready to start issuing commands to the server(s) - -let's connect and get a key: - - scala> import com.redis._ - scala> val r = new Redis("localhost", 6379) - scala> val r.set("key", "some value") - scala> val r.get("key") - - -Alejandro Crosa <> - diff --git a/client-libraries/scala/project/build.properties b/client-libraries/scala/project/build.properties deleted file mode 100644 index 22da51f9..00000000 --- a/client-libraries/scala/project/build.properties +++ /dev/null @@ -1,8 +0,0 @@ -#Project properties -#Wed Aug 19 07:54:05 ART 2009 -project.organization=com.redis -project.name=RedisClient -sbt.version=0.5.1 -project.version=1.0.1 -scala.version=2.7.5 -project.initialize=false diff --git a/client-libraries/scala/project/build/RedisClientProject.scala b/client-libraries/scala/project/build/RedisClientProject.scala deleted file mode 100644 index 60dff43b..00000000 --- a/client-libraries/scala/project/build/RedisClientProject.scala +++ /dev/null @@ -1,12 +0,0 @@ -import sbt._ - -class RedisClientProject(info: ProjectInfo) extends DefaultProject(info) with AutoCompilerPlugins -{ - override def useDefaultConfigurations = true - - val scalatest = "org.scala-tools.testing" % "scalatest" % "0.9.5" % "test->default" - val specs = "org.scala-tools.testing" % "specs" % "1.5.0" - val mockito = "org.mockito" % "mockito-all" % "1.7" - val junit = "junit" % "junit" % "4.5" - val sxr = compilerPlugin("org.scala-tools.sxr" %% "sxr" % "0.2.1") -} diff --git a/client-libraries/scala/src/main/scala/com/redis/Connection.scala b/client-libraries/scala/src/main/scala/com/redis/Connection.scala deleted file mode 100644 index d4b51ed7..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/Connection.scala +++ /dev/null @@ -1,8 +0,0 @@ -package com.redis - -/** - * Redis client Connection - * - */ - -case class Connection(val host: String, val port: Int) extends SocketOperations diff --git a/client-libraries/scala/src/main/scala/com/redis/HashRing.scala b/client-libraries/scala/src/main/scala/com/redis/HashRing.scala deleted file mode 100644 index e16cc182..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/HashRing.scala +++ /dev/null @@ -1,66 +0,0 @@ -package com.redis - -/** - * Hash Ring - * - */ - -import java.util.zip.CRC32 -import scala.collection.mutable.ArrayBuffer -import scala.collection.mutable.Map - -trait HashRing { - - val replicas: Int - - var sortedKeys: List[Long] = List() - var cluster = new ArrayBuffer[Redis] - val ring = Map[Long, Redis]() - - // Adds the node to the hashRing - // including a number of replicas. - def addNode(node: Redis) = { - cluster += node - (1 to replicas).foreach{ replica => - val key = calculateChecksum(node+":"+replica) - ring += (key -> node) - sortedKeys = sortedKeys ::: List(key) - } - sortedKeys = sortedKeys.sort(_ < _) - } - - // get the node in the hash ring for this key - def getNode(key: String) = getNodePos(key)._1 - - def getNodePos(key: String): (Redis, Int) = { - val crc = calculateChecksum(key) - val idx = binarySearch(crc) - (ring(sortedKeys(idx)), idx) - } - - // TODO this should perform a Bynary search - def binarySearch(value: Long): Int = { - var upper = (sortedKeys.length -1) - var lower = 0 - var idx = 0 - var comp: Long = 0 - - while(lower <= upper){ - idx = (lower + upper) / 2 - comp = sortedKeys(idx) - - if(comp == value) { return idx } - if(comp < value) { upper = idx -1 } - if(comp > value) { lower = idx +1 } - } - return upper - } - - // Computes the CRC-32 of the given String - def calculateChecksum(value: String): Long = { - val checksum = new CRC32 - checksum.update(value.getBytes) - checksum.getValue - } -} - diff --git a/client-libraries/scala/src/main/scala/com/redis/Operations/KeySpaceOperations.scala b/client-libraries/scala/src/main/scala/com/redis/Operations/KeySpaceOperations.scala deleted file mode 100644 index 13dc593c..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/Operations/KeySpaceOperations.scala +++ /dev/null @@ -1,47 +0,0 @@ -package com.redis.operations - -/** - * Redis key space operations - * - */ - -trait KeySpaceOperations{ - - val connection: Connection - var db: Int - - // KEYS - // returns all the keys matching the glob-style pattern. - def keys(pattern: String): Array[String] = { - connection.write("KEYS "+pattern+"\r\n") - connection.readResponse.toString.split(" ") - } - - // RANDKEY - // return a randomly selected key from the currently selected DB. - def randomKey: String = { - connection.write("RANDOMKEY\r\n") - connection.readResponse.toString.split('+')(1) - } - - // RENAME (oldkey, newkey) - // atomically renames the key oldkey to newkey. - def rename(oldkey: String, newkey: String): Boolean = { - connection.write("RENAME "+oldkey+" "+newkey+"\r\n") - connection.readBoolean - } - - // RENAMENX (oldkey, newkey) - // rename oldkey into newkey but fails if the destination key newkey already exists. - def renamenx(oldkey: String, newkey: String): Boolean = { - connection.write("RENAMENX "+oldkey+" "+newkey+"\r\n") - connection.readBoolean - } - - // DBSIZE - // return the size of the db. - def dbSize: Int = { - connection.write("DBSIZE\r\n") - connection.readInt - } -} \ No newline at end of file diff --git a/client-libraries/scala/src/main/scala/com/redis/Operations/ListOperations.scala b/client-libraries/scala/src/main/scala/com/redis/Operations/ListOperations.scala deleted file mode 100644 index 6538311b..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/Operations/ListOperations.scala +++ /dev/null @@ -1,94 +0,0 @@ -package com.redis.operations - -/** - * Redis list operations - * - */ - -trait ListOperations{ - - def getConnection(key: String): Connection - - // add the string value to the head (LPUSH) or tail (RPUSH) of the list stored at key. - // If the key does not exist an empty list is created just before the append operation. If the key exists but is not a List an error is returned. - // LPUSH - def pushHead(key: String, value: String): Boolean = { - val connection = getConnection(key) - connection.write("LPUSH "+key+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } - - // RPUSH - def pushTail(key: String, value: String): Boolean = { - val connection = getConnection(key) - connection.write("RPUSH "+key+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } - - // LPOP - // atomically return and remove the first (LPOP) or last (RPOP) element of the list - def popHead(key: String): String = { - val connection = getConnection(key) - connection.write("LPOP "+key+"\r\n") - connection.readString - } - - // RPOP - // atomically return and remove the first (LPOP) or last (RPOP) element of the list - def popTail(key: String): String = { - val connection = getConnection(key) - connection.write("RPOP "+key+"\r\n") - connection.readString - } - - // LINDEX - // return the especified element of the list stored at the specified key. 0 is the first element, 1 the second and so on. - // Negative indexes are supported, for example -1 is the last element, -2 the penultimate and so on. - def listIndex(key: String, index: Int): String = { - val connection = getConnection(key) - connection.write("LINDEX "+key+" "+index+"\r\n") - connection.readString - } - - // LSET - // set the list element at index with the new value. Out of range indexes will generate an error - def listSet(key: String, index: Int, value: String): Boolean = { - val connection = getConnection(key) - connection.write("LSET "+key+" "+index+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } - - // LLEN - // return the length of the list stored at the specified key. - // If the key does not exist zero is returned (the same behaviour as for empty lists). If the value stored at key is not a list an error is returned. - def listLength(key: String): Int = { - val connection = getConnection(key) - connection.write("LLEN "+key+"\r\n") - connection.readInt - } - - // LRANGE - // return the specified elements of the list stored at the specified key. - // Start and end are zero-based indexes. 0 is the first element of the list (the list head), 1 the next element and so on. - def listRange(key: String, start: Int, end: Int): List[String] = { - val connection = getConnection(key) - connection.write("LRANGE "+key+" "+start+" "+end+"\r\n") - connection.readList - } - - // LTRIM - // Trim an existing list so that it will contain only the specified range of elements specified. - def listTrim(key: String, start: Int, end: Int): Boolean = { - val connection = getConnection(key) - connection.write("LTRIM "+key+" "+start+" "+end+"\r\n") - connection.readBoolean - } - - // LREM - // Remove the first count occurrences of the value element from the list. - def listRem(key: String, count: Int, value: String): Boolean = { - val connection = getConnection(key) - connection.write("LREM "+key+" "+count+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } -} diff --git a/client-libraries/scala/src/main/scala/com/redis/Operations/NodeOperations.scala b/client-libraries/scala/src/main/scala/com/redis/Operations/NodeOperations.scala deleted file mode 100644 index 3deb8dd0..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/Operations/NodeOperations.scala +++ /dev/null @@ -1,121 +0,0 @@ -package com.redis.operations - -/** - * Redis node operations - * - */ - -trait NodeOperations { - - val connection: Connection - var db: Int - - // SAVE - // save the DB on disk now. - def save: Boolean = { - connection.write("SAVE\r\n") - connection.readBoolean - } - - // BGSAVE - // save the DB in the background. - def bgSave: Boolean = { - connection.write("BGSAVE\r\n") - connection.readBoolean - } - - // LASTSAVE - // return the UNIX TIME of the last DB SAVE executed with success. - def lastSave: Int = { - connection.write("LASTSAVE\r\n") - connection.readInt - } - - // SHUTDOWN - // Stop all the clients, save the DB, then quit the server. - def shutdown: Boolean = { - connection.write("SHUTDOWN\r\n") - connection.readBoolean - } - - // MGET (key, key, key, ...) - // get the values of all the specified keys. - def mget(keys: String*) = { - connection.write("MGET "+keys.mkString(" ")+"\r\n") - connection.readList - } - - // INFO - // the info command returns different information and statistics about the server. - def info = { - connection.write("INFO\r\n") - connection.readResponse - } - - // MONITOR - // is a debugging command that outputs the whole sequence of commands received by the Redis server. - def monitor: Boolean = { - connection.write("MONITOR\r\n") - connection.readBoolean - } - - // SLAVEOF - // The SLAVEOF command can change the replication settings of a slave on the fly. - def slaveOf(options: Any): Boolean = options match { - case (host: String, port: Int) => { - connection.write("SLAVEOF "+host+" "+port.toString+"\r\n") - connection.readBoolean - } - case _ => setAsMaster - } - - def setAsMaster: Boolean = { - connection.write("SLAVEOF NO ONE\r\n") - connection.readBoolean - } - - // SELECT (index) - // selects the DB to connect, defaults to 0 (zero). - def selectDb(index: Int): Boolean = { - connection.write("SELECT "+index+"\r\n") - connection.readBoolean match { - case true => { db = index; true } - case _ => false - } - } - - // FLUSHDB the DB - // removes all the DB data. - def flushDb: Boolean = { - connection.write("FLUSHDB\r\n") - connection.readBoolean - } - - // FLUSHALL the DB's - // removes data from all the DB's. - def flushAll: Boolean = { - connection.write("FLUSHALL\r\n") - connection.readBoolean - } - - // MOVE - // Move the specified key from the currently selected DB to the specified destination DB. - def move(key: String, db: Int) = { - connection.write("MOVE "+key+" "+db.toString+"\r\n") - connection.readBoolean - } - - // QUIT - // exits the server. - def quit: Boolean = { - connection.write("QUIT\r\n") - connection.disconnect - } - - // AUTH - // auths with the server. - def auth(secret: String): Boolean = { - connection.write("AUTH "+secret+"\r\n") - connection.readBoolean - } -} diff --git a/client-libraries/scala/src/main/scala/com/redis/Operations/Operations.scala b/client-libraries/scala/src/main/scala/com/redis/Operations/Operations.scala deleted file mode 100644 index fb5c23d6..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/Operations/Operations.scala +++ /dev/null @@ -1,124 +0,0 @@ -package com.redis.operations - -/** - * Redis operations - * - */ - -trait Operations{ - - def getConnection(key: String): Connection - - // SET (key, value) - // SET (key, value, expiry) - // sets the key with the specified value, and with an optional expiry. - def set(key: String, value: String) = setKey(key, value) - def set(key: String, value: String, expiry: Int) = { setKey(key, value) && expire(key, expiry) } - - // SET KEY (key, value) - // sets the key with the specified value. - def setKey(key: String, value: String): Boolean = { - val connection = getConnection(key) - connection.write("SET "+key+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } - - // EXPIRE (key, expiry) - // sets the expire time (in sec.) for the specified key. - def expire(key: String, expiry: Int): Boolean = { - val connection = getConnection(key) - connection.write("EXPIRE "+key+" "+expiry+"\r\n") - connection.readBoolean - } - - // GET (key) - // gets the value for the specified key. - def get(key: String): String = { - val connection = getConnection(key) - val a = connection.write("GET "+key+"\r\n") - connection.readResponse match { - case r: String => r.toString - case _ => null - } - } - - // GETSET (key, value) - // is an atomic set this value and return the old value command. - def getSet(key: String, value: String): String = { - val connection = getConnection(key) - val a = connection.write("GETSET "+key+" "+value.length+"\r\n"+value+"\r\n") - connection.readResponse match { - case r: String => r.toString - case _ => null - } - } - - // SETNX (key, value) - // sets the value for the specified key, only if the key is not there. - def setUnlessExists(key: String, value: String): Boolean = { - val connection = getConnection(key) - connection.write("SETNX "+key+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } - - // DELETE (key) - // deletes the specified key. - def delete(key: String): Boolean = { - val connection = getConnection(key) - connection.write("DEL "+key+"\r\n") - connection.readBoolean - } - - // INCR (key) - // INCR (key, increment) - // increments the specified key, optional the increment value. - def incr(x: Any): Int = x match { - case (key: String, increment: Int) => incrBy(key, increment) - case (key: String) => incrOne(key) - case _ => 0 - } - def incrBy(key: String, increment: Int): Int = { - val connection = getConnection(key) - connection.write("INCRBY "+key+" "+increment+"\r\n") - connection.readInt - } - def incrOne(key: String): Int = { - val connection = getConnection(key) - connection.write("INCR "+key+"\r\n") - connection.readInt - } - - // DECR (key) - // DECRBY (key, decrement) - // decrements the specified key, optional the decrement value. - def decr(key: String, decrement: Int) = decrBy(key, decrement) - def decr(key: String) = decrOne(key) - - def decrBy(key: String, decrement: Int): Int = { - val connection = getConnection(key) - connection.write("DECRBY "+key+" "+decrement+"\r\n") - connection.readInt - } - def decrOne(key: String): Int = { - val connection = getConnection(key) - connection.write("DECR "+key+"\r\n") - connection.readInt - } - - // EXISTS (key) - // test if the specified key exists. - def exists(key: String): Boolean = { - val connection = getConnection(key) - connection.write("EXISTS "+key+"\r\n") - connection.readBoolean - } - - // TYPE (key) - // return the type of the value stored at key in form of a string. - def getType(key: String): Any = { - val connection = getConnection(key) - connection.write("TYPE "+key+"\r\n") - connection.readResponse - } - -} \ No newline at end of file diff --git a/client-libraries/scala/src/main/scala/com/redis/Operations/SetOperations.scala b/client-libraries/scala/src/main/scala/com/redis/Operations/SetOperations.scala deleted file mode 100644 index 13432d35..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/Operations/SetOperations.scala +++ /dev/null @@ -1,115 +0,0 @@ -package com.redis.operations - -/** - * Redis set operations - * - */ - -trait SetOperations{ - - def getConnection(key: String): Connection - - // SADD - // Add the specified member to the set value stored at key. - def setAdd(key: String, value: String): Boolean = { - val connection = getConnection(key) - connection.write("SADD "+key+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } - - // SREM - // Remove the specified member from the set value stored at key. - def setDelete(key: String, value: String): Boolean = { - val connection = getConnection(key) - connection.write("SREM "+key+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } - - // SCARD - // Return the number of elements (the cardinality) of the Set at key. - def setCount(key: String): Int = { - val connection = getConnection(key) - connection.write("SCARD "+key+"\r\n") - connection.readInt - } - - // SMEMBERS - // Return all the members of the Set value at key. - def setMembers(key: String): Set[String] = { - val connection = getConnection(key) - connection.write("SMEMBERS "+key+"\r\n") - connection.readSet - } - - // SPOP - // Remove and return (pop) a random element from the Set value at key. - def setPop(key: String): String = { - val connection = getConnection(key) - connection.write("SPOP "+key+"\r\n") - connection.readString - } - - // SMOVE - // Move the specified member from one Set to another atomically. - def setMove(sourceKey: String, destKey: String, value: String): Boolean = { - val connection = getConnection(sourceKey) - connection.write("SMOVE "+sourceKey+" "+destKey+" "+value+"\r\n") - connection.readBoolean - } - - // SISMEMBER - // Test if the specified value is a member of the Set at key. - def setMemberExists(key: String, value: String): Boolean = { - val connection = getConnection(key) - connection.write("SISMEMBER "+key+" "+value.length+"\r\n"+value+"\r\n") - connection.readBoolean - } - - // SINTER - // Return the intersection between the Sets stored at key1, key2, ..., keyN. - def setIntersect(keys: String*): Set[String] = { - val connection = getConnection(keys(0)) - connection.write("SINTER "+keys.mkString(" ")+"\r\n") - connection.readSet - } - - // SINTERSTORE - // Compute the intersection between the Sets stored at key1, key2, ..., keyN, and store the resulting Set at dstkey. - def setInterStore(key: String, keys: String*): Boolean = { - val connection = getConnection(key) - connection.write("SINTERSTORE "+key+" "+keys.mkString(" ")+"\r\n") - connection.readBoolean - } - - // SDIFF - // Return the difference between the Set stored at key1 and all the Sets key2, ..., keyN. - def setDiff(keys: String*): Set[String] = { - val connection = getConnection(keys(0)) - connection.write("SDIFF "+keys.mkString(" ")+"\r\n") - connection.readSet - } - - // SDIFFSTORE - // Compute the difference between the Set key1 and all the Sets key2, ..., keyN, and store the resulting Set at dstkey. - def setDiffStore(key: String, keys: String*): Boolean = { - val connection = getConnection(key) - connection.write("SDIFFSTORE "+key+" "+keys.mkString(" ")+"\r\n") - connection.readBoolean - } - - // SUNION - // Return the union between the Sets stored at key1, key2, ..., keyN. - def setUnion(keys: String*): Set[String] = { - val connection = getConnection(keys(0)) - connection.write("SUNION "+keys.mkString(" ")+"\r\n") - connection.readSet - } - - // SUNIONSTORE - // Compute the union between the Sets stored at key1, key2, ..., keyN, and store the resulting Set at dstkey. - def setUnionStore(key: String, keys: String*): Boolean = { - val connection = getConnection(key) - connection.write("SUNIONSTORE "+key+" "+keys.mkString(" ")+"\r\n") - connection.readBoolean - } -} \ No newline at end of file diff --git a/client-libraries/scala/src/main/scala/com/redis/Operations/SortOperations.scala b/client-libraries/scala/src/main/scala/com/redis/Operations/SortOperations.scala deleted file mode 100644 index f3d0ca14..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/Operations/SortOperations.scala +++ /dev/null @@ -1,28 +0,0 @@ -package com.redis.operations - -/** - * Redis sort operations - * - */ - -trait SortOperations{ - - def getConnection(key: String): Connection - - // SORT - // Sort a Set or a List accordingly to the specified parameters. - def sort(args: Any): List[String] = args match { - case (key: String, command: String) => doSort(key, command) - case (key: String) => doSort(key, "") - } - - def doSort(key: String, command: String): List[String] = { - val connection = getConnection(key) - if(command != "") { - connection.write("SORT "+key+" "+command+"\r\n") - } else { - connection.write("SORT "+key+"\r\n") - } - connection.readList - } -} \ No newline at end of file diff --git a/client-libraries/scala/src/main/scala/com/redis/RedisClient.scala b/client-libraries/scala/src/main/scala/com/redis/RedisClient.scala deleted file mode 100644 index ac051cc5..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/RedisClient.scala +++ /dev/null @@ -1,33 +0,0 @@ -package com.redis - -import com.redis.operations._ - -/** - * Redis client - * - */ - -class Redis(val host: String, val port: Int) extends Operations with ListOperations with SetOperations with NodeOperations with KeySpaceOperations with SortOperations { - - // auxiliary constructor - def this() = this("localhost", 6379) - - // Points to the connection to a server instance - val connection = Connection(host, port) - var db: Int = 0 - - // Connect and Disconnect to the Redis server - def connect = connection.connect - def disconnect = connection.disconnect - def connected: Boolean = connection.connected - - // Establish the connection to the server instance on initialize - connect - - // Get Redis Client connection. - def getConnection(key: String) = getConnection - def getConnection = connection - - // Outputs a formatted representation of the Redis server. - override def toString = connection.host+":"+connection.port+" " -} diff --git a/client-libraries/scala/src/main/scala/com/redis/RedisCluster.scala b/client-libraries/scala/src/main/scala/com/redis/RedisCluster.scala deleted file mode 100644 index 0a753719..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/RedisCluster.scala +++ /dev/null @@ -1,42 +0,0 @@ -package com.redis - -import com.redis.operations._ - -/** - * Redis cluster - * - */ - -import scala.collection.mutable.ArrayBuffer - -class RedisCluster(val hosts: String*) extends Operations with ListOperations with SetOperations with HashRing with SortOperations { - - // Get Redis Client connection inside the HashRing. - def getConnection(key: String) = { - getNode(key).connection - } - - // Default value used on MemCache client. - private val NUMBER_OF_REPLICAS = 160 - val replicas = NUMBER_OF_REPLICAS - - // Outputs a formatted representation of the Redis server. - override def toString = cluster.mkString(", ") - - // Connect the client and add it to the cluster. - def connectClient(host: String): Boolean = { - val h = host.split(":")(0) - val p = host.split(":")(1) - val client = new Redis(h.toString, p.toString.toInt) - addNode(client) - client.connected - } - - // Connect all clients in the cluster. - def connect = cluster.map(c => c.connect) - - // Initialize cluster. - def initialize_cluster = hosts.map(connectClient(_)) - - initialize_cluster -} diff --git a/client-libraries/scala/src/main/scala/com/redis/SocketOperations.scala b/client-libraries/scala/src/main/scala/com/redis/SocketOperations.scala deleted file mode 100644 index 137ecae3..00000000 --- a/client-libraries/scala/src/main/scala/com/redis/SocketOperations.scala +++ /dev/null @@ -1,167 +0,0 @@ -package com.redis - -/** - * Socket operations - * - */ - -import java.io._ -import java.net.Socket - -trait SocketOperations { - - // Response codes from the Redis server - // they tell you what's coming next from the server. - val ERR: String = "-" - val OK: String = "+OK" - val SINGLE: String = "+" - val BULK: String = "$" - val MULTI: String = "*" - val INT:String = ":" - - val host: String - val port: Int - - // File descriptors. - var socket: Socket = null - var out: OutputStream = null - var in: BufferedReader = null - - def getOutputStream: OutputStream = out - def getInputStream: BufferedReader = in - def getSocket: Socket = socket - - def connected = { getSocket != null } - def reconnect = { disconnect && connect; } - - // Connects the socket, and sets the input and output streams. - def connect: Boolean = { - try { - socket = new Socket(host, port) - out = getSocket.getOutputStream - in = new BufferedReader(new InputStreamReader(getSocket.getInputStream)); - true - } catch { - case _ => clear_fd; false; - } - } - - // Disconnects the socket. - def disconnect: Boolean = { - try { - socket.close - out.close - in.close - clear_fd - true - } catch { - case _ => false - } - } - - def clear_fd = { - socket = null - out = null - in = null - } - - // Reads the server responses as Scala types. - def readString: String = readResponse.toString // Reads the server response as an Int - def readInt: Int = Integer.parseInt(readResponse.toString) // Reads the server response as an Int - def readList: List[String] = listReply(readResponse.toString) // Reads the server response as a List - def readSet: Set[String] = setReply(readResponse.toString) // Reads the server response as a String - def readBoolean: Boolean = readResponse match { - case 1 => true - case OK => true - case _ => false - } - - // Read from Input Stream. - def readline: String = { - try { - getInputStream.readLine() - } catch { - case _ => ERR; - } - } - - // Gets the type of response the server is going to send. - def readtype = { - val res = readline - if(res !=null){ - (res(0).toString(), res) - }else{ - ("-", "") - } - } - - // Reads the response from the server based on the response code. - def readResponse = { - - val responseType = readtype - try{ - responseType._1 match { - case ERR => reconnect; // RECONNECT - case SINGLE => lineReply(responseType._2) - case BULK => bulkReply(responseType._2) - case MULTI => responseType._2 - case INT => integerReply(responseType._2) - case _ => reconnect; // RECONNECT - } - }catch{ - case e: Exception => false - } - } - - def integerReply(response: String): Int = Integer.parseInt(response.split(":")(1).toString) - - def lineReply(response: String): String = response - - def listReply(response: String): List[String] = { - val total = Integer.parseInt(response.split('*')(1)) - var list: List[String] = List() - for(i <- 1 to total){ - list = (list ::: List(bulkReply(readtype._2))) - } - list - } - - def bulkReply(response: String) = { - if(response(1).toString() != ERR){ - var length: Int = Integer.parseInt(response.split('$')(1).split("\r\n")(0)) - var line, res: String = "" - while(length >= 0){ - line = readline - length -= (line.length+2) - res += line - if(length > 0) res += "\r\n" - } - res - }else{ null } - } - - def setReply(response: String): Set[String] = { - val total = Integer.parseInt(response.split('*')(1)) - var set: Set[String] = Set() - for(i <- 1 to total){ - set += bulkReply(readtype._2) - } - set - } - - // Wraper for the socket write operation. - def write_to_socket(data: String)(op: OutputStream => Unit) = op(getOutputStream) - - // Writes data to a socket using the specified block. - def write(data: String) = { - if(!connected) connect; - write_to_socket(data){ - getSocket => - try { - getSocket.write(data.getBytes) - } catch { - case _ => reconnect; - } - } - } -} \ No newline at end of file diff --git a/client-libraries/scala/src/test/scala/com/redis/RedisClientSpec.scala b/client-libraries/scala/src/test/scala/com/redis/RedisClientSpec.scala deleted file mode 100644 index 804a19ae..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/RedisClientSpec.scala +++ /dev/null @@ -1,27 +0,0 @@ -import org.specs._ -import com.redis._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ -import org.mockito.Mockito.doNothing - -object RedisClientSpec extends Specification with Mockito { - - "Redis Client" should { - var client: Redis = null - - "print formatted client status" in { - client = new Redis("localhost", 121212) - client.toString must be matching("localhost:121212 ") - } - - "get the same connection when passing key para or not since it's a single node" in { - client.getConnection("key") mustEqual client.getConnection - } - - "use db zero as default" in { - client.db mustEqual 0 - } - } -} diff --git a/client-libraries/scala/src/test/scala/com/redis/RedisClusterSpec.scala b/client-libraries/scala/src/test/scala/com/redis/RedisClusterSpec.scala deleted file mode 100644 index cee08d70..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/RedisClusterSpec.scala +++ /dev/null @@ -1,51 +0,0 @@ -import org.specs._ -import com.redis._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ -import org.mockito.Mockito.doNothing - -object RedisClusterSpec extends Specification with Mockito { - - "Redis Cluster" should { - var cluster: RedisCluster = null - var mockedRedis: Redis = null - - doBefore { - cluster = new RedisCluster("localhost:11221", "localhost:99991") - mockedRedis = mock[Redis] - } - - "print formatted client status" in { - cluster.toString must be matching("localhost:11221 , localhost:99991 ") - } - - "get the connection for the specified key" in { - cluster.getConnection("key") mustEqual Connection("localhost", 99991) - cluster.getConnection("anotherkey") mustEqual Connection("localhost", 11221) - } - - "use the default number of replicas" in { - cluster.replicas mustEqual 160 - } - - "initialize cluster" in { - val initializedCluster = cluster.initialize_cluster - initializedCluster.size mustEqual 2 - initializedCluster(0) mustEqual false - initializedCluster(1) mustEqual false - } - - "connect all the redis instances" in { - cluster.cluster(1) = mockedRedis - - cluster.cluster(1).connect returns true - val connectResult = cluster.connect - connectResult.size mustEqual 2 - connectResult(0) mustEqual false - connectResult(1) mustEqual true - cluster.cluster(1).connect was called - } - } -} diff --git a/client-libraries/scala/src/test/scala/com/redis/SocketOperationsSpec.scala b/client-libraries/scala/src/test/scala/com/redis/SocketOperationsSpec.scala deleted file mode 100644 index 4f7bbac4..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/SocketOperationsSpec.scala +++ /dev/null @@ -1,97 +0,0 @@ -import org.specs._ -import com.redis._ - -import java.io._ -import java.net.Socket - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ - -class SocketOperationTest(val host:String, val port: Int) extends SocketOperations - -object SocketOperationsSpec extends Specification with Mockito { - - "Socket Operations" should { - var socketOperation: SocketOperationTest = null - var socket: Socket = null - var in: BufferedReader = null - - doBefore { - socketOperation = new SocketOperationTest("localhost", 6379666) - socket = mock[Socket] - in = mock[BufferedReader] - socketOperation.socket = socket - socketOperation.in = in - } - - def readOkFromInput = { when(in.readLine()).thenReturn(socketOperation.OK) } - def readSingleFromInput = { when(in.readLine()).thenReturn(socketOperation.SINGLE) } - def readBulkFromInput = { in.readLine() returns("$6\r\nfoobar\r\n") thenReturns("$6\r\nfoobar\r\n") } - def readIntFromInput = { when(in.readLine()).thenReturn(socketOperation.INT+"666") } - - "tell if it's connected" in { - socketOperation.connected mustEqual true - socketOperation.socket = null - socketOperation.connected mustEqual false - } - - "return false when can't connect" in { - socketOperation.connect mustEqual false - } - - "return current data input stream" in { - socketOperation.getInputStream mustEqual in - } - - "read a line from socket" in { - readOkFromInput - socketOperation.in mustEqual in - socketOperation.readline mustEqual socketOperation.OK - } - - "read type response" in { - readOkFromInput - socketOperation.readtype mustEqual ("+", socketOperation.OK) - } - - "when reading responses" in { - - "read OK" in { - readOkFromInput - socketOperation.readResponse mustEqual socketOperation.OK - } - - "read single line" in { - readSingleFromInput - socketOperation.readResponse mustEqual socketOperation.SINGLE - } - - "reconnect on error" in { - socketOperation.readResponse mustEqual false - socket.close was called - socketOperation.connected mustEqual true - } - - "read in bulk" in { - // readBulkFromInput - // this shouldn't be the response, it doesn't seem to work return and then returns. - // Here's what should happen: '$6\r\n' on first readLine and then 'foobar\r\n' - readBulkFromInput - socketOperation.readtype mustEqual ("$", "$6\r\nfoobar\r\n") - socketOperation.readResponse mustEqual "$6\r\nfoobar\r\n" - socketOperation.bulkReply("$6\r\nfoobar\r\n") was called - } - - "read integer" in { - readIntFromInput - socketOperation.readInt mustEqual 666 - } - - "read a boolean return value" in { - readOkFromInput - socketOperation.readBoolean mustEqual true - } - } - } -} diff --git a/client-libraries/scala/src/test/scala/com/redis/helpers/RedisClientTestHelper.scala b/client-libraries/scala/src/test/scala/com/redis/helpers/RedisClientTestHelper.scala deleted file mode 100644 index 402520ab..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/helpers/RedisClientTestHelper.scala +++ /dev/null @@ -1,13 +0,0 @@ -import org.specs._ -import com.redis._ -import com.redis.operations._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ -import org.mockito.Mockito.doNothing - -class RedisTestClient(val connection: Connection) extends Operations with ListOperations with SetOperations with NodeOperations with KeySpaceOperations with SortOperations { - var db: Int = 0 - def getConnection(key: String): Connection = connection -} \ No newline at end of file diff --git a/client-libraries/scala/src/test/scala/com/redis/operations/KeySpaceOperationsSpec.scala b/client-libraries/scala/src/test/scala/com/redis/operations/KeySpaceOperationsSpec.scala deleted file mode 100644 index ced34fef..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/operations/KeySpaceOperationsSpec.scala +++ /dev/null @@ -1,50 +0,0 @@ -import org.specs._ -import com.redis._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ -import org.mockito.Mockito.doNothing - -object KeySpaceOperationsSpec extends Specification with Mockito { - - "Redis Client Key Operations" should { - var client: RedisTestClient = null - var connection: Connection = null - - doBefore{ - connection = mock[Connection] - client = new RedisTestClient(connection) - } - - "return all keys matching" in { - connection.readResponse returns "akey anotherkey adiffkey" - client.keys("a*") - connection.write("KEYS a*\r\n") was called - } - - "return a random key" in { - connection.readResponse returns "+somerandonkey" - client.randomKey mustEqual "somerandonkey" - connection.write("RANDOMKEY\r\n") was called - } - - "remame a key" in { - connection.readBoolean returns true - client.rename("a", "b") must beTrue - connection.write("RENAME a b\r\n") was called - } - - "rename a key only if destintation doesn't exist" in { - connection.readBoolean returns false - client.renamenx("a", "b") must beFalse - connection.write("RENAMENX a b\r\n") was called - } - - "tell the size of the db, # of keys" in { - connection.readInt returns 4 - client.dbSize mustEqual 4 - connection.write("DBSIZE\r\n") was called - } - } -} \ No newline at end of file diff --git a/client-libraries/scala/src/test/scala/com/redis/operations/ListOperationsSpec.scala b/client-libraries/scala/src/test/scala/com/redis/operations/ListOperationsSpec.scala deleted file mode 100644 index 95c66b55..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/operations/ListOperationsSpec.scala +++ /dev/null @@ -1,81 +0,0 @@ -import org.specs._ -import com.redis._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ -import org.mockito.Mockito.doNothing - -object ListOperationsSpec extends Specification with Mockito { - - "Redis Client List Operations" should { - var client: RedisTestClient = null - var connection: Connection = null - - doBefore{ - connection = mock[Connection] - client = new RedisTestClient(connection) - } - - "push to head" in { - connection.readBoolean returns true - client.pushHead("k", "v") must beTrue - connection.write("LPUSH k 1\r\nv\r\n") was called - } - - "push to tail" in { - connection.readBoolean returns true - client.pushTail("k", "v") must beTrue - connection.write("RPUSH k 1\r\nv\r\n") was called - } - - "pop from head" in { - connection.readString returns "value" - client.popHead("key") mustEqual "value" - connection.write("LPOP key\r\n") was called - } - - "pop from tail" in { - connection.readString returns "value" - client.popTail("key") mustEqual "value" - connection.write("RPOP key\r\n") was called - } - - "return list index" in { - connection.readString returns "value" - client.listIndex("k", 2) mustEqual "value" - connection.write("LINDEX k 2\r\n") was called - } - - "return set element at index" in { - connection.readBoolean returns true - client.listSet("k", 1, "value") mustEqual true - connection.write("LSET k 1 5\r\nvalue\r\n") was called - } - - "return list size" in { - connection.readInt returns 3 - client.listLength("k") mustEqual 3 - connection.write("LLEN k\r\n") was called - } - - "return list range" in { - val listResult: List[String] = List("one", "two", "three", "four", "five") - connection.readList returns listResult - client.listRange("k", 2, 4) mustEqual listResult - connection.write("LRANGE k 2 4\r\n") was called - } - - "trim a list" in { - connection.readBoolean returns true - client.listTrim("k", 2, 4) mustEqual true - connection.write("LTRIM k 2 4\r\n") was called - } - - "remove occurrences of a value in the list" in { - connection.readBoolean returns true - client.listRem("k", 2, "value") mustEqual true - connection.write("LREM k 2 5\r\nvalue\r\n") was called - } - } -} \ No newline at end of file diff --git a/client-libraries/scala/src/test/scala/com/redis/operations/NodeOperationsSpec.scala b/client-libraries/scala/src/test/scala/com/redis/operations/NodeOperationsSpec.scala deleted file mode 100644 index 629c4635..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/operations/NodeOperationsSpec.scala +++ /dev/null @@ -1,113 +0,0 @@ -import org.specs._ -import com.redis._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ -import org.mockito.Mockito.doNothing - -object NodeOperationsSpec extends Specification with Mockito { - - "Redis Client Node Operations" should { - var client: RedisTestClient = null - var connection: Connection = null - - doBefore{ - connection = mock[Connection] - client = new RedisTestClient(connection) - } - - "save the db to disk" in { - connection.readBoolean returns true - client.save must beTrue - connection.write("SAVE\r\n") was called - } - - "return the last time saved data to the db" in { - connection.readInt returns 1250421891 - client.lastSave mustEqual 1250421891 - connection.write("LASTSAVE\r\n") was called - } - - "return all specified keys" in { - connection.readList returns List[String]("hola", null, null) - client.mget("a", "b", "c") mustEqual List[String]("hola", null, null) - connection.write("MGET a b c\r\n") was called - } - - "return server info" in { - val sampleInfo = "res0: Any = \nredis_version:0.091\nconnected_clients:2\nconnected_slaves:0\nused_memory:3036\nchanges_since_last_save:0\nlast_save_time:1250440893\ntotal_connections_received:2\ntotal_commands_processed:0\nuptime_in_seconds:7\nuptime_in_days:0\n" - connection.readResponse returns sampleInfo - client.info mustEqual sampleInfo - connection.write("INFO\r\n") was called - } - - "start monitor debug on the server" in { - connection.readBoolean returns true - client.monitor mustEqual true - connection.write("MONITOR\r\n") was called - } - - "set a server as slave of a remote master" in { - connection.readBoolean returns true - client.slaveOf("localhost", 9999) mustEqual true - connection.write("SLAVEOF localhost 9999\r\n") was called - } - - "set a server as master if no params sent" in { - connection.readBoolean returns true - client.slaveOf() mustEqual true - connection.write("SLAVEOF NO ONE\r\n") was called - } - - "set a server as master" in { - connection.readBoolean returns true - client.setAsMaster mustEqual true - connection.write("SLAVEOF NO ONE\r\n") was called - } - - "select the current db" in { - connection.readBoolean returns true - client.selectDb(3) mustEqual true - client.db mustEqual 3 - connection.write("SELECT 3\r\n") was called - } - - "flush the db" in { - connection.readBoolean returns true - client.flushDb mustEqual true - connection.write("FLUSHDB\r\n") was called - } - - "flush all the dbs" in { - connection.readBoolean returns true - client.flushAll mustEqual true - connection.write("FLUSHALL\r\n") was called - } - - "shutdown the db" in { - connection.readBoolean returns true - client.shutdown mustEqual true - connection.write("SHUTDOWN\r\n") was called - } - - "move keys from one db to another" in { - connection.readBoolean returns true - client.move("a", 2) mustEqual true - connection.write("MOVE a 2\r\n") was called - } - - "quit" in { - connection.disconnect returns true - client.quit mustEqual true - connection.write("QUIT\r\n") was called - connection.disconnect was called - } - - "auth with the server" in { - connection.readBoolean returns true - client.auth("secret") mustEqual true - connection.write("AUTH secret\r\n") was called - } - } -} diff --git a/client-libraries/scala/src/test/scala/com/redis/operations/OperationsSpec.scala b/client-libraries/scala/src/test/scala/com/redis/operations/OperationsSpec.scala deleted file mode 100644 index 7fe26be3..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/operations/OperationsSpec.scala +++ /dev/null @@ -1,105 +0,0 @@ -import org.specs._ -import com.redis._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ - -object OperationsSpec extends Specification with Mockito { - - "Redis Client Operations" should { - - var client: RedisTestClient = null - var connection: Connection = null - - doBefore{ - connection = mock[Connection] - client = new RedisTestClient(connection) - } - - "set a key" in { - connection.readBoolean returns true - client.set("a", "b") mustEqual true - connection.write("SET a 1\r\nb\r\n") was called - } - - "set a key with setKey" in { - connection.readBoolean returns true - client.setKey("a", "b") mustEqual true - connection.write("SET a 1\r\nb\r\n") was called - } - - "set a key with expiration" in { - connection.readBoolean returns true - client.set("a", "b", 4) mustEqual true - connection.write("SET a 1\r\nb\r\n") was called - connection.write("EXPIRE a 4\r\n") was called - } - - "expire a key" in { - connection.readBoolean returns true - client.expire("a", 4) mustEqual true - connection.write("EXPIRE a 4\r\n") was called - } - - "get a key" in { - connection.readResponse returns "b" - client.get("a") mustEqual "b" - connection.write("GET a\r\n") was called - } - - "get and set a key" in { - connection.readResponse returns "old" - client.getSet("a", "new") mustEqual "old" - connection.write("GETSET a 3\r\nnew\r\n") was called - } - - "delete a key" in { - connection.readBoolean returns true - client.delete("a") mustEqual true - connection.write("DEL a\r\n") was called - } - - "tell if a key exists" in { - connection.readBoolean returns true - client.exists("a") mustEqual true - connection.write("EXISTS a\r\n") was called - } - - "tell if a key exists" in { - connection.readBoolean returns true - client.exists("a") mustEqual true - connection.write("EXISTS a\r\n") was called - } - - "increment a value" in { - connection.readInt returns 1 - client.incr("a") mustEqual 1 - connection.write("INCR a\r\n") was called - } - - "increment a value by N" in { - connection.readInt returns 27 - client.incr("a", 23) mustEqual 27 - connection.write("INCRBY a 23\r\n") was called - } - - "decrement a value" in { - connection.readInt returns 0 - client.decr("a") mustEqual 0 - connection.write("DECR a\r\n") was called - } - - "decrement a value by N" in { - connection.readInt returns 25 - client.decr("a", 2) mustEqual 25 - connection.write("DECRBY a 2\r\n") was called - } - - "return type of key" in { - connection.readResponse returns "String" - client.getType("a") mustEqual "String" - connection.write("TYPE a\r\n") was called - } - } -} diff --git a/client-libraries/scala/src/test/scala/com/redis/operations/SetOperationsSpec.scala b/client-libraries/scala/src/test/scala/com/redis/operations/SetOperationsSpec.scala deleted file mode 100644 index 78e6a5f2..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/operations/SetOperationsSpec.scala +++ /dev/null @@ -1,102 +0,0 @@ -import org.specs._ -import com.redis._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ -import org.mockito.Mockito.doNothing - -object SetOperationsSpec extends Specification with Mockito { - - "Redis Client Set Operations" should { - var client: RedisTestClient = null - var connection: Connection = null - - doBefore{ - connection = mock[Connection] - client = new RedisTestClient(connection) - } - - "add a member to a set" in { - connection.readBoolean returns true - client.setAdd("set", "value") must beTrue - connection.write("SADD set 5\r\nvalue\r\n") was called - } - - "remove an member from a set" in { - connection.readBoolean returns true - client.setDelete("set", "value") must beTrue - connection.write("SREM set 5\r\nvalue\r\n") was called - } - - "return the number of elements in the set" in { - connection.readInt returns 5 - client.setCount("set") mustEqual 5 - connection.write("SCARD set\r\n") was called - } - - "return all the members from a set" in { - val setResult = Set("one", "two", "three") - connection.readSet returns setResult - client.setMembers("set") mustEqual setResult - connection.write("SMEMBERS set\r\n") was called - } - - "pop an element from the set" in { - connection.readString returns "one" - client.setPop("set") mustEqual "one" - connection.write("SPOP set\r\n") was called - } - - "move an element from one set to another" in { - connection.readBoolean returns true - client.setMove("set", "toset", "value") mustEqual true - connection.write("SMOVE set toset value\r\n") was called - } - - "tell if member exists on the set" in { - connection.readBoolean returns true - client.setMemberExists("set", "value") mustEqual true - connection.write("SISMEMBER set 5\r\nvalue\r\n") was called - } - - "return the intersection between N sets" in { - val setResult = Set("one", "two", "three") - connection.readSet returns setResult - client.setIntersect("set", "otherset", "another") mustEqual setResult - connection.write("SINTER set otherset another\r\n") was called - } - - "return the intersection between N sets and store it a new one" in { - connection.readBoolean returns true - client.setInterStore("set", "oneset", "twoset") mustEqual true - connection.write("SINTERSTORE set oneset twoset\r\n") was called - } - - "return the difference between N sets" in { - val setResult = Set("one", "two", "three") - connection.readSet returns setResult - client.setDiff("set", "oneset", "twoset") mustEqual setResult - connection.write("SDIFF set oneset twoset\r\n") was called - } - - "return the difference between N sets and store it in a new one" in { - connection.readBoolean returns true - client.setDiffStore("newset", "oneset", "twoset") mustEqual true - connection.write("SDIFFSTORE newset oneset twoset\r\n") was called - } - - "return the union between N sets" in { - val setResult = Set("one", "two", "three") - connection.readSet returns setResult - client.setUnion("set", "oneset", "twoset") mustEqual setResult - connection.write("SUNION set oneset twoset\r\n") was called - } - - "return the union between N sets and store it in a new one" in { - connection.readBoolean returns true - client.setUnionStore("set", "oneset", "twoset") mustEqual true - connection.write("SUNIONSTORE set oneset twoset\r\n") was called - } - } -} \ No newline at end of file diff --git a/client-libraries/scala/src/test/scala/com/redis/operations/SortOperationsSpec.scala b/client-libraries/scala/src/test/scala/com/redis/operations/SortOperationsSpec.scala deleted file mode 100644 index 95f3c91d..00000000 --- a/client-libraries/scala/src/test/scala/com/redis/operations/SortOperationsSpec.scala +++ /dev/null @@ -1,34 +0,0 @@ -import org.specs._ -import com.redis._ - -import org.specs.mock.Mockito -import org.mockito.Mock._ -import org.mockito.Mockito._ - -object SortOperationsSpec extends Specification with Mockito { - - "Redis Client Sort Operations" should { - - var client: RedisTestClient = null - var connection: Connection = null - - doBefore{ - connection = mock[Connection] - client = new RedisTestClient(connection) - } - - "sort the contents of the specified key" in { - val listResult: List[String] = List("one", "two", "three") - connection.readList returns listResult - client.sort("set", "ALPHA DESC") mustEqual listResult - connection.write("SORT set ALPHA DESC\r\n") was called - } - - "sort the contents of the specified key with default" in { - val listResult: List[String] = List("one", "two", "three") - connection.readList returns listResult - client.sort("set") mustEqual listResult - connection.write("SORT set\r\n") was called - } - } -} diff --git a/client-libraries/tcl/redis.tcl b/client-libraries/tcl/redis.tcl deleted file mode 100644 index 61dae0c1..00000000 --- a/client-libraries/tcl/redis.tcl +++ /dev/null @@ -1,131 +0,0 @@ -# Tcl clinet library - used by test-redis.tcl script for now -# Copyright (C) 2009 Salvatore Sanfilippo -# Released under the BSD license like Redis itself -# -# Example usage: -# -# set r [redis 127.0.0.1 6379] -# $r lpush mylist foo -# $r lpush mylist bar -# $r lrange mylist 0 -1 -# $r close - -package provide redis 0.1 - -namespace eval redis {} -set ::redis::id 0 -array set ::redis::fd {} -array set ::redis::bulkarg {} -array set ::redis::multibulkarg {} - -# Flag commands requiring last argument as a bulk write operation -foreach redis_bulk_cmd { - set setnx rpush lpush lset lrem sadd srem sismember echo getset smove zadd zrem zscore -} { - set ::redis::bulkarg($redis_bulk_cmd) {} -} - -# Flag commands requiring last argument as a bulk write operation -foreach redis_multibulk_cmd { - mset msetnx -} { - set ::redis::multibulkarg($redis_multibulk_cmd) {} -} - -unset redis_bulk_cmd -unset redis_multibulk_cmd - -proc redis {{server 127.0.0.1} {port 6379}} { - set fd [socket $server $port] - fconfigure $fd -translation binary - set id [incr ::redis::id] - set ::redis::fd($id) $fd - interp alias {} ::redis::redisHandle$id {} ::redis::__dispatch__ $id -} - -proc ::redis::__dispatch__ {id method args} { - set fd $::redis::fd($id) - if {[info command ::redis::__method__$method] eq {}} { - if {[info exists ::redis::bulkarg($method)]} { - set cmd "$method " - append cmd [join [lrange $args 0 end-1]] - append cmd " [string length [lindex $args end]]\r\n" - append cmd [lindex $args end] - ::redis::redis_writenl $fd $cmd - } elseif {[info exists ::redis::multibulkarg($method)]} { - set cmd "*[expr {[llength $args]+1}]\r\n" - append cmd "$[string length $method]\r\n$method\r\n" - foreach a $args { - append cmd "$[string length $a]\r\n$a\r\n" - } - ::redis::redis_write $fd $cmd - flush $fd - } else { - set cmd "$method " - append cmd [join $args] - ::redis::redis_writenl $fd $cmd - } - ::redis::redis_read_reply $fd - } else { - uplevel 1 [list ::redis::__method__$method $id $fd] $args - } -} - -proc ::redis::__method__close {id fd} { - catch {close $fd} - catch {unset ::redis::fd($id)} - catch {interp alias {} ::redis::redisHandle$id {}} -} - -proc ::redis::__method__channel {id fd} { - return $fd -} - -proc ::redis::redis_write {fd buf} { - puts -nonewline $fd $buf -} - -proc ::redis::redis_writenl {fd buf} { - redis_write $fd $buf - redis_write $fd "\r\n" - flush $fd -} - -proc ::redis::redis_readnl {fd len} { - set buf [read $fd $len] - read $fd 2 ; # discard CR LF - return $buf -} - -proc ::redis::redis_bulk_read {fd} { - set count [redis_read_line $fd] - if {$count == -1} return {} - set buf [redis_readnl $fd $count] - return $buf -} - -proc ::redis::redis_multi_bulk_read fd { - set count [redis_read_line $fd] - if {$count == -1} return {} - set l {} - for {set i 0} {$i < $count} {incr i} { - lappend l [redis_read_reply $fd] - } - return $l -} - -proc ::redis::redis_read_line fd { - string trim [gets $fd] -} - -proc ::redis::redis_read_reply fd { - set type [read $fd 1] - switch -exact -- $type { - : - - + {redis_read_line $fd} - - {return -code error [redis_read_line $fd]} - $ {redis_bulk_read $fd} - * {redis_multi_bulk_read $fd} - default {return -code error "Bad protocol, $type as reply type byte"} - } -} diff --git a/client-libraries/update-clojure-client.sh b/client-libraries/update-clojure-client.sh deleted file mode 100755 index 125ad2ca..00000000 --- a/client-libraries/update-clojure-client.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -rm -rf temp -mkdir temp -cd temp -git clone git://github.com/ragnard/redis-clojure.git -cd redis-clojure -rm -rf .git -cd .. -cd .. -rm -rf clojure -mv temp/redis-clojure clojure -rm -rf temp diff --git a/client-libraries/update-cpp-client.sh b/client-libraries/update-cpp-client.sh deleted file mode 100755 index 87236f6a..00000000 --- a/client-libraries/update-cpp-client.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -rm -rf temp -mkdir temp -cd temp -git clone git://github.com/fictorial/redis-cpp-client.git -cd redis-cpp-client -rm -rf .git -cd .. -cd .. -rm -rf cpp -mv temp/redis-cpp-client cpp -rm -rf temp diff --git a/client-libraries/update-erlang-client.sh b/client-libraries/update-erlang-client.sh deleted file mode 100755 index 9d05c0cf..00000000 --- a/client-libraries/update-erlang-client.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -echo "Sorry for now this must be done by hand... don't know mercurial enough" diff --git a/client-libraries/update-lua-client.sh b/client-libraries/update-lua-client.sh deleted file mode 100755 index 1843997f..00000000 --- a/client-libraries/update-lua-client.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -rm -rf temp -mkdir temp -cd temp -git clone git://github.com/nrk/redis-lua.git -cd redis-lua -rm -rf .git -cd .. -cd .. -rm -rf lua -mv temp/redis-lua lua -rm -rf temp diff --git a/client-libraries/update-perl-client.sh b/client-libraries/update-perl-client.sh deleted file mode 100755 index 164b40dc..00000000 --- a/client-libraries/update-perl-client.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -rm -rf temp -mkdir temp -cd temp -svn checkout svn://svn.rot13.org/Redis/ -find . -name '.svn' -exec rm -rf {} \; 2> /dev/null -cd .. -rm -rf perl -mv temp/Redis perl -rm -rf temp diff --git a/client-libraries/update-python-client.sh b/client-libraries/update-python-client.sh deleted file mode 100755 index e5f03833..00000000 --- a/client-libraries/update-python-client.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -rm -rf temp -mkdir temp -cd temp -git clone git://github.com/ludoo/redis.git -cd .. -rm -rf python -mv temp/redis/client-libraries/python python -rm -rf temp diff --git a/client-libraries/update-ruby-client.sh b/client-libraries/update-ruby-client.sh deleted file mode 100755 index 56cfab51..00000000 --- a/client-libraries/update-ruby-client.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -rm -rf temp -mkdir temp -cd temp -git clone git://github.com/ezmobius/redis-rb.git -#git clone git://github.com/jodosha/redis-rb.git -cd redis-rb -rm -rf .git -cd .. -cd .. -rm -rf ruby -mv temp/redis-rb ruby -rm -rf temp diff --git a/client-libraries/update-scala-client.sh b/client-libraries/update-scala-client.sh deleted file mode 100755 index 622097b8..00000000 --- a/client-libraries/update-scala-client.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -rm -rf temp -mkdir temp -cd temp -git clone git://github.com/acrosa/scala-redis.git -cd scala-redis -rm -rf .git -cd .. -cd .. -rm -rf scala -mv temp/scala-redis scala -rm -rf temp -- 2.45.2