Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Caching system (proposed)

From MoodleDocs
Revision as of 13:04, 14 July 2021 by David Mudrak (talk | contribs) (Text replacement - "</code>" to "</syntaxhighlight>")
Warning: This page is no longer in use. The information contained on the page should NOT be seen as relevant or reliable.


Introduction

This page documents a proposed design for an implementation of MDL25290.

The purpose is to provide a staging area for the design before it is implemented into code, and document the expected functionality.

The caching system should be a general architecture that can support all uses of caching within Moodle.

Please visit the discussion thread at http://moodle.org/mod/forum/discuss.php?d=189498.

Basic Requirements

Suggestions

Things the caching system should or must do:

  1. it should support different backends (static, session, DB, shared memory...).
  2. any attempt of caching within Moodle should end using it (and not other solutions).
  3. code should continue working 100% without caching enabled.
  4. each use should define one fallback of backend to use so, for example, for caching CFG we could use (shared memory, DB) and the 1st one available is picked.
  5. each cached element must be hash-based (hash selection will be critical to determine if it's globsl/per user/whatever).
  6. each cached element must have one TTL

(mostly taken from MDL25290, thanks Eloy!)

The real thing

These items have been relaxed or modified somewhat:

  • (Re #1) supports multiple backend types, one instance of each type is permitted
    • a backend implementation is a 'method', methods implement 'types'
    • e.g there is a 'shmem' cache type, which can be backed by either APC or XCache methods
  • (Re #2) most caches inside Moodle can use this system, some specialized cases may need to be exempted
  • (Re #3) disabling caching is supported, but static cache will remain active in this case for sanity
  • (Re #3) elements may disappear at any time from the cache, except static with no size constraint
  • (Re #4) Fallback is NOT required, but multiple backends are supported
  • (Re #5) callers must provide a unique key for elements, it is their job to form this according to context
    • Hashing if needed should be performed inside cache_methods, and collisions must NOT be visible to callers (check full keys too)
  • (Re #5) key length is a string with fixed maximum length
    • callers could wrap keys+values and store these with using a cache-key that is md5 of the full key
    • it should be possible to implement an optional extra layer (like the multicache) which does this for us
  • (Re #6) each cache (namespace/tag) has one TTL, NOT per-element

These changes minimise overheads in code and performance while permitting the most common cache uses.

Outline

Caches

The caching system shall provide access to a series of different caches, referenced by a tag.

Each cache may store many objects stored within which are referenced by a key and may utilise several backend storage methods.

Therefore, to refer to a particular cached element requires a (tag, key) pair.

Additional options such as default ttl or maximum desired cache size can be passed in an options array when the cache is created. These 'parameters' are (strong) advisory, and certain backends may ignore or override them where it is necessary.

Keys

Keys identify a particular element within a cache. Key collisions between elements are NOT allowed and will overwrite each other.

Keys are limited to 256 characters. If a longer key is required, use the 'md5' option. Internally, this packs the full key with data and validates the full key after it is retrieved from cache to stop collisions.

TODO: evaluate removing this limit

Methods

A cache method is a particular backend storage engine, these are categorised into types.

A cache method implements a single type, and each type may only have one active implementation. This means code inside moodle may request storage types such as static, database, sharedmem and doesn't need to know about all implementations, or which are available. Whichever method is chosen by the server admin (via $CFG) or default will be transparently used for storage.

Methods are implemented as a new plugin type, so they may be added, upgraded etc like any other plugin within moodle. This allows easy customisation and extension as needed. Core should gradually add the most useful methods by default.

Cache interface

Interface to the cache manager from moodle code, which allows to create/access caches and overall maintainance: class core_cache_manager {

   public static function init(); // returns the singleton
   public function get_cache($tag, array $types = array('static'), array $options = array());
   public function purge_all();
   public function cron();
   /* Magic methods for convienience */
   public function __isset($name);
   public function __get($name);

} $CACHE = core_cache_manager::init(); // in setup.php </syntaxhighlight>

The manager must be able to run a cron and purge for each method, as well as perform get/set operations, this necessitates the following interface for cache methods: interface cache_method_intf {

   public static function get_cache($tag, array $opts);
   public static function purge_all();
   public static function init(); // self-test and initialisation (e.g a DB connection), returns boolean
   public static function cron();
   public static function type();
   public function get($key);
   public function put($key, $value); // put(key, null) === remove(key)
   public function remove($key);
   public function clear();
   public function __get($name);
   public function __set($name, $value);
   public function __isset($name);
   public function __unset($name);

} </syntaxhighlight> ...moodle code outside the cache_manager should never touch the static functions, it is not necessary.

For easy implementation of the magic methods, each cache_method should extend this class instead: abstract class cache_method_base implements cache_method_intf {

   public function __get($name) {
       return $this->get($name);
   }
   public function __set($name, $value) {
       $this->put($name, $value);
   }
   public function __isset($name) {
       return $this->get($name) !== null;
   }
   public function __unset($name) {
       $this->remove($name);
   }

} </syntaxhighlight> This interface allows each method type to run a cron for cleanup purposes and purge_all for upgrades and the 'purge all caches' page.

Other

Things that didn't fit above.