jodosha-redis-store 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Luca Guidi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,35 @@
1
+ h1. Redis cache and session stores for Ruby web frameworks
2
+
3
+ h2. Installation
4
+
5
+ Download and install Redis from http://code.google.com/p/redis/
6
+
7
+ wget http://redis.googlecode.com/files/redis-0.094.tar.gz
8
+ tar -zxvf redis-0.094.tar.gz
9
+ cd redis-0.094
10
+ make
11
+
12
+ Install the gems
13
+
14
+ sudo gem install ezmobius-redis-rb -s http://gems.github.com
15
+ sudo gem install jodosha-redis-store -s http://gems.github.com
16
+
17
+ h2. How to use with Rails
18
+
19
+ In your configuration files:
20
+
21
+ config.gem "jodosha-redis-store", :source => "http://gems.github.com", :lib => "redis-store"
22
+ require "redis-store" # HACK Rails tries to instantiate cache first, then load configured gems
23
+ config.cache_store = :redis_store
24
+
25
+ h2. How to use with Merb
26
+
27
+ dependency "merb-cache" do
28
+ Merb::Cache.setup do
29
+ register(:redis, RedisStore, :servers => ["127.0.0.1:6379"])
30
+ end
31
+ end
32
+
33
+ h2. Copyright
34
+
35
+ (c) 2009 Luca Guidi - http://lucaguidi.com, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ $:.unshift 'lib'
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'spec/rake/spectask'
7
+
8
+ REDIS_STORE_VERSION = "0.0.2"
9
+
10
+ task :default => :spec
11
+
12
+ desc 'Build and install the gem (useful for development purposes).'
13
+ task :install do
14
+ system "gem build redis-store.gemspec"
15
+ system "sudo gem uninstall redis-store"
16
+ system "sudo gem install --local --no-rdoc --no-ri redis-store-#{REDIS_STORE_VERSION}.gem"
17
+ system "rm redis-store-*.gem"
18
+ end
19
+
20
+ Spec::Rake::SpecTask.new do |t|
21
+ t.spec_files = FileList['spec/**/*_spec.rb']
22
+ t.spec_opts = %w(-fs --color)
23
+ end
24
+
25
+ desc 'Show the file list for the gemspec file'
26
+ task :files do
27
+ puts "Files:\n #{Dir['**/*'].reject {|f| File.directory?(f)}.sort.inspect}"
28
+ puts "Test files:\n #{Dir['spec/**/*_spec.rb'].reject {|f| File.directory?(f)}.sort.inspect}"
29
+ end
30
+
31
+ namespace :redis do
32
+ desc 'Start the Redis cluster'
33
+ task :start => :clean do
34
+ system "redis-server spec/config/single.conf"
35
+ system "redis-server spec/config/master.conf"
36
+ system "redis-server spec/config/slave.conf"
37
+ end
38
+
39
+ desc 'Stop the Redis cluster'
40
+ task :stop do
41
+ # TODO replace with:
42
+ # system "kill -9 `tmp/redis-single.pid`"
43
+ # system "kill -9 `tmp/redis-master.pid`"
44
+ # system "kill -9 `tmp/redis-slave.pid`"
45
+ system "ps -eo pid,comm | grep redis | xargs kill -9"
46
+ end
47
+
48
+ desc 'Clean the tmp/ directory'
49
+ task :clean do
50
+ system "rm tmp/*" rescue nil
51
+ end
52
+ end
@@ -0,0 +1,83 @@
1
+ module Merb
2
+ module Cache
3
+ class RedisStore < AbstractStore
4
+ # Instantiate the store.
5
+ #
6
+ # Example:
7
+ # RedisStore.new # => host: localhost, port: 6379, db: 0
8
+ # RedisStore.new :servers => ["example.com"] # => host: example.com, port: 6379, db: 0
9
+ # RedisStore.new :servers => ["example.com:23682"] # => host: example.com, port: 23682, db: 0
10
+ # RedisStore.new :servers => ["example.com:23682/1"] # => host: example.com, port: 23682, db: 1
11
+ # RedisStore.new :servers => ["localhost:6379/0", "localhost:6380/0"] # => instantiate a cluster
12
+ def initialize(config = {})
13
+ addresses = extract_addresses(config[:servers])
14
+ @data = if addresses.size > 1
15
+ DistributedMarshaledRedis.new addresses
16
+ else
17
+ MarshaledRedis.new addresses.first || {}
18
+ end
19
+ end
20
+
21
+ def writable?(key, parameters = {}, conditions = {})
22
+ true
23
+ end
24
+
25
+ def read(key, parameters = {}, conditions = {})
26
+ @data.get normalize(key, parameters), conditions
27
+ end
28
+
29
+ def write(key, data = nil, parameters = {}, conditions = {})
30
+ if writable?(key, parameters, conditions)
31
+ method = conditions && conditions[:unless_exist] ? :set_unless_exists : :set
32
+ @data.send method, normalize(key, parameters), data, conditions
33
+ end
34
+ end
35
+
36
+ def write_all(key, data = nil, parameters = {}, conditions = {})
37
+ write key, data, parameters, conditions
38
+ end
39
+
40
+ def fetch(key, parameters = {}, conditions = {}, &blk)
41
+ read(key, parameters) || (write key, yield, parameters, conditions if block_given?)
42
+ end
43
+
44
+ def exists?(key, parameters = {})
45
+ @data.key? normalize(key, parameters)
46
+ end
47
+
48
+ def delete(key, parameters = {})
49
+ @data.delete normalize(key, parameters)
50
+ end
51
+
52
+ def delete_all
53
+ @data.flush_db
54
+ end
55
+
56
+ def delete_all!
57
+ delete_all
58
+ end
59
+
60
+ private
61
+ def extract_addresses(addresses) # TODO extract in a module or a class
62
+ return [] unless addresses
63
+ addresses = addresses.flatten.compact
64
+ addresses.inject([]) do |result, address|
65
+ host, port = address.split /\:/
66
+ port, db = port.split /\// if port
67
+ address = {}
68
+ address[:host] = host if host
69
+ address[:port] = port if port
70
+ address[:db] = db.to_i if db
71
+ result << address
72
+ result
73
+ end
74
+ end
75
+
76
+ # Returns cache key calculated from base key
77
+ # and SHA2 hex from parameters.
78
+ def normalize(key, parameters = {})
79
+ parameters.empty? ? "#{key}" : "#{key}--#{parameters.to_sha2}"
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,129 @@
1
+ module ActiveSupport
2
+ module Cache
3
+ class RedisStore < Store
4
+ # Instantiate the store.
5
+ #
6
+ # Example:
7
+ # RedisStore.new # => host: localhost, port: 6379, db: 0
8
+ # RedisStore.new "example.com" # => host: example.com, port: 6379, db: 0
9
+ # RedisStore.new "example.com:23682" # => host: example.com, port: 23682, db: 0
10
+ # RedisStore.new "example.com:23682/1" # => host: example.com, port: 23682, db: 1
11
+ # RedisStore.new "localhost:6379/0", "localhost:6380/0" # => instantiate a cluster
12
+ def initialize(*addresses)
13
+ addresses = extract_addresses(addresses)
14
+ @data = if addresses.size > 1
15
+ DistributedMarshaledRedis.new addresses
16
+ else
17
+ MarshaledRedis.new addresses.first || {}
18
+ end
19
+ end
20
+
21
+ def write(key, value, options = nil)
22
+ super
23
+ method = options && options[:unless_exist] ? :set_unless_exists : :set
24
+ @data.send method, key, value, options
25
+ end
26
+
27
+ def read(key, options = nil)
28
+ super
29
+ @data.get key, options
30
+ end
31
+
32
+ def delete(key, options = nil)
33
+ super
34
+ @data.delete key
35
+ end
36
+
37
+ def exist?(key, options = nil)
38
+ super
39
+ @data.key? key
40
+ end
41
+
42
+ # Increment a key in the store.
43
+ #
44
+ # If the key doesn't exist it will be initialized on 0.
45
+ # If the key exist but it isn't a Fixnum it will be initialized on 0.
46
+ #
47
+ # Example:
48
+ # We have two objects in cache:
49
+ # counter # => 23
50
+ # rabbit # => #<Rabbit:0x5eee6c>
51
+ #
52
+ # cache.increment "counter"
53
+ # cache.read "counter", :raw => true # => "24"
54
+ #
55
+ # cache.increment "counter", 6
56
+ # cache.read "counter", :raw => true # => "30"
57
+ #
58
+ # cache.increment "a counter"
59
+ # cache.read "a counter", :raw => true # => "1"
60
+ #
61
+ # cache.increment "rabbit"
62
+ # cache.read "rabbit", :raw => true # => "1"
63
+ def increment(key, amount = 1)
64
+ log "increment", key, amount
65
+ @data.incr key, amount
66
+ end
67
+
68
+ # Decrement a key in the store
69
+ #
70
+ # If the key doesn't exist it will be initialized on 0.
71
+ # If the key exist but it isn't a Fixnum it will be initialized on 0.
72
+ #
73
+ # Example:
74
+ # We have two objects in cache:
75
+ # counter # => 23
76
+ # rabbit # => #<Rabbit:0x5eee6c>
77
+ #
78
+ # cache.decrement "counter"
79
+ # cache.read "counter", :raw => true # => "22"
80
+ #
81
+ # cache.decrement "counter", 2
82
+ # cache.read "counter", :raw => true # => "20"
83
+ #
84
+ # cache.decrement "a counter"
85
+ # cache.read "a counter", :raw => true # => "-1"
86
+ #
87
+ # cache.decrement "rabbit"
88
+ # cache.read "rabbit", :raw => true # => "-1"
89
+ def decrement(key, amount = 1)
90
+ log "decrement", key, amount
91
+ @data.decr key, amount
92
+ end
93
+
94
+ # Delete objects for matched keys.
95
+ #
96
+ # Example:
97
+ # cache.delete_matched "rab*"
98
+ def delete_matched(matcher, options = nil)
99
+ super
100
+ @data.keys(matcher).each { |key| @data.delete key }
101
+ end
102
+
103
+ # Clear all the data from the store.
104
+ def clear
105
+ log "clear", nil, nil
106
+ @data.flush_db
107
+ end
108
+
109
+ def stats
110
+ @data.info
111
+ end
112
+
113
+ private
114
+ def extract_addresses(addresses)
115
+ addresses = addresses.flatten.compact
116
+ addresses.inject([]) do |result, address|
117
+ host, port = address.split /\:/
118
+ port, db = port.split /\// if port
119
+ address = {}
120
+ address[:host] = host if host
121
+ address[:port] = port if port
122
+ address[:db] = db.to_i if db
123
+ result << address
124
+ result
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,10 @@
1
+ class DistributedMarshaledRedis < DistRedis
2
+ def initialize(addresses)
3
+ nodes = addresses.map do |address|
4
+ MarshaledRedis.new address
5
+ end
6
+ @ring = HashRing.new nodes
7
+ end
8
+
9
+ alias_method :flush_db, :delete_cloud!
10
+ end
@@ -0,0 +1,28 @@
1
+ class MarshaledRedis < Redis
2
+ def set(key, val, options = nil)
3
+ val = Marshal.dump val unless raw?(options)
4
+ super key, val, expires_in(options)
5
+ end
6
+
7
+ def set_unless_exists(key, val, options = nil)
8
+ val = Marshal.dump val unless raw?(options)
9
+ super key, val
10
+ end
11
+
12
+ def get(key, options = nil)
13
+ result = super key
14
+ result = Marshal.load result if result && !raw?(options)
15
+ result
16
+ end
17
+
18
+ private
19
+ def raw?(options)
20
+ options && options[:raw]
21
+ end
22
+
23
+ def expires_in(options)
24
+ if options
25
+ options[:expires_in] || options[:expire_in]
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ require "redis"
2
+ require "dist_redis"
3
+ require "redis/marshaled_redis"
4
+ require "redis/distributed_marshaled_redis"
5
+
6
+ if defined?(Merb)
7
+ require "cache/merb/redis_store"
8
+ else # rails or ruby application
9
+ require "activesupport"
10
+ require "cache/rails/redis_store"
11
+ end
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "redis-store"
3
+ s.version = "0.0.2"
4
+ s.date = "2009-04-16"
5
+ s.summary = "Redis cache and session stores for Ruby web frameworks"
6
+ s.author = "Luca Guidi"
7
+ s.email = "guidi.luca@gmail.com"
8
+ s.homepage = "http://lucaguidi.com"
9
+ s.description = "Redis cache and session stores for Ruby web frameworks"
10
+ s.has_rdoc = true
11
+ s.files = ["MIT-LICENSE", "README.textile", "Rakefile", "lib/cache/merb/redis_store.rb", "lib/cache/rails/redis_store.rb", "lib/redis-store.rb", "lib/redis/distributed_marshaled_redis.rb", "lib/redis/marshaled_redis.rb", "redis-store.gemspec", "spec/cache/merb/redis_store_spec.rb", "spec/cache/rails/redis_store_spec.rb", "spec/config/master.conf", "spec/config/single.conf", "spec/config/slave.conf", "spec/redis/distributed_marshaled_redis_spec.rb", "spec/redis/marshaled_redis_spec.rb", "spec/spec_helper.rb"]
12
+ s.test_files = ["spec/cache/merb/redis_store_spec.rb", "spec/cache/rails/redis_store_spec.rb", "spec/redis/distributed_marshaled_redis_spec.rb", "spec/redis/marshaled_redis_spec.rb"]
13
+ s.extra_rdoc_files = ["README.textile"]
14
+ end
@@ -0,0 +1,132 @@
1
+ require File.join(File.dirname(__FILE__), "/../../spec_helper")
2
+
3
+ module Merb
4
+ module Cache
5
+ describe "RedisStore" do
6
+ before(:each) do
7
+ @store = RedisStore.new
8
+ @dstore = RedisStore.new :servers => ["localhost:6380/1", "localhost:6381/1"]
9
+ @rabbit = OpenStruct.new :name => "bunny"
10
+ @white_rabbit = OpenStruct.new :color => "white"
11
+ with_store_management do |store|
12
+ store.write "rabbit", @rabbit
13
+ store.delete "rub-a-dub"
14
+ end
15
+ end
16
+
17
+ it "should accept connection params" do
18
+ redis = instantiate_store
19
+ redis.instance_variable_get(:@db).should == 0
20
+ redis.host.should == "localhost"
21
+ redis.port.should == "6379"
22
+
23
+ redis = instantiate_store "redis.com"
24
+ redis.host.should == "redis.com"
25
+
26
+ redis = instantiate_store "redis.com:6380"
27
+ redis.host.should == "redis.com"
28
+ redis.port.should == "6380"
29
+
30
+ redis = instantiate_store "redis.com:6380/23"
31
+ redis.instance_variable_get(:@db).should == 23
32
+ redis.host.should == "redis.com"
33
+ redis.port.should == "6380"
34
+ end
35
+
36
+ it "should instantiate a ring" do
37
+ store = instantiate_store
38
+ store.should be_kind_of(MarshaledRedis)
39
+ store = instantiate_store ["localhost:6379/0", "localhost:6379/1"]
40
+ store.should be_kind_of(DistributedMarshaledRedis)
41
+ end
42
+
43
+ it "should verify if writable" do
44
+ with_store_management do |store|
45
+ store.writable?("rabbit").should be_true
46
+ end
47
+ end
48
+
49
+ it "should read the data" do
50
+ with_store_management do |store|
51
+ store.read("rabbit").should === @rabbit
52
+ end
53
+ end
54
+
55
+ it "should read raw data" do
56
+ with_store_management do |store|
57
+ store.read("rabbit", {}, :raw => true).should == "\004\bU:\017OpenStruct{\006:\tname\"\nbunny"
58
+ end
59
+ end
60
+
61
+ it "should write the data" do
62
+ with_store_management do |store|
63
+ store.write "rabbit", @white_rabbit
64
+ store.read("rabbit").should === @white_rabbit
65
+ end
66
+ end
67
+
68
+ it "should write raw data" do
69
+ with_store_management do |store|
70
+ store.write "rabbit", @white_rabbit, {}, :raw => true
71
+ store.read("rabbit", {}, :raw => true).should == %(#<OpenStruct color="white">)
72
+ end
73
+ end
74
+
75
+ # it "should write the data with expiration time" do
76
+ # @store.write "rabbit", @white_rabbit, :expires_in => 1.second
77
+ # @store.read("rabbit").should === @white_rabbit ; sleep 2
78
+ # @store.read("rabbit").should be_nil
79
+ # end
80
+
81
+ it "should not write data if :unless_exist option is true" do
82
+ with_store_management do |store|
83
+ store.write "rabbit", @white_rabbit, {}, :unless_exist => true
84
+ store.read("rabbit").should === @rabbit
85
+ end
86
+ end
87
+
88
+ it "should fetch data" do
89
+ with_store_management do |store|
90
+ store.fetch("rabbit").should == @rabbit
91
+ store.fetch("rub-a-dub").should be_nil
92
+ store.fetch("rub-a-dub") { "Flora de Cana" }
93
+ store.fetch("rub-a-dub").should === "Flora de Cana"
94
+ # store.fetch("rabbit", {}, :force => true, :expires_in => 1.second) { @white_rabbit }
95
+ # store.fetch("rabbit").should === @white_rabbit ; sleep 2
96
+ # store.fetch("rabbit").should be_nil
97
+ end
98
+ end
99
+
100
+ it "should verify existence" do
101
+ with_store_management do |store|
102
+ store.exists?("rabbit").should be_true
103
+ store.exists?("rab-a-dub").should be_false
104
+ end
105
+ end
106
+
107
+ it "should delete data" do
108
+ with_store_management do |store|
109
+ store.delete "rabbit"
110
+ store.read("rabbit").should be_nil
111
+ end
112
+ end
113
+
114
+ it "should delete all the data" do
115
+ with_store_management do |store|
116
+ store.delete_all
117
+ store.instance_variable_get(:@data).keys("*").should be_empty
118
+ end
119
+ end
120
+
121
+ private
122
+ def instantiate_store(addresses = nil)
123
+ RedisStore.new(:servers => [addresses].flatten).instance_variable_get(:@data)
124
+ end
125
+
126
+ def with_store_management
127
+ yield @store
128
+ yield @dstore
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,170 @@
1
+ require File.join(File.dirname(__FILE__), "/../../spec_helper")
2
+
3
+ module ActiveSupport
4
+ module Cache
5
+ describe "RedisStore" do
6
+ before(:each) do
7
+ @store = RedisStore.new
8
+ @dstore = RedisStore.new "localhost:6380/1", "localhost:6381/1"
9
+ @rabbit = OpenStruct.new :name => "bunny"
10
+ @white_rabbit = OpenStruct.new :color => "white"
11
+ with_store_management do |store|
12
+ store.write "rabbit", @rabbit
13
+ store.delete "counter"
14
+ end
15
+ end
16
+
17
+ it "should accept connection params" do
18
+ redis = instantiate_store
19
+ redis.instance_variable_get(:@db).should == 0
20
+ redis.host.should == "localhost"
21
+ redis.port.should == "6379"
22
+
23
+ redis = instantiate_store "redis.com"
24
+ redis.host.should == "redis.com"
25
+
26
+ redis = instantiate_store "redis.com:6380"
27
+ redis.host.should == "redis.com"
28
+ redis.port.should == "6380"
29
+
30
+ redis = instantiate_store "redis.com:6380/23"
31
+ redis.instance_variable_get(:@db).should == 23
32
+ redis.host.should == "redis.com"
33
+ redis.port.should == "6380"
34
+ end
35
+
36
+ it "should instantiate a ring" do
37
+ store = instantiate_store
38
+ store.should be_kind_of(MarshaledRedis)
39
+ store = instantiate_store ["localhost:6379/0", "localhost:6379/1"]
40
+ store.should be_kind_of(DistributedMarshaledRedis)
41
+ end
42
+
43
+ it "should read the data" do
44
+ with_store_management do |store|
45
+ store.read("rabbit").should === @rabbit
46
+ end
47
+ end
48
+
49
+ it "should write the data" do
50
+ with_store_management do |store|
51
+ store.write "rabbit", @white_rabbit
52
+ store.read("rabbit").should === @white_rabbit
53
+ end
54
+ end
55
+
56
+ # it "should write the data with expiration time" do
57
+ # @store.write "rabbit", @white_rabbit, :expires_in => 1.second
58
+ # @store.read("rabbit").should === @white_rabbit ; sleep 2
59
+ # @store.read("rabbit").should be_nil
60
+ # end
61
+
62
+ it "should not write data if :unless_exist option is true" do
63
+ with_store_management do |store|
64
+ store.write "rabbit", @white_rabbit, :unless_exist => true
65
+ store.read("rabbit").should === @rabbit
66
+ end
67
+ end
68
+
69
+ it "should read raw data" do
70
+ with_store_management do |store|
71
+ store.read("rabbit", :raw => true).should == "\004\bU:\017OpenStruct{\006:\tname\"\nbunny"
72
+ end
73
+ end
74
+
75
+ it "should write raw data" do
76
+ with_store_management do |store|
77
+ store.write "rabbit", @white_rabbit, :raw => true
78
+ store.read("rabbit", :raw => true).should == %(#<OpenStruct color="white">)
79
+ end
80
+ end
81
+
82
+ it "should delete data" do
83
+ with_store_management do |store|
84
+ store.delete "rabbit"
85
+ store.read("rabbit").should be_nil
86
+ end
87
+ end
88
+
89
+ it "should delete matched data" do
90
+ with_store_management do |store|
91
+ store.delete_matched "rabb*"
92
+ store.read("rabbit").should be_nil
93
+ end
94
+ end
95
+
96
+ it "should verify existence of an object in the store" do
97
+ with_store_management do |store|
98
+ store.exist?("rabbit").should be_true
99
+ store.exist?("rab-a-dub").should be_false
100
+ end
101
+ end
102
+
103
+ it "should increment a key" do
104
+ with_store_management do |store|
105
+ 3.times { store.increment "counter" }
106
+ store.read("counter", :raw => true).to_i.should == 3
107
+ end
108
+ end
109
+
110
+ it "should decrement a key" do
111
+ with_store_management do |store|
112
+ 3.times { store.increment "counter" }
113
+ 2.times { store.decrement "counter" }
114
+ store.read("counter", :raw => true).to_i.should == 1
115
+ end
116
+ end
117
+
118
+ it "should increment a key by given value" do
119
+ with_store_management do |store|
120
+ store.increment "counter", 3
121
+ store.read("counter", :raw => true).to_i.should == 3
122
+ end
123
+ end
124
+
125
+ it "should decrement a key by given value" do
126
+ with_store_management do |store|
127
+ 3.times { store.increment "counter" }
128
+ store.decrement "counter", 2
129
+ store.read("counter", :raw => true).to_i.should == 1
130
+ end
131
+ end
132
+
133
+ it "should clear the store" do
134
+ with_store_management do |store|
135
+ store.clear
136
+ store.instance_variable_get(:@data).keys("*").should be_empty
137
+ end
138
+ end
139
+
140
+ it "should return store stats" do
141
+ with_store_management do |store|
142
+ store.stats.should_not be_empty
143
+ end
144
+ end
145
+
146
+ it "should fetch data" do
147
+ with_store_management do |store|
148
+ store.fetch("rabbit").should == @rabbit
149
+ store.fetch("rub-a-dub").should be_nil
150
+ store.fetch("rub-a-dub") { "Flora de Cana" }
151
+ store.fetch("rub-a-dub").should === "Flora de Cana"
152
+ store.fetch("rabbit", :force => true).should be_nil # force cache miss
153
+ # store.fetch("rabbit", :force => true, :expires_in => 1.second) { @white_rabbit }
154
+ # store.fetch("rabbit").should === @white_rabbit ; sleep 2
155
+ # store.fetch("rabbit").should be_nil
156
+ end
157
+ end
158
+
159
+ private
160
+ def instantiate_store(addresses = nil)
161
+ RedisStore.new(addresses).instance_variable_get(:@data)
162
+ end
163
+
164
+ def with_store_management
165
+ yield @store
166
+ yield @dstore
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,87 @@
1
+ # Redis configuration file example
2
+
3
+ # By default Redis does not run as a daemon. Use 'yes' if you need it.
4
+ # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
5
+ daemonize yes
6
+
7
+ # When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
8
+ # You can specify a custom pid file location here.
9
+ pidfile ./tmp/redis-master.pid
10
+
11
+ # Accept connections on the specified port, default is 6379
12
+ port 6380
13
+
14
+ # If you want you can bind a single interface, if the bind option is not
15
+ # specified all the interfaces will listen for connections.
16
+ #
17
+ # bind 127.0.0.1
18
+
19
+ # Close the connection after a client is idle for N seconds
20
+ timeout 300
21
+
22
+ # Save the DB on disk:
23
+ #
24
+ # save <seconds> <changes>
25
+ #
26
+ # Will save the DB if both the given number of seconds and the given
27
+ # number of write operations against the DB occurred.
28
+ #
29
+ # In the example below the behaviour will be to save:
30
+ # after 900 sec (15 min) if at least 1 key changed
31
+ # after 300 sec (5 min) if at least 10 keys changed
32
+ # after 60 sec if at least 10000 keys changed
33
+ save 900 1
34
+ save 300 10
35
+ save 60 10000
36
+
37
+ # For default save/load DB in/from the working directory
38
+ # Note that you must specify a directory not a file name.
39
+ dir ./tmp
40
+
41
+ # Set server verbosity to 'debug'
42
+ # it can be one of:
43
+ # debug (a lot of information, useful for development/testing)
44
+ # notice (moderately verbose, what you want in production probably)
45
+ # warning (only very important / critical messages are logged)
46
+ loglevel debug
47
+
48
+ # Specify the log file name. Also 'stdout' can be used to force
49
+ # the demon to log on the standard output. Note that if you use standard
50
+ # output for logging but daemonize, logs will be sent to /dev/null
51
+ logfile stdout
52
+
53
+ # Set the number of databases.
54
+ databases 16
55
+
56
+ ################################# REPLICATION #################################
57
+
58
+ # Master-Slave replication. Use slaveof to make a Redis instance a copy of
59
+ # another Redis server. Note that the configuration is local to the slave
60
+ # so for example it is possible to configure the slave to save the DB with a
61
+ # different interval, or to listen to another port, and so on.
62
+
63
+ # slaveof <masterip> <masterport>
64
+
65
+ ################################## SECURITY ###################################
66
+
67
+ # Require clients to issue AUTH <PASSWORD> before processing any other
68
+ # commands. This might be useful in environments in which you do not trust
69
+ # others with access to the host running redis-server.
70
+ #
71
+ # This should stay commented out for backward compatibility and because most
72
+ # people do not need auth (e.g. they run their own servers).
73
+
74
+ # requirepass foobared
75
+
76
+ ############################### ADVANCED CONFIG ###############################
77
+
78
+ # Glue small output buffers together in order to send small replies in a
79
+ # single TCP packet. Uses a bit more CPU but most of the times it is a win
80
+ # in terms of number of queries per second. Use 'yes' if unsure.
81
+ glueoutputbuf yes
82
+
83
+ # Use object sharing. Can save a lot of memory if you have many common
84
+ # string in your dataset, but performs lookups against the shared objects
85
+ # pool so it uses more CPU and can be a bit slower. Usually it's a good
86
+ # idea.
87
+ shareobjects no
@@ -0,0 +1,87 @@
1
+ # Redis configuration file example
2
+
3
+ # By default Redis does not run as a daemon. Use 'yes' if you need it.
4
+ # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
5
+ daemonize yes
6
+
7
+ # When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
8
+ # You can specify a custom pid file location here.
9
+ pidfile ./tmp/redis-single.pid
10
+
11
+ # Accept connections on the specified port, default is 6379
12
+ port 6379
13
+
14
+ # If you want you can bind a single interface, if the bind option is not
15
+ # specified all the interfaces will listen for connections.
16
+ #
17
+ # bind 127.0.0.1
18
+
19
+ # Close the connection after a client is idle for N seconds
20
+ timeout 300
21
+
22
+ # Save the DB on disk:
23
+ #
24
+ # save <seconds> <changes>
25
+ #
26
+ # Will save the DB if both the given number of seconds and the given
27
+ # number of write operations against the DB occurred.
28
+ #
29
+ # In the example below the behaviour will be to save:
30
+ # after 900 sec (15 min) if at least 1 key changed
31
+ # after 300 sec (5 min) if at least 10 keys changed
32
+ # after 60 sec if at least 10000 keys changed
33
+ save 900 1
34
+ save 300 10
35
+ save 60 10000
36
+
37
+ # For default save/load DB in/from the working directory
38
+ # Note that you must specify a directory not a file name.
39
+ dir ./tmp
40
+
41
+ # Set server verbosity to 'debug'
42
+ # it can be one of:
43
+ # debug (a lot of information, useful for development/testing)
44
+ # notice (moderately verbose, what you want in production probably)
45
+ # warning (only very important / critical messages are logged)
46
+ loglevel debug
47
+
48
+ # Specify the log file name. Also 'stdout' can be used to force
49
+ # the demon to log on the standard output. Note that if you use standard
50
+ # output for logging but daemonize, logs will be sent to /dev/null
51
+ logfile stdout
52
+
53
+ # Set the number of databases.
54
+ databases 16
55
+
56
+ ################################# REPLICATION #################################
57
+
58
+ # Master-Slave replication. Use slaveof to make a Redis instance a copy of
59
+ # another Redis server. Note that the configuration is local to the slave
60
+ # so for example it is possible to configure the slave to save the DB with a
61
+ # different interval, or to listen to another port, and so on.
62
+
63
+ # slaveof <masterip> <masterport>
64
+
65
+ ################################## SECURITY ###################################
66
+
67
+ # Require clients to issue AUTH <PASSWORD> before processing any other
68
+ # commands. This might be useful in environments in which you do not trust
69
+ # others with access to the host running redis-server.
70
+ #
71
+ # This should stay commented out for backward compatibility and because most
72
+ # people do not need auth (e.g. they run their own servers).
73
+
74
+ # requirepass foobared
75
+
76
+ ############################### ADVANCED CONFIG ###############################
77
+
78
+ # Glue small output buffers together in order to send small replies in a
79
+ # single TCP packet. Uses a bit more CPU but most of the times it is a win
80
+ # in terms of number of queries per second. Use 'yes' if unsure.
81
+ glueoutputbuf yes
82
+
83
+ # Use object sharing. Can save a lot of memory if you have many common
84
+ # string in your dataset, but performs lookups against the shared objects
85
+ # pool so it uses more CPU and can be a bit slower. Usually it's a good
86
+ # idea.
87
+ shareobjects no
@@ -0,0 +1,87 @@
1
+ # Redis configuration file example
2
+
3
+ # By default Redis does not run as a daemon. Use 'yes' if you need it.
4
+ # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
5
+ daemonize yes
6
+
7
+ # When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
8
+ # You can specify a custom pid file location here.
9
+ pidfile ./tmp/redis-slave.pid
10
+
11
+ # Accept connections on the specified port, default is 6379
12
+ port 6381
13
+
14
+ # If you want you can bind a single interface, if the bind option is not
15
+ # specified all the interfaces will listen for connections.
16
+ #
17
+ # bind 127.0.0.1
18
+
19
+ # Close the connection after a client is idle for N seconds
20
+ timeout 300
21
+
22
+ # Save the DB on disk:
23
+ #
24
+ # save <seconds> <changes>
25
+ #
26
+ # Will save the DB if both the given number of seconds and the given
27
+ # number of write operations against the DB occurred.
28
+ #
29
+ # In the example below the behaviour will be to save:
30
+ # after 900 sec (15 min) if at least 1 key changed
31
+ # after 300 sec (5 min) if at least 10 keys changed
32
+ # after 60 sec if at least 10000 keys changed
33
+ save 900 1
34
+ save 300 10
35
+ save 60 10000
36
+
37
+ # For default save/load DB in/from the working directory
38
+ # Note that you must specify a directory not a file name.
39
+ dir ./tmp
40
+
41
+ # Set server verbosity to 'debug'
42
+ # it can be one of:
43
+ # debug (a lot of information, useful for development/testing)
44
+ # notice (moderately verbose, what you want in production probably)
45
+ # warning (only very important / critical messages are logged)
46
+ loglevel debug
47
+
48
+ # Specify the log file name. Also 'stdout' can be used to force
49
+ # the demon to log on the standard output. Note that if you use standard
50
+ # output for logging but daemonize, logs will be sent to /dev/null
51
+ logfile stdout
52
+
53
+ # Set the number of databases.
54
+ databases 16
55
+
56
+ ################################# REPLICATION #################################
57
+
58
+ # Master-Slave replication. Use slaveof to make a Redis instance a copy of
59
+ # another Redis server. Note that the configuration is local to the slave
60
+ # so for example it is possible to configure the slave to save the DB with a
61
+ # different interval, or to listen to another port, and so on.
62
+
63
+ # slaveof 127.0.0.1 6380
64
+
65
+ ################################## SECURITY ###################################
66
+
67
+ # Require clients to issue AUTH <PASSWORD> before processing any other
68
+ # commands. This might be useful in environments in which you do not trust
69
+ # others with access to the host running redis-server.
70
+ #
71
+ # This should stay commented out for backward compatibility and because most
72
+ # people do not need auth (e.g. they run their own servers).
73
+
74
+ # requirepass foobared
75
+
76
+ ############################### ADVANCED CONFIG ###############################
77
+
78
+ # Glue small output buffers together in order to send small replies in a
79
+ # single TCP packet. Uses a bit more CPU but most of the times it is a win
80
+ # in terms of number of queries per second. Use 'yes' if unsure.
81
+ glueoutputbuf yes
82
+
83
+ # Use object sharing. Can save a lot of memory if you have many common
84
+ # string in your dataset, but performs lookups against the shared objects
85
+ # pool so it uses more CPU and can be a bit slower. Usually it's a good
86
+ # idea.
87
+ shareobjects no
@@ -0,0 +1,35 @@
1
+ require File.join(File.dirname(__FILE__), "/../spec_helper")
2
+
3
+ describe "DistributedMarshaledRedis" do
4
+ before(:each) do
5
+ @dmr = DistributedMarshaledRedis.new [
6
+ {:host => "localhost", :port => "6380", :db => 0},
7
+ {:host => "localhost", :port => "6381", :db => 0}
8
+ ]
9
+ @rabbit = OpenStruct.new :name => "bunny"
10
+ @white_rabbit = OpenStruct.new :color => "white"
11
+ @dmr.set "rabbit", @rabbit
12
+ end
13
+
14
+ after(:all) do
15
+ @dmr.ring.nodes.each { |server| server.flush_db }
16
+ end
17
+
18
+ it "should accept connection params" do
19
+ dmr = DistributedMarshaledRedis.new [ :host => "redis.com", :port => "6380", :db => 1 ]
20
+ dmr.ring.should have(1).node
21
+ mr = dmr.ring.nodes.first
22
+ mr.host.should == "redis.com"
23
+ mr.port.should == "6380"
24
+ mr.instance_variable_get(:@db).should == 1
25
+ end
26
+
27
+ it "should set an object" do
28
+ @dmr.set "rabbit", @white_rabbit
29
+ @dmr.get("rabbit").should == @white_rabbit
30
+ end
31
+
32
+ it "should get an object" do
33
+ @dmr.get("rabbit").should == @rabbit
34
+ end
35
+ end
@@ -0,0 +1,44 @@
1
+ require File.join(File.dirname(__FILE__), "/../spec_helper")
2
+
3
+ describe "MarshaledRedis" do
4
+ before(:each) do
5
+ @mr = MarshaledRedis.new
6
+ @rabbit = OpenStruct.new :name => "bunny"
7
+ @white_rabbit = OpenStruct.new :color => "white"
8
+ @mr.set "rabbit", @rabbit
9
+ @mr.delete "rabbit2"
10
+ end
11
+
12
+ it "should unmarshal an object on get" do
13
+ @mr.get("rabbit").should === @rabbit
14
+ end
15
+
16
+ it "should marshal object on set" do
17
+ @mr.set "rabbit", @white_rabbit
18
+ @mr.get("rabbit").should === @white_rabbit
19
+ end
20
+
21
+ it "should not unmarshal object on get if raw option is true" do
22
+ @mr.get("rabbit", :raw => true).should == "\004\bU:\017OpenStruct{\006:\tname\"\nbunny"
23
+ end
24
+
25
+ it "should not marshal object on set if raw option is true" do
26
+ @mr.set "rabbit", @white_rabbit, :raw => true
27
+ @mr.get("rabbit", :raw => true).should == %(#<OpenStruct color="white">)
28
+ end
29
+
30
+ it "should not set an object if already exist" do
31
+ @mr.set_unless_exists "rabbit", @white_rabbit
32
+ @mr.get("rabbit").should === @rabbit
33
+ end
34
+
35
+ it "should marshal object on set_unless_exists" do
36
+ @mr.set_unless_exists "rabbit2", @white_rabbit
37
+ @mr.get("rabbit2").should === @white_rabbit
38
+ end
39
+
40
+ it "should not marshal object on set_unless_exists if raw option is true" do
41
+ @mr.set_unless_exists "rabbit2", @white_rabbit, :raw => true
42
+ @mr.get("rabbit2", :raw => true).should == %(#<OpenStruct color="white">)
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ $: << File.join(File.dirname(__FILE__), "/../lib")
2
+ require "rubygems"
3
+ require "ostruct"
4
+ require "spec"
5
+ require "redis"
6
+ require "merb"
7
+ require "redis-store"
8
+ require "activesupport"
9
+ require "cache/rails/redis_store"
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jodosha-redis-store
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Luca Guidi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-16 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Redis cache and session stores for Ruby web frameworks
17
+ email: guidi.luca@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.textile
24
+ files:
25
+ - MIT-LICENSE
26
+ - README.textile
27
+ - Rakefile
28
+ - lib/cache/merb/redis_store.rb
29
+ - lib/cache/rails/redis_store.rb
30
+ - lib/redis-store.rb
31
+ - lib/redis/distributed_marshaled_redis.rb
32
+ - lib/redis/marshaled_redis.rb
33
+ - redis-store.gemspec
34
+ - spec/cache/merb/redis_store_spec.rb
35
+ - spec/cache/rails/redis_store_spec.rb
36
+ - spec/config/master.conf
37
+ - spec/config/single.conf
38
+ - spec/config/slave.conf
39
+ - spec/redis/distributed_marshaled_redis_spec.rb
40
+ - spec/redis/marshaled_redis_spec.rb
41
+ - spec/spec_helper.rb
42
+ has_rdoc: true
43
+ homepage: http://lucaguidi.com
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.2.0
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: Redis cache and session stores for Ruby web frameworks
68
+ test_files:
69
+ - spec/cache/merb/redis_store_spec.rb
70
+ - spec/cache/rails/redis_store_spec.rb
71
+ - spec/redis/distributed_marshaled_redis_spec.rb
72
+ - spec/redis/marshaled_redis_spec.rb