cache-machine 0.1.10 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +3 -1
  2. data/.travis.yml +6 -0
  3. data/Gemfile +0 -2
  4. data/Gemfile.lock +0 -2
  5. data/README.md +258 -0
  6. data/VERSION +1 -1
  7. data/cache-machine.gemspec +7 -22
  8. data/db/.gitignore +1 -0
  9. data/lib/cache-machine.rb +6 -2
  10. data/lib/cache_machine/adapter.rb +127 -0
  11. data/lib/cache_machine/adapters/rails.rb +58 -0
  12. data/lib/cache_machine/cache.rb +34 -85
  13. data/lib/cache_machine/cache/associations.rb +29 -0
  14. data/lib/cache_machine/cache/class_timestamp.rb +31 -0
  15. data/lib/cache_machine/cache/collection.rb +131 -0
  16. data/lib/cache_machine/cache/map.rb +97 -241
  17. data/lib/cache_machine/cache/mapper.rb +135 -0
  18. data/lib/cache_machine/cache/resource.rb +108 -0
  19. data/lib/cache_machine/cache/scope.rb +24 -0
  20. data/lib/cache_machine/cache/timestamp_builder.rb +58 -0
  21. data/lib/cache_machine/helpers/cache_helper.rb +3 -3
  22. data/lib/cache_machine/logger.rb +9 -8
  23. data/lib/cache_machine/railtie.rb +11 -0
  24. data/lib/cache_machine/tasks.rb +10 -0
  25. data/spec/fixtures.rb +11 -6
  26. data/spec/lib/cache_machine/adapters/rails_spec.rb +149 -0
  27. data/spec/lib/cache_machine/cache/associations_spec.rb +32 -0
  28. data/spec/lib/cache_machine/cache/class_timestam_spec.rb +29 -0
  29. data/spec/lib/cache_machine/cache/collection_spec.rb +106 -0
  30. data/spec/lib/cache_machine/cache/map_spec.rb +34 -0
  31. data/spec/lib/cache_machine/cache/mapper_spec.rb +61 -0
  32. data/spec/lib/cache_machine/cache/resource_spec.rb +86 -0
  33. data/spec/lib/cache_machine/cache/scope_spec.rb +50 -0
  34. data/spec/lib/cache_machine/cache/timestamp_builder_spec.rb +52 -0
  35. data/spec/spec_helper.rb +9 -3
  36. metadata +35 -61
  37. data/README.rdoc +0 -186
  38. data/spec/lib/cache_machine_spec.rb +0 -161
@@ -0,0 +1,58 @@
1
+ module CacheMachine
2
+ module Adapters
3
+ require "cache_machine/adapter"
4
+
5
+ class Rails < CacheMachine::Adapter
6
+
7
+ def initialize(*options)
8
+ CacheMachine::Logger.info "CACHE_MACHINE: initialized default Rails adapter"
9
+ end
10
+
11
+ def append_id_to_map(target, association, id)
12
+ key = get_map_key(target, association)
13
+ ::Rails.cache.write(key, (::Rails.cache.read(key) || []) | [id])
14
+ end
15
+
16
+ def append_id_to_reverse_map(resource, association, target, id)
17
+ key = get_reverse_map_key(resource, association, target)
18
+ ::Rails.cache.write(key, (::Rails.cache.read(key) || []) | [id])
19
+ end
20
+
21
+ def association_ids(target, association)
22
+ ::Rails.cache.fetch(get_map_key(target, association)) do
23
+ target.association_ids(association)
24
+ end
25
+ end
26
+
27
+ def fetch(key, options = {}, &block)
28
+ ::Rails.cache.fetch(get_content_key(key), options, &block)
29
+ end
30
+
31
+ def fetch_timestamp(name, options = {}, &block)
32
+ ::Rails.cache.fetch(get_timestamp_key(name), options, &block)
33
+ end
34
+
35
+ def delete(key)
36
+ ::Rails.cache.delete(key)
37
+ end
38
+
39
+ def delete_content(key)
40
+ delete(get_content_key(key))
41
+ end
42
+
43
+ def reset_timestamp(name)
44
+ ::Rails.cache.delete(get_timestamp_key(name))
45
+ end
46
+
47
+ def reverse_association_ids(resource, association, target)
48
+ ::Rails.cache.fetch(get_reverse_map_key(resource, association, target)) do
49
+ target.cache_map_ids(resource, association)
50
+ end
51
+ end
52
+
53
+ def write_timestamp(name, &block)
54
+ ::Rails.cache.write(get_timestamp_key(name), &block)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,29 +1,19 @@
1
+ require "cache_machine/adapters/rails"
1
2
  require "cache_machine/cache/map"
