preheatable_cache 0.1.0
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/Gemfile +7 -0
- data/Gemfile.lock +21 -0
- data/Rakefile +19 -0
- data/Readme.md +27 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/preheatable_cache.rb +73 -0
- data/preheatable_cache.gemspec +44 -0
- data/spec/preheatable_cache_spec.rb +57 -0
- metadata +70 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: http://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
actionpack (2.3.8)
|
|
5
|
+
activesupport (= 2.3.8)
|
|
6
|
+
rack (~> 1.1.0)
|
|
7
|
+
activesupport (2.3.8)
|
|
8
|
+
memcache-client (1.8.5)
|
|
9
|
+
rack (1.1.0)
|
|
10
|
+
rake (0.8.7)
|
|
11
|
+
rspec (1.3.0)
|
|
12
|
+
|
|
13
|
+
PLATFORMS
|
|
14
|
+
ruby
|
|
15
|
+
|
|
16
|
+
DEPENDENCIES
|
|
17
|
+
actionpack (= 2.3.8)
|
|
18
|
+
activesupport (= 2.3.8)
|
|
19
|
+
memcache-client
|
|
20
|
+
rake
|
|
21
|
+
rspec
|
data/Rakefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
task :default => :spec
|
|
2
|
+
require 'spec/rake/spectask'
|
|
3
|
+
Spec::Rake::SpecTask.new {|t| t.spec_opts = ['--color --backtrace']}
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require 'jeweler'
|
|
7
|
+
project_name = 'preheatable_cache'
|
|
8
|
+
Jeweler::Tasks.new do |gem|
|
|
9
|
+
gem.name = project_name
|
|
10
|
+
gem.summary = "Reduce cache requests by preheating via multi_get"
|
|
11
|
+
gem.email = "grosser.michael@gmail.com"
|
|
12
|
+
gem.homepage = "http://github.com/grosser/#{project_name}"
|
|
13
|
+
gem.authors = ["Michael Grosser"]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
Jeweler::GemcutterTasks.new
|
|
17
|
+
rescue LoadError
|
|
18
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
|
19
|
+
end
|
data/Readme.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Reduce cache requests by preheating via multi_get.
|
|
2
|
+
|
|
3
|
+
Makes Rails MemCacheStore preheatable via read_multi, for keys that will later be used.
|
|
4
|
+
Clears the preheated cache after each request.
|
|
5
|
+
|
|
6
|
+
- not threadsave
|
|
7
|
+
- not altered when writing/incrementing/... underlying cache store
|
|
8
|
+
|
|
9
|
+
# Install
|
|
10
|
+
script/plugin install http://github.com/grosser/preheatable_cache
|
|
11
|
+
|
|
12
|
+
# Usage
|
|
13
|
+
|
|
14
|
+
# controller - multi_get to fetch all keys at once
|
|
15
|
+
Rails.cache.preheat @products.map{|p| "views/product_#{p.id}" }
|
|
16
|
+
|
|
17
|
+
# view - no requests to the cache server
|
|
18
|
+
<% cache "product_#{product.id}" do %>
|
|
19
|
+
...
|
|
20
|
+
<% end %>
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
Author
|
|
24
|
+
======
|
|
25
|
+
[Michael Grosser](http://pragmatig.wordpress.com)
|
|
26
|
+
grosser.michael@gmail.com
|
|
27
|
+
Hereby placed under public domain, do what you want, just do not hold me accountable...
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.0
|
data/init.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'preheatable_cache'
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module PreheatableCache
|
|
2
|
+
VERSION = File.read( File.join(File.dirname(__FILE__),'..','VERSION') ).strip
|
|
3
|
+
|
|
4
|
+
NULL = 'preheatable_cache:null'
|
|
5
|
+
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.class_eval do
|
|
8
|
+
def read_with_preheatable_cache(key, options=nil)
|
|
9
|
+
if not @preheatable_cache
|
|
10
|
+
return read_without_preheatable_cache(key, options)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
locally_cached = @preheatable_cache[key]
|
|
14
|
+
if locally_cached == NULL
|
|
15
|
+
nil
|
|
16
|
+
elsif locally_cached.nil?
|
|
17
|
+
read_without_preheatable_cache(key, options)
|
|
18
|
+
else
|
|
19
|
+
# keep preheatable cached immutable
|
|
20
|
+
locally_cached.duplicable? ? locally_cached.dup : locally_cached
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
alias_method_chain :read, :preheatable_cache
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def preheat(keys)
|
|
29
|
+
@preheatable_cache ||= {}
|
|
30
|
+
|
|
31
|
+
data = fetch_via_read_multi(keys)
|
|
32
|
+
store_into_preheatable_cache data
|
|
33
|
+
add_cache_clearing_callback
|
|
34
|
+
|
|
35
|
+
data
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def clear_preheatable_cache
|
|
39
|
+
@preheatable_cache = nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def add_cache_clearing_callback
|
|
45
|
+
return if @clear_callback_added
|
|
46
|
+
@clear_callback_added = true
|
|
47
|
+
ActionDispatch::Callbacks.before proc{ clear_preheatable_cache }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def fetch_via_read_multi(keys)
|
|
51
|
+
if respond_to?(:read_multi)
|
|
52
|
+
hash = read_multi(keys)
|
|
53
|
+
# add keys for unfound values
|
|
54
|
+
keys.each{|k| hash[k] = nil if hash[k].nil? }
|
|
55
|
+
hash
|
|
56
|
+
else
|
|
57
|
+
keys.map{|key| read_without_preheatable_cache(key) }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def store_into_preheatable_cache(data)
|
|
62
|
+
data.each do |key, value|
|
|
63
|
+
@preheatable_cache[key] = if value.nil?
|
|
64
|
+
NULL
|
|
65
|
+
else
|
|
66
|
+
value
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# must be included in lowest classes, to overwrite reads
|
|
73
|
+
ActiveSupport::Cache::MemCacheStore.send(:include, PreheatableCache)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = %q{preheatable_cache}
|
|
8
|
+
s.version = "0.1.0"
|
|
9
|
+
|
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
+
s.authors = ["Michael Grosser"]
|
|
12
|
+
s.date = %q{2010-08-14}
|
|
13
|
+
s.email = %q{grosser.michael@gmail.com}
|
|
14
|
+
s.files = [
|
|
15
|
+
"Gemfile",
|
|
16
|
+
"Gemfile.lock",
|
|
17
|
+
"Rakefile",
|
|
18
|
+
"Readme.md",
|
|
19
|
+
"VERSION",
|
|
20
|
+
"init.rb",
|
|
21
|
+
"lib/preheatable_cache.rb",
|
|
22
|
+
"preheatable_cache.gemspec",
|
|
23
|
+
"spec/preheatable_cache_spec.rb"
|
|
24
|
+
]
|
|
25
|
+
s.homepage = %q{http://github.com/grosser/preheatable_cache}
|
|
26
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
27
|
+
s.require_paths = ["lib"]
|
|
28
|
+
s.rubygems_version = %q{1.3.6}
|
|
29
|
+
s.summary = %q{Reduce cache requests by preheating via multi_get}
|
|
30
|
+
s.test_files = [
|
|
31
|
+
"spec/preheatable_cache_spec.rb"
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
if s.respond_to? :specification_version then
|
|
35
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
36
|
+
s.specification_version = 3
|
|
37
|
+
|
|
38
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
39
|
+
else
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH << 'lib'
|
|
4
|
+
require 'active_support/all' # very messy to get working with 2.3 otherwise
|
|
5
|
+
require 'action_controller'
|
|
6
|
+
require 'preheatable_cache'
|
|
7
|
+
|
|
8
|
+
describe PreheatableCache do
|
|
9
|
+
let(:cache){ ActiveSupport::Cache::MemCacheStore.new }
|
|
10
|
+
let(:store){ cache.instance_variable_get '@data' }
|
|
11
|
+
|
|
12
|
+
describe :read do
|
|
13
|
+
before do
|
|
14
|
+
store.set('xxx', nil)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "reads nil as usual" do
|
|
18
|
+
cache.read('xxx').should == nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "reads as usual" do
|
|
22
|
+
store.set('xxx', 1)
|
|
23
|
+
cache.read('xxx').should == 1
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "uses get when reading" do
|
|
27
|
+
cache.write('xxx', 1)
|
|
28
|
+
store.should_receive(:get).and_return 2
|
|
29
|
+
cache.read('xxx').should == 2
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "does not use get when it is preheated" do
|
|
33
|
+
cache.write('xxx', 1)
|
|
34
|
+
cache.preheat ['xxx']
|
|
35
|
+
store.should_not_receive(:get)
|
|
36
|
+
cache.read('xxx')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "does not use get when it is preheated with nil" do
|
|
40
|
+
cache.preheat ['xxx']
|
|
41
|
+
store.should_not_receive(:get)
|
|
42
|
+
cache.read('xxx').should == nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "uses get when preheated cache was cleared" do
|
|
46
|
+
cache.write('xxx', 1)
|
|
47
|
+
cache.preheat ['xxx']
|
|
48
|
+
cache.clear_preheatable_cache
|
|
49
|
+
store.should_receive(:get).and_return 2
|
|
50
|
+
cache.read('xxx').should == 2
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "has a VERSION" do
|
|
55
|
+
PreheatableCache::VERSION.should =~ /^\d+\.\d+\.\d+$/
|
|
56
|
+
end
|
|
57
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: preheatable_cache
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease: false
|
|
5
|
+
segments:
|
|
6
|
+
- 0
|
|
7
|
+
- 1
|
|
8
|
+
- 0
|
|
9
|
+
version: 0.1.0
|
|
10
|
+
platform: ruby
|
|
11
|
+
authors:
|
|
12
|
+
- Michael Grosser
|
|
13
|
+
autorequire:
|
|
14
|
+
bindir: bin
|
|
15
|
+
cert_chain: []
|
|
16
|
+
|
|
17
|
+
date: 2010-08-14 00:00:00 +02:00
|
|
18
|
+
default_executable:
|
|
19
|
+
dependencies: []
|
|
20
|
+
|
|
21
|
+
description:
|
|
22
|
+
email: grosser.michael@gmail.com
|
|
23
|
+
executables: []
|
|
24
|
+
|
|
25
|
+
extensions: []
|
|
26
|
+
|
|
27
|
+
extra_rdoc_files: []
|
|
28
|
+
|
|
29
|
+
files:
|
|
30
|
+
- Gemfile
|
|
31
|
+
- Gemfile.lock
|
|
32
|
+
- Rakefile
|
|
33
|
+
- Readme.md
|
|
34
|
+
- VERSION
|
|
35
|
+
- init.rb
|
|
36
|
+
- lib/preheatable_cache.rb
|
|
37
|
+
- preheatable_cache.gemspec
|
|
38
|
+
- spec/preheatable_cache_spec.rb
|
|
39
|
+
has_rdoc: true
|
|
40
|
+
homepage: http://github.com/grosser/preheatable_cache
|
|
41
|
+
licenses: []
|
|
42
|
+
|
|
43
|
+
post_install_message:
|
|
44
|
+
rdoc_options:
|
|
45
|
+
- --charset=UTF-8
|
|
46
|
+
require_paths:
|
|
47
|
+
- lib
|
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
segments:
|
|
53
|
+
- 0
|
|
54
|
+
version: "0"
|
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
segments:
|
|
60
|
+
- 0
|
|
61
|
+
version: "0"
|
|
62
|
+
requirements: []
|
|
63
|
+
|
|
64
|
+
rubyforge_project:
|
|
65
|
+
rubygems_version: 1.3.6
|
|
66
|
+
signing_key:
|
|
67
|
+
specification_version: 3
|
|
68
|
+
summary: Reduce cache requests by preheating via multi_get
|
|
69
|
+
test_files:
|
|
70
|
+
- spec/preheatable_cache_spec.rb
|