aub-cache_advance 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +0 -47
- data/TODO.textile +0 -6
- data/cache_advance.gemspec +3 -3
- data/lib/cache_advance/active_record_sweeper.rb +1 -1
- data/lib/cache_advance/cache_set.rb +13 -17
- data/lib/cache_advance/named_cache.rb +58 -83
- data/lib/cache_advance/rails_cache.rb +15 -0
- data/lib/cache_advance.rb +3 -13
- data/rails/init.rb +14 -36
- data/test/cache_set_test.rb +3 -3
- data/test/named_cache_test.rb +2 -121
- data/test/rails_cache_test.rb +7 -0
- data/test/test_helper.rb +0 -1
- metadata +8 -14
- data/lib/cache_advance/cached_key_list.rb +0 -46
- data/lib/cache_advance/lock.rb +0 -40
- data/lib/cache_advance/named_cache_configuration.rb +0 -7
- data/test/cache_mock.rb +0 -15
- data/test/spec/db/schema.rb +0 -18
- data/test/spec/mapper_spec.rb +0 -16
- data/test/spec/mocks/memcache.rb +0 -41
- data/test/spec/spec_helper.rb +0 -30
data/README.textile
CHANGED
@@ -1,47 +0,0 @@
|
|
1
|
-
h1. cache advance
|
2
|
-
|
3
|
-
CacheAdvance is a wrapper around the Rails caching system that provides a simple, centralized
|
4
|
-
configuration file for defining caches and an even simpler way to apply them.
|
5
|
-
|
6
|
-
Written by "Aubrey Holland":mailto:aubreyholland@gmail.com.
|
7
|
-
|
8
|
-
h3. download
|
9
|
-
|
10
|
-
Github: "Page":http://github.com/aub/cache_advance/tree/master
|
11
|
-
|
12
|
-
Gem: <pre>gem install aub-cache_advance --source http://gems.github.com</pre>
|
13
|
-
|
14
|
-
Note: if you install using the gem from Github, you'll need this
|
15
|
-
in your environment.rb if you want to use Rails 2.1's dependency manager:
|
16
|
-
|
17
|
-
<pre><code>
|
18
|
-
config.gem 'aub-cache_advance', :lib => 'cache_advance', :source => 'http://gems.github.com'
|
19
|
-
</code></pre>
|
20
|
-
|
21
|
-
h3. cache definition
|
22
|
-
|
23
|
-
Caches are defined in the file config/caches.rb, which will be loaded automatically by the gem.
|
24
|
-
This file is similar in format to the rails routes config file, allowing you to specify named
|
25
|
-
caches and configure their keys and how they will be expired.
|
26
|
-
|
27
|
-
<pre><code>
|
28
|
-
CacheAdvance::Caches.define_caches do |config|
|
29
|
-
|
30
|
-
config.qualifier(:params) do |request|
|
31
|
-
request.params
|
32
|
-
end
|
33
|
-
|
34
|
-
config.plugin :template_handler_observer_cache_plugin
|
35
|
-
|
36
|
-
config.content_block :expiration_time => 10.minutes, :qualifiers => [ :subdomain, :params ]
|
37
|
-
|
38
|
-
config.change_towns_all :expiration_types => [ :publication ]
|
39
|
-
config.change_towns_limited :expiration_types => [ :publication ]
|
40
|
-
|
41
|
-
config.publication_twitter_update :expiration_time => 10.minutes, :qualifiers => [ :subdomain ]
|
42
|
-
|
43
|
-
config.weather_widget :expiration_time => 10.minutes, :qualifiers => [ :subdomain ]
|
44
|
-
end
|
45
|
-
</code></pre>
|
46
|
-
|
47
|
-
..............More later.
|
data/TODO.textile
CHANGED
@@ -1,6 +0,0 @@
|
|
1
|
-
- Fix to allow keys of > 256 characters with memcache
|
2
|
-
- Make test coverage not pitiful
|
3
|
-
- Add ability for cache to expire when a specific object changes
|
4
|
-
- Apply plugins only to specific caches
|
5
|
-
- Test with caching strategies other than memcache
|
6
|
-
- Improve documentation
|
data/cache_advance.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
|
-
s.version = '0.
|
2
|
+
s.version = '1.0.0'
|
3
3
|
s.date = %q{2009-01-08}
|
4
4
|
|
5
5
|
s.name = %q{cache_advance}
|
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.authors = ['Aubrey Holland']
|
8
8
|
s.description = %q{A system for spiffy declarative caching}
|
9
9
|
s.email = %q{aubrey@patch.com}
|
10
|
-
s.files = %w(
|
10
|
+
s.files = %w(cache_advance.gemspec lib/cache_advance/active_record_sweeper.rb lib/cache_advance/cache_set.rb lib/cache_advance/mapper.rb lib/cache_advance/named_cache.rb lib/cache_advance/rails_cache.rb lib/cache_advance.rb rails/init.rb Rakefile README.textile test/active_record_sweeper_test.rb test/cache_set_test.rb test/mapper_test.rb test/named_cache_test.rb test/rails_cache_test.rb test/test_helper.rb TODO.textile)
|
11
11
|
s.homepage = %q{http://github.com/aub/cache_advance}
|
12
12
|
s.require_paths = ['lib']
|
13
13
|
s.rubygems_version = %q{1.2.0}
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.has_rdoc = true
|
16
16
|
s.extra_rdoc_files = ['README.textile']
|
17
17
|
s.rdoc_options = ['--line-numbers', '--inline-source', '--main', 'README.textile']
|
18
|
-
s.test_files = %w(test/active_record_sweeper_test.rb test/cache_set_test.rb test/mapper_test.rb test/named_cache_test.rb)
|
18
|
+
s.test_files = %w(test/active_record_sweeper_test.rb test/cache_set_test.rb test/mapper_test.rb test/named_cache_test.rb test/rails_cache_test.rb)
|
19
19
|
|
20
20
|
if s.respond_to? :specification_version then
|
21
21
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
@@ -3,19 +3,19 @@ module CacheAdvance
|
|
3
3
|
attr_reader :named_caches
|
4
4
|
attr_reader :qualifiers
|
5
5
|
attr_reader :plugins
|
6
|
+
attr_accessor :observer_type
|
7
|
+
attr_accessor :cache
|
6
8
|
|
7
|
-
def initialize
|
8
|
-
@
|
9
|
-
|
10
|
-
|
11
|
-
def setup_complete
|
12
|
-
|
9
|
+
def initialize
|
10
|
+
@named_caches = {}
|
11
|
+
@qualifiers = {}
|
12
|
+
@plugins = []
|
13
13
|
end
|
14
14
|
|
15
15
|
def apply(cache_name, request, options, &block)
|
16
|
-
|
17
|
-
raise UnknownNamedCacheException if
|
18
|
-
|
16
|
+
cache = @named_caches[cache_name]
|
17
|
+
raise UnknownNamedCacheException if cache.nil?
|
18
|
+
cache.value_for(request, options, &block)
|
19
19
|
end
|
20
20
|
|
21
21
|
def add_qualifier(name, proc)
|
@@ -27,7 +27,7 @@ module CacheAdvance
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def add_named_cache(name, options)
|
30
|
-
@named_caches[name] = NamedCache.new(name, options, self,
|
30
|
+
@named_caches[name] = NamedCache.new(name, options, self, cache)
|
31
31
|
end
|
32
32
|
|
33
33
|
def define_caches
|
@@ -35,17 +35,13 @@ module CacheAdvance
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def create_sweepers
|
38
|
-
|
38
|
+
observer_type.initialize_observed(@named_caches.values.map { |c| c.expiration_types }.flatten.compact.uniq)
|
39
39
|
end
|
40
40
|
|
41
41
|
def expire_for_class(class_name)
|
42
|
-
@named_caches.values.each do |
|
43
|
-
|
42
|
+
@named_caches.values.each do |cache|
|
43
|
+
cache.expire_for(class_name)
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
47
|
-
def sweeper_type=(type)
|
48
|
-
@sweeper_type = type
|
49
|
-
end
|
50
46
|
end
|
51
47
|
end
|
@@ -1,37 +1,51 @@
|
|
1
|
-
module CacheAdvance
|
1
|
+
module CacheAdvance
|
2
2
|
class NamedCache
|
3
|
-
|
4
|
-
ENABLED_CHECK_INTERVAL = 60
|
3
|
+
STORED_KEY = 'STORED_CACHES'
|
5
4
|
|
6
|
-
def initialize(name, params,
|
5
|
+
def initialize(name, params, configuration, cache)
|
7
6
|
@name = name.to_s
|
8
7
|
@params = params
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@cached_key_list = CachedKeyList.new(@store, "#{@name}/STORED_CACHES", expiration_time)
|
12
|
-
@enabled_check_time = Time.now + ENABLED_CHECK_INTERVAL
|
13
|
-
@enabled = nil
|
8
|
+
@configuration = configuration
|
9
|
+
@cache = cache
|
14
10
|
end
|
15
|
-
|
11
|
+
|
12
|
+
def key_for(request, suffix='')
|
13
|
+
key = @name.dup
|
14
|
+
key << suffix.to_s
|
15
|
+
|
16
|
+
qualifiers.each do |q|
|
17
|
+
if (qualifier = @configuration.qualifiers[q])
|
18
|
+
this_one = qualifier.call(request)
|
19
|
+
key << this_one.to_s unless this_one.nil?
|
20
|
+
end
|
21
|
+
end if qualifiers
|
22
|
+
key
|
23
|
+
end
|
24
|
+
|
16
25
|
def value_for(request, options, &block)
|
17
|
-
return block.call unless enabled?
|
18
|
-
|
19
26
|
key = key_for(request, options[:key])
|
20
|
-
|
21
|
-
if (
|
22
|
-
|
23
|
-
return
|
27
|
+
|
28
|
+
if (cache = @cache.read(key))
|
29
|
+
call_plugins('after_read', key, request)
|
30
|
+
return cache
|
24
31
|
end
|
25
32
|
|
26
|
-
|
33
|
+
call_plugins('before_write', key, request)
|
27
34
|
result = block.call
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
35
|
+
@cache.write(key, result, rails_options)
|
36
|
+
call_plugins('after_write', key, request)
|
37
|
+
|
38
|
+
add_to_cached_keys_list(key)
|
39
|
+
|
32
40
|
result
|
33
41
|
end
|
34
|
-
|
42
|
+
|
43
|
+
def rails_options
|
44
|
+
options = {}
|
45
|
+
options[:expires_in] = expiration_time if expiration_time
|
46
|
+
options
|
47
|
+
end
|
48
|
+
|
35
49
|
def expire_for(type)
|
36
50
|
if expiration_types.include?(type)
|
37
51
|
expire_all
|
@@ -39,82 +53,43 @@ module CacheAdvance
|
|
39
53
|
end
|
40
54
|
|
41
55
|
def expire_all
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
56
|
+
if (data = @cache.read(@name + STORED_KEY))
|
57
|
+
data = Array(Marshal.load(data))
|
58
|
+
data.each { |key| @cache.delete(key) }
|
59
|
+
else
|
60
|
+
@cache.delete(@name)
|
61
|
+
end
|
47
62
|
end
|
48
63
|
|
49
64
|
def expiration_types
|
50
65
|
Array(@params[:expiration_types])
|
51
66
|
end
|
52
67
|
|
53
|
-
def
|
54
|
-
@params[:
|
55
|
-
end
|
56
|
-
|
57
|
-
def enabled=(state)
|
58
|
-
@enabled = !!state
|
59
|
-
write_to_store(enabled_key, @enabled, false)
|
68
|
+
def expiration_time
|
69
|
+
@params[:expiration_time]
|
60
70
|
end
|
61
71
|
|
62
|
-
def
|
63
|
-
|
64
|
-
@enabled = [nil, true].include?(read_from_store(enabled_key))
|
65
|
-
@enabled_check_time = Time.now + ENABLED_CHECK_INTERVAL
|
66
|
-
end
|
67
|
-
@enabled
|
72
|
+
def qualifiers
|
73
|
+
Array(@params[:qualifiers])
|
68
74
|
end
|
69
75
|
|
70
76
|
protected
|
71
77
|
|
72
|
-
def
|
73
|
-
@
|
74
|
-
end
|
75
|
-
|
76
|
-
def write_to_store(key, value, add_to_key_list=true)
|
77
|
-
expiration_time ? @store.set(key, value, expiration_time) : @store.set(key, value)
|
78
|
-
if add_to_key_list
|
79
|
-
@cached_key_list.add_key(key)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def delete_from_store(key)
|
84
|
-
@store.delete(key)
|
85
|
-
@cached_key_list.delete_key(key)
|
86
|
-
end
|
87
|
-
|
88
|
-
def delete_all_from_store
|
89
|
-
@cached_key_list.all_keys.each { |key| delete_from_store(key) }
|
90
|
-
@cached_key_list.clear
|
91
|
-
end
|
92
|
-
|
93
|
-
def each_plugin
|
94
|
-
@cache_set.plugins.each do |p|
|
95
|
-
yield p
|
96
|
-
end
|
78
|
+
def call_plugins(method, key, request)
|
79
|
+
@configuration.plugins.each { |p| p.send(method, @name, key, request) if p.respond_to?(method) }
|
97
80
|
end
|
98
81
|
|
99
|
-
def
|
100
|
-
|
101
|
-
if (
|
102
|
-
(
|
82
|
+
def add_to_cached_keys_list(key)
|
83
|
+
unless expiration_types.blank? || key == @name
|
84
|
+
if (data = @cache.read(@name + STORED_KEY))
|
85
|
+
data = Array(Marshal.load(data))
|
86
|
+
else
|
87
|
+
data = []
|
103
88
|
end
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
def enabled_key
|
109
|
-
"#{@name}/ENABLED_STATUS"
|
110
|
-
end
|
111
|
-
|
112
|
-
def expiration_time
|
113
|
-
@params[:expiration_time]
|
114
|
-
end
|
115
|
-
|
116
|
-
def qualifiers
|
117
|
-
Array(@params[:qualifiers])
|
89
|
+
unless data.include?(key)
|
90
|
+
@cache.write(@name + STORED_KEY, Marshal.dump(data << key))
|
91
|
+
end
|
92
|
+
end
|
118
93
|
end
|
119
94
|
end
|
120
95
|
end
|
data/lib/cache_advance.rb
CHANGED
@@ -1,19 +1,9 @@
|
|
1
|
+
require 'cache_advance/named_cache'
|
1
2
|
require 'cache_advance/cache_set'
|
2
|
-
require 'cache_advance/cached_key_list'
|
3
3
|
require 'cache_advance/mapper'
|
4
|
-
require 'cache_advance/named_cache'
|
5
|
-
require 'cache_advance/named_cache_configuration'
|
6
4
|
|
7
5
|
module CacheAdvance
|
8
6
|
class UnknownNamedCacheException < Exception; end
|
9
|
-
|
10
|
-
|
11
|
-
attr_reader :cache_set
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.define_caches(store)
|
15
|
-
@cache_set = CacheSet.new(store)
|
16
|
-
yield Mapper.new(@cache_set)
|
17
|
-
@cache_set.setup_complete # This allows the cache set to finalize some of its configuration
|
18
|
-
end
|
7
|
+
|
8
|
+
Caches = CacheSet.new
|
19
9
|
end
|
data/rails/init.rb
CHANGED
@@ -1,47 +1,25 @@
|
|
1
1
|
require 'cache_advance'
|
2
|
-
require 'cache_advance/
|
3
|
-
|
4
|
-
require
|
2
|
+
require 'cache_advance/active_record_observer'
|
3
|
+
require 'cache_advance/rails_cache'
|
4
|
+
require 'config/caches'
|
5
5
|
require 'dispatcher'
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# This is the helper method that can be used in rails views/controllers/helpers.
|
11
|
-
# If caching is disabled, just make it yield the results of the block.
|
12
|
-
if config.action_controller.perform_caching
|
13
|
-
ActionController::Base.helper do
|
14
|
-
def cache_it(cache, options={}, &block)
|
15
|
-
CacheAdvance.cache_set.apply(cache, request, options) do
|
16
|
-
capture(&block)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
else
|
21
|
-
ActionController::Base.helper do
|
22
|
-
def cache_it(cache, options={}, &block)
|
7
|
+
ActionController::Base.helper do
|
8
|
+
def cache_it(cache, options={}, &block)
|
9
|
+
CacheAdvance::Caches.apply(cache, request, options) do
|
23
10
|
capture(&block)
|
24
11
|
end
|
25
12
|
end
|
26
13
|
end
|
27
14
|
|
28
|
-
ActionMailer::Base.helper do
|
29
|
-
def cache_it(cache, options={}, &block)
|
30
|
-
capture(&block)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# This will get called after the standard rails environment is initialized.
|
35
15
|
config.after_initialize do
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
CacheAdvance::ActiveRecordSweeper.instance.reload_sweeper
|
45
|
-
end
|
16
|
+
CacheAdvance::Caches.observer_type = CacheAdvance::ActiveRecordObserver
|
17
|
+
CacheAdvance::Caches.cache = CacheAdvance::RailsCache.new
|
18
|
+
|
19
|
+
CacheAdvance::Caches.create_sweepers
|
20
|
+
ActiveRecord::Base.observers << CacheAdvance::ActiveRecordObserver
|
21
|
+
|
22
|
+
ActionController::Dispatcher.to_prepare(:cache_advance_reload) do
|
23
|
+
CacheAdvance::ActiveRecordSweeper.instance.reload_sweeper
|
46
24
|
end
|
47
25
|
end
|
data/test/cache_set_test.rb
CHANGED
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/test_helper.rb'
|
|
2
2
|
|
3
3
|
class Plugin; end
|
4
4
|
|
5
|
-
require 'cache_advance/
|
5
|
+
require 'cache_advance/active_record_observer'
|
6
6
|
|
7
7
|
class CacheSetTest < Test::Unit::TestCase
|
8
8
|
def setup
|
@@ -30,10 +30,10 @@ class CacheSetTest < Test::Unit::TestCase
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_should_pass_expiration_types_to_the_sweeper
|
33
|
-
@cache_set.
|
33
|
+
@cache_set.observer_type = CacheAdvance::ActiveRecordObserver
|
34
34
|
@cache_set.add_named_cache(:kewl, { :expiration_types => [:publication, :article] })
|
35
35
|
@cache_set.add_named_cache(:howza, { :expiration_types => [:publication] })
|
36
|
-
CacheAdvance::
|
36
|
+
CacheAdvance::ActiveRecordObserver.expects(:initialize_observed).with([:publication, :article])
|
37
37
|
@cache_set.create_sweepers
|
38
38
|
end
|
39
39
|
end
|
data/test/named_cache_test.rb
CHANGED
@@ -1,126 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
2
|
|
3
3
|
class NamedCacheTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
6
|
-
@request = mock
|
7
|
-
end
|
8
|
-
|
9
|
-
def test_key_for_in_basic_case
|
10
|
-
create_named_cache
|
11
|
-
assert_equal 'test_cache', @named_cache.key_for(@request)
|
12
|
-
assert_equal 'test_cachesuf', @named_cache.key_for(@request, 'suf')
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_key_with_qualifiers
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
protected
|
20
|
-
|
21
|
-
def create_named_cache(options={})
|
22
|
-
@name = options[:name] || 'test_cache'
|
23
|
-
@params = {}
|
24
|
-
@cache_set = CacheAdvance::CacheSet.new
|
25
|
-
@cache = CacheAdvance::CacheMock.new
|
26
|
-
@named_cache = CacheAdvance::NamedCache.new(@name, @params, @cache_set, @cache)
|
4
|
+
def test_fake
|
5
|
+
assert true
|
27
6
|
end
|
28
7
|
end
|
29
|
-
|
30
|
-
|
31
|
-
# module CacheAdvance
|
32
|
-
# class NamedCache
|
33
|
-
# STORED_KEY = 'STORED_CACHES'
|
34
|
-
#
|
35
|
-
# def initialize(name, params, configuration, cache)
|
36
|
-
# @name = name.to_s
|
37
|
-
# @params = params
|
38
|
-
# @configuration = configuration
|
39
|
-
# @cache = cache
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# def key_for(request, suffix='')
|
43
|
-
# key = @name.dup
|
44
|
-
# key << suffix.to_s
|
45
|
-
#
|
46
|
-
# qualifiers.each do |q|
|
47
|
-
# if (qualifier = @configuration.qualifiers[q])
|
48
|
-
# this_one = qualifier.call(request)
|
49
|
-
# key << this_one.to_s unless this_one.nil?
|
50
|
-
# end
|
51
|
-
# end if qualifiers
|
52
|
-
# key
|
53
|
-
# end
|
54
|
-
#
|
55
|
-
# def value_for(request, options, &block)
|
56
|
-
# key = key_for(request, options[:key])
|
57
|
-
#
|
58
|
-
# if (cache = @cache.read(key))
|
59
|
-
# call_plugins('after_read', key, request)
|
60
|
-
# return cache
|
61
|
-
# end
|
62
|
-
#
|
63
|
-
# call_plugins('before_write', key, request)
|
64
|
-
# result = block.call
|
65
|
-
# @cache.write(key, result, rails_options)
|
66
|
-
# call_plugins('after_write', key, request)
|
67
|
-
#
|
68
|
-
# add_to_cached_keys_list(key)
|
69
|
-
#
|
70
|
-
# result
|
71
|
-
# end
|
72
|
-
#
|
73
|
-
# def rails_options
|
74
|
-
# options = {}
|
75
|
-
# options[:expires_in] = expiration_time if expiration_time
|
76
|
-
# options
|
77
|
-
# end
|
78
|
-
#
|
79
|
-
# def expire_for(type)
|
80
|
-
# if expiration_types.include?(type)
|
81
|
-
# expire_all
|
82
|
-
# end
|
83
|
-
# end
|
84
|
-
#
|
85
|
-
# def expire_all
|
86
|
-
# if (data = @cache.read(@name + STORED_KEY))
|
87
|
-
# data = Array(Marshal.load(data))
|
88
|
-
# data.each { |key| @cache.delete(key) }
|
89
|
-
# else
|
90
|
-
# @cache.delete(@name)
|
91
|
-
# end
|
92
|
-
# end
|
93
|
-
#
|
94
|
-
# def expiration_types
|
95
|
-
# Array(@params[:expiration_types])
|
96
|
-
# end
|
97
|
-
#
|
98
|
-
# def expiration_time
|
99
|
-
# @params[:expiration_time]
|
100
|
-
# end
|
101
|
-
#
|
102
|
-
# def qualifiers
|
103
|
-
# Array(@params[:qualifiers])
|
104
|
-
# end
|
105
|
-
#
|
106
|
-
# protected
|
107
|
-
#
|
108
|
-
# def call_plugins(method, key, request)
|
109
|
-
# @configuration.plugins.each { |p| p.send(method, @name, key, request) if p.respond_to?(method) }
|
110
|
-
# end
|
111
|
-
#
|
112
|
-
# def add_to_cached_keys_list(key)
|
113
|
-
# unless expiration_types.blank? || key == @name
|
114
|
-
# if (data = @cache.read(@name + STORED_KEY))
|
115
|
-
# data = Array(Marshal.load(data))
|
116
|
-
# else
|
117
|
-
# data = []
|
118
|
-
# end
|
119
|
-
# unless data.include?(key)
|
120
|
-
# @cache.write(@name + STORED_KEY, Marshal.dump(data << key))
|
121
|
-
# end
|
122
|
-
# end
|
123
|
-
# end
|
124
|
-
# end
|
125
|
-
# end
|
126
|
-
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aub-cache_advance
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aubrey Holland
|
@@ -22,30 +22,23 @@ extensions: []
|
|
22
22
|
extra_rdoc_files:
|
23
23
|
- README.textile
|
24
24
|
files:
|
25
|
-
- README.textile
|
26
|
-
- Rakefile
|
27
|
-
- TODO.textile
|
28
|
-
- cache_advance-1.0.9.gem
|
29
25
|
- cache_advance.gemspec
|
30
|
-
- lib/cache_advance.rb
|
31
26
|
- lib/cache_advance/active_record_sweeper.rb
|
32
27
|
- lib/cache_advance/cache_set.rb
|
33
|
-
- lib/cache_advance/cached_key_list.rb
|
34
|
-
- lib/cache_advance/lock.rb
|
35
28
|
- lib/cache_advance/mapper.rb
|
36
29
|
- lib/cache_advance/named_cache.rb
|
37
|
-
- lib/cache_advance/
|
30
|
+
- lib/cache_advance/rails_cache.rb
|
31
|
+
- lib/cache_advance.rb
|
38
32
|
- rails/init.rb
|
33
|
+
- Rakefile
|
34
|
+
- README.textile
|
39
35
|
- test/active_record_sweeper_test.rb
|
40
|
-
- test/cache_mock.rb
|
41
36
|
- test/cache_set_test.rb
|
42
37
|
- test/mapper_test.rb
|
43
38
|
- test/named_cache_test.rb
|
44
|
-
- test/
|
45
|
-
- test/spec/mapper_spec.rb
|
46
|
-
- test/spec/mocks/memcache.rb
|
47
|
-
- test/spec/spec_helper.rb
|
39
|
+
- test/rails_cache_test.rb
|
48
40
|
- test/test_helper.rb
|
41
|
+
- TODO.textile
|
49
42
|
has_rdoc: true
|
50
43
|
homepage: http://github.com/aub/cache_advance
|
51
44
|
post_install_message:
|
@@ -80,3 +73,4 @@ test_files:
|
|
80
73
|
- test/cache_set_test.rb
|
81
74
|
- test/mapper_test.rb
|
82
75
|
- test/named_cache_test.rb
|
76
|
+
- test/rails_cache_test.rb
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module CacheAdvance
|
2
|
-
class CachedKeyList
|
3
|
-
def initialize(store, cache_key, expiration_time=nil)
|
4
|
-
@store, @cache_key, @expiration_time = store, cache_key, expiration_time
|
5
|
-
end
|
6
|
-
|
7
|
-
def all_keys
|
8
|
-
key_list.keys
|
9
|
-
end
|
10
|
-
|
11
|
-
def add_key(key)
|
12
|
-
Lock.new(@store).execute_locked(@cache_key) do
|
13
|
-
data = key_list
|
14
|
-
unless data.has_key?(key)
|
15
|
-
data[key] = @expiration_time.nil? ? nil : Time.now + @expiration_time
|
16
|
-
@store.set(@cache_key, data)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def delete_key(key)
|
22
|
-
Lock.new(@store).execute_locked(@cache_key) do
|
23
|
-
data = key_list
|
24
|
-
if data.has_key?(key)
|
25
|
-
data.delete(key)
|
26
|
-
@store.set(@cache_key, data)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def clear
|
32
|
-
@store.set(@cache_key, {})
|
33
|
-
end
|
34
|
-
|
35
|
-
protected
|
36
|
-
|
37
|
-
def key_list
|
38
|
-
list = @store.get(@cache_key) || {}
|
39
|
-
if @expiration_time
|
40
|
-
now = Time.now
|
41
|
-
list.delete_if { |k,v| v <= now }
|
42
|
-
end
|
43
|
-
list
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
data/lib/cache_advance/lock.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
module CacheAdvance
|
2
|
-
class Lock
|
3
|
-
|
4
|
-
class LockAcquisitionFailureException < Exception; end
|
5
|
-
|
6
|
-
DEFAULT_RETRIES = 5
|
7
|
-
DEFAULT_EXPIRATION_TIME = 30
|
8
|
-
|
9
|
-
def initialize(store)
|
10
|
-
@store = store
|
11
|
-
end
|
12
|
-
|
13
|
-
def execute_locked(key, lock_expiry = DEFAULT_EXPIRATION_TIME, retries = DEFAULT_RETRIES)
|
14
|
-
begin
|
15
|
-
acquire(key, lock_expiry, retries)
|
16
|
-
yield
|
17
|
-
ensure
|
18
|
-
release_lock(key)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def acquire(key, lock_expiry = DEFAULT_EXPIRATION_TIME, retries = DEFAULT_RETRIES)
|
23
|
-
retries.times do |count|
|
24
|
-
begin
|
25
|
-
return if @store.set("lock/#{key}", Process.pid, lock_expiry) == "STORED\r\n"
|
26
|
-
end
|
27
|
-
exponential_sleep(count) unless count == retries - 1
|
28
|
-
end
|
29
|
-
raise LockAcquisitionFailureException, "Couldn't acquire memcache lock for: #{key}"
|
30
|
-
end
|
31
|
-
|
32
|
-
def release_lock(key)
|
33
|
-
@store.delete("lock/#{key}")
|
34
|
-
end
|
35
|
-
|
36
|
-
def exponential_sleep(count)
|
37
|
-
@runtime += Benchmark::measure { sleep((2**count) / 10.0) }
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
data/test/cache_mock.rb
DELETED
data/test/spec/db/schema.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
ActiveRecord::Schema.define(:version => 1) do
|
2
|
-
create_table "publications", :force => true do |t|
|
3
|
-
t.string "name", "subdomain"
|
4
|
-
end
|
5
|
-
|
6
|
-
create_table "articles", :force => true do |t|
|
7
|
-
t.references 'publication'
|
8
|
-
t.string 'title'
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class Publication < ActiveRecord::Base
|
13
|
-
has_many :articles
|
14
|
-
end
|
15
|
-
|
16
|
-
class Article < ActiveRecord::Base
|
17
|
-
belongs_to :publication
|
18
|
-
end
|
data/test/spec/mapper_spec.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
-
|
3
|
-
module CacheAdvance
|
4
|
-
before :each do
|
5
|
-
@cache_set = CacheSet.new
|
6
|
-
@mapper = Mapper.new(@cache_set)
|
7
|
-
end
|
8
|
-
|
9
|
-
describe 'Mapper' do
|
10
|
-
it 'should pass qualifiers directly to the cache set' do
|
11
|
-
proc = Proc.new { 2 }
|
12
|
-
@cache_set.should_receive(:add_qualifier).with(proc)
|
13
|
-
@mapper.qualifier(:testy, proc)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/test/spec/mocks/memcache.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
class MemCache
|
2
|
-
attr_reader :data
|
3
|
-
|
4
|
-
def initialize
|
5
|
-
@data = {}
|
6
|
-
end
|
7
|
-
|
8
|
-
def decr(key, amount = 1)
|
9
|
-
end
|
10
|
-
|
11
|
-
def get(key, raw = false)
|
12
|
-
return @data[key]
|
13
|
-
end
|
14
|
-
|
15
|
-
def get_multi(*keys)
|
16
|
-
end
|
17
|
-
|
18
|
-
def incr(key, amount = 1)
|
19
|
-
end
|
20
|
-
|
21
|
-
def set(key, value, expiry = 0, raw = false)
|
22
|
-
@data[key] = value
|
23
|
-
end
|
24
|
-
|
25
|
-
def add(key, value, expiry = 0, raw = false)
|
26
|
-
end
|
27
|
-
|
28
|
-
def delete(key, expiry = 0)
|
29
|
-
@data.delete(key)
|
30
|
-
end
|
31
|
-
|
32
|
-
def flush_all
|
33
|
-
end
|
34
|
-
|
35
|
-
def reset
|
36
|
-
@data = {}
|
37
|
-
end
|
38
|
-
|
39
|
-
def stats
|
40
|
-
end
|
41
|
-
end
|
data/test/spec/spec_helper.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
-
$: << File.join(File.dirname(__FILE__))
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'ruby-debug'
|
6
|
-
|
7
|
-
gem 'sqlite3-ruby'
|
8
|
-
require 'spec'
|
9
|
-
require 'cache_advance'
|
10
|
-
|
11
|
-
require 'activerecord'
|
12
|
-
|
13
|
-
ActiveRecord::Base.establish_connection(
|
14
|
-
:adapter => 'sqlite3',
|
15
|
-
:dbfile => ':memory:'
|
16
|
-
)
|
17
|
-
|
18
|
-
require File.join(File.dirname(__FILE__), 'db', 'schema')
|
19
|
-
require File.join(File.dirname(__FILE__), 'mocks', 'memcache')
|
20
|
-
|
21
|
-
Spec::Runner.configure do |config|
|
22
|
-
# config.mock_with :rr
|
23
|
-
config.before :each do
|
24
|
-
@memcache = MemCache.new
|
25
|
-
|
26
|
-
CacheAdvance.define_caches(@memcache) do |cache_config|
|
27
|
-
cache_config.publication
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|