2
3
 
3
4
  module CacheMachine
4
5
  module Cache
5
- extend ActiveSupport::Concern
6
6
 
7
7
  # Enable cache by default.
8
8
  @enabled = true
9
9
 
10
- # Supported by default cache formats.
11
- @formats = [nil, :ehtml, :html, :json, :xml]
12
-
13
10
  # Returns if cache is enabled.
14
11
  #
15
12
  # @return [ false, true ]
16
- def self.enabled?
13
+ def self.enabled
17
14
  @enabled
18
15
  end
19
16
 
20
- # Returns currently set formats.
21
- #
22
- # @return [Array<Symbol>]
23
- def self.formats
24
- @formats
25
- end
26
-
27
17
  # Enables/disables cache.
28
18
  #
29
19
  # @param [ false, true ] is_enabled
@@ -31,87 +21,46 @@ module CacheMachine
31
21
  @enabled = is_enabled
32
22
  end
33
23
 
34
- # Sets default formats.
35
- #
36
- # @note Empty format entry will always be present.
24
+ # Returns adapter used for storing maps of cache.
37
25
  #
38
- # @param [ Array<Symbol> ] formats
39
- def self.formats= formats
40
- @formats = [nil] | [*formats]
26
+ # @return [CacheMachine::Adapter]
27
+ def self.map_adapter
28
+ @map_adapter ||= CacheMachine::Adapters::Rails.new
41
29
  end
42
30
 
43
- included do
44
- after_save { self.class.reset_timestamps }
45
- after_destroy { self.class.reset_timestamps }
31
+ # Sets adapter used for storing maps of cache.
32
+ #
33
+ # @param [CacheMachine::Adapter]
34
+ def self.map_adapter=(adapter)
35
+ @map_adapter = adapter
46
36
  end
47
37
 
48
- module ClassMethods
49
-
50
- # Initializes tracking associations to write and reset cache.
51
- #
52
- # @example Cache associated collections.
53
- # acts_as_cache_machine_for :cats, :dogs
54
- # @example Cache result of method to be expired when collection changes.
55
- # acts_as_cache_machine_for :cats => :cat_ids
56
- # @example Cache and expire dependent collections (_mouse_ change invalidates all other collection caches by chain)
57
- # acts_as_cache_machine_for :mouses => :cats, :cats => [:dogs, :bears], :dogs, :bears
58
- #
59
- # @param [ Hash<Symbol, Array> ] associations Cache Map
60
- def acts_as_cache_machine_for *associations
61
- Time.zone ||= ActiveSupport::TimeZone[0]
62
-
63
- include CacheMachine::Cache::Map
64
- cache_associated(associations)
65
- end
66
- alias :cache_map :acts_as_cache_machine_for
67
-
68
- # Returns timestamp of class collection.
69
- #
70
- # @example Return timestamp of the class.
71
- # MyActiveRecordClass.timestamp
72
- #
73
- # @param [ Symbol ] format
74
- #
75
- # @return [ String ]
76
- def timestamp format = nil
77
- Rails.cache.fetch(timestamp_key format) { Time.now.to_i.to_s }
78
- end
79
-
80
- # Returns cache key to fetch timestamp from memcached.
81
- #
82
- # @param [ Symbol ] format
83
- #
84
- # @return [ String ]
85
- def timestamp_key format = nil
86
- [self.name, format, 'timestamp'].join '_'
87
- end
38
+ # Returns adapter used for storing content being cached.
39
+ #
40
+ # @return [CacheMachine::Adapter]
41
+ def self.storage_adapter
42
+ @storage_adapter ||= CacheMachine::Adapters::Rails.new
43
+ end
88
44
 
