CPSPortlets - RAM cache

Authors: Jean-Marc Orliaguet <mailto:jmo@ita.chalmers.se>
Julien Anguenot <mailto:ja@nuxeo.com>
M.-A. Darche <madarche@nuxeo.com>
Revision: $Id$

Contents

1   RAM Cache

The cache implementation in CPSPortlets is the same as in CPSSkins (see CPSSkins/RAMCache.py) but the caching algorithm is different (see below)

Cache entries are also stored in a dictionary: {(index, ): value} where '(index, )' is a tuple that represents the cached object.

The tuple consist of: (object_path, (..., ..., ) ) where 'object_path' is the physical path of the cached object and (..., ..., ) is a collection of values that uniquely describes the object's context (the URL, the current language, ...).

Cache entries can be:

The entire cache can be:

2   Caching algorithm

A portlet can be global or local and while the content displayed may be the same the presentation logic is different:

The caching algorithms are different in CPSSkins and in CPSPortlets.

2.1   In CPSSkins:

The caching algorithm in CPSSkins is based on the principle that cache entries are updated or invalidated only when the cached object is being displayed. There is no other purging mechanism other than this one...

Each object that is in the cache has a time-to-live (TTL) that, when it has expired causes all cache entries associated to the object to be removed from the cache. The cache entries for a given object can also be invalidated manually by calling the expireCache() method on the cached object.

This caching mechanism works well with objects that are displayed often such as the global UI elements of a portal (images, breadcrumbs, menus, global boxes, global portlets...). But the mechanism is not efficient when the elements of the portal are seldom displayed -- such as the local portlets..

2.2   In CPSPortlets:

The local portlets in CPSPortlets are designed to be specifically associated to some given users or group of users; they may be visible only inside some limited areas of the portal. Hence they are in comparison to global portlets very seldom displayed and it is not very efficient to use the same algorithm as the one used with global portlets.

Instead the current implementation relies entirely on the event service of CPS3 to invalidate cache entries whenever an invalidation is required, i.e. when content has been created, deleted, published, etc.

2.3   Cache index

The cache index is a minimal collection of parameter values that represent a portlet in a unique way.

The cache index may include:

  • the current language name
  • the current URL
  • the current month name
  • the current user
  • ...

Some portlets are completely independent of the context; for instance an image portlet is the same for every user, in all languages, and the cache index associated to it will be reduced to the portlet's path.

To increase performance the parameter values must be fast to compute, these can typically be:

  • request variables
  • variables that can be obtained through a simple method (absolute_url(), getId(), ...)

2.4   Cache parameters

Cache parameters are variable names that are used to identify the parameter values of the cache index. These are specific to portlet types and could be set in the factory type information.

2.5   Contextual variables:

  • url

    description:

    the entire current URL including the query string

    examples:

    http://www.yourhost.com/cps/view?pp=1

    used in:

    portal actions

  • server_url

    description:

    the URL of the server hosting the portal

    examples:

    http://localhost:8080 http://mymachinename:8080 http://mysite.net https://mysite.net

    used in:

    search portlet

  • baseurl

    description:

    The absolute path of the base or root of the portal as seen from the client. The baseurl name is misleading, it isn't in any way an URL.

    examples:

    This is generally either / or /cps.

    used in:

    search portlet and conformance portlet

  • protocol

    description:

    The protocol used in the URL scheme. This variable is now actually useless and thus deprecated since the addition of the server_url variable.

    examples:

    http https

  • current_lang

    description:

    the current language

    used in:

    the language portlet

  • object:path

    description:

    the path of the object

    examples:

    /cps/workspaces/members

  • object:published_path

    description:

    the path of the published object

    examples:

    /cps/workspaces/members/view

    used in:

    breadcrumbs

  • object:lang

    description:

    the default language of the current object

    examples:

    ('en', 'fr')

    used in:

    language portlet

  • object:langs

    description:

    the list of existing language revisions of the current object

    examples:

    ('en', 'fr')

    used in:

    language portlet

  • user

    description:

    the name of the current user

    examples:

    'root'

    used in:

    navigation portlets, login portlet ...

  • request:var

    description:

    the content of the 'var' request variable

  • actions:cat1,cat2,cat3

    description:

    the CMF actions by categories (cat1, cat2, ...)

    examples:

    actions:object,global,user,maintabs

    used in:

    the actions portlet

  • actions:(categories)

    description:

    the CMF actions by categories where 'categories' is a property of the portlet that contains a list/tuple of categories

    used in:

    the actions portlet

  • actions:(categories),(custom_categories),user

    ...

  • event_ids

    description:

    the list of event ids that will trigger an expiration of the portlet's cache.

    examples:

    event_ids:workflow_publish,workflow_unpublish

    used in:

    the content portlet

  • event_in_folders

    description:

    the list of folder paths inside which events will be monitored

    used in:

    the content portlet

  • event_on_types

    description:

    the list of portal types for which events will be monitored

    used in:

    the content portlet

  • cache_timeout

    The timeout of the cache, expressed in seconds.

    If this parameter is not specified, the value of the cache timeout will be read from the corresponding portlet's field (defined in schema portlet_common).

    Otherwise, the specified value will supersede the value in the field for all portlets of given type.

  • no-cache:

    description:

    the portlet should not be cached.

  • no-cache:(field1),(field2),...

    description:

    the portlet will not be cached if any of the specified field's value is True.

    examples:

    no-cache:(contextual)

    will disable the portlet's cache if the 'contextual' option is set.

    used in:

    the content portlet

  • random:n

    description:

    generates a random integer between 0 and n-1. The integer is passed as a keyword parameter to the portlet as 'random_int'.

    used in:

    Image Portlet (banner rotation, etc.)

