def open_get(self, key, url, mode, params, reload, data): """open() method specialized for GET request. Performs several steps: 1. Check for the URL in the cache. 2. If it is in the cache, 1. Create a SharedItem for it. 2. Reload the cached copy if reload flag is on. 3. Refresh the page if the freshness test fails. If it isn't in the cache, 1. Create a SharedItem (which will create a CacheEntry after the page has been loaded.) 3. call activate(), which adds the URL to the shared object list and creates a SharedAPI for the item """ try: api = self.cache_read(key) except CacheReadFailed as err: (cache, ) = err.args cache.evict(key) api = None if api: # creating reference to cached item try: if reload: item = SharedItem(url, mode, params, self, key, data, api, reload=reload) self.touch(key) elif not self.fresh_p(key): item = SharedItem(url, mode, params, self, key, data, api, refresh=self.items[key].lastmod) self.touch(key, refresh=1) else: item = SharedItem(url, mode, params, self, key, data, api) except: api.close() raise else: # cause item to be loaded (and perhaps cached) item = SharedItem(url, mode, params, self, key, data) return self.activate(item)
class CacheManager: """Manages one or more caches in hierarchy. The only methods that should be used by the application is open() and add_cache(). Other methods are intended for use by the cache itself. overview of CacheManager and Cache organization CM has list of caches (could have more than one cache) items = {}: contains an entry for all the URLs in all the caches. value is a cache entry object (cf DiskCacheEntry below), has a get method that returns an protocol API object active = {}: contains an entry for each URL that is open in a browser window. this is the shared object list. if there is a request for an active page, a second SharedAPI for the same object is returned. the list stores SharedItems, which contain a reference count; when that cound reaches zero, it removes itself from the list. freshness: CM is partly responsible for checking the freshness of pages. (pages with explicit TTL know when they expire.) freshness tests are preference driven, can be never, per session, or per time-unit. on each open, check to see if we should send an If-Mod-Since to the original server (based on fresh_p method). """ def __init__(self, app): """Initializes cache manager, creates disk cache. Basic disk cache characteristics loaded from """ self.app = app self.caches = [] self.items = {} self.active = {} self.disk = None self.disk = DiskCache( self, self.app.prefs.GetInt('disk-cache', 'size') * 1024, self.app.prefs.Get('disk-cache', 'directory')) self.set_freshness_test() self.app.prefs.AddGroupCallback('disk-cache', self.update_prefs) # check preferences bool = self.app.prefs.GetInt('disk-cache', 'checkpoint') if bool: self.app.register_on_exit( lambda save=self.save_cache_state: save()) def save_cache_state(self): for cache in self.caches: cache._checkpoint_metadata() def update_prefs(self): self.set_freshness_test() size = self.caches[0].max_size = self.app.prefs.GetInt('disk-cache', 'size') \ * 1024 new_dir = self.app.prefs.Get('disk-cache', 'directory') if new_dir != self.disk.pref_dir: self.disk._checkpoint_metadata() self.reset_disk_cache(size, new_dir) def reset_disk_cache(self, size=None, dir=None, flush_log=0): """Close the current disk cache and open a new one. Used primarily to change the cache directory or to clear everything out of the cache when it is erased. The flush_log argument is passed to DiskCache.close(), allowing this routine to be used in both of the cases described. On erase, we want to write a new, empty log; on change directory, we want to keep the old log intact. """ if not size: size = self.disk.max_size if not dir: dir = self.disk.directory self.disk.close(flush_log) self.disk = DiskCache(self, size, dir) def set_freshness_test(self): # read preferences to determine when pages should be checked # for freshness -- once per session, every n secs, or never fresh_type = self.app.prefs.Get('disk-cache', 'freshness-test-type') fresh_rate = int( self.app.prefs.GetFloat('disk-cache', 'freshness-test-period') * 3600.0) if fresh_type == 'per session': self.fresh_p = lambda key, self=self: \ self.fresh_every_session(self.items[key]) self.session_freshen = [] elif fresh_type == 'periodic': self.fresh_p = lambda key, self=self, t=fresh_rate: \ self.fresh_periodic(self.items[key],t) elif fresh_type == 'never': self.fresh_p = lambda x: 1 else: # == 'always' self.fresh_p = lambda x: 0 def open(self, url, mode, params, reload=0, data=None): """Opens a URL and returns a protocol API for it. This is the method called by the Application to load a URL. First, it checks the shared object list (and returns a second reference to a URL that is currently active). Then it calls open routines specialized for GET or POST. """ key = self.url2key(url, mode, params) if mode == 'GET': if self.active.has_key(key): # XXX This appeared to be a bad idea! ## if reload: ## self.active[key].reset() return SharedAPI(self.active[key]) return self.open_get(key, url, mode, params, reload, data) elif mode == 'POST': return self.open_post(key, url, mode, params, reload, data) def open_get(self, key, url, mode, params, reload, data): """open() method specialized for GET request. Performs several steps: 1. Check for the URL in the cache. 2. If it is in the cache, 1. Create a SharedItem for it. 2. Reload the cached copy if reload flag is on. 3. Refresh the page if the freshness test fails. If it isn't in the cache, 1. Create a SharedItem (which will create a CacheEntry after the page has been loaded.) 3. call activate(), which adds the URL to the shared object list and creates a SharedAPI for the item """ try: api = self.cache_read(key) except CacheReadFailed, cache: cache.evict(key) api = None if api: # creating reference to cached item if reload: item = SharedItem(url, mode, params, self, key, data, api, reload=reload) self.touch(key) elif not self.fresh_p(key): item = SharedItem(url, mode, params, self, key, data, api, refresh=self.items[key].lastmod) self.touch(key, refresh=1) else: item = SharedItem(url, mode, params, self, key, data, api) else: # cause item to be loaded (and perhaps cached) item = SharedItem(url, mode, params, self, key, data) return self.activate(item)
def open_post(self, key, url, mode, params, reload, data): """Open a URL with a POST request. Do not cache.""" key = self.url2key(url, mode, params) return self.activate(SharedItem(url, mode, params, None, key, data))