89
- # Returns cache key of anything with timestamp attached.
90
- #
91
- # @example Return timestamped key of the class.
92
- # MyActiveRecordClass.timestamped_key
93
- #
94
- # @param [Symbol] format
95
- #
96
- # @return [ String ]
97
- def timestamped_key format = nil
98
- [timestamp_key(format), timestamp(format)].join '_'
99
- end
45
+ # Sets adapter used for storing content being cached.
46
+ #
47
+ # @param [CacheMachine::Adapter]
48
+ def self.storage_adapter=(adapter)
49
+ @storage_adapter = adapter
50
+ end
100
51
 
101
- # Resets timestamp of class collection.
102
- #
103
- # @param [ Symbol ] format
104
- def reset_timestamp format = nil
105
- cache_key = timestamp_key format
106
- CacheMachine::Logger.info "CACHE_MACHINE (reset_timestamp): deleting '#{cache_key}'."
107
- Rails.cache.delete(cache_key)
108
- end
52
+ # Returns adapter used for storing content being cached.
53
+ #
54
+ # @return [CacheMachine::Adapter]
55
+ def self.timestamps_adapter
56
+ @timestamps_adapter ||= CacheMachine::Adapters::Rails.new
57
+ end
109
58
 
110
- # Resets all timestams for all formats.
111
- def reset_timestamps
112
- CacheMachine::Cache.formats.each { |format| reset_timestamp format }
113
- end
59
+ # Sets adapter used for storing content being cached.
60
+ #
61
+ # @param [CacheMachine::Adapter]
62
+ def self.timestamps_adapter=(adapter)
63
+ @timestamps_adapter = adapter
114
64
  end
115
65
  end
116
66
  end
