Commit 15f0e033 by Scott

Refactor cache handler

Move functionality to FileCacheDriver, strip down manager class
parent 5c554165
<?php
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/Q2A/Storage/CacheManager.php
Description: Handler for caching system.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
/**
* Caches data (typically from database queries) to the filesystem.
*/
class Q2A_Storage_CacheFactory
{
/**
* Get the appropriate cache handler.
* @return Q2A_Storage_CacheInterface The cache handler.
*/
public static function getCacheDriver()
{
$config = array(
'enabled' => (int) qa_opt('caching_enabled') === 1,
'dir' => defined('QA_CACHE_DIRECTORY') ? QA_CACHE_DIRECTORY : null,
);
return new Q2A_Storage_FileCacheDriver($config);
}
}
<?php
/*
Question2Answer by Gideon Greenspan and contributors
http://www.question2answer.org/
File: qa-include/Q2A/Storage/CacheManager.php
Description: Handler for caching system.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
More about this license: http://www.question2answer.org/license.php
*/
/**
* Caches data (typically from database queries) to the filesystem.
*/
class Q2A_Storage_CacheManager
{
private static $instance;
private $enabled = false;
private $cacheDriver;
/**
* Creates a new CacheManager instance and sets up the cache driver.
*/
private function __construct()
{
if (qa_opt('caching_enabled') != 1)
return;
$config = array(
'dir' => defined('QA_CACHE_DIRECTORY') ? QA_CACHE_DIRECTORY : null,
);
$this->cacheDriver = new Q2A_Storage_FileCache($config);
$this->enabled = $this->cacheDriver->isEnabled();
}
/**
* Initializes the class and returns the singleton.
* @return Q2A_Storage_CacheManager
*/
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Get the cached data for the supplied key.
* @param string $key The unique cache identifier
* @return mixed The cached data, or null otherwise.
*/
public function get($key)
{
if ($this->enabled) {
$encData = $this->cacheDriver->get($key);
// retrieve data, ignoring any notices
$data = @unserialize($encData);
if ($data !== false) {
return $data;
}
}
return null;
}
/**
* Serialize some data and store it in the cache.
* @param string $key The unique cache identifier
* @param mixed $data The data to cache - must be scalar values (i.e. string, int, array).
* @param int $ttl Number of minutes for which to cache the data.
* @return bool Whether the data was successfully cached.
*/
public function set($key, $data, $ttl)
{
if ($this->enabled) {
$encData = serialize($data);
return $this->cacheDriver->set($key, $encData, $ttl);
}
return false;
}
/**
* Whether caching is available.
* @return bool
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* Get the last error.
* @return string
*/
public function getError()
{
return isset($this->cacheDriver) ? $this->cacheDriver->getError() : '';
}
}
......@@ -23,7 +23,7 @@
/**
* Caches data (typically from database queries) to the filesystem.
*/
class Q2A_Storage_FileCache
class Q2A_Storage_FileCacheDriver
{
private $enabled = false;
private $error;
......@@ -35,6 +35,10 @@ class Q2A_Storage_FileCache
*/
public function __construct($config)
{
if (!$config['enabled']) {
return;
}
if (isset($config['dir'])) {
$this->cacheDir = realpath($config['dir']);
......@@ -58,6 +62,10 @@ class Q2A_Storage_FileCache
*/
public function get($key)
{
if (!$this->enabled) {
return null;
}
$file = $this->getFilename($key);
if (is_readable($file)) {
......@@ -69,7 +77,12 @@ class Q2A_Storage_FileCache
$expiry = array_shift($lines);
if (is_numeric($expiry) && time() < $expiry) {
return implode("\n", $lines);
$encData = implode("\n", $lines);
// decode data, ignoring any notices
$data = @unserialize($encData);
if ($data !== false) {
return $data;
}
}
}
}
......@@ -78,23 +91,24 @@ class Q2A_Storage_FileCache
}
/**
* Store a string (usually serialized data) in the cache along with the key and expiry time.
* Store something in the cache along with the key and expiry time. Data gets 'serialized' to a string before storing.
* @param string $key The unique cache identifier.
* @param string $str The data to cache (usually a serialized string).
* @param mixed $data The data to cache (in core Q2A this is usually an array).
* @param int $ttl Number of minutes for which to cache the data.
* @return bool Whether the file was successfully cached.
*/
public function set($key, $str, $ttl)
public function set($key, $data, $ttl)
{
$success = false;
$ttl = (int) $ttl;
if ($this->enabled && $ttl > 0) {
$file = $this->getFilename($key);
$dir = dirname($file);
$encData = serialize($data);
$expiry = time() + ($ttl * 60);
$cache = $key . "\n" . $expiry . "\n" . $str;
$cache = $key . "\n" . $expiry . "\n" . $encData;
$file = $this->getFilename($key);
$dir = dirname($file);
if (is_dir($dir) || mkdir($dir, 0777, true)) {
$success = file_put_contents($file, $cache) !== false;
}
......
......@@ -1790,8 +1790,8 @@ switch ($adminsection) {
break;
case 'caching':
$cacheManager = Q2A_Storage_CacheManager::getInstance();
$qa_content['error'] = $cacheManager->getError();
$cacheDriver = Q2A_Storage_CacheFactory::getCacheDriver();
$qa_content['error'] = $cacheDriver->getError();
break;
}
......
......@@ -42,13 +42,13 @@ $pagestate = qa_get_state();
// Get information about this question
$cacheHandler = Q2A_Storage_CacheManager::getInstance();
$cacheDriver = Q2A_Storage_CacheFactory::getCacheDriver();
$cacheKey = "page:question:$questionid";
$useCache = $userid === null && $cacheHandler->isEnabled() && !qa_is_http_post() && empty($pagestate);
$useCache = $userid === null && $cacheDriver->isEnabled() && !qa_is_http_post() && empty($pagestate);
$saveCache = false;
if ($useCache) {
$questionData = $cacheHandler->get($cacheKey);
$questionData = $cacheDriver->get($cacheKey);
}
if (!isset($questionData)) {
......@@ -158,7 +158,7 @@ if ($permiterror && (qa_is_human_probably() || !qa_opt('allow_view_q_bots'))) {
if ($saveCache) {
$questionAge = qa_opt('db_time') - $question['created'];
if ($questionAge > 86400 * qa_opt('caching_q_start')) {
$cacheHandler->set($cacheKey, $questionData, qa_opt('caching_q_time'));
$cacheDriver->set($cacheKey, $questionData, qa_opt('caching_q_time'));
}
}
......
......@@ -511,11 +511,11 @@ function qa_db_single_select($selectspec)
{
// check for cached results
if (isset($selectspec['caching'])) {
$cacheHandler = Q2A_Storage_CacheManager::getInstance();
$cacheDriver = Q2A_Storage_CacheFactory::getCacheDriver();
$cacheKey = 'query:' . $selectspec['caching']['key'];
if ($cacheHandler->isEnabled()) {
$queryData = $cacheHandler->get($cacheKey);
if ($cacheDriver->isEnabled()) {
$queryData = $cacheDriver->get($cacheKey);
if ($queryData !== null)
return $queryData;
}
......@@ -535,8 +535,8 @@ function qa_db_single_select($selectspec)
// save cached results
if (isset($selectspec['caching'])) {
if ($cacheHandler->isEnabled()) {
$cacheHandler->set($cacheKey, $results, $selectspec['caching']['ttl']);
if ($cacheDriver->isEnabled()) {
$cacheDriver->set($cacheKey, $results, $selectspec['caching']['ttl']);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment