MDL-40903 cache: converted persistent into persistentdata
authorSam Hemelryk <sam@moodle.com>
Thu, 1 Aug 2013 06:13:58 +0000 (18:13 +1200)
committerSam Hemelryk <sam@moodle.com>
Tue, 24 Sep 2013 21:04:35 +0000 (09:04 +1200)
At the same time all cache instances were made persistent

cache/README.md
cache/classes/definition.php
cache/classes/dummystore.php
cache/classes/factory.php
cache/classes/helper.php
cache/classes/loaders.php
cache/tests/cache_test.php
cache/tests/fixtures/lib.php
lib/db/caches.php

index c1f67c2..535d0e3 100644 (file)
@@ -24,7 +24,7 @@ A definition:
             'overrideclassfile' => null,              // Optional
             'datasource' => null,                     // Optional
             'datasourcefile' => null,                 // Optional
-            'persistent' => false,                    // Optional
+            'persistentdata' => false,                // Optional
             'persistentmaxsize' => false,             // Optional
             'ttl' => 0,                               // Optional
             'mappingsonly' => false                   // Optional
@@ -144,8 +144,8 @@ The following optional settings can also be defined:
 * overrideclassfile - Included if required when using the overrideclass param.
 * datasource - If provided this class will be used as a data source for the definition. It must implement the cache_data_source interface.
 * datasourcefile - Included if required when using the datasource param.
-* persistent - If set to true the loader will be stored when first created and provided to subsequent requests. More on this later.
-* persistentmaxsize - If set to an int this will be the maximum number of items stored in the persistent cache.
+* persistentdata - Any data passing through the cache will be held onto to make subsequent requests for it faster.
+* persistentmaxsize - If set to an int this will be the maximum number of items stored in the persistent data cache.
 * ttl - Can be used to set a ttl value for data being set for this cache.
 * mappingsonly - This definition can only be used if there is a store mapping for it. More on this later.
 * invalidationevents - An array of events that should trigger this cache to invalidate.
@@ -154,11 +154,10 @@ The following optional settings can also be defined:
 
 It's important to note that internally the definition is also aware of the component. This is picked up when the definition is read, based upon the location of the caches.php file.
 
-The persistent option.
-As noted the persistent option causes the loader generated for this definition to be stored when first created. Subsequent requests for this definition will be given the original loader instance.
+The persistentdata option.
 Data passed to or retrieved from the loader and its chained loaders gets cached by the instance.
-This option should be used when you know you will require the loader several times and perhaps in different areas of code.
 Because it caches key=>value data it avoids the need to re-fetch things from stores after the first request. Its good for performance, bad for memory.
+Memeory use can be controlled by setting the persistentmaxsize option.
 It should be used sparingly.
 
 The mappingsonly option.
index da5cd4c..f4d1ea9 100644 (file)
@@ -77,15 +77,10 @@ defined('MOODLE_INTERNAL') || die();
  *     + datasourcefile
  *          [string] Suplements the above setting indicated the file containing the class to be used. This file is included when
  *          required.
- *     + persistent
- *          [bool] This setting does two important things. First it tells the cache API to only instantiate the cache structure for
- *          this definition once, further requests will be given the original instance.
- *          Second the cache loader will keep an array of the items set and retrieved to the cache during the request.
- *          This has several advantages including better performance without needing to start passing the cache instance between
- *          function calls, the downside is that the cache instance + the items used stay within memory.
- *          Consider using this setting when you know that there are going to be many calls to the cache for the same information
- *          or when you are converting existing code to the cache and need to access the cache within functions but don't want
- *          to add it as an argument to the function.
+ *     + persistentdata
+ *          The cache loader will keep an array of the items set and retrieved to the cache during the request.
+ *          Consider using this setting when you know that there are going to be many calls to the cache for the same information.
+ *          Requests for data in this array will be ultra fast, but it will cost memory.
  *     + persistentmaxsize
  *          [int] This supplements the above setting by limiting the number of items in the caches persistent array of items.
  *          Tweaking this setting lower will allow you to minimise the memory implications above while hopefully still managing to
@@ -253,10 +248,10 @@ class cache_definition {
     protected $datasourceaggregate = null;
 
     /**
-     * Set to true if the definitions cache should be persistent
+     * Set to true if the cache should hold onto items passing through it to speed up subsequent requests.
      * @var bool
      */
-    protected $persistent = false;
+    protected $persistentdata = false;
 
     /**
      * The persistent item array max size.
@@ -363,7 +358,7 @@ class cache_definition {
         $overrideclassfile = null;
         $datasource = null;
         $datasourcefile = null;
-        $persistent = false;
+        $persistentdata = false;
         $persistentmaxsize = false;
         $ttl = 0;
         $mappingsonly = false;
@@ -419,7 +414,11 @@ class cache_definition {
         }
 
         if (array_key_exists('persistent', $definition)) {
-            $persistent = (bool)$definition['persistent'];
+            // Ahhh this is the legacy persistent option.
+            $persistentdata = (bool)$definition['persistent'];
+        }
+        if (array_key_exists('persistentdata', $definition)) {
+            $persistentdata = (bool)$definition['persistentdata'];
         }
         if (array_key_exists('persistentmaxsize', $definition)) {
             $persistentmaxsize = (int)$definition['persistentmaxsize'];
@@ -518,7 +517,7 @@ class cache_definition {
         $cachedefinition->datasource = $datasource;
         $cachedefinition->datasourcefile = $datasourcefile;
         $cachedefinition->datasourceaggregate = $datasourceaggregate;
-        $cachedefinition->persistent = $persistent;
+        $cachedefinition->persistentdata = $persistentdata;
         $cachedefinition->persistentmaxsize = $persistentmaxsize;
         $cachedefinition->ttl = $ttl;
         $cachedefinition->mappingsonly = $mappingsonly;
@@ -543,7 +542,8 @@ class cache_definition {
      *   - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
      *   - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
      *   - overrideclass : The class to use as the loader.
-     *   - persistent : If set to true the cache will persist construction requests.
+     *   - persistentdata : If set to true the cache will hold onto data passing through it.
+     *   - persistentmaxsize : Set it to an int to limit the size of the persistentdata cache.
      * @return cache_application|cache_session|cache_request
      */
     public static function load_adhoc($mode, $component, $area, array $options = array()) {
@@ -560,7 +560,14 @@ class cache_definition {
             $definition['simpledata'] = $options['simpledata'];
         }
         if (!empty($options['persistent'])) {
-            $definition['persistent'] = $options['persistent'];
+            // Ahhh this is the legacy persistent option.
+            $definition['persistentdata'] = (bool)$options['persistent'];
+        }
+        if (!empty($options['persistentdata'])) {
+            $definition['persistentdata'] = (bool)$options['persistentdata'];
+        }
+        if (!empty($options['persistentmaxsize'])) {
+            $definition['persistentmaxsize'] = (int)$options['persistentmaxsize'];
         }
         if (!empty($options['overrideclass'])) {
             $definition['overrideclass'] = $options['overrideclass'];
@@ -788,10 +795,26 @@ class cache_definition {
 
     /**
      * Returns true if this definitions cache should be made persistent.
+     *
+     * Please call data_should_be_persistent instead.
+     *
+     * @deprecated since 2.6
      * @return bool
      */
     public function should_be_persistent() {
-        return $this->persistent || $this->mode === cache_store::MODE_SESSION;
+        return $this->data_should_be_persistent();
+    }
+
+    /**
+     * Returns true if the cache loader for this definition should be persistent.
+     * @return bool
+     */
+    public function data_should_be_persistent() {
+        if ($this->mode === cache_store::MODE_REQUEST) {
+            // Request caches should never use persistent data - it just doesn't make sense.
+            return false;
+        }
+        return $this->persistentdata || $this->mode === cache_store::MODE_SESSION;
     }
 
     /**
index 43d9229..cc6fbb9 100644 (file)
@@ -112,7 +112,7 @@ class cachestore_dummy extends cache_store {
         //     store things in its persistent cache.
         //   - If the definition is not persistent then the cache loader won't try to store anything
         //     and we will need to store it here in order to make sure it is accessible.
-        $this->persist = !$definition->should_be_persistent();
+        $this->persist = !$definition->data_should_be_persistent();
     }
 
     /**
index 476ec0b..7860ac4 100644 (file)
@@ -150,9 +150,7 @@ class cache_factory {
      */
     public static function reset() {
         $factory = self::instance();
-        $factory->cachesfromdefinitions = array();
-        $factory->cachesfromparams = array();
-        $factory->stores = array();
+        $factory->reset_cache_instances();
         $factory->configs = array();
         $factory->definitions = array();
         $factory->lockplugins = array(); // MUST be null in order to force its regeneration.
@@ -160,6 +158,18 @@ class cache_factory {
         $factory->state = self::STATE_UNINITIALISED;
     }
 
+    /**
+     * Resets the stores, clearing the array of created stores.
+     *
+     * Cache objects still held onto by the code that initialised them will remain as is
+     * however all future requests for a cache/store will lead to a new instance being re-initialised.
+     */
+    public function reset_cache_instances() {
+        $this->cachesfromdefinitions = array();
+        $this->cachesfromparams = array();
+        $this->stores = array();
+    }
+
     /**
      * Creates a cache object given the parameters for a definition.
      *
@@ -181,9 +191,8 @@ class cache_factory {
         $definition = $this->create_definition($component, $area, $aggregate);
         $definition->set_identifiers($identifiers);
         $cache = $this->create_cache($definition, $identifiers);
-        if ($definition->should_be_persistent()) {
-            $this->cachesfromdefinitions[$definitionname] = $cache;
-        }
+        // Loaders are always held onto to speed up subsequent requests.
+        $this->cachesfromdefinitions[$definitionname] = $cache;
         return $cache;
     }
 
@@ -210,9 +219,7 @@ class cache_factory {
         $definition = cache_definition::load_adhoc($mode, $component, $area, $options);
         $definition->set_identifiers($identifiers);
         $cache = $this->create_cache($definition, $identifiers);
-        if ($definition->should_be_persistent()) {
-            $this->cachesfromparams[$key] = $cache;
-        }
+        $this->cachesfromparams[$key] = $cache;
         return $cache;
     }
 
@@ -585,7 +592,9 @@ class cache_factory {
      * </code>
      */
     public static function disable_stores() {
+        // First reset to clear any persistent caches.
         $factory = self::instance();
+        $factory->reset_cache_instances();
         $factory->set_state(self::STATE_STORES_DISABLED);
     }
 }
index 6f30b4b..15870ac 100644 (file)
@@ -244,7 +244,8 @@ class cache_helper {
                 // OK at this point we know that the definition has information to invalidate on the event.
                 // There are two routes, either its an application cache in which case we can invalidate it now.
                 // or it is a persistent cache that also needs to be invalidated now.
-                if ($definition->get_mode() === cache_store::MODE_APPLICATION || $definition->should_be_persistent()) {
+                $applicationcache = $definition->get_mode() === cache_store::MODE_APPLICATION;
+                if ($applicationcache || $definition->data_should_be_persistent()) {
                     $cache = $factory->create_cache_from_definition($definition->get_component(), $definition->get_area());
                     $cache->delete_many($keys);
                 }
@@ -315,8 +316,8 @@ class cache_helper {
         foreach ($instance->get_definitions() as $name => $definitionarr) {
             $definition = cache_definition::load($name, $definitionarr);
             if ($definition->invalidates_on_event($event)) {
-                // Check if this definition would result in a persistent loader being in use.
-                if ($definition->should_be_persistent()) {
+                // Check if this definition would result in a loader with persistent data being in use.
+                if ($definition->data_should_be_persistent()) {
                     // There may be a persistent cache loader. Lets purge that first so that any persistent data is removed.
                     $cache = $factory->create_cache_from_definition($definition->get_component(), $definition->get_area());
                     $cache->purge();
index 6de94e2..2973394 100644 (file)
@@ -99,7 +99,7 @@ class cache implements cache_loader {
      * There are several other variables to control how this persist cache works.
      * @var bool
      */
-    private $persist = false;
+    private $persistdata = false;
 
     /**
      * The persist cache itself.
@@ -218,8 +218,8 @@ class cache implements cache_loader {
             $this->datasource = $loader;
         }
         $this->definition->generate_definition_hash();
-        $this->persist = $this->definition->should_be_persistent();
-        if ($this->persist) {
+        $this->persistdata = $this->definition->data_should_be_persistent();
+        if ($this->persistdata) {
             $this->persistmaxsize = $this->definition->get_persistent_max_size();
         }
         $this->hasattl = ($this->definition->get_ttl() > 0);
@@ -239,12 +239,12 @@ class cache implements cache_loader {
         if ($setting) {
             $this->subloader = true;
             // Subloaders should not keep persistent data.
-            $this->persist = false;
+            $this->persistdata = false;
             $this->persistmaxsize = false;
         } else {
             $this->subloader = true;
-            $this->persist = $this->definition->should_be_persistent();
-            if ($this->persist) {
+            $this->persistdata = $this->definition->data_should_be_persistent();
+            if ($this->persistdata) {
                 $this->persistmaxsize = $this->definition->get_persistent_max_size();
             }
         }
@@ -913,7 +913,7 @@ class cache implements cache_loader {
      * @return bool
      */
     protected function is_using_persist_cache() {
-        return $this->persist;
+        return $this->persistdata;
     }
 
     /**
@@ -929,7 +929,7 @@ class cache implements cache_loader {
         }
         // This could be written as a single line, however it has been split because the ttl check is faster than the instanceof
         // and has_expired calls.
-        if (!$this->persist || !array_key_exists($key, $this->persistcache)) {
+        if (!$this->persistdata || !array_key_exists($key, $this->persistcache)) {
             return false;
         }
         if ($this->has_a_ttl() && $this->store_supports_native_ttl()) {
@@ -953,7 +953,7 @@ class cache implements cache_loader {
         // for null values, meaning null values will come from backing store not
         // the persist cache. We think this okay because null usage should be
         // very rare (see comment in MDL-39472).
-        if (!$this->persist || !isset($this->persistcache[$key])) {
+        if (!$this->persistdata || !isset($this->persistcache[$key])) {
             $result = false;
         } else {
             $data = $this->persistcache[$key];
index 23df737..701ec11 100644 (file)
@@ -149,7 +149,7 @@ class core_cache_testcase extends advanced_testcase {
             'mode' => cache_store::MODE_APPLICATION,
             'component' => 'phpunit',
             'area' => 'test_default_application_cache',
-            'persistent' => true,
+            'persistentdata' => true,
             'persistentmaxsize' => 1
         ));
         $cache = cache::make('phpunit', 'test_default_application_cache');
@@ -189,7 +189,7 @@ class core_cache_testcase extends advanced_testcase {
             'mode' => cache_store::MODE_APPLICATION,
             'component' => 'phpunit',
             'area' => 'nostoretest2',
-            'persistent' => true
+            'persistentdata' => true
         ));
         $instance->phpunit_remove_stores();
 
@@ -924,11 +924,11 @@ class core_cache_testcase extends advanced_testcase {
                 'crazyevent'
             )
         ));
-        $instance->phpunit_add_definition('phpunit/eventpurgetestpersistent', array(
+        $instance->phpunit_add_definition('phpunit/eventpurgetestpersistentapp', array(
             'mode' => cache_store::MODE_APPLICATION,
             'component' => 'phpunit',
-            'area' => 'eventpurgetestpersistent',
-            'persistent' => true,
+            'area' => 'eventpurgetestpersistentapp',
+            'persistentdata' => true,
             'invalidationevents' => array(
                 'crazyevent'
             )
@@ -948,7 +948,7 @@ class core_cache_testcase extends advanced_testcase {
         $this->assertFalse($cache->get('testkey2'));
 
         // Now test the persistent cache.
-        $cache = cache::make('phpunit', 'eventpurgetestpersistent');
+        $cache = cache::make('phpunit', 'eventpurgetestpersistentapp');
         $this->assertTrue($cache->set('testkey1', 'test data 1'));
         $this->assertEquals('test data 1', $cache->get('testkey1'));
         $this->assertTrue($cache->set('testkey2', 'test data 2'));
@@ -979,7 +979,7 @@ class core_cache_testcase extends advanced_testcase {
             'mode' => cache_store::MODE_SESSION,
             'component' => 'phpunit',
             'area' => 'eventpurgetestpersistent',
-            'persistent' => true,
+            'persistentdata' => true,
             'invalidationevents' => array(
                 'crazyevent'
             )
@@ -1400,7 +1400,7 @@ class core_cache_testcase extends advanced_testcase {
             'mode' => cache_store::MODE_APPLICATION,
             'component' => 'phpunit',
             'area' => 'test_application_locking',
-            'persistent' => true,
+            'persistentdata' => true,
             'persistentmaxsize' => 1,
             'requirelockingread' => true,
             'requirelockingwrite' => true
@@ -1535,4 +1535,4 @@ class core_cache_testcase extends advanced_testcase {
         $this->assertInstanceOf('cache_request', $cache);
         $this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
     }
-}
\ No newline at end of file
+}
index b6d7358..d999583 100644 (file)
@@ -251,6 +251,26 @@ class cache_phpunit_application extends cache_application {
     public function phpunit_get_store_implements() {
         return class_implements($this->get_store());
     }
+
+    /**
+     * Returns the given key directly from the persistdata cache.
+     *
+     * @param string $key
+     * @return false|mixed
+     */
+    public function phpunit_get_directly_from_persistcache($key) {
+        $key = $this->parse_key($key);
+        return $this->get_from_persist_cache($key);
+    }
+
+    /**
+     * Returns the cache loaders definition.
+     *
+     * @return cache_definition
+     */
+    public function phpunit_get_definition() {
+        return $this->get_definition();
+    }
 }
 
 /**
index 0b1a99d..688b986 100644 (file)
@@ -36,7 +36,7 @@ $definitions = array(
         'mode' => cache_store::MODE_APPLICATION,
         'simplekeys' => true,
         'simpledata' => true,
-        'persistent' => true,
+        'persistentdata' => true,
         'persistentmaxsize' => 30
     ),
 
@@ -58,7 +58,7 @@ $definitions = array(
         'requireidentifiers' => array(
             'dbfamily'
         ),
-        'persistent' => true,
+        'persistentdata' => true,
         'persistentmaxsize' => 15
     ),
 
@@ -71,7 +71,7 @@ $definitions = array(
     // cache will likely be used either lots or never.
     'eventinvalidation' => array(
         'mode' => cache_store::MODE_APPLICATION,
-        'persistent' => true,
+        'persistentdata' => true,
         'requiredataguarantee' => true,
         'simpledata' => true,
     ),
@@ -103,7 +103,7 @@ $definitions = array(
     // Persistence is used because normally several settings within a script.
     'config' => array(
         'mode' => cache_store::MODE_APPLICATION,
-        'persistent' => true,
+        'persistentdata' => true,
         'simpledata' => true
     ),
 
@@ -114,7 +114,7 @@ $definitions = array(
         'mode' => cache_store::MODE_APPLICATION,
         'simplekeys' => true, // The course id the groupings exist for.
         'simpledata' => true, // Array of stdClass objects containing only strings.
-        'persistent' => true, // Likely there will be a couple of calls to this.
+        'persistentdata' => true, // Likely there will be a couple of calls to this.
         'persistmaxsize' => 2, // The original cache used 1, we've increased that to two.
     ),
 
@@ -123,7 +123,7 @@ $definitions = array(
         'mode' => cache_store::MODE_APPLICATION,
         'simplekeys' => true,
         'simpledata' => true,
-        'persistent' => true,
+        'persistentdata' => true,
     ),
 
     // YUI Module cache.
@@ -137,7 +137,7 @@ $definitions = array(
         'mode' => cache_store::MODE_APPLICATION,
         'simplekeys' => true,
         'simpledata' => true,
-        'persistent' => true,
+        'persistentdata' => true,
         'persistentmaxsize' => 2,
     ),
 
@@ -147,46 +147,91 @@ $definitions = array(
         'mode' => cache_store::MODE_APPLICATION,
         'simplekeys' => true,
         'simpledata' => true,
-        'persistent' => false,
+        'persistentdata' => true,
+        'persistentmaxsize' => 2,
     ),
 
-    // Used to store the full tree of course categories
+    // Cache used by the {@link plugininfo_mod} class.
+    'plugininfo_mod' => array(
+        'mode' => cache_store::MODE_APPLICATION,
+        'simplekeys' => true,
+        'simpledata' => true,
+        'persistentdata' => true,
+        'persistentmaxsize' => 1,
+    ),
+
+    // Cache used by the {@link plugininfo_block} class.
+    'plugininfo_block' => array(
+        'mode' => cache_store::MODE_APPLICATION,
+        'simplekeys' => true,
+        'simpledata' => true,
+        'persistentdata' => true,
+        'persistentmaxsize' => 1,
+    ),
+
+    // Cache used by the {@link plugininfo_filter} class.
+    'plugininfo_filter' => array(
+        'mode' => cache_store::MODE_APPLICATION,
+        'simplekeys' => true,
+        'simpledata' => true,
+        'persistentdata' => true,
+        'persistentmaxsize' => 1,
+    ),
+
+    // Cache used by the {@link plugininfo_repository} class.
+    'plugininfo_repository' => array(
+        'mode' => cache_store::MODE_APPLICATION,
+        'simplekeys' => true,
+        'simpledata' => true,
+        'persistentdata' => true,
+        'persistentmaxsize' => 1,
+    ),
+
+    // Cache used by the {@link plugininfo_portfolio} class.
+    'plugininfo_portfolio' => array(
+        'mode' => cache_store::MODE_APPLICATION,
+        'simplekeys' => true,
+        'simpledata' => true,
+        'persistentdata' => true,
+        'persistentmaxsize' => 1,
+>>>>>>> MDL-40903 cache: converted persistent into persistentdata
+    ),
+
+    // Used to store the full tree of course categories.
     'coursecattree' => array(
         'mode' => cache_store::MODE_APPLICATION,
-        'persistent' => true,
+        'persistentdata' => true,
         'invalidationevents' => array(
             'changesincoursecat',
         )
     ),
-    // Used to store data for course categories visible to current user. Helps to browse list of categories
+    // Used to store data for course categories visible to current user. Helps to browse list of categories.
     'coursecat' => array(
         'mode' => cache_store::MODE_SESSION,
-        'persistent' => true,
+        'persistentdata' => true,
         'invalidationevents' => array(
             'changesincoursecat',
             'changesincourse',
         ),
         'ttl' => 600,
     ),
-    // Used to store data for course categories visible to current user. Helps to browse list of categories
+    // Used to store data for course categories visible to current user. Helps to browse list of categories.
     'coursecatrecords' => array(
         'mode' => cache_store::MODE_REQUEST,
         'simplekeys' => true,
-        'persistent' => true,
         'invalidationevents' => array(
             'changesincoursecat',
         ),
     ),
-    // Cache course contacts for the courses
+    // Cache course contacts for the courses.
     'coursecontacts' => array(
         'mode' => cache_store::MODE_APPLICATION,
-        'persistent' => true,
+        'persistentdata' => true,
         'simplekeys' => true,
     ),
-    // Used to store data for repositories to avoid repetitive DB queries within one request
+    // Used to store data for repositories to avoid repetitive DB queries within one request.
     'repositories' => array(
         'mode' => cache_store::MODE_REQUEST,
-        'persistent' => true,
     ),
     // Used to store external badges.
     'externalbadges' => array(