117
-
@@ -0,0 +1,29 @@
1
+ module CacheMachine
2
+ module Cache
3
+ module Associations
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ # Returns ids of an association.
8
+ #
9
+ # @param [ String, Symbol ] association
10
+ #
11
+ # @return [ Array ]
12
+ def association_ids(association)
13
+ pk = self.class.reflect_on_association(association).klass.primary_key.to_sym
14
+ send(association).map &pk
15
+ end
16
+
17
+ # Returns associated relation from cache.
18
+ #
19
+ # @param [ String, Symbol ] association_name
20
+ #
21
+ # @return [ ActiveRecord::Relation ]
22
+ def associated_from_cache(association_name)
23
+ klass = self.class.reflect_on_association(association_name).klass
24
+ klass.where(klass.primary_key => CacheMachine::Cache::map_adapter.association_ids(self, association_name))
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+ module CacheMachine
2
+ module Cache
3
+ module ClassTimestamp
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ after_destroy { self.class.reset_timestamp }
8
+ after_save { self.class.reset_timestamp }
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ # Returns timestamp of class collection.
14
+ #
15
+ # @example Return timestamp of the class.
16
+ # MyActiveRecordClass.timestamp
17
+ #
18
+ # @return [ String ]
19
+ def timestamp
20
+ CacheMachine::Cache::timestamps_adapter.fetch_timestamp(self.name) { Time.now.to_i.to_s }
21
+ end
22
+
23
+ # Resets timestamp of class collection.
24
+ #
25
+ def reset_timestamp
26
+ CacheMachine::Cache::timestamps_adapter.reset_timestamp(self.name)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,131 @@
1
+ module CacheMachine
2
+ module Cache
3
+ module Collection
4
+ extend ActiveSupport::Concern
5
+
6
+ DEFAULT_DEPENDENCY_OPTIONS = { :on => :after_save, :scopes => :scoped, :members => [] }
7
+
8
+ included do
9
+ include CacheMachine::Cache::Associations
10
+ include CacheMachine::Cache::Scope
11
+
12
+ cattr_accessor :cache_map_members
13
+ self.cache_map_members = {}
14
+
15
+ # Updates cache map per collection update.
16
+ #
17
+ # @param resource_instance
18
+ # @param [ String, Symbol ] collection_name
19
+ def update_cache_map!(resource_instance, collection_name)
20
+ resource_id = resource_instance.send(resource_instance.class.primary_key)
21
+ collection_id = self.send(self.class.primary_key)
22
+ CacheMachine::Cache.map_adapter.append_id_to_map(resource_instance, collection_name, collection_id)
23
+ CacheMachine::Cache.map_adapter.append_id_to_reverse_map(resource_instance.class, collection_name, self, resource_id)
24
+ end
25
+
26
+ # Updates cache of the related resources.
27
+ #
28
+ # @param [ Class ] cache_resource
29
+ def update_resource_collections_cache!(cache_resource)
30
+ self.class.cache_map_members[cache_resource].each do |collection_name, options|
31
+ cache_map_ids = CacheMachine::Cache::map_adapter.reverse_association_ids(cache_resource, collection_name, self)
32
+ unless cache_map_ids.empty?
33
+ (options[:members] + [collection_name]).each do |member|
34
+ CacheMachine::Cache::Map.reset_cache_on_map(cache_resource, cache_map_ids, member)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ # Updates cache of the related resource.
41
+ #
42
+ # @param [ Class ] cache_resource
43
+ def update_dependent_cache!(cache_resource = nil)
44
+ if cache_resource
45
+ update_resource_collections_cache!(cache_resource)
46
+ else
47
+ self.class.cache_map_members.keys.each &:update_resource_collections_cache!
48
+ end
49
+ end
50
+
51
+ # Returns all ids from resource associated with this collection member.
52
+ #
53
+ # @param [ Class ] cache_resource
54
+ # @param [ String, Symbol ] collection_name
55
+ #
56
+ # @return [ Array ]
57
+ def cache_map_ids(cache_resource, collection_name)
58
+ pk = self.class.primary_key.to_sym
59
+ resource_table_name = cache_resource.table_name
60
+ resource_pk = cache_resource.primary_key.to_sym
61
+
62
+ cache_resource.under_cache_scopes.joins(collection_name).
63
+ where(collection_name => { pk => self.send(pk) }).
64
+ select("#{resource_table_name}.#{resource_pk}").to_a.map &resource_pk
65
+ end
66
+ end
67
+
68
+ module ClassMethods
69
+
70
+ # Builds cache dependency.
71
+ #
72
+ # @param [ Class ] cache_resource
73
+ # @param [ String, Symbol ] collection_name
74
+ # @param [ Hash ] options
75
+ def register_cache_dependency(cache_resource, collection_name, options = {})
76
+ return if self.cache_map_members[cache_resource].try('[]', collection_name)
77
+
78
+ options.reverse_merge!(CacheMachine::Cache::Collection::DEFAULT_DEPENDENCY_OPTIONS)
79
+
80
+ # Register scopes.
81
+ self.cache_scopes = [*options[:scopes]]
82
+
83
+ # Save dependency options.
84
+ (self.cache_map_members[cache_resource] ||= {}).tap do |resource_collection|
85
+ resource_collection[collection_name] = options
86
+ end
87
+
88
+ # Prepare callbacks to be executed when it is time to expire the cache.
89
+ reset_cache_proc = Proc.new do
90
+ update_resource_collections_cache!(cache_resource)
91
+ end
92
+
93
+ # Bind callbacks.
94
+ [*options[:on]].each { |callback| self.send(callback, &reset_cache_proc) }
95
+
96
+ # When new element appears - update maps.
97
+ cache_resource.send(:add_association_callbacks, collection_name,
98
+ :after_add => lambda { |resource_instance, collection_instance|
99
+ collection_instance.update_cache_map!(resource_instance, collection_name)
100
+ })
101
+
102
+ # Hook on '<<', 'concat' operations.
103
+ #cache_resource.send(:add_association_callbacks, collection_name,
104
+ # :after_add => lambda { |resource_instance, collection_instance|
105
+ # collection_instance.update_resource_collections_cache!(resource_instance.class)
106
+ # })
107
+ end
108
+
109
+ # Resets cache of associated resource instance.
110
+ #
111
+ # @param resource_instance
112
+ # @param [ String, Symbol ] association_name
113
+ def reset_resource_cache(resource_instance, association_name)
114
+ CacheMachine::Cache::Map.reset_cache_on_map(resource_instance.class,
115
+ resource_instance.send(resource_instance.class.primary_key),
116
+ association_name)
117
+
118
+ collection = self.cache_map_members[resource_instance.class][association_name]
119
+
120
+ if collection
121
+ collection[:members].each do |member|
122
+ CacheMachine::Cache::Map.reset_cache_on_map(resource_instance.class,
123
+ resource_instance.send(resource_instance.class.primary_key),
124
+ member)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -1,262 +1,118 @@
1
1
  module CacheMachine
