Class: Rack::Cache::MetaStore
- Inherits:
-
Object
- Object
- Rack::Cache::MetaStore
- Defined in:
- lib/rack/cache/meta_store.rb
Overview
The MetaStore is responsible for storing meta information about a request/response pair keyed by the request’s URL.
The meta store keeps a list of request/response pairs for each canonical request URL. A request/response pair is a two element Array of the form:
[request, response]
The request
element is a Hash of Rack environment keys. Only protocol keys (i.e., those that start with “HTTP_”) are stored. The response
element is a Hash of cached HTTP response headers for the paired request.
The MetaStore class is abstract and should not be instanstiated directly. Concrete subclasses should implement the protected #read, #write, and #purge methods. Care has been taken to keep these low-level methods dumb and straight-forward to implement.
Direct Known Subclasses
Defined Under Namespace
Classes: Dalli, Disk, GAEStore, Heap, MemCacheBase, MemCached
Constant Summary collapse
- HEAP =
Heap
- MEM =
HEAP
- DISK =
Disk
- FILE =
Disk
- MEMCACHE =
if defined?(::Memcached) MemCached else Dalli end
- MEMCACHED =
MEMCACHE
- GAECACHE =
GAEStore
- GAE =
GAEStore
Instance Method Summary collapse
-
#cache_key(request) ⇒ Object
Generate a cache key for the request.
-
#invalidate(request, entity_store) ⇒ Object
Invalidate all cache entries that match the request.
-
#lookup(request, entity_store) ⇒ Object
Locate a cached response for the request provided.
-
#store(request, response, entity_store) ⇒ Object
Write a cache entry to the store under the given key.
Instance Method Details
#cache_key(request) ⇒ Object
Generate a cache key for the request.
112 113 114 115 |
# File 'lib/rack/cache/meta_store.rb', line 112 def cache_key(request) keygen = request.env['rack-cache.cache_key'] || Key keygen.call(request) end |
#invalidate(request, entity_store) ⇒ Object
Invalidate all cache entries that match the request.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/rack/cache/meta_store.rb', line 118 def invalidate(request, entity_store) modified = false key = cache_key(request) entries = read(key).map do |req, res| response = restore_response(res) if response.fresh? response.expire! modified = true end [req, persist_response(response)] end write key, entries if modified end |
#lookup(request, entity_store) ⇒ Object
Locate a cached response for the request provided. Returns a Rack::Cache::Response object if the cache hits or nil if no cache entry was found.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/rack/cache/meta_store.rb', line 28 def lookup(request, entity_store) key = cache_key(request) entries = read(key) # bail out if we have nothing cached return nil if entries.empty? # find a cached entry that matches the request. env = request.env match = entries.detect{ |req,res| requests_match?((res['vary'] || res['vary']), env, req) } return nil if match.nil? _, res = match entity_key = res['x-content-digest'] if entity_key && body = entity_store.open(entity_key) restore_response(res, body) else # the metastore referenced an entity that doesn't exist in # the entitystore, purge the entry from the meta-store begin purge(key) rescue NotImplementedError @@warned_on_purge ||= begin warn "WARNING: Future releases may require purge implementation for #{self.class.name}" true end nil end end end |
#store(request, response, entity_store) ⇒ Object
Write a cache entry to the store under the given key. Existing entries are read and any that match the response are removed. This method calls #write with the new list of cache entries.
62 63 64 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 107 108 109 |
# File 'lib/rack/cache/meta_store.rb', line 62 def store(request, response, entity_store) key = cache_key(request) stored_env = persist_request(request) # write the response body to the entity store if this is the # original response. if response.headers['x-content-digest'].nil? if request.env['rack-cache.use_native_ttl'] && response.fresh? digest, size = entity_store.write(response.body, response.ttl) else digest, size = entity_store.write(response.body) end response.headers['x-content-digest'] = digest response.headers['content-length'] = size.to_s unless response.headers['Transfer-Encoding'] # If the entitystore backend is a Noop, do not try to read the body from the backend, it always returns an empty array unless entity_store.is_a? Rack::Cache::EntityStore::Noop # A stream body can only be read once and is currently closed by #write. # (To avoid having to keep giant objects in memory when writing to disk cache # the body is never converted to a single string) # We cannot always reply on body to be re-readable, # so we have to read it from the cache. # BUG: if the cache was unable to store a stream, the stream will be closed # and rack will try to read it again, resulting in hard to track down exception response.body = entity_store.open(digest) || response.body end end # read existing cache entries, remove non-varying, and add this one to # the list vary = response.vary entries = read(key).reject do |env, res| (vary == (res['vary'])) && requests_match?(vary, env, stored_env) end headers = persist_response(response) headers.delete('age') entries.unshift [stored_env, headers] if request.env['rack-cache.use_native_ttl'] && response.fresh? write key, entries, response.ttl else write key, entries end key end |