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)
Example #2
0
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)
Example #3
0
 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))