2
2
  module Cache
3
+ require 'cache_machine/cache/mapper'
3
4
 
4
- module Map
5
- extend ActiveSupport::Concern
5
+ class Map
6
+ cattr_accessor :registered_models
7
+ self.registered_models = []
6
8
 
7
- included do
8
- CacheMachine::Logger.info "CACHE_MACHINE: bind cache-map on class #{self.name}"
9
+ cattr_accessor :registered_maps
10
+ self.registered_maps = []
9
11
 
10
- # Stores associations map to be cached.
11
- cattr_accessor :cache_map
12
- self.cache_map = {}
12
+ # Draws cache dependency graph.
13
+ #
14
+ # @return [ nil ]
15
+ def draw(&block)
16
+ self.class.registered_maps << block
17
+ nil
13
18
  end
14
19
 
15
- module ClassMethods
16
-
17
- # Fills cache map.
18
- #
19
- # @param [ Hash<Symbol, Array> ] associations
20
- def cache_associated associations
21
- [*associations].each do |association|
22
- self.cache_map.merge! association.is_a?(Hash) ? association : {association => []}
23
- end
24
- end
25
-
26
- # Defines timestamp for object.
27
- #
28
- # @example Define timestamp to be updated every hour.
29
- # class MyModel < ActiveRecord::Base
30
- # include CacheMachine::Cache
31
- # define_timestamp(:my_timestamp, :expires_in => 1.hour) { my_optional_value }
32
- # end
33
- #
34
- # @param [ String, Symbol ] timestamp_name
35
- # @param [ Hash ] options
36
- def define_timestamp timestamp_name, options = {}, &block
37
- if block_given?
38
- options[:timestamp] = block
39
- end
40
-
41
- define_method timestamp_name do
42
- fetch_cache_of(timestamp_key_of(timestamp_name), options) do
43
- CacheMachine::Logger.info "CACHE_MACHINE (define_timestamp): deleting old timestamp '#{timestamp_name}'."
44
- delete_cache_of timestamp_name # Case when cache expired by time.
45
- Time.zone.now.to_i.to_s
20
+ # Fills association map in cache.
21
+ #
22
+ # @param [ Class ] resource
23
+ def self.fill_associations_map(resource)
24
+ resource.under_cache_scopes.
25
+ select("#{resource.table_name}.#{resource.primary_key}").find_each do |instance|
26
+ resource.cached_collections.each do |collection_name|
27
+ CacheMachine::Cache::map_adapter.association_ids(instance, collection_name)
28
+ association_class = resource.reflect_on_association(collection_name).klass
29
+ association_class.under_cache_scopes.
30
+ select("#{association_class.table_name}.#{association_class.primary_key}").
31
+ find_each do |associated_instance|
32
+ CacheMachine::Cache::map_adapter.reverse_association_ids(resource, collection_name, associated_instance)
46
33
  end
