cachedis 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +24 -13
- data/benchmarks/serialization.rb +75 -0
- data/lib/cachedis.rb +32 -30
- data/lib/cachedis/version.rb +2 -2
- data/spec/base_spec.rb +9 -11
- data/spec/interface_spec.rb +4 -4
- data/spec/spec_helper.rb +1 -1
- metadata +3 -2
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -8,24 +8,13 @@ Cachedis caches your expensive queries to a Redis instance so the next time you
|
|
8
8
|
|
9
9
|
## Documentation
|
10
10
|
|
11
|
-
You can specify two types of options via constants:
|
12
|
-
|
13
|
-
* `CACHEDIS_DEFAULT_OPTIONS`
|
14
|
-
- Passed directly to [redis-rb][rr]
|
15
|
-
- Options like host options, port options, etc.
|
16
|
-
* `CACHEDIS_DEFAULT_QUERY_OPTIONS`
|
17
|
-
- Default options for the `cachedis` queries
|
18
|
-
- For instance if you always want queries to expire in an hour:
|
19
|
-
- `CACHEDIS_DEFAULT_QUERY_OPTIONS = { :expire => 60 * 60 * 60}`
|
20
|
-
- Overridden by options passed to `cachedis` directly
|
21
|
-
|
22
11
|
`cachedis` takes two arguments in addition to a block which should return whatever you want `cachedis` to cache:
|
23
12
|
|
24
13
|
key, options = {}
|
25
14
|
|
26
15
|
The key is the name of the key under which the objects are saved as in Redis. Options are send directly to the Redis instance in along. For instance the option could be expiring the key at a certain time:
|
27
16
|
|
28
|
-
include
|
17
|
+
include Cachedis::Interface
|
29
18
|
|
30
19
|
# expire in an hour using Redis' EXPIRE command
|
31
20
|
cachedis 'users:all:with_avatars', :expire => 60 * 60 * 60 do
|
@@ -37,6 +26,15 @@ The key is the name of the key under which the objects are saved as in Redis. Op
|
|
37
26
|
# insert expensive query here
|
38
27
|
end
|
39
28
|
|
29
|
+
### Configuration
|
30
|
+
|
31
|
+
If you want to configure the server(s) or port(s) for `cachedis` to use, you should override the default `Cachedis::Interface#cachedis` method. Whatever you pass to `#new` is passed directly to the instance of the Redis object from the [redis-rb][rr] library:
|
32
|
+
|
33
|
+
def cachedis(name, options = {}, &block)
|
34
|
+
@cachedis ||= Cachedis.new(:host => "10.0.1.1", :port => 6380)
|
35
|
+
@cachedis.cachedis(name, options, &block)
|
36
|
+
end
|
37
|
+
|
40
38
|
## Installation and dependencies
|
41
39
|
|
42
40
|
Dependencies: [redis-rb][rr]
|
@@ -45,12 +43,25 @@ Install: `gem install cachedis`
|
|
45
43
|
|
46
44
|
[Redis](http://redis.io) should be running in the background, start it with `redis-server`.
|
47
45
|
|
46
|
+
## Serialization
|
47
|
+
|
48
|
+
I experimented and benchmarked with `JSON`, `YAML` and `Marshal` using the drivers in the Ruby standard libary with [this script](https://gist.github.com/858604).
|
49
|
+
|
50
|
+
Marshal is about 2x as fast as the other formats. However, it's also the one that is gonna take up the most space, but it's so little that it should not matter.
|
51
|
+
|
52
|
+
You can switch serialization driver if you need to by overriding `Cachedis.serializer`. The serializer must respond to `#load` and `#dump`, remember to require it before using it with `cachedis`:
|
53
|
+
|
54
|
+
module Cachedis
|
55
|
+
def self.serializer
|
56
|
+
"YAML"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
48
60
|
## Wishlist/To do/To consider
|
49
61
|
|
50
62
|
* ActiveRecord integration
|
51
63
|
- `Post.all.expensive_operation.cachedis`
|
52
64
|
* Make expirement time optional
|
53
|
-
* Best serializing?
|
54
65
|
* Sexify the API
|
55
66
|
- Make it easier to specialize expirement time (e.g. `:expire => 4.hours`), or just let this be for ActiveSupport users only?
|
56
67
|
* Rename `Cachedis#cachedis`?
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'redis'
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
N = 10000
|
7
|
+
|
8
|
+
Benchmark.bm do |r|
|
9
|
+
@redis = Redis.new
|
10
|
+
@serialize_me = { :lol => 'test', "ohai" => 'llllll', :array => [12,321,231,23, { :hi => 'hej'}]}
|
11
|
+
|
12
|
+
r.report("YAML Save") do
|
13
|
+
puts 'Yaml'
|
14
|
+
puts YAML.dump(@serialize_me).length
|
15
|
+
|
16
|
+
N.times do |n|
|
17
|
+
@redis.set "yaml-#{n}", YAML.dump(@serialize_me)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
r.report("YAML Load") do
|
22
|
+
N.times do |n|
|
23
|
+
YAML.load(@redis.get "yaml-#{n}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
r.report("Marshal Save") do
|
28
|
+
puts 'Marshal'
|
29
|
+
puts Marshal.dump(@serialize_me).length
|
30
|
+
|
31
|
+
N.times do |n|
|
32
|
+
@redis.set "marshal-#{n}", Marshal.dump(@serialize_me)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
r.report("Marshal Load") do
|
37
|
+
N.times do |n|
|
38
|
+
Marshal.load(@redis.get "marshal-#{n}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
r.report("JSON Save") do
|
43
|
+
puts 'JSON'
|
44
|
+
puts JSON.dump(@serialize_me).length
|
45
|
+
|
46
|
+
N.times do |n|
|
47
|
+
@redis.set "json-#{n}", JSON.dump(@serialize_me)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
r.report("JSON Load") do
|
52
|
+
N.times do |n|
|
53
|
+
JSON.load(@redis.get "json-#{n}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# N = 10000
|
59
|
+
# user system total real
|
60
|
+
# YAML Save 1.170000 0.160000 1.330000 ( 1.444772)
|
61
|
+
# YAML Load 0.560000 0.130000 0.690000 ( 0.781064)
|
62
|
+
# Marshal Save 0.290000 0.140000 0.430000 ( 0.527284)
|
63
|
+
# Marshal Load 0.260000 0.160000 0.420000 ( 0.507964)
|
64
|
+
# JSON Save 0.670000 0.170000 0.840000 ( 0.970764)
|
65
|
+
# JSON Load 0.310000 0.190000 0.500000 ( 0.568105
|
66
|
+
#
|
67
|
+
# N = 100000
|
68
|
+
# user system total real
|
69
|
+
# YAML Save 1.170000 0.160000 1.330000 ( 1.444772)
|
70
|
+
# YAML Load 0.560000 0.130000 0.690000 ( 0.781064)
|
71
|
+
# Marshal Save 0.290000 0.140000 0.430000 ( 0.527284)
|
72
|
+
# Marshal Load 0.260000 0.160000 0.420000 ( 0.507964)
|
73
|
+
# JSON Save 0.670000 0.170000 0.840000 ( 0.970764)
|
74
|
+
# JSON Load 0.310000 0.190000 0.500000 ( 0.568105
|
75
|
+
|
data/lib/cachedis.rb
CHANGED
@@ -1,43 +1,45 @@
|
|
1
1
|
require 'redis'
|
2
|
-
require 'yaml'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(options = {})
|
8
|
-
redis(options)
|
3
|
+
module Cachedis
|
4
|
+
def self.serializer
|
5
|
+
"Marshal"
|
9
6
|
end
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
class Cacher
|
9
|
+
def initialize(options = {})
|
10
|
+
redis(options)
|
11
|
+
end
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
def cachedis(key, options = {}, &block)
|
14
|
+
result = yield
|
15
|
+
|
16
|
+
serializer = Kernel.const_get(Cachedis.serializer)
|
17
|
+
return serializer.load(redis.get(key)) if redis.exists key
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
result = serializer.dump(result)
|
20
|
+
redis.set key, result
|
21
|
+
pass_options_to_redis(options)
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
23
|
+
result
|
24
|
+
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
def redis(options = {})
|
27
|
+
@redis_instance ||= Redis.new(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def pass_options_to_redis(options)
|
32
|
+
options.each do |option, argument|
|
33
|
+
arguments = *[argument] if argument.is_a?(Array)
|
34
|
+
redis.send(option, arguments || argument)
|
35
|
+
end
|
32
36
|
end
|
33
37
|
end
|
34
|
-
end
|
35
38
|
|
36
|
-
module
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
cachedis.cachedis(name, query_options, &block)
|
39
|
+
module Interface
|
40
|
+
def self.cachedis(name, options = {}, &block)
|
41
|
+
cachedis = Cacher.new
|
42
|
+
cachedis.cachedis(name, options, &block)
|
43
|
+
end
|
42
44
|
end
|
43
45
|
end
|
data/lib/cachedis/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0.
|
1
|
+
module Cachedis
|
2
|
+
VERSION = "0.0.3"
|
3
3
|
end
|
data/spec/base_spec.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Cachedis do
|
3
|
+
describe Cachedis::Cacher do
|
4
4
|
include HelperMethods
|
5
5
|
|
6
6
|
before do
|
7
|
-
@cachedis = Cachedis.new
|
7
|
+
@cachedis = Cachedis::Cacher.new
|
8
8
|
end
|
9
9
|
|
10
10
|
describe 'when setting something' do
|
@@ -20,14 +20,12 @@ describe Cachedis do
|
|
20
20
|
|
21
21
|
describe 'when setting and later retrieving something' do
|
22
22
|
it 'retrieves from redis cache' do
|
23
|
-
with_cache('query')
|
24
|
-
@cachedis.
|
23
|
+
with_cache(Marshal.dump('query'))
|
24
|
+
@cachedis.redis.should_not_receive(:set)
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
result.should == "query".to_yaml
|
26
|
+
@cachedis.cachedis 'expensive-query' do
|
27
|
+
"query"
|
28
|
+
end
|
31
29
|
end
|
32
30
|
end
|
33
31
|
|
@@ -36,7 +34,7 @@ describe Cachedis do
|
|
36
34
|
it 'sets them in redis' do
|
37
35
|
with_no_cache
|
38
36
|
|
39
|
-
@cachedis.
|
37
|
+
@cachedis.redis.should_receive(:expire).exactly(1).times
|
40
38
|
|
41
39
|
@cachedis.cachedis 'name', :expire => 60 * 60 do
|
42
40
|
end
|
@@ -46,7 +44,7 @@ describe Cachedis do
|
|
46
44
|
context 'with an array of arguments' do
|
47
45
|
it 'sets them in redis' do
|
48
46
|
with_no_cache
|
49
|
-
@cachedis.
|
47
|
+
@cachedis.redis.should_receive(:rename).exactly(1).times
|
50
48
|
|
51
49
|
@cachedis.cachedis 'name', :rename => ['key', 'otherkey'] do
|
52
50
|
end
|
data/spec/interface_spec.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Cachedis::Interface do
|
4
4
|
include HelperMethods
|
5
5
|
|
6
6
|
describe 'when setting something' do
|
7
7
|
it 'sets without errors' do
|
8
|
-
@mock = mock(Cachedis)
|
9
|
-
Cachedis.should_receive(:new).exactly(1).times.and_return(@mock)
|
8
|
+
@mock = mock(Cachedis::Cacher)
|
9
|
+
Cachedis::Cacher.should_receive(:new).exactly(1).times.and_return(@mock)
|
10
10
|
@mock.stub!(:cachedis).and_return(['element', 'element 2'])
|
11
11
|
|
12
|
-
|
12
|
+
Cachedis::Interface.cachedis 'expensive-query' do
|
13
13
|
['element', 'element 2']
|
14
14
|
end
|
15
15
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -11,6 +11,6 @@ module HelperMethods
|
|
11
11
|
|
12
12
|
def with_cache(cache)
|
13
13
|
@cachedis.redis.should_receive(:exists).exactly(1).times.and_return(true)
|
14
|
-
@cachedis.redis.should_receive(:get).exactly(1).times.and_return(cache
|
14
|
+
@cachedis.redis.should_receive(:get).exactly(1).times.and_return(cache)
|
15
15
|
end
|
16
16
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- "Simon H\xC3\xB8rup Eskildsen"
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- Gemfile.lock
|
73
73
|
- README.md
|
74
74
|
- Rakefile
|
75
|
+
- benchmarks/serialization.rb
|
75
76
|
- cachedis.gemspec
|
76
77
|
- lib/cachedis.rb
|
77
78
|
- lib/cachedis/version.rb
|