Class: CachedModel
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- CachedModel
- Defined in:
- lib/cached_model.rb
Overview
An abstract ActiveRecord descendant that caches records in memcache and in local memory.
Constant Summary collapse
- KEY =
'active_record'
- TTL =
seconds
60 * 15
Class Attribute Summary collapse
-
.cache_local ⇒ Object
readonly
Returns the value of attribute cache_local.
Class Method Summary collapse
-
.cache_delete(klass, id) ⇒ Object
Invalidate the cache entry for an record.
-
.cache_reset ⇒ Object
Invalidate the local process cache.
-
.class_name_of_active_record_descendant(klass) ⇒ Object
Override the flawed assumption ActiveRecord::Base makes about inheritance.
-
.descends_from_active_record? ⇒ Boolean
Override the flawed assumption ActiveRecord::Base makes about inheritance.
-
.find(*args) ⇒ Object
Override the find method to look for values in the cache before going to the database.
-
.find_by_sql(*args) ⇒ Object
Skip the special handling for find by primary key if this method was called from find.
Instance Method Summary collapse
-
#cache_delete ⇒ Object
Remove this record from the cache.
-
#cache_key_local ⇒ Object
The local cache key for this record.
-
#cache_key_memcache ⇒ Object
The memcache key for this record.
-
#cache_local ⇒ Object
The local object cache.
-
#cache_store ⇒ Object
Store this record in the cache without associations.
-
#destroy ⇒ Object
Delete the entry from the cache now that it isn’t in the DB.
-
#reload ⇒ Object
Invalidate the cache for this record before reloading from the DB.
-
#update ⇒ Object
Store a new copy of ourselves into the cache.
Class Attribute Details
.cache_local ⇒ Object (readonly)
Returns the value of attribute cache_local.
17 18 19 |
# File 'lib/cached_model.rb', line 17 def cache_local @cache_local end |
Class Method Details
.cache_delete(klass, id) ⇒ Object
Invalidate the cache entry for an record. The update method will automatically invalidate the cache when updates are made through ActiveRecord model record. However, several methods update tables with direct sql queries for effeciency. These methods should call this method to invalidate the cache after making those changes.
NOTE - if a SQL query updates multiple rows with one query, there is currently no way to invalidate the affected entries unless the entire cache is dumped or until the TTL expires, so try not to do this.
50 51 52 53 54 |
# File 'lib/cached_model.rb', line 50 def self.cache_delete(klass, id) key = "#{klass}:#{id}" CachedModel.cache_local.delete key Cache.delete "#{KEY}:#{key}" end |
.cache_reset ⇒ Object
Invalidate the local process cache. This should be called from a before filter at the beginning of each request.
60 61 62 |
# File 'lib/cached_model.rb', line 60 def self.cache_reset CachedModel.cache_local.clear end |
.class_name_of_active_record_descendant(klass) ⇒ Object
Override the flawed assumption ActiveRecord::Base makes about inheritance.
29 30 31 32 33 34 35 36 37 |
# File 'lib/cached_model.rb', line 29 def self.class_name_of_active_record_descendant(klass) if klass.superclass == CachedModel then return klass.name elsif klass.superclass.nil? then raise ActiveRecordError, "#{name} doesn't descend from ActiveRecord::Base" else class_name_of_active_record_descendant klass.superclass end end |
.descends_from_active_record? ⇒ Boolean
Override the flawed assumption ActiveRecord::Base makes about inheritance.
22 23 24 |
# File 'lib/cached_model.rb', line 22 def self.descends_from_active_record? superclass == CachedModel end |
.find(*args) ⇒ Object
Override the find method to look for values in the cache before going to the database.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/cached_model.rb', line 68 def self.find(*args) args[0] = args.first.to_i if args.first =~ /\A\d+\Z/ # Only handle simple find requests. If the request was more complicated, # let the base class handle it, but store the retrieved records in the # local cache in case we need them later. if ($TESTING and $TESTING != :cached_model) or args.length != 1 or not Fixnum === args.first then records = super return records if RAILS_ENV == 'test' case records when Array then records.each { |r| r.cache_store } when CachedModel then records.cache_store end return records end # Try to find the record in the local cache. id = args.first cache_key_local = "#{name}:#{id}" record = CachedModel.cache_local[cache_key_local] return record unless record.nil? # Try to find the record in memcache and add it to the local cache record = Cache.get "#{KEY}:#{cache_key_local}" unless record.nil? then CachedModel.cache_local[cache_key_local] = record return record end # Fetch the record from the DB and cache it. # # We don't want the subsequent find_by_sql to loop back here, so guard # the call. # # NOTE - this guard isn't thread safe. begin @skip_find_hack = true record = super(args).first record.cache_store ensure @skip_find_hack = false end return record end |
.find_by_sql(*args) ⇒ Object
Skip the special handling for find by primary key if this method was called from find. If this is really a lookup for a single row by primary key, use a simple find call instead.
121 122 123 124 125 126 127 128 129 |
# File 'lib/cached_model.rb', line 121 def self.find_by_sql(*args) unless @skip_find_hack or ($TESTING and $TESTING != :cached_model) then if args.first =~ /SELECT \* FROM #{table_name} WHERE \(#{table_name}\.#{primary_key} = '?(\d+)'?\) LIMIT 1/ then return [find($1.to_i)] end end return super end |
Instance Method Details
#cache_delete ⇒ Object
Remove this record from the cache.
162 163 164 165 |
# File 'lib/cached_model.rb', line 162 def cache_delete cache_local.delete cache_key_local Cache.delete cache_key_memcache end |
#cache_key_local ⇒ Object
The local cache key for this record.
170 171 172 |
# File 'lib/cached_model.rb', line 170 def cache_key_local return "#{self.class}:#{id}" end |
#cache_key_memcache ⇒ Object
The memcache key for this record.
177 178 179 |
# File 'lib/cached_model.rb', line 177 def cache_key_memcache return "#{KEY}:#{cache_key_local}" end |
#cache_local ⇒ Object
The local object cache.
184 185 186 |
# File 'lib/cached_model.rb', line 184 def cache_local return CachedModel.cache_local end |
#cache_store ⇒ Object
Store this record in the cache without associations. Storing associations leads to wasted cache space and hard-to-debug problems.
192 193 194 195 196 197 |
# File 'lib/cached_model.rb', line 192 def cache_store obj = dup obj.send :instance_variable_set, :@attributes, attributes_before_type_cast cache_local[cache_key_local] = obj Cache.put cache_key_memcache, obj, TTL end |
#destroy ⇒ Object
Delete the entry from the cache now that it isn’t in the DB.
134 135 136 137 138 |
# File 'lib/cached_model.rb', line 134 def destroy return super ensure cache_delete end |
#reload ⇒ Object
Invalidate the cache for this record before reloading from the DB.
143 144 145 146 147 148 |
# File 'lib/cached_model.rb', line 143 def reload cache_delete return super ensure cache_store end |
#update ⇒ Object
Store a new copy of ourselves into the cache.
153 154 155 156 157 |
# File 'lib/cached_model.rb', line 153 def update return super ensure cache_store end |