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 per-request 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.
-
#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
Delete the entry from the cache so that the next call goes to the database for the freshest copy of the record.
Class Attribute Details
.cache_local ⇒ Object (readonly)
Returns the value of attribute cache_local.
14 15 16 |
# File 'lib/cached_model.rb', line 14 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.
47 48 49 50 51 |
# File 'lib/cached_model.rb', line 47 def self.cache_delete(klass, id) key = "#{klass}:#{id}" CachedModel.cache_local.delete key Cache.delete "#{KEY}:#{key}" end |
.cache_reset ⇒ Object
Invalidate the per-request cache. This should be called from a before filter at the beginning of each request.
57 58 59 |
# File 'lib/cached_model.rb', line 57 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.
26 27 28 29 30 31 32 33 34 |
# File 'lib/cached_model.rb', line 26 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.
19 20 21 |
# File 'lib/cached_model.rb', line 19 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.
65 66 67 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 |
# File 'lib/cached_model.rb', line 65 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 or args.length != 1 or not Fixnum === args.first then records = super if RAILS_ENV != 'test' and Array === records then records.each { |r| r.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.
113 114 115 116 117 118 119 120 121 |
# File 'lib/cached_model.rb', line 113 def self.find_by_sql(*args) unless @skip_find_hack or $TESTING then if args.first =~ /SELECT \* FROM #{table_name} WHERE \(#{table_name}\.#{primary_key} = '?(\d+)'?\) LIMIT 1/ then return [self.find($1.to_i)] end end return super end |
Instance Method Details
#cache_delete ⇒ Object
Remove this record from the cache.
170 171 172 173 |
# File 'lib/cached_model.rb', line 170 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.
178 179 180 |
# File 'lib/cached_model.rb', line 178 def cache_key_local return "#{self.class.name}:#{self.id}" end |
#cache_key_memcache ⇒ Object
The memcache key for this record.
185 186 187 |
# File 'lib/cached_model.rb', line 185 def cache_key_memcache return "#{KEY}:#{cache_key_local}" end |
#cache_local ⇒ Object
The local object cache.
155 156 157 |
# File 'lib/cached_model.rb', line 155 def cache_local return CachedModel.cache_local end |
#cache_store ⇒ Object
Store this record in the cache.
162 163 164 165 |
# File 'lib/cached_model.rb', line 162 def cache_store cache_local[cache_key_memcache] = self Cache.put cache_key_memcache, self, TTL end |
#destroy ⇒ Object
Delete the entry from the cache now that it isn’t in the DB.
138 139 140 141 142 |
# File 'lib/cached_model.rb', line 138 def destroy return super ensure cache_delete end |
#reload ⇒ Object
Invalidate the cache for this record before reloading from the DB.
147 148 149 150 |
# File 'lib/cached_model.rb', line 147 def reload cache_delete return super end |
#update ⇒ Object
Delete the entry from the cache so that the next call goes to the database for the freshest copy of the record. This will also ensure that if for some reason a stale copy of the record was cached we can get rid of it.
128 129 130 131 132 133 |
# File 'lib/cached_model.rb', line 128 def update cache_delete val = super cache_store return val end |