cache-machine 0.1.10 → 0.2.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.
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