2.6   Contextual objects:

  • objects:relative_path

    description:

    the list of objects from the current object to the portal.

    used in:

    the breadcrumbs portlet

  • objects:context

    description:

    the context object.

    used in:

    portlets that display information about the current object

  • objects:(list_variable)

    description:

    a list of objects described by their physical path as listed in the 'list_variable' property.

    used in:

    the Internal Links Portlet.

3   Cache invalidation

3.1   Principal

The cache invalidation has to be lazy. It means that when a portlet has to invalided its cache, we will set a flag on the portlet (Like the datetime) just wait for the next time he will be rendered to set the destroy the cache and to set the new one.

3.2   Actors

The portlet is able to cope with its own cache. The portlet tool is a subscriber of the central event service and will check for interested events. Then after, it will lookup for all the portlets interested about this event and flag the portlet.

3.3   API on the tool

  • notify_event:

    notify_event(self, event_type, object, infos)
    """ Standard event hook
    """
    
  • listPortletsInterestedInEvent``:

    listPortletsInterestedInEvent(self, event_id, context=None)
    """ return all the portlets interested about a particular event
    """
    

3.4   API on the portlet

  • isInterestedInEvent:

    isInterestedInEvent(self, event_id):
    """Is the portlet interested in a particular event
    
    The portlet will have to store in a certain way the list of events
    in which he's interested about
    """
    
  • expireCache:

    expireCache(self)
    """...
    Already in here.
    Will be call from sendEvent() if the event_id is related to cache invalidation
    """
    
  • sendEvent:

    sendEvent(self, event_id)
    """React on a given event
    
    It's designed to be used primarily for cache invalidation
    but it's intended to be generic enough to do other stuffs than that.
    """
    

3.5   Storing "event-reactive" objects in the cache

The cache entries currently consist of:

  • The portlet's physical path

  • The cache index

  • The rendered portlet

  • The cache entry creation date

  • The name of the user for whom the entry has been created

  • A list of "reactive" objects (see below):

    { ((portlet1_path), (cache index)): {'rendered': rendered,
                                         'user': user,
                                         'date': creation_date,
                                         'objects': [...],
                                        }, }
    

Notes:

  • The CACHE INDEX is used for DISCRIMINATION purposes to make sure that the cache entries are specific to the context.

  • The USER NAME is stored for CLEANING purposes to increase the efficiency of the cache, for instance to find and remove all user-dependent entries when a user logs out.

    • Scope: The cleaning of the cache does not need to propagate between all ZEO instances.
    • API: ptltool.invalidateCacheEntriesById(), ...
  • REACTIVE OBJECTS are stored for INVALIDATION purposes.

    • Method A:

      The list of objects that have been used to create the portlet's content are recorded in the cache. If any of these objects were to be affected by an event then the cache entries associated to the portlet should be invalidated.

      For instance, if the portlet is a "Breadcumbs portlet" and its content is "Workspaces > members", the objects <workspaces proxy folder> and <members proxy folder> will be stored in the cache as object reactive to events.

      • Scope: global - the invalidation of cache entries must propagate between all ZEO instances.
      • API: portlet.expireCache(), ...
    • Method B:

      When the portlet is rendered, we compare the modification date of the cache objects with the cache entry creation date. If any of the cache objects were modified after the cache entry creation date we consider the cache entry as invalid and the portlet must be rendered again.

      • Scope: local - the invalidation concerns the cache entry which is being used when rendering the portlet. The other cache entries associated to the portlet are not affected.
      • API: See CPSPortlet.render_cache().

4   Cache Policy Manager

The RAM cache acts as a cache policy manager by setting the HTTP headers to inform front-end proxy caches when pages have expired, etc.