Caching stuff.

This commit is contained in:
flash 2018-07-16 00:39:39 +02:00
parent d52cb3af63
commit af4ec2ac45
8 changed files with 226 additions and 45 deletions

View file

@ -135,6 +135,7 @@ if (PHP_SAPI === 'cli') {
exit; exit;
} }
$app->startCache();
$app->startTemplating(); $app->startTemplating();
$tpl = $app->getTemplating(); $tpl = $app->getTemplating();

View file

@ -1,11 +1,11 @@
<?php <?php
use Misuzu\Cache;
use Misuzu\Database; use Misuzu\Database;
require_once __DIR__ . '/../misuzu.php'; require_once __DIR__ . '/../misuzu.php';
$config = $app->getConfig(); $config = $app->getConfig();
$tpl = $app->getTemplating(); $tpl = $app->getTemplating();
$db = Database::connection();
if ($config->get('Site', 'embed_linked_data', 'bool', false)) { if ($config->get('Site', 'embed_linked_data', 'bool', false)) {
$tpl->vars([ $tpl->vars([
@ -17,7 +17,7 @@ if ($config->get('Site', 'embed_linked_data', 'bool', false)) {
]); ]);
} }
$featuredNews = $db->query(' $news = Database::query('
SELECT SELECT
p.`post_id`, p.`post_title`, p.`post_text`, p.`created_at`, p.`post_id`, p.`post_title`, p.`post_text`, p.`created_at`,
u.`user_id`, u.`username`, u.`user_id`, u.`username`,
@ -32,12 +32,13 @@ $featuredNews = $db->query('
LIMIT 3 LIMIT 3
')->fetchAll(PDO::FETCH_ASSOC); ')->fetchAll(PDO::FETCH_ASSOC);
$usersCount = (int)$db->query(' $statistics = Cache::instance()->get('index:stats:v1', function () {
return [
'users' => (int)Database::query('
SELECT COUNT(`user_id`) SELECT COUNT(`user_id`)
FROM `msz_users` FROM `msz_users`
')->fetchColumn(); ')->fetchColumn(),
'lastUser' => Database::query('
$lastUser = $db->query('
SELECT SELECT
u.`user_id`, u.`username`, u.`created_at`, u.`user_id`, u.`username`, u.`created_at`,
COALESCE(r.`role_colour`, CAST(0x40000000 AS UNSIGNED)) as `user_colour` COALESCE(r.`role_colour`, CAST(0x40000000 AS UNSIGNED)) as `user_colour`
@ -46,9 +47,12 @@ $lastUser = $db->query('
ON r.`role_id` = u.`display_role` ON r.`role_id` = u.`display_role`
ORDER BY u.`user_id` DESC ORDER BY u.`user_id` DESC
LIMIT 1 LIMIT 1
')->fetch(PDO::FETCH_ASSOC); ')->fetch(PDO::FETCH_ASSOC),
];
}, 10800);
$featuredChangelog = $db->query(' $changelog = Cache::instance()->get('index:changelog:v1', function () {
return Database::query('
SELECT SELECT
c.`change_id`, c.`change_log`, c.`change_id`, c.`change_log`,
a.`action_name`, a.`action_colour`, a.`action_class`, a.`action_name`, a.`action_colour`, a.`action_class`,
@ -66,12 +70,11 @@ $featuredChangelog = $db->query('
) )
ORDER BY c.`change_created` DESC ORDER BY c.`change_created` DESC
')->fetchAll(PDO::FETCH_ASSOC); ')->fetchAll(PDO::FETCH_ASSOC);
}, 1800);
//var_dump(Database::connection()->query('SHOW SESSION STATUS LIKE "Questions"')->fetch()['Value']);
echo $tpl->render('home.index', [ echo $tpl->render('home.index', [
'users_count' => $usersCount, 'users_count' => $statistics['users'],
'last_user' => $lastUser, 'last_user' => $statistics['lastUser'],
'featured_changelog' => $featuredChangelog, 'featured_changelog' => $changelog,
'featured_news' => $featuredNews, 'featured_news' => $news,
]); ]);

View file

@ -217,12 +217,30 @@ class Application extends ApplicationBase
public function startDatabase(): void public function startDatabase(): void
{ {
if (Database::hasInstance()) { if (Database::hasInstance()) {
throw new UnexpectedValueException('Database module has already been started.'); throw new UnexpectedValueException('Database has already been started.');
} }
new Database($this->configInstance, self::DATABASE_CONNECTIONS[0]); new Database($this->configInstance, self::DATABASE_CONNECTIONS[0]);
} }
/**
* Sets up the caching stuff.
*/
public function startCache(): void
{
if (Cache::hasInstance()) {
throw new UnexpectedValueException('Cache has already been started.');
}
new Cache(
$this->configInstance->get('Cache', 'host', 'string', null),
$this->configInstance->get('Cache', 'port', 'int', null),
$this->configInstance->get('Cache', 'database', 'int', null),
$this->configInstance->get('Cache', 'password', 'string', null),
$this->configInstance->get('Cache', 'prefix', 'string', '')
);
}
/** /**
* Sets up the templating engine module. * Sets up the templating engine module.
*/ */

127
src/Cache.php Normal file
View file

@ -0,0 +1,127 @@
<?php
namespace Misuzu;
use Misuzu\Config\ConfigManager;
use Redis;
use InvalidArgumentException;
use UnexpectedValueException;
final class Cache
{
/**
* @var Cache
*/
private static $instance;
private $redis;
public static function instance(): Cache
{
if (!self::hasInstance()) {
throw new UnexpectedValueException('No instance of Cache exists yet.');
}
return self::$instance;
}
public function getRedis(): Redis
{
return $this->redis;
}
public static function hasInstance(): bool
{
return self::$instance instanceof static;
}
public function __construct(
string $host,
?int $port = null,
?int $database = null,
?string $password = null,
string $prefix = ''
) {
if (self::hasInstance()) {
throw new UnexpectedValueException('Only one instance of Cache may exist.');
}
self::$instance = $this;
$this->redis = new Redis;
$this->redis->connect($host, $port);
if ($password !== null && !$this->redis->auth($password)) {
throw new InvalidArgumentException('Redis auth failed.');
}
if ($database !== null && !$this->redis->select($database)) {
throw new UnexpectedValueException('Redis select failed.');
}
$this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
$this->redis->setOption(Redis::OPT_PREFIX, $prefix);
}
public function __destruct()
{
$this->redis->close();
self::$instance = null;
}
public function set(string $key, $value, int $ttl = 0)
{
if (is_callable($value)) {
$value = $value();
}
if ($ttl < 0) {
return $value;
} elseif ($ttl < 1) {
$this->redis->set($key, $value);
} else {
$this->redis->setEx($key, $ttl, $value);
}
return $value;
}
public function exists(string $key): bool
{
return $this->redis->exists($key);
}
public function delete($keys): int
{
return $this->redis->delete($keys);
}
public function increment(string $key, int $amount = 1): int
{
if ($amount <= 1) {
return $this->redis->incr($key);
}
return $this->redis->incrBy($key, $amount);
}
public function decrement(string $key, int $amount = 1): int
{
if ($amount <= 1) {
return $this->redis->decr($key);
}
return $this->redis->decrBy($key, $amount);
}
public function get(string $key, $fallback, int $ttl = 0)
{
if ($ttl < 0) {
return is_callable($fallback) ? $fallback() : $fallback;
}
if (!$this->exists($key)) {
return $this->set($key, $fallback, $ttl);
}
return $this->redis->get($key);
}
}

View file

@ -3,7 +3,9 @@ namespace Misuzu;
use Misuzu\Config\ConfigManager; use Misuzu\Config\ConfigManager;
use PDO; use PDO;
use PDOStatement;
use InvalidArgumentException; use InvalidArgumentException;
use UnexpectedValueException;
final class Database final class Database
{ {
@ -48,7 +50,7 @@ final class Database
public static function getInstance(): Database public static function getInstance(): Database
{ {
if (!self::hasInstance()) { if (!self::hasInstance()) {
throw new \UnexpectedValueException('No instance of Database exists yet.'); throw new UnexpectedValueException('No instance of Database exists yet.');
} }
return self::$instance; return self::$instance;
@ -63,8 +65,8 @@ final class Database
ConfigManager $config, ConfigManager $config,
string $default = 'default' string $default = 'default'
) { ) {
if (self::$instance instanceof static) { if (self::hasInstance()) {
throw new \UnexpectedValueException('Only one instance of Database may exist.'); throw new UnexpectedValueException('Only one instance of Database may exist.');
} }
self::$instance = $this; self::$instance = $this;
@ -77,6 +79,26 @@ final class Database
return self::getInstance()->getConnection($name); return self::getInstance()->getConnection($name);
} }
public static function prepare(string $statement, ?string $connection = null, $options = []): PDOStatement
{
return self::connection($connection)->prepare($statement, $options);
}
public static function query(string $statement, ?string $connection = null): PDOStatement
{
return self::connection($connection)->query($statement);
}
public static function exec(string $statement, ?string $connection = null)
{
return self::connection($connection)->exec($statement);
}
public static function queryCount(?string $connection = null): int
{
return (int)Database::query('SHOW SESSION STATUS LIKE "Questions"', $connection)->fetch()['Value'];
}
public function getConnection(?string $name = null): PDO public function getConnection(?string $name = null): PDO
{ {
$name = $name ?? $this->default; $name = $name ?? $this->default;

View file

@ -167,6 +167,10 @@ class TemplateEngine
*/ */
public function render(string $path, ?array $vars = null): string public function render(string $path, ?array $vars = null): string
{ {
if ($this->twig->isDebug()) {
$this->var('query_count', Database::queryCount());
}
$path = self::fixPath($path); $path = self::fixPath($path);
if ($vars !== null) { if ($vars !== null) {

View file

@ -67,6 +67,9 @@
''|date('Y') }} / ''|date('Y') }} /
{{ ('https://github.com/flashwave/misuzu/tree/' ~ git_branch())|html_link(git_branch(), 'footer__link')|raw }} {{ ('https://github.com/flashwave/misuzu/tree/' ~ git_branch())|html_link(git_branch(), 'footer__link')|raw }}
# {{ ('https://github.com/flashwave/misuzu/commit/' ~ git_commit_hash(true))|html_link(git_commit_hash(), 'footer__link')|raw }} # {{ ('https://github.com/flashwave/misuzu/commit/' ~ git_commit_hash(true))|html_link(git_commit_hash(), 'footer__link')|raw }}
{% if query_count is defined %}
/ SQL Queries: {{ query_count|number_format }}
{% endif %}
</footer> </footer>
</div> </div>
<script src="/js/libraries.js" charset="utf-8"></script> <script src="/js/libraries.js" charset="utf-8"></script>

View file

@ -70,6 +70,9 @@
''|date('Y') }} / ''|date('Y') }} /
{{ ('https://github.com/flashwave/misuzu/tree/' ~ git_branch())|html_link(git_branch(), 'footer__copyright__link') }} {{ ('https://github.com/flashwave/misuzu/tree/' ~ git_branch())|html_link(git_branch(), 'footer__copyright__link') }}
# {{ ('https://github.com/flashwave/misuzu/commit/' ~ git_commit_hash(true))|html_link(git_commit_hash(), 'footer__copyright__link') }} # {{ ('https://github.com/flashwave/misuzu/commit/' ~ git_commit_hash(true))|html_link(git_commit_hash(), 'footer__copyright__link') }}
{% if query_count is defined %}
/ SQL Queries: {{ query_count|number_format }}
{% endif %}
</div> </div>
<div class="footer__links"> <div class="footer__links">