Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch '40903-24' of git://github.com/samhemelryk/moodle into M…

…OODLE_24_STABLE
  • Loading branch information...
commit b152769f448e9a5320133e678ef10020fbea03de 2 parents 77b4970 + f621e8e
@stronk7 stronk7 authored
View
15 cache/README.md
@@ -24,8 +24,8 @@ A definition:
'overrideclassfile' => null, // Optional
'datasource' => null, // Optional
'datasourcefile' => null, // Optional
- 'persistent' => false, // Optional
- 'persistentmaxsize' => false, // Optional
+ 'staticacceleration' => false, // Optional
+ 'staticaccelerationsize' => false, // Optional
'ttl' => 0, // Optional
'mappingsonly' => false // Optional
'invalidationevents' => array( // Optional
@@ -142,19 +142,18 @@ 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.
+* staticacceleration - Any data passing through the cache will be held onto to make subsequent requests for it faster.
+* staticaccelerationsize - If set to an int this will be the maximum number of items stored in the static acceleration array.
* 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.
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 persist option.
-As noted the persist 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 staticacceleration 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.
+Memory use can be controlled by setting the staticaccelerationsize option.
It should be used sparingly.
The mappingsonly option.
@@ -227,4 +226,4 @@ Cache information can be invalidated in two ways.
The first method is designed to be used when you have a single known definition you want to invalidate entries within.
The second method is a lot more intensive for the system. There are defined invalidation events that definitions can "subscribe" to (through the definitions invalidationevents option).
When you invalidate by event the cache API finds all of the definitions that subscribe to the event, it then loads the stores for each of those definitions and purges the keys from each store.
-This is obviously a recursive, and therefore, intense process.
View
102 cache/classes/definition.php
@@ -75,19 +75,14 @@
* [string] A class to use as the data loader for this definition.
* Any class used here must inherit the cache_data_loader interface.
* + datasourcefile
- * [string] Suplements the above setting indicated the file containing the class to be used. This file is included when
+ * [string] Supplements the above setting indicating 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.
- * + persistentmaxsize
- * [int] This supplements the above setting by limiting the number of items in the caches persistent array of items.
+ * + staticacceleration
+ * 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.
+ * + staticaccelerationsize
+ * [int] This supplements the above setting by limiting the number of items in the static acceleration array.
* Tweaking this setting lower will allow you to minimise the memory implications above while hopefully still managing to
* offset calls to the cache store.
* + ttl
@@ -228,16 +223,16 @@ 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 $staticacceleration = false;
/**
- * The persistent item array max size.
+ * The maximum number of items that static acceleration cache should hold onto.
* @var int
*/
- protected $persistentmaxsize = false;
+ protected $staticaccelerationsize = false;
/**
* The TTL for data in this cache. Please don't use this, instead use event driven invalidation.
@@ -320,8 +315,8 @@ public static function load($id, array $definition, $datasourceaggregate = null)
$overrideclassfile = null;
$datasource = null;
$datasourcefile = null;
- $persistent = false;
- $persistentmaxsize = false;
+ $staticacceleration = false;
+ $staticaccelerationsize = false;
$ttl = 0;
$mappingsonly = false;
$invalidationevents = array();
@@ -373,10 +368,18 @@ public static function load($id, array $definition, $datasourceaggregate = null)
}
if (array_key_exists('persistent', $definition)) {
- $persistent = (bool)$definition['persistent'];
+ // Ahhh this is the legacy persistent option.
+ $staticacceleration = (bool)$definition['persistent'];
+ }
+ if (array_key_exists('staticacceleration', $definition)) {
+ $staticacceleration = (bool)$definition['staticacceleration'];
}
if (array_key_exists('persistentmaxsize', $definition)) {
- $persistentmaxsize = (int)$definition['persistentmaxsize'];
+ // Ahhh this is the legacy persistentmaxsize option.
+ $staticaccelerationsize = (int)$definition['persistentmaxsize'];
+ }
+ if (array_key_exists('staticaccelerationsize', $definition)) {
+ $staticaccelerationsize = (int)$definition['staticaccelerationsize'];
}
if (array_key_exists('ttl', $definition)) {
$ttl = (int)$definition['ttl'];
@@ -452,8 +455,8 @@ public static function load($id, array $definition, $datasourceaggregate = null)
$cachedefinition->datasource = $datasource;
$cachedefinition->datasourcefile = $datasourcefile;
$cachedefinition->datasourceaggregate = $datasourceaggregate;
- $cachedefinition->persistent = $persistent;
- $cachedefinition->persistentmaxsize = $persistentmaxsize;
+ $cachedefinition->staticacceleration = $staticacceleration;
+ $cachedefinition->staticaccelerationsize = $staticaccelerationsize;
$cachedefinition->ttl = $ttl;
$cachedefinition->mappingsonly = $mappingsonly;
$cachedefinition->invalidationevents = $invalidationevents;
@@ -474,7 +477,8 @@ public static function load($id, array $definition, $datasourceaggregate = null)
* - 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.
+ * - staticacceleration : If set to true the cache will hold onto data passing through it.
+ * - staticaccelerationsize : Set it to an int to limit the size of the staticacceleration cache.
* @return cache_application|cache_session|cache_request
*/
public static function load_adhoc($mode, $component, $area, array $options = array()) {
@@ -491,7 +495,14 @@ public static function load_adhoc($mode, $component, $area, array $options = arr
$definition['simpledata'] = $options['simpledata'];
}
if (!empty($options['persistent'])) {
- $definition['persistent'] = $options['persistent'];
+ // Ahhh this is the legacy persistent option.
+ $definition['staticacceleration'] = (bool)$options['persistent'];
+ }
+ if (!empty($options['staticacceleration'])) {
+ $definition['staticacceleration'] = (bool)$options['staticacceleration'];
+ }
+ if (!empty($options['staticaccelerationsize'])) {
+ $definition['staticaccelerationsize'] = (int)$options['staticaccelerationsize'];
}
if (!empty($options['overrideclass'])) {
$definition['overrideclass'] = $options['overrideclass'];
@@ -716,18 +727,53 @@ public function get_requirements_bin() {
/**
* Returns true if this definitions cache should be made persistent.
+ *
+ * Please call {@link cache_definition::use_static_acceleration()} instead.
+ *
+ * @deprecated since 2.4.7
* @return bool
*/
public function should_be_persistent() {
- return $this->persistent || $this->mode === cache_store::MODE_SESSION;
+ debugging('Please upgrade your code to use cache_definition::use_static_acceleration', DEBUG_DEVELOPER);
+ return $this->use_static_acceleration();
+ }
+
+ /**
+ * Returns true if we should hold onto the data flowing through the cache.
+ *
+ * If set to true data flowing through the cache will be stored in a static variable
+ * to make subsequent requests for the data much faster.
+ *
+ * @return bool
+ */
+ public function use_static_acceleration() {
+ if ($this->mode === cache_store::MODE_REQUEST) {
+ // Request caches should never use static acceleration - it just doesn't make sense.
+ return false;
+ }
+ return $this->staticacceleration || $this->mode === cache_store::MODE_SESSION;
}
/**
- * Returns the max size for the persistent item array in the cache.
+ * Returns the max size for the static acceleration array.
+ *
+ * Please call {@link cache_definition::get_static_acceleration_size()} instead.
+ *
+ * @see cache_definition::get_static_acceleration_size()
+ * @deprecated since 2.4.7
* @return int
*/
public function get_persistent_max_size() {
- return $this->persistentmaxsize;
+ debugging('Please upgrade your code to call cache_definition::get_static_acceleration_size', DEBUG_DEVELOPER);
+ return $this->get_static_acceleration_size();
+ }
+
+ /**
+ * Returns the max size for the static acceleration array.
+ * @return int
+ */
+ public function get_static_acceleration_size() {
+ return $this->staticaccelerationsize;
}
/**
@@ -821,4 +867,4 @@ public function get_invalidation_events() {
protected function get_cache_identifier() {
return cache_helper::get_site_identifier();
}
-}
View
17 cache/classes/dummystore.php
@@ -46,14 +46,15 @@ class cachestore_dummy extends cache_store {
protected $name;
/**
- * Gets set to true if this store is going to persist data.
- * This happens when the definition doesn't require it as the loader will not be persisting information and something has to.
+ * Gets set to true if this store is going to store data.
+ * This happens when the definition doesn't require static acceleration as the loader will not be storing information and
+ * something has to.
* @var bool
*/
protected $persist = false;
/**
- * The persistent store array
+ * The stored data array
* @var array
*/
protected $store = array();
@@ -106,13 +107,13 @@ public static function get_supported_modes(array $configuration = array()) {
* @param cache_definition $definition
*/
public function initialise(cache_definition $definition) {
- // If the definition isn't persistent then we need to be persistent here.
+ // If the definition isn't using static acceleration then we need to be store data here.
// The reasoning behind this is that:
- // - If the definition is persistent then the cache loader is going to
- // store things in its persistent cache.
- // - If the definition is not persistent then the cache loader won't try to store anything
+ // - If the definition is using static acceleration then the cache loader is going to
+ // store things in its static array.
+ // - If the definition is not using static acceleration 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->use_static_acceleration();
}
/**
View
39 cache/classes/factory.php
@@ -150,9 +150,7 @@ protected function __construct() {
*/
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.
@@ -161,6 +159,18 @@ public static function reset() {
}
/**
+ * 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.
*
* If a cache has already been created for the given definition then that cache instance will be returned.
@@ -181,9 +191,8 @@ public function create_cache_from_definition($component, $area, array $identifie
$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;
}
@@ -199,7 +208,8 @@ public function create_cache_from_definition($component, $area, array $identifie
* @param array $options An array of options, available options are:
* - 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
- * - persistent : If set to true the cache will persist construction requests.
+ * - staticacceleration : If set to true the cache will hold onto data passing through it.
+ * - staticaccelerationsize : The maximum number of items to hold onto for acceleration purposes.
* @return cache_application|cache_session|cache_request
*/
public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
@@ -210,9 +220,7 @@ public function create_cache_from_params($mode, $component, $area, array $identi
$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;
}
@@ -298,6 +306,15 @@ public function get_store_instances_in_use(cache_definition $definition) {
}
/**
+ * Returns the cache instances that have been used within this request.
+ * @since 2.4.7
+ * @return array
+ */
+ public function get_caches_in_use() {
+ return $this->cachesfromdefinitions;
+ }
+
+ /**
* Creates a cache config instance with the ability to write if required.
*
* @param bool $writer If set to true an instance that can update the configuration will be returned.
@@ -585,7 +602,9 @@ public function stores_disabled() {
* </code>
*/
public static function disable_stores() {
+ // First reset to clear any static acceleration array.
$factory = self::instance();
+ $factory->reset_cache_instances();
$factory->set_state(self::STATE_STORES_DISABLED);
}
}
View
47 cache/classes/helper.php
@@ -238,19 +238,24 @@ public static function invalidate_by_event($event, array $keys) {
$instance = cache_config::instance();
$invalidationeventset = false;
$factory = cache_factory::instance();
+ $inuse = $factory->get_caches_in_use();
foreach ($instance->get_definitions() as $name => $definitionarr) {
$definition = cache_definition::load($name, $definitionarr);
if ($definition->invalidates_on_event($event)) {
- // 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()) {
- $cache = $factory->create_cache_from_definition($definition->get_component(), $definition->get_area());
- $cache->delete_many($keys);
+ // First up check if there is a cache loader for this definition already.
+ // If there is we need to invalidate the keys from there.
+ $definitionkey = $definition->get_component().'/'.$definition->get_area();
+ if (isset($inuse[$definitionkey])) {
+ $inuse[$definitionkey]->delete_many($keys);
}
- // We need to flag the event in the "Event invalidation" cache if it hasn't already happened.
- if ($invalidationeventset === false) {
+ // We should only log events for application and session caches.
+ // Request caches shouldn't have events as all data is lost at the end of the request.
+ // Events should only be logged once of course and likely several definitions are watching so we
+ // track its logging with $invalidationeventset.
+ $logevent = ($invalidationeventset === false && $definition->get_mode() !== cache_store::MODE_REQUEST);
+
+ if ($logevent) {
// Get the event invalidation cache.
$cache = cache::make('core', 'eventinvalidation');
// Get any existing invalidated keys for this cache.
@@ -307,23 +312,25 @@ public static function purge_by_event($event) {
$instance = cache_config::instance();
$invalidationeventset = false;
$factory = cache_factory::instance();
+ $inuse = $factory->get_caches_in_use();
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()) {
- // 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();
- }
- // Get all of the store instances that are in use for this store.
- $stores = $factory->get_store_instances_in_use($definition);
- foreach ($stores as $store) {
- // Purge each store individually.
- $store->purge();
+ // First up check if there is a cache loader for this definition already.
+ // If there is we need to invalidate the keys from there.
+ $definitionkey = $definition->get_component().'/'.$definition->get_area();
+ if (isset($inuse[$definitionkey])) {
+ $inuse[$definitionkey]->purge();
}
+
+ // We should only log events for application and session caches.
+ // Request caches shouldn't have events as all data is lost at the end of the request.
+ // Events should only be logged once of course and likely several definitions are watching so we
+ // track its logging with $invalidationeventset.
+ $logevent = ($invalidationeventset === false && $definition->get_mode() !== cache_store::MODE_REQUEST);
+
// We need to flag the event in the "Event invalidation" cache if it hasn't already happened.
- if ($invalidationeventset === false) {
+ if ($logevent && $invalidationeventset === false) {
// Get the event invalidation cache.
$cache = cache::make('core', 'eventinvalidation');
// Create a key to invalidate all.
View
151 cache/classes/loaders.php
@@ -93,43 +93,46 @@ class cache implements cache_loader {
private $supportsnativettl = null;
/**
- * Gets set to true if the cache is going to be using the build in static "persist" cache.
- * The persist cache statically caches items used during the lifetime of the request. This greatly speeds up interaction
+ * Gets set to true if the cache is going to be using a static array for acceleration.
+ * The array statically caches items used during the lifetime of the request. This greatly speeds up interaction
* with the cache in areas where it will be repetitively hit for the same information such as with strings.
- * There are several other variables to control how this persist cache works.
+ * There are several other variables to control how this static acceleration array works.
* @var bool
*/
- private $persist = false;
+ private $staticacceleration = false;
/**
- * The persist cache itself.
+ * The static acceleration array.
* Items will be stored in this cache as they were provided. This ensure there is no unnecessary processing taking place.
* @var array
*/
- private $persistcache = array();
+ private $staticaccelerationarray = array();
/**
- * The number of items in the persist cache. Avoids count calls like you wouldn't believe.
+ * The number of items in the static acceleration array. Avoids count calls like you wouldn't believe.
* @var int
*/
- private $persistcount = 0;
+ private $staticaccelerationcount = 0;
/**
- * An array containing just the keys being used in the persist cache.
- * This seems redundant perhaps but is used when managing the size of the persist cache.
+ * An array containing just the keys being used in the static acceleration array.
+ * This seems redundant perhaps but is used when managing the size of the static acceleration array.
* Items are added to the end of the array and the when we need to reduce the size of the cache we use the
* key that is first on this array.
* @var array
*/
- private $persistkeys = array();
+ private $staticaccelerationkeys = array();
/**
- * The maximum size of the persist cache. If set to false there is no max size.
- * Caches that make use of the persist cache should seriously consider setting this to something reasonably small, but
+ * The maximum size of the static acceleration array.
+ *
+ * If set to false there is no max size.
+ * Caches that make use of static acceleration should seriously consider setting this to something reasonably small, but
* still large enough to offset repetitive calls.
+ *
* @var int|false
*/
- private $persistmaxsize = false;
+ private $staticaccelerationsize = false;
/**
* Gets set to true during initialisation if the definition is making use of a ttl.
@@ -181,7 +184,8 @@ public static function make($component, $area, array $identifiers = array(), $ag
* @param array $options An array of options, available options are:
* - 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
- * - persistent : If set to true the cache will persist construction requests.
+ * - staticacceleration : If set to true the cache will hold onto data passing through it.
+ * - staticaccelerationsize : The max size for the static acceleration array.
* @return cache_application|cache_session|cache_store
*/
public static function make_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
@@ -218,9 +222,9 @@ public function __construct(cache_definition $definition, cache_store $store, $l
$this->datasource = $loader;
}
$this->definition->generate_definition_hash();
- $this->persist = $this->definition->should_be_persistent();
- if ($this->persist) {
- $this->persistmaxsize = $this->definition->get_persistent_max_size();
+ $this->staticacceleration = $this->definition->use_static_acceleration();
+ if ($this->staticacceleration) {
+ $this->staticaccelerationsize = $this->definition->get_static_acceleration_size();
}
$this->hasattl = ($this->definition->get_ttl() > 0);
}
@@ -228,7 +232,7 @@ public function __construct(cache_definition $definition, cache_store $store, $l
/**
* Used to inform the loader of its state as a sub loader, or as the top of the chain.
*
- * This is important as it ensures that we do not have more than one loader keeping persistent data.
+ * This is important as it ensures that we do not have more than one loader keeping static acceleration data.
* Subloaders need to be "pure" loaders in the sense that they are used to store and retrieve information from stores or the
* next loader/data source in the chain.
* Nothing fancy, nothing flash.
@@ -238,14 +242,14 @@ public function __construct(cache_definition $definition, cache_store $store, $l
protected function set_is_sub_loader($setting = true) {
if ($setting) {
$this->subloader = true;
- // Subloaders should not keep persistent data.
- $this->persist = false;
- $this->persistmaxsize = false;
+ // Subloaders should not keep static acceleration data.
+ $this->staticacceleration = false;
+ $this->staticaccelerationsize = false;
} else {
$this->subloader = true;
- $this->persist = $this->definition->should_be_persistent();
- if ($this->persist) {
- $this->persistmaxsize = $this->definition->get_persistent_max_size();
+ $this->staticacceleration = $this->definition->use_static_acceleration();
+ if ($this->staticacceleration) {
+ $this->staticaccelerationsize = $this->definition->get_static_acceleration_size();
}
}
}
@@ -276,7 +280,7 @@ public function set_identifiers(array $identifiers) {
public function get($key, $strictness = IGNORE_MISSING) {
// 1. Parse the key.
$parsedkey = $this->parse_key($key);
- // 2. Get it from the persist cache if we can (only when persist is enabled and it has already been requested/set).
+ // 2. Get it from the static acceleration array if we can (only when it is enabled and it has already been requested/set).
$result = false;
if ($this->is_using_persist_cache()) {
$result = $this->get_from_persist_cache($parsedkey);
@@ -291,7 +295,7 @@ public function get($key, $strictness = IGNORE_MISSING) {
}
return $result;
}
- // 3. Get it from the store. Obviously wasn't in the persist cache.
+ // 3. Get it from the store. Obviously wasn't in the static acceleration array.
$result = $this->store->get($parsedkey);
if ($result !== false) {
if ($result instanceof cache_ttl_wrapper) {
@@ -404,6 +408,9 @@ public function get_many(array $keys, $strictness = IGNORE_MISSING) {
if ($value instanceof cache_cached_object) {
$value = $value->restore_object();
}
+ if ($value !== false && $this->is_using_persist_cache()) {
+ $this->set_in_persist_cache($key, $value);
+ }
$resultstore[$key] = $value;
}
}
@@ -604,7 +611,7 @@ public function set_many(array $keyvaluearray) {
}
$data = array();
$simulatettl = $this->has_a_ttl() && !$this->store_supports_native_ttl();
- $usepersistcache = $this->is_using_persist_cache();
+ $usestaticaccelerationarray = $this->is_using_persist_cache();
foreach ($keyvaluearray as $key => $value) {
if (is_object($value) && $value instanceof cacheable_object) {
$value = new cache_cached_object($value);
@@ -622,7 +629,7 @@ public function set_many(array $keyvaluearray) {
'key' => $this->parse_key($key),
'value' => $value
);
- if ($usepersistcache) {
+ if ($usestaticaccelerationarray) {
$this->set_in_persist_cache($data[$key]['key'], $value);
}
}
@@ -656,7 +663,7 @@ public function set_many(array $keyvaluearray) {
public function has($key, $tryloadifpossible = false) {
$parsedkey = $this->parse_key($key);
if ($this->is_in_persist_cache($parsedkey)) {
- // Hoorah, that was easy. It exists in the persist cache so we definitely have it.
+ // Hoorah, that was easy. It exists in the static acceleration array so we definitely have it.
return true;
}
if ($this->has_a_ttl() && !$this->store_supports_native_ttl()) {
@@ -798,8 +805,12 @@ public function delete_many(array $keys, $recurse = true) {
* @return bool True on success, false otherwise
*/
public function purge() {
- // 1. Purge the persist cache.
- $this->persistcache = array();
+ // 1. Purge the static acceleration array.
+ $this->staticaccelerationarray = array();
+ if ($this->staticaccelerationsize !== false) {
+ $this->staticaccelerationkeys = array();
+ $this->staticaccelerationcount = 0;
+ }
// 2. Purge the store.
$this->store->purge();
// 3. Optionally pruge any stacked loaders.
@@ -908,16 +919,16 @@ protected function store_supports_native_locking() {
}
/**
- * Returns true if this cache is making use of the persist cache.
+ * Returns true if this cache is making use of the static acceleration array.
*
* @return bool
*/
protected function is_using_persist_cache() {
- return $this->persist;
+ return $this->staticacceleration;
}
/**
- * Returns true if the requested key exists within the persist cache.
+ * Returns true if the requested key exists within the static acceleration array.
*
* @param string $key The parsed key
* @return bool
@@ -929,20 +940,21 @@ protected function is_in_persist_cache($key) {
}
// 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->staticacceleration || !array_key_exists($key, $this->staticaccelerationarray)) {
return false;
}
if ($this->has_a_ttl() && $this->store_supports_native_ttl()) {
- return !($this->persistcache[$key] instanceof cache_ttl_wrapper && $this->persistcache[$key]->has_expired());
+ return !($this->staticaccelerationarray[$key] instanceof cache_ttl_wrapper &&
+ $this->staticaccelerationarray[$key]->has_expired());
}
return true;
}
/**
- * Returns the item from the persist cache if it exists there.
+ * Returns the item from the static acceleration array if it exists there.
*
* @param string $key The parsed key
- * @return mixed|false The data from the persist cache or false if it wasn't there.
+ * @return mixed|false The data from the static acceleration array or false if it wasn't there.
*/
protected function get_from_persist_cache($key) {
// This method of checking if an array was supplied is faster than is_array.
@@ -951,12 +963,12 @@ protected function get_from_persist_cache($key) {
}
// This isset check is faster than array_key_exists but will return false
// for null values, meaning null values will come from backing store not
- // the persist cache. We think this okay because null usage should be
+ // the static acceleration array. 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->staticacceleration || !isset($this->staticaccelerationarray[$key])) {
$result = false;
} else {
- $data = $this->persistcache[$key];
+ $data = $this->staticaccelerationarray[$key];
if (!$this->has_a_ttl() || !$data instanceof cache_ttl_wrapper) {
if ($data instanceof cache_cached_object) {
$data = $data->restore_object();
@@ -974,28 +986,28 @@ protected function get_from_persist_cache($key) {
}
if ($result) {
if ($this->perfdebug) {
- cache_helper::record_cache_hit('** static persist **', $this->definition->get_id());
+ cache_helper::record_cache_hit('** static acceleration **', $this->definition->get_id());
}
- if ($this->persistmaxsize > 1 && $this->persistcount > 1) {
- // Check to see if this is the last item on the persist keys array.
- if (end($this->persistkeys) !== $key) {
+ if ($this->staticaccelerationsize > 1 && $this->staticaccelerationcount > 1) {
+ // Check to see if this is the last item on the static acceleration keys array.
+ if (end($this->staticaccelerationkeys) !== $key) {
// It isn't the last item.
// Move the item to the end of the array so that it is last to be removed.
- unset($this->persistkeys[$key]);
- $this->persistkeys[$key] = $key;
+ unset($this->staticaccelerationkeys[$key]);
+ $this->staticaccelerationkeys[$key] = $key;
}
}
return $result;
} else {
if ($this->perfdebug) {
- cache_helper::record_cache_miss('** static persist **', $this->definition->get_id());
+ cache_helper::record_cache_miss('** static acceleration **', $this->definition->get_id());
}
return false;
}
}
/**
- * Sets a key value pair into the persist cache.
+ * Sets a key value pair into the static acceleration array.
*
* @param string $key The parsed key
* @param mixed $data
@@ -1006,32 +1018,36 @@ protected function set_in_persist_cache($key, $data) {
if ($key === (array)$key) {
$key = $key['key'];
}
- $this->persistcache[$key] = $data;
- if ($this->persistmaxsize !== false) {
- $this->persistcount++;
- $this->persistkeys[$key] = $key;
- if ($this->persistcount > $this->persistmaxsize) {
- $dropkey = array_shift($this->persistkeys);
- unset($this->persistcache[$dropkey]);
- $this->persistcount--;
+ if ($this->staticaccelerationsize !== false && isset($this->staticaccelerationkeys[$key])) {
+ $this->staticaccelerationcount--;
+ unset($this->staticaccelerationkeys[$key]);
+ }
+ $this->staticaccelerationarray[$key] = $data;
+ if ($this->staticaccelerationsize !== false) {
+ $this->staticaccelerationcount++;
+ $this->staticaccelerationkeys[$key] = $key;
+ if ($this->staticaccelerationcount > $this->staticaccelerationsize) {
+ $dropkey = array_shift($this->staticaccelerationkeys);
+ unset($this->staticaccelerationarray[$dropkey]);
+ $this->staticaccelerationcount--;
}
}
return true;
}
/**
- * Deletes an item from the persist cache.
+ * Deletes an item from the static acceleration array.
*
* @param string|int $key As given to get|set|delete
* @return bool True on success, false otherwise.
*/
protected function delete_from_persist_cache($key) {
- unset($this->persistcache[$key]);
- if ($this->persistmaxsize !== false) {
- $dropkey = array_search($key, $this->persistkeys);
+ unset($this->staticaccelerationarray[$key]);
+ if ($this->staticaccelerationsize !== false) {
+ $dropkey = array_search($key, $this->staticaccelerationkeys);
if ($dropkey) {
- unset($this->persistkeys[$dropkey]);
- $this->persistcount--;
+ unset($this->staticaccelerationkeys[$dropkey]);
+ $this->staticaccelerationcount--;
}
}
return true;
@@ -1448,9 +1464,8 @@ public function delete_many(array $keys, $recurse = true) {
* This class is used for session caches returned by the cache::make methods.
*
* It differs from the application loader in a couple of noteable ways:
- * 1. Sessions are always expected to be persistent.
- * Because of this we don't ever use the persist cache and instead a session array
- * containing all of the data is maintained by this object.
+ * 1. Sessions are always expected to exist.
+ * Because of this we don't ever use the static acceleration array.
* 2. Session data for a loader instance (store + definition) is consolidate into a
* single array for storage within the store.
* Along with this we embed a lastaccessed time with the data. This way we can
@@ -2063,7 +2078,7 @@ public function has_any(array $keys) {
}
/**
- * The session loader never uses the persist cache.
+ * The session loader never uses static acceleration.
* Instead it stores things in the static $session variable. Shared between all session loaders.
*
* @return bool
View
6 cache/disabledlib.php
@@ -49,8 +49,7 @@ class cache_disabled extends cache {
* @param null $loader Unused.
*/
public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
- $this->definition = $definition;
- $this->store = $store;
+ // Nothing to do here.
}
/**
@@ -228,7 +227,8 @@ public function create_cache_from_definition($component, $area, array $identifie
* @param array $options An array of options, available options are:
* - 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
- * - persistent : If set to true the cache will persist construction requests.
+ * - staticacceleration : If set to true the cache will hold onto all data passing through it.
+ * - staticaccelerationsize : Sets the max size of the static acceleration array.
* @return cache_application|cache_session|cache_request
*/
public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
View
188 cache/tests/cache_test.php
@@ -149,8 +149,8 @@ public function test_default_application_cache() {
'mode' => cache_store::MODE_APPLICATION,
'component' => 'phpunit',
'area' => 'test_default_application_cache',
- 'persistent' => true,
- 'persistentmaxsize' => 1
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 1
));
$cache = cache::make('phpunit', 'test_default_application_cache');
$this->assertInstanceOf('cache_application', $cache);
@@ -189,7 +189,7 @@ public function test_on_cache_without_store() {
'mode' => cache_store::MODE_APPLICATION,
'component' => 'phpunit',
'area' => 'nostoretest2',
- 'persistent' => true
+ 'staticacceleration' => true
));
$instance->phpunit_remove_stores();
@@ -907,11 +907,11 @@ public function test_application_event_purge() {
'crazyevent'
)
));
- $instance->phpunit_add_definition('phpunit/eventpurgetestpersistent', array(
+ $instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array(
'mode' => cache_store::MODE_APPLICATION,
'component' => 'phpunit',
- 'area' => 'eventpurgetestpersistent',
- 'persistent' => true,
+ 'area' => 'eventpurgetestaccelerated',
+ 'staticacceleration' => true,
'invalidationevents' => array(
'crazyevent'
)
@@ -930,8 +930,8 @@ public function test_application_event_purge() {
$this->assertFalse($cache->get('testkey1'));
$this->assertFalse($cache->get('testkey2'));
- // Now test the persistent cache.
- $cache = cache::make('phpunit', 'eventpurgetestpersistent');
+ // Now test the static acceleration array.
+ $cache = cache::make('phpunit', 'eventpurgetestaccelerated');
$this->assertTrue($cache->set('testkey1', 'test data 1'));
$this->assertEquals('test data 1', $cache->get('testkey1'));
$this->assertTrue($cache->set('testkey2', 'test data 2'));
@@ -958,11 +958,11 @@ public function test_session_event_purge() {
'crazyevent'
)
));
- $instance->phpunit_add_definition('phpunit/eventpurgetestpersistent', array(
+ $instance->phpunit_add_definition('phpunit/eventpurgetestaccelerated', array(
'mode' => cache_store::MODE_SESSION,
'component' => 'phpunit',
- 'area' => 'eventpurgetestpersistent',
- 'persistent' => true,
+ 'area' => 'eventpurgetestaccelerated',
+ 'staticacceleration' => true,
'invalidationevents' => array(
'crazyevent'
)
@@ -981,8 +981,8 @@ public function test_session_event_purge() {
$this->assertFalse($cache->get('testkey1'));
$this->assertFalse($cache->get('testkey2'));
- // Now test the persistent cache.
- $cache = cache::make('phpunit', 'eventpurgetestpersistent');
+ // Now test the static acceleration array.
+ $cache = cache::make('phpunit', 'eventpurgetestaccelerated');
$this->assertTrue($cache->set('testkey1', 'test data 1'));
$this->assertEquals('test data 1', $cache->get('testkey1'));
$this->assertTrue($cache->set('testkey2', 'test data 2'));
@@ -1383,8 +1383,8 @@ public function test_application_locking() {
'mode' => cache_store::MODE_APPLICATION,
'component' => 'phpunit',
'area' => 'test_application_locking',
- 'persistent' => true,
- 'persistentmaxsize' => 1,
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 1,
'requirelockingread' => true,
'requirelockingwrite' => true
));
@@ -1449,4 +1449,162 @@ public function test_defaults_support_searching() {
$this->assertInstanceOf('cache_request', $cache);
$this->assertArrayHasKey('cache_is_searchable', $cache->phpunit_get_store_implements());
}
+
+ public function test_static_acceleration() {
+ $instance = cache_config_phpunittest::instance();
+ $instance->phpunit_add_definition('phpunit/accelerated', array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'component' => 'phpunit',
+ 'area' => 'accelerated',
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 3,
+ ));
+ $instance->phpunit_add_definition('phpunit/accelerated2', array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'component' => 'phpunit',
+ 'area' => 'accelerated2',
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 3,
+ ));
+ $instance->phpunit_add_definition('phpunit/accelerated3', array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'component' => 'phpunit',
+ 'area' => 'accelerated3',
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 3,
+ ));
+ $instance->phpunit_add_definition('phpunit/accelerated4', array(
+ 'mode' => cache_store::MODE_APPLICATION,
+ 'component' => 'phpunit',
+ 'area' => 'accelerated4',
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 4,
+ ));
+ $cache = cache::make('phpunit', 'accelerated');
+ $this->assertInstanceOf('cache_phpunit_application', $cache);
+
+ // Set and get three elements.
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('b', 'B'));
+ $this->assertTrue($cache->set('c', 'C'));
+ $this->assertEquals('A', $cache->get('a'));
+ $this->assertEquals(array('b' => 'B', 'c' => 'C'), $cache->get_many(array('b', 'c')));
+
+ // Make sure all items are in static acceleration array.
+ $this->assertEquals('A', $cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertEquals('B', $cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+
+ // Add new value and make sure it is in cache and it is in array.
+ $this->assertTrue($cache->set('d', 'D'));
+ $this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+ $this->assertEquals('D', $cache->get('d'));
+
+ // Now the least recent accessed item (a) is no longer in acceleration array.
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertEquals('B', $cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+
+ // Adding and deleting element.
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->delete('a'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertFalse($cache->has('a'));
+
+ // Make sure "purge" deletes from the array as well.
+ $cache->purge();
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('e'));
+
+ // Check that the array holds the last accessed items by get/set.
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('b', 'B'));
+ $this->assertTrue($cache->set('c', 'C'));
+ $this->assertTrue($cache->set('d', 'D'));
+ $this->assertTrue($cache->set('e', 'E'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+ $this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+ $this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
+
+ /** @var cache_phpunit_application $cache */
+ $cache = cache::make('phpunit', 'accelerated2');
+ $this->assertInstanceOf('cache_phpunit_application', $cache);
+
+ // Check that the array holds the last accessed items by get/set.
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('b', 'B'));
+ $this->assertTrue($cache->set('c', 'C'));
+ $this->assertTrue($cache->set('d', 'D'));
+ $this->assertTrue($cache->set('e', 'E'));
+ // Current keys in the array: c, d, e.
+ $this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+ $this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+ $this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+
+ $this->assertEquals('A', $cache->get('a'));
+ // Current keys in the array: d, e, a.
+ $this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+ $this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
+ $this->assertEquals('A', $cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+
+ // Current keys in the array: d, e, a.
+ $this->assertEquals(array('c' => 'C'), $cache->get_many(array('c')));
+ // Current keys in the array: e, a, c.
+ $this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
+ $this->assertEquals('A', $cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+
+
+ $cache = cache::make('phpunit', 'accelerated3');
+ $this->assertInstanceOf('cache_phpunit_application', $cache);
+
+ // Check that the array holds the last accessed items by get/set.
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('b', 'B'));
+ $this->assertTrue($cache->set('c', 'C'));
+ $this->assertTrue($cache->set('d', 'D'));
+ $this->assertTrue($cache->set('e', 'E'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertEquals('C', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+ $this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+ $this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
+
+ $this->assertTrue($cache->set('b', 'B2'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertEquals('B2', $cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+ $this->assertEquals('D', $cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+ $this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
+
+ $this->assertEquals(2, $cache->set_many(array('b' => 'B3', 'c' => 'C3')));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertEquals('B3', $cache->phpunit_get_directly_from_staticaccelerationarray('b'));
+ $this->assertEquals('C3', $cache->phpunit_get_directly_from_staticaccelerationarray('c'));
+ $this->assertFalse($cache->phpunit_get_directly_from_staticaccelerationarray('d'));
+ $this->assertEquals('E', $cache->phpunit_get_directly_from_staticaccelerationarray('e'));
+
+ $cache = cache::make('phpunit', 'accelerated4');
+ $this->assertInstanceOf('cache_phpunit_application', $cache);
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertTrue($cache->set('a', 'A'));
+ $this->assertEquals('A', $cache->phpunit_get_directly_from_staticaccelerationarray('a'));
+ $this->assertEquals('A', $cache->get('a'));
+ }
}
View
11 cache/tests/fixtures/lib.php
@@ -243,6 +243,17 @@ public function phpunit_get_store_class() {
public function phpunit_get_store_implements() {
return class_implements($this->get_store());
}
+
+ /**
+ * Returns the given key directly from the static acceleration array.
+ *
+ * @param string $key
+ * @return false|mixed
+ */
+ public function phpunit_get_directly_from_staticaccelerationarray($key) {
+ $key = $this->parse_key($key);
+ return $this->get_from_persist_cache($key);
+ }
}
/**
View
12 cache/upgrade.txt
@@ -1,8 +1,16 @@
This files describes API changes in /cache/stores/* - cache store plugins.
Information provided here is intended especially for developers.
-=== 2.5 ===
+=== 2.4.7 ===
+* All cache instances are recorded and subsequent requests are given a reference to the original instance.
+* The persistent option for the cache definition has been deprecated. Please use the staticacceleration option instead.
+* There is a new static acceleration option. If enabled data passing through the cache is held onto.
+* The persistentmaxsize option has been renamed to staticaccelerationsize. It does the same thing.
+* cache_definition::should_be_persistent has been deprecated. Please call cache_definition::use_static_acceleration instead.
+* cache_definition::get_persistent_max_size has been deprecated. Please call cache_definition::get_static_acceleration_size instead.
+
+=== 2.4.2 ===
* cleanup method renamed to instance_deleted.
It is now called when the store is deleted as all comments suggested anyway.
* instance_created method added.
- It is called when the store is created for the very first time.
+ It is called when the store is created for the very first time.
View
10 lib/db/caches.php
@@ -35,8 +35,8 @@
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true,
'simpledata' => true,
- 'persistent' => true,
- 'persistentmaxsize' => 30
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 30
),
// Used to store database meta information.
@@ -48,8 +48,8 @@
'requireidentifiers' => array(
'dbfamily'
),
- 'persistent' => true,
- 'persistentmaxsize' => 15
+ 'staticacceleration' => true,
+ 'staticaccelerationsize' => 15
),
// Event invalidation cache.
@@ -61,7 +61,7 @@
// cache will likely be used either lots or never.
'eventinvalidation' => array(
'mode' => cache_store::MODE_APPLICATION,
- 'persistent' => true,
+ 'staticacceleration' => true,
'requiredataguarantee' => true,
'simpledata' => true,
),
Please sign in to comment.
Something went wrong with that request. Please try again.