47
34
  end
48
35
  end
49
-
50
- # Deletes cache of collection associated via many-to-many.
51
- #
52
- # @param [ ActiveRecord::Base ]
53
- def delete_association_cache_on record, reflection
54
- pk = record.class.primary_key
55
-
56
- joining = unless reflection.options[:source_type]
57
- reflection.through_reflection ? { reflection.through_reflection.name => reflection.source_reflection.name } : reflection.name
58
- else
59
- reflection.name
60
- end
61
-
62
- self.joins(joining).where(reflection.table_name => { pk => record.send(pk) }).find_each do |cache_source_record|
63
- cache_source_record.delete_cache_of reflection.name
64
- end
65
- end
66
-
67
- # Hooks association changes.
68
- #
69
- # @private
70
- def has_many(association_id, options = {}) #:nodoc:
71
- # Ensure what collection should be tracked.
72
- if (should_be_on_hook = self.cache_map.keys.include?(association_id)) && options[:through]
73
- # If relation is _many_to_many_ track collection changes.
74
- options[:after_add] = \
75
- options[:before_remove] = :delete_association_cache_on
76
- end
77
- super
78
- hook_cache_machine_on association_id if should_be_on_hook
79
- end
80
-
81
- # Hooks association changes.
82
- #
83
- # @private
84
- def has_and_belongs_to_many(association_id, options = {}) #:nodoc:
85
-
86
- # Ensure what collection should be tracked.
87
- if(should_be_on_hook = self.cache_map.keys.include?(association_id))
88
-
89
- # If relation is many-to-many track collection changes.
90
- options[:after_add] = \
91
- options[:before_remove] = :delete_association_cache_on
92
- end
93
- super
94
- hook_cache_machine_on association_id if should_be_on_hook
95
- end
96
-
97
- protected
98
-
99
- # Hooks Cache Machine.
100
- #
101
- # @param [ Symbol ] association_id
102
- def hook_cache_machine_on association_id
103
- reset_cache_proc = Proc.new do |reflection, target_class, &block|
104
- block ||= lambda { target_class.delete_association_cache_on self, reflection }
105
-
106
- reflection.klass.after_save &block
107
- reflection.klass.before_destroy &block
108
- end
109
-
110
- case (reflection = (target_class = self).reflect_on_association association_id)
111
- when ActiveRecord::Reflection::ThroughReflection
112
- # If association is _many_to_many_ it should reset its cache for all associated objects with class +target_class+.
113
- reset_cache_proc.call(reflection, target_class)
114
- when ActiveRecord::Reflection::AssociationReflection
115
- if reflection.macro == :has_and_belongs_to_many
116
- reset_cache_proc.call(reflection, target_class)
117
- else
118
- # If association is _has_many_ or _has_one_ it should reset its cache for associated object with class +target_class+.
119
- reset_cache_proc.call(reflection) do
120
- target_class.where((reflection.options[:primary_key] || :id) =>
121
- send(reflection.options[:foreign_key] || reflection.primary_key_name)).first.try(:delete_cache_of, association_id)
122
- end
123
- end
124
- end
125
- end
126
36
  end
127
37
 
