Skip to content

Commit

Permalink
MDL-55922 cache: Improve static cache performance
Browse files Browse the repository at this point in the history
Static cache has a very flexible storage capability
and does not need all the checks performed on it.
Enabling dereferencing handling and multiple identifiers
removes a lot of unneeded overhead for request caches that
have many get calls.

The changes were modelled on the static acceleration changes
done in MDL-53208.
  • Loading branch information
mr-russ committed Sep 12, 2016
1 parent 0344082 commit ec4b83b
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 46 deletions.
3 changes: 3 additions & 0 deletions cache/classes/loaders.php
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,9 @@ public function get_many(array $keys, $strictness = IGNORE_MISSING) {
$isusingpersist = $this->use_static_acceleration();
foreach ($keys as $key) {
$pkey = $this->parse_key($key);
if (is_array($pkey)) {
$pkey = $pkey['key'];
}
$keysparsed[$key] = $pkey;
$parsedkeys[$pkey] = $key;
$keystofind[$pkey] = $key;
Expand Down
113 changes: 67 additions & 46 deletions cache/stores/static/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,17 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
*/
protected $store;

/**
* The ttl if there is one. Hopefully not.
* @var int
*/
protected $ttl = 0;

/**
* The maximum size for the store, or false if there isn't one.
* @var bool
*/
protected $maxsize = false;

/**
* Where this cache uses simpledata and we don't need to serialize it.
* @var bool
*/
protected $simpledata = false;
/**
* The number of items currently being stored.
* @var int
Expand Down Expand Up @@ -146,18 +145,20 @@ public function __construct($name, array $configuration = array()) {
public static function get_supported_features(array $configuration = array()) {
return self::SUPPORTS_DATA_GUARANTEE +
self::SUPPORTS_NATIVE_TTL +
self::IS_SEARCHABLE;
self::IS_SEARCHABLE +
self::SUPPORTS_MULTIPLE_IDENTIFIERS +
self::DEREFERENCES_OBJECTS;
}

/**
* Returns false as this store does not support multiple identifiers.
* Returns true as this store does support multiple identifiers.
* (This optional function is a performance optimisation; it must be
* consistent with the value from get_supported_features.)
*
* @return bool False
* @return bool true
*/
public function supports_multiple_identifiers() {
return false;
return true;
}

/**
Expand Down Expand Up @@ -197,10 +198,11 @@ public static function is_supported_mode($mode) {
* @param cache_definition $definition
*/
public function initialise(cache_definition $definition) {
$this->storeid = $definition->generate_definition_hash();
$keyarray = $definition->generate_multi_key_parts();
$this->storeid = $keyarray['mode'].'/'.$keyarray['component'].'/'.$keyarray['area'].'/'.$keyarray['siteidentifier'];
$this->store = &self::register_store_id($this->storeid);
$this->ttl = $definition->get_ttl();
$maxsize = $definition->get_maxsize();
$this->simpledata = $definition->uses_simple_data();
if ($maxsize !== null) {
// Must be a positive int.
$this->maxsize = abs((int)$maxsize);
Expand All @@ -224,11 +226,16 @@ public function is_initialised() {
* @return mixed The data that was associated with the key, or false if the key did not exist.
*/
public function get($key) {
if (!is_array($key)) {
$key = array('key' => $key);
}

$key = $key['key'];
if (isset($this->store[$key])) {
if ($this->ttl == 0) {
return $this->store[$key][0];
} else if ($this->store[$key][1] >= (cache::now() - $this->ttl)) {
return $this->store[$key][0];
if ($this->store[$key]['serialized']) {
return unserialize($this->store[$key]['data']);
} else {
return $this->store[$key]['data'];
}
}
return false;
Expand All @@ -245,17 +252,18 @@ public function get($key) {
*/
public function get_many($keys) {
$return = array();
if ($this->ttl != 0) {
$maxtime = cache::now() - $this->ttl;
}

foreach ($keys as $key) {
if (!is_array($key)) {
$key = array('key' => $key);
}
$key = $key['key'];
$return[$key] = false;
if (isset($this->store[$key])) {
if ($this->ttl == 0) {
$return[$key] = $this->store[$key][0];
} else if ($this->store[$key][1] >= $maxtime) {
$return[$key] = $this->store[$key][0];
if ($this->store[$key]['serialized']) {
$return[$key] = unserialize($this->store[$key]['data']);
} else {
$return[$key] = $this->store[$key]['data'];
}
}
}
Expand All @@ -271,15 +279,23 @@ public function get_many($keys) {
* @return bool True if the operation was a success false otherwise.
*/
public function set($key, $data, $testmaxsize = true) {
if (!is_array($key)) {
$key = array('key' => $key);
}
$key = $key['key'];
$testmaxsize = ($testmaxsize && $this->maxsize !== false);
if ($testmaxsize) {
$increment = (!isset($this->store[$key]));
}
if ($this->ttl == 0) {
$this->store[$key][0] = $data;

if ($this->simpledata || is_scalar($data)) {
$this->store[$key]['data'] = $data;
$this->store[$key]['serialized'] = false;
} else {
$this->store[$key] = array($data, cache::now());
$this->store[$key]['data'] = serialize($data);
$this->store[$key]['serialized'] = true;
}

if ($testmaxsize && $increment) {
$this->storecount++;
if ($this->storecount > $this->maxsize) {
Expand All @@ -300,8 +316,11 @@ public function set($key, $data, $testmaxsize = true) {
public function set_many(array $keyvaluearray) {
$count = 0;
foreach ($keyvaluearray as $pair) {
if (!is_array($pair['key'])) {
$pair['key'] = array('key' => $pair['key']);
}
// Don't test the maxsize here. We'll do it once when we are done.
$this->set($pair['key'], $pair['value'], false);
$this->set($pair['key']['key'], $pair['value'], false);
$count++;
}
if ($this->maxsize !== false) {
Expand All @@ -320,14 +339,10 @@ public function set_many(array $keyvaluearray) {
* @return bool
*/
public function has($key) {
if (isset($this->store[$key])) {
if ($this->ttl == 0) {
return true;
} else if ($this->store[$key][1] >= (cache::now() - $this->ttl)) {
return true;
}
if (is_array($key)) {
$key = $key['key'];
}
return false;
return isset($this->store[$key]);
}

/**
Expand All @@ -337,15 +352,12 @@ public function has($key) {
* @return bool
*/
public function has_all(array $keys) {
if ($this->ttl != 0) {
$maxtime = cache::now() - $this->ttl;
}

foreach ($keys as $key) {
if (!isset($this->store[$key])) {
return false;
if (!is_array($key)) {
$key = array('key' => $key);
}
if ($this->ttl != 0 && $this->store[$key][1] < $maxtime) {
$key = $key['key'];
if (!isset($this->store[$key])) {
return false;
}
}
Expand All @@ -359,12 +371,13 @@ public function has_all(array $keys) {
* @return bool
*/
public function has_any(array $keys) {
if ($this->ttl != 0) {
$maxtime = cache::now() - $this->ttl;
}

foreach ($keys as $key) {
if (isset($this->store[$key]) && ($this->ttl == 0 || $this->store[$key][1] >= $maxtime)) {
if (!is_array($key)) {
$key = array('key' => $key);
}
$key = $key['key'];

if (isset($this->store[$key])) {
return true;
}
}
Expand All @@ -378,6 +391,10 @@ public function has_any(array $keys) {
* @return bool Returns true if the operation was a success, false otherwise.
*/
public function delete($key) {
if (!is_array($key)) {
$key = array('key' => $key);
}
$key = $key['key'];
$result = isset($this->store[$key]);
unset($this->store[$key]);
if ($this->maxsize !== false) {
Expand All @@ -395,6 +412,10 @@ public function delete($key) {
public function delete_many(array $keys) {
$count = 0;
foreach ($keys as $key) {
if (!is_array($key)) {
$key = array('key' => $key);
}
$key = $key['key'];
if (isset($this->store[$key])) {
$count++;
}
Expand Down
9 changes: 9 additions & 0 deletions cache/tests/fixtures/stores.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public function test_test_instance() {
* Test the store for basic functionality.
*/
public function run_tests(cache_store $instance) {
$object = new stdClass;
$object->data = 1;

// Test set with a string.
$this->assertTrue($instance->set('test1', 'test1'));
Expand Down Expand Up @@ -113,6 +115,13 @@ public function run_tests(cache_store $instance) {
$this->assertSame(true, $instance->get('test1'));
$this->assertInternalType('boolean', $instance->get('test1'));

// Test with an object.
$this->assertTrue($instance->set('obj', $object));
if ($instance::get_supported_features() & cache_store::DEREFERENCES_OBJECTS) {
$this->assertNotSame($object, $instance->get('obj'), 'Objects must be dereferenced when returned.');
}
$this->assertEquals($object, $instance->get('obj'));

// Test delete.
$this->assertTrue($instance->delete('test1'));
$this->assertTrue($instance->delete('test3'));
Expand Down

0 comments on commit ec4b83b

Please sign in to comment.