Merge branch 'wip-MDL-40677-m26' of git://github.com/samhemelryk/moodle

This commit is contained in:
Eloy Lafuente (stronk7)
2013-07-23 12:52:50 +02:00
4 changed files with 285 additions and 7 deletions
+69 -3
View File
@@ -116,6 +116,18 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
*/
protected $ttl = 0;
/**
* The maximum size for the store, or false if there isn't one.
* @var bool
*/
protected $maxsize = false;
/**
* The number of items currently being stored.
* @var int
*/
protected $storecount = 0;
/**
* Constructs the store instance.
*
@@ -192,6 +204,12 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
$this->storeid = $definition->generate_definition_hash();
$this->store = &self::register_store_id($definition->get_id());
$this->ttl = $definition->get_ttl();
$maxsize = $definition->get_maxsize();
if ($maxsize !== null) {
// Must be a positive int.
$this->maxsize = abs((int)$maxsize);
$this->storecount = count($this->store);
}
}
/**
@@ -261,14 +279,25 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
*
* @param string $key The key to use.
* @param mixed $data The data to set.
* @param bool $testmaxsize If set to true then we test the maxsize arg and reduce if required.
* @return bool True if the operation was a success false otherwise.
*/
public function set($key, $data) {
public function set($key, $data, $testmaxsize = true) {
$testmaxsize = ($testmaxsize && $this->maxsize !== false);
if ($testmaxsize) {
$increment = (!isset($this->store[$key]));
}
if ($this->ttl == 0) {
$this->store[$key][0] = $data;
} else {
$this->store[$key] = array($data, cache::now());
}
if ($testmaxsize && $increment) {
$this->storecount++;
if ($this->storecount > $this->maxsize) {
$this->reduce_for_maxsize();
}
}
return true;
}
@@ -283,9 +312,15 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
public function set_many(array $keyvaluearray) {
$count = 0;
foreach ($keyvaluearray as $pair) {
$this->set($pair['key'], $pair['value']);
$this->set($pair['key'], $pair['value'], false);
$count++;
}
if ($this->maxsize !== false) {
$this->storecount += $count;
if ($this->storecount > $this->maxsize) {
$this->reduce_for_maxsize();
}
}
return $count;
}
@@ -356,6 +391,9 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
public function delete($key) {
$result = isset($this->store[$key]);
unset($this->store[$key]);
if ($this->maxsize !== false) {
$this->storecount--;
}
return $result;
}
@@ -373,6 +411,9 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
}
unset($this->store[$key]);
}
if ($this->maxsize !== false) {
$this->storecount -= $count;
}
return $count;
}
@@ -383,9 +424,34 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
*/
public function purge() {
$this->store = array();
// Don't worry about checking if we're using max size just set it as thats as fast as the check.
$this->storecount = 0;
return true;
}
/**
* Reduces the size of the array if maxsize has been hit.
*
* This function reduces the size of the store reducing it by 10% of its maxsize.
* It removes the oldest items in the store when doing this.
* The reason it does this an doesn't use a least recently used system is purely the overhead such a system
* requires. The current approach is focused on speed, MUC already adds enough overhead to static/session caches
* and avoiding more is of benefit.
*
* @return int
*/
protected function reduce_for_maxsize() {
$diff = $this->storecount - $this->maxsize;
if ($diff < 1) {
return 0;
}
// Reduce it by an extra 10% to avoid calling this repetitively if we are in a loop.
$diff += floor($this->maxsize / 10);
$this->store = array_slice($this->store, $diff, null, true);
$this->storecount -= $diff;
return $diff;
}
/**
* Returns true if the user can add an instance of the store plugin.
*
@@ -406,7 +472,7 @@ class cachestore_session extends session_data_store implements cache_is_key_awar
* Generates an instance of the cache store that can be used for testing.
*
* @param cache_definition $definition
* @return false
* @return cachestore_session
*/
public static function initialise_test_instance(cache_definition $definition) {
// Do something here perhaps.
+72
View File
@@ -44,4 +44,76 @@ class cachestore_session_test extends cachestore_tests {
protected function get_class_name() {
return 'cachestore_session';
}
/**
* Test the maxsize option.
*/
public function test_maxsize() {
$defid = 'phpunit/testmaxsize';
$config = cache_config_phpunittest::instance();
$config->phpunit_add_definition($defid, array(
'mode' => cache_store::MODE_SESSION,
'component' => 'phpunit',
'area' => 'testmaxsize',
'maxsize' => 3
));
$definition = cache_definition::load($defid, $config->get_definition_by_id($defid));
$instance = cachestore_session::initialise_test_instance($definition);
$this->assertTrue($instance->set('key1', 'value1'));
$this->assertTrue($instance->set('key2', 'value2'));
$this->assertTrue($instance->set('key3', 'value3'));
$this->assertTrue($instance->has('key1'));
$this->assertTrue($instance->has('key2'));
$this->assertTrue($instance->has('key3'));
$this->assertTrue($instance->set('key4', 'value4'));
$this->assertTrue($instance->set('key5', 'value5'));
$this->assertFalse($instance->has('key1'));
$this->assertFalse($instance->has('key2'));
$this->assertTrue($instance->has('key3'));
$this->assertTrue($instance->has('key4'));
$this->assertTrue($instance->has('key5'));
$this->assertFalse($instance->get('key1'));
$this->assertFalse($instance->get('key2'));
$this->assertEquals('value3', $instance->get('key3'));
$this->assertEquals('value4', $instance->get('key4'));
$this->assertEquals('value5', $instance->get('key5'));
// Test adding one more.
$this->assertTrue($instance->set('key6', 'value6'));
$this->assertFalse($instance->get('key3'));
// Test reducing and then adding to make sure we don't lost one.
$this->assertTrue($instance->delete('key6'));
$this->assertTrue($instance->set('key7', 'value7'));
$this->assertEquals('value4', $instance->get('key4'));
// Set the same key three times to make sure it doesn't count overrides.
for ($i = 0; $i < 3; $i++) {
$this->assertTrue($instance->set('key8', 'value8'));
}
$this->assertEquals('value7', $instance->get('key7'), 'Overrides are incorrectly incrementing size');
// Test adding many.
$this->assertEquals(3, $instance->set_many(array(
array('key' => 'keyA', 'value' => 'valueA'),
array('key' => 'keyB', 'value' => 'valueB'),
array('key' => 'keyC', 'value' => 'valueC')
)));
$this->assertEquals(array(
'key4' => false,
'key5' => false,
'key6' => false,
'key7' => false,
'keyA' => 'valueA',
'keyB' => 'valueB',
'keyC' => 'valueC'
), $instance->get_many(array(
'key4', 'key5', 'key6', 'key7', 'keyA', 'keyB', 'keyC'
)));
}
}
+70 -3
View File
@@ -112,6 +112,18 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
*/
protected $ttl = 0;
/**
* The maximum size for the store, or false if there isn't one.
* @var bool
*/
protected $maxsize = false;
/**
* The number of items currently being stored.
* @var int
*/
protected $storecount = 0;
/**
* Constructs the store instance.
*
@@ -188,6 +200,12 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
$this->storeid = $definition->generate_definition_hash();
$this->store = &self::register_store_id($this->storeid);
$this->ttl = $definition->get_ttl();
$maxsize = $definition->get_maxsize();
if ($maxsize !== null) {
// Must be a positive int.
$this->maxsize = abs((int)$maxsize);
$this->storecount = count($this->store);
}
}
/**
@@ -257,14 +275,25 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
*
* @param string $key The key to use.
* @param mixed $data The data to set.
* @param bool $testmaxsize If set to true then we test the maxsize arg and reduce if required.
* @return bool True if the operation was a success false otherwise.
*/
public function set($key, $data) {
public function set($key, $data, $testmaxsize = true) {
$testmaxsize = ($testmaxsize && $this->maxsize !== false);
if ($testmaxsize) {
$increment = (!isset($this->store[$key]));
}
if ($this->ttl == 0) {
$this->store[$key][0] = $data;
} else {
$this->store[$key] = array($data, cache::now());
}
if ($testmaxsize && $increment) {
$this->storecount++;
if ($this->storecount > $this->maxsize) {
$this->reduce_for_maxsize();
}
}
return true;
}
@@ -279,9 +308,16 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
public function set_many(array $keyvaluearray) {
$count = 0;
foreach ($keyvaluearray as $pair) {
$this->set($pair['key'], $pair['value']);
// Don't test the maxsize here. We'll do it once when we are done.
$this->set($pair['key'], $pair['value'], false);
$count++;
}
if ($this->maxsize !== false) {
$this->storecount += $count;
if ($this->storecount > $this->maxsize) {
$this->reduce_for_maxsize();
}
}
return $count;
}
@@ -352,6 +388,9 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
public function delete($key) {
$result = isset($this->store[$key]);
unset($this->store[$key]);
if ($this->maxsize !== false) {
$this->storecount--;
}
return $result;
}
@@ -369,6 +408,9 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
}
unset($this->store[$key]);
}
if ($this->maxsize !== false) {
$this->storecount -= $count;
}
return $count;
}
@@ -380,9 +422,34 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
public function purge() {
$this->flush_store_by_id($this->storeid);
$this->store = &self::register_store_id($this->storeid);
// Don't worry about checking if we're using max size just set it as thats as fast as the check.
$this->storecount = 0;
return true;
}
/**
* Reduces the size of the array if maxsize has been hit.
*
* This function reduces the size of the store reducing it by 10% of its maxsize.
* It removes the oldest items in the store when doing this.
* The reason it does this an doesn't use a least recently used system is purely the overhead such a system
* requires. The current approach is focused on speed, MUC already adds enough overhead to static/session caches
* and avoiding more is of benefit.
*
* @return int
*/
protected function reduce_for_maxsize() {
$diff = $this->storecount - $this->maxsize;
if ($diff < 1) {
return 0;
}
// Reduce it by an extra 10% to avoid calling this repetitively if we are in a loop.
$diff += floor($this->maxsize / 10);
$this->store = array_slice($this->store, $diff, null, true);
$this->storecount -= $diff;
return $diff;
}
/**
* Returns true if the user can add an instance of the store plugin.
*
@@ -403,7 +470,7 @@ class cachestore_static extends static_data_store implements cache_is_key_aware,
* Generates an instance of the cache store that can be used for testing.
*
* @param cache_definition $definition
* @return false
* @return cachestore_static
*/
public static function initialise_test_instance(cache_definition $definition) {
// Do something here perhaps.
+74 -1
View File
@@ -1,5 +1,5 @@
<?php
// This static is part of Moodle - http://moodle.org/
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -44,4 +44,77 @@ class cachestore_static_test extends cachestore_tests {
protected function get_class_name() {
return 'cachestore_static';
}
/**
* Test the maxsize option.
*/
public function test_maxsize() {
$defid = 'phpunit/testmaxsize';
$config = cache_config_phpunittest::instance();
$config->phpunit_add_definition($defid, array(
'mode' => cache_store::MODE_REQUEST,
'component' => 'phpunit',
'area' => 'testmaxsize',
'maxsize' => 3
));
$definition = cache_definition::load($defid, $config->get_definition_by_id($defid));
$instance = cachestore_static::initialise_test_instance($definition);
$this->assertTrue($instance->set('key1', 'value1'));
$this->assertTrue($instance->set('key2', 'value2'));
$this->assertTrue($instance->set('key3', 'value3'));
$this->assertTrue($instance->has('key1'));
$this->assertTrue($instance->has('key2'));
$this->assertTrue($instance->has('key3'));
$this->assertTrue($instance->set('key4', 'value4'));
$this->assertTrue($instance->set('key5', 'value5'));
$this->assertFalse($instance->has('key1'));
$this->assertFalse($instance->has('key2'));
$this->assertTrue($instance->has('key3'));
$this->assertTrue($instance->has('key4'));
$this->assertTrue($instance->has('key5'));
$this->assertFalse($instance->get('key1'));
$this->assertFalse($instance->get('key2'));
$this->assertEquals('value3', $instance->get('key3'));
$this->assertEquals('value4', $instance->get('key4'));
$this->assertEquals('value5', $instance->get('key5'));
// Test adding one more.
$this->assertTrue($instance->set('key6', 'value6'));
$this->assertFalse($instance->get('key3'));
// Test reducing and then adding to make sure we don't lost one.
$this->assertTrue($instance->delete('key6'));
$this->assertTrue($instance->set('key7', 'value7'));
$this->assertEquals('value4', $instance->get('key4'));
// Set the same key three times to make sure it doesn't count overrides.
for ($i = 0; $i < 3; $i++) {
$this->assertTrue($instance->set('key8', 'value8'));
}
$this->assertEquals('value7', $instance->get('key7'), 'Overrides are incorrectly incrementing size');
// Test adding many.
$this->assertEquals(3, $instance->set_many(array(
array('key' => 'keyA', 'value' => 'valueA'),
array('key' => 'keyB', 'value' => 'valueB'),
array('key' => 'keyC', 'value' => 'valueC')
)));
$this->assertEquals(array(
'key4' => false,
'key5' => false,
'key6' => false,
'key7' => false,
'keyA' => 'valueA',
'keyB' => 'valueB',
'keyC' => 'valueC'
), $instance->get_many(array(
'key4', 'key5', 'key6', 'key7', 'keyA', 'keyB', 'keyC'
)));
}
}