128
- module InstanceMethods
129
-
130
- # Returns cache key of the member.
131
- #
132
- # @param [ Symbol ] _member
133
- # @param [ Hash ] options
134
- #
135
- # @return [ String ]
136
- def cache_key_of _member, options = {}
137
- timestamp = instance_eval(&options[:timestamp]) if options.has_key? :timestamp
138
-
139
- [ self.class.name,
140
- self.to_param,
141
- _member,
142
- options[:format],
143
- options[:page] || 1,
144
- timestamp ].flatten.compact.join '/'
145
- end
146
-
147
- # Fetches cache of the member.
148
- #
149
- # @example Fetch cache of associated collection to be refreshed every hour.
150
- # @instance.fetch_cache_of :association, :timestamp => lambda { custom_instance_method },
151
- # :expires_in => 1.hour
152
- #
153
- # @param [ Symbol ] _member
154
- # @param [ Hash ] options
155
- #
156
- # @return [ * ]
157
- def fetch_cache_of _member, options = {}, &block
158
- if CacheMachine::Cache::enabled?
159
- expires_in = if expires_at = options[:expires_at]
160
- if expires_at.kind_of? Proc
161
- expires_at = expires_at.call
162
- end
163
-
164
- if expires_at.kind_of? Time
165
- expires_at - Time.zone.now
166
- else
167
- raise ArgumentError, "expires_at is not a Time"
168
- end
169
- else
170
- options[:expires_in]
171
- end
172
-
173
- CacheMachine::Logger.info "CACHE_MACHINE (fetch_cache_of): reading '#{cache_key}'."
174
- Rails.cache.fetch(cache_key_of(_member, options), :expires_in => expires_in, &block)
175
- else
176
- yield
177
- end
178
- end
179
-
180
- # Removes all caches using map.
181
- def delete_all_caches
182
- self.class.cache_map.to_a.flatten.uniq.each &method(:delete_cache_of)
183
- end
184
-
185
- # Recursively deletes cache by map starting from the member.
186
- #
187
- # @param [ Symbol ] _member
188
- def delete_cache_of _member
189
- delete_cache_of_only _member
190
- if chain = self.class.cache_map[_member]
191
- [*chain].each &method(:delete_cache_of)
192
- end
193
- end
194
-
195
- # Deletes cache of the only member ignoring cache map.
196
- #
197
- # @param [ Symbol ] _member
198
- def delete_cache_of_only _member
199
- CacheMachine::Cache.formats.each do |cache_format|
200
- page_nr = 0; begin
201
- cache_key = cache_key_of(_member, {:format => cache_format, :page => page_nr += 1})
202
- CacheMachine::Logger.info "CACHE_MACHINE (delete_cache_of_only): deleting '#{cache_key}'"
203
- end while Rails.cache.delete(cache_key)
204
- end
205
- reset_timestamp_of _member
206
- end
207
-
208
- # Returns timestamp cache key for anything.
209
- #
210
- # @param [ String, Symbol ] anything
211
- #
212
- # @return [ String ]
213
- def timestamp_key_of anything
214
- [self.class.name, self.to_param, anything, 'timestamp'].join '/'
215
- end
38
+ # Returns cache key for cache resource.
39
+ #
40
+ # @param [ Class ] resource
41
+ # @param [ String, Numeric ] id
42
+ # @param [ String, Symbol ] member
43
+ #
44
+ # @return [ String ]
45
+ def self.resource_cache_key(resource, id, member)
46
+ "#{resource}##{id}:#{member}"
47
+ end
216
48
 
217
- # Returns timestamp of anything from memcached.
218
- #
219
- # @param [ String, Symbol ] anything
220
- #
221
- # @return [ String ]
222
- def timestamp_of anything
223
- if CacheMachine::Cache::enabled?
224
- key = timestamp_key_of anything
225
- CacheMachine::Logger.info "CACHE_MACHINE (timestamp_of): reading timestamp '#{key}'."
226
- Rails.cache.fetch(key) { Time.zone.now.to_i.to_s }
227
- else
228
- Time.zone.now.to_i.to_s
229
- end
230
- end
49
+ # Returns timestamp key for cache resource.
50
+ #
51
+ # @param [ Class ] resource
52
+ # @param [ String, Numeric ] id
53
+ # @param [ String, Symbol ] member
54
+ #
55
+ # @return [ String ]
56
+ def self.timestamp_key(resource, id, member)
57
+ "#{resource}##{id}:#{member}_timestamp"
58
+ end
231
59
 
232
- # Returns cache key of +anything+ with timestamp attached.
233
- #
234
- # @return [ String ]
235
- def timestamped_key_of anything, options = {}
236
- [cache_key_of(anything, options), timestamp_of(anything)].join '/'
237
- end
60
+ # Returns cache key for cache resource.
61
+ #
62
+ # @param [ Class ] resource
63
+ # @param [ String, Numeric ] id
64
+ # @param [ String, Symbol ] member
65
+ #
66
+ # @return [ String ]
67
+ def self.timestamped_resource_member_key(resource, id, member, timestamp)
68
+ key = timestamp_key(resource, id, member)
69
+ collection_timestamp = CacheMachine::Cache::timestamps_adapter.fetch_timestamp(key) { Time.now.to_i.to_s }
70
+ "#{key}_#{collection_timestamp}_#{timestamp}"
71
+ end
238
72
 
239
- # Deletes cache of anything from memory.
240
- def reset_timestamp_of anything
241
- cache_key = timestamp_key_of anything
242
- CacheMachine::Logger.info "CACHE_MACHINE (reset_timestamp_of): deleting '#{cache_key}'."
243
- Rails.cache.delete(cache_key)
73
+ # Returns cache key for cache resource.
74
+ #
75
+ # @param [ Class ] resource
76
+ # @param [ String, Numeric, Array ] id
77
+ # @param [ String, Symbol ] member
78
+ #
79
+ # @return [ String ]
80
+ def self.reset_cache_on_map(resource, ids, member)
81
+ [*ids].each do |id|
82
+ key = resource_cache_key(resource, id, member)
83
+ CacheMachine::Logger.info "Deleting cache by map: #{key}"
84
+ CacheMachine::Cache::storage_adapter.delete_content(key)
85
+
86
+ key = timestamp_key(resource, id, member)
87
+ CacheMachine::Logger.info "CACHE_MACHINE (reset_timestamp_of): deleting '#{key}'."
88
+ CacheMachine::Cache::timestamps_adapter.reset_timestamp(key)
244
89
  end
90
+ end
245
91
 
246
- protected
247
-
248
- # Deletes cache of associated collection what contains record.
249
- # Called only when many-to-many collection changed.
250
- #
251
- # @param [ ActiveRecord::Base ] record
252
- def delete_association_cache_on record
253
-
254
- # Find all associations with +record+ by its class.
255
- associations = self.class.reflect_on_all_associations.find_all { |association| association.klass == record.class }
92
+ # Returns cache key for cache resource.
93
+ #
94
+ # @param [ Class ] resource
95
+ # @param [ String, Numeric, Array ] id
96
+ # @param [ String, Symbol ] member
97
+ #
98
+ # @return [ String ]
99
+ def self.reset_resource_cache(resource, id, member)
100
+ key = resource_cache_key(resource, id, member)
101
+ CacheMachine::Logger.info "Deleting cache by map: #{key}"
102
+ CacheMachine::Cache::storage_adapter.delete_content(key)
103
+ end
256
104
 
257
- # Delete cache of each associated collection what may contain +record+.
258
- associations.map(&:name).each &method(:delete_cache_of)
259
- end
105
+ # Returns cache key for cache resource.
106
+ #
107
+ # @param [ Class ] resource
108
+ # @param [ String, Numeric, Array ] id
109
+ # @param [ String, Symbol ] member
110
+ #
111
+ # @return [ String ]
112
+ def self.reset_resource_timestamp(resource, id, member)
113
+ key = timestamp_key(resource, id, member)
114
+ CacheMachine::Logger.info "CACHE_MACHINE (reset_timestamp_of): deleting '#{key}'."
115
+ CacheMachine::Cache::timestamps_adapter.reset_timestamp(key)
260
116
  end
261
117
  end
262
118
  end