Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Languages/en_US/Help.php
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@
$helptxt['cache_enable'] = 'SMF performs caching at a variety of levels. The higher the level of caching enabled the more CPU time will be spent retrieving cached information. If caching is available on your machine it is recommended that you try caching at level 1 first.';
$helptxt['cache_memcached'] = 'If you are using memcached you need to provide the server details. This should be entered as a comma separated list as shown in the example below:<br><br> &quot;server1,server2,server3:port,server4&quot;<br><br>Note that if no port is specified SMF will use port 11211 unless the host contains a slash, then it is assumed to be an alternative transport and the port will be set to 0. SMF will attempt to perform rough/random load balancing across the specified servers.';
$helptxt['cache_cachedir'] = 'This setting is only for the smf file-based cache system. It specifies the path to the cache directory. It is recommended that you place this in /tmp/ if you are going to use this, although it will work in any directory';
$helptxt['cache_sqlite_cachedir'] = 'This setting is only for the SQLite database cache system. It specifies the path to the cache directory. It is recommended that you place this in /tmp/ if you are going to use this, although it will work in any directory';
$helptxt['cache_sqlite_cachedir'] = 'This setting is only for the SQLite database cache system. It specifies the path to the cache directory. It is recommended that you place this in /tmp/ if you are going to use this, although it will work in any directory<br>';
$helptxt['enableErrorLogging'] = 'This will log any errors, like a failed login, so you can see what went wrong.';
$helptxt['enableErrorQueryLogging'] = 'This will include the full query sent to the database in the error log. It requires error logging to be turned on.<br><br><strong>Note: This will affect the ability to filter the error log by the error message.</strong>';
$helptxt['disallow_sendBody'] = 'This setting removes the option to receive the text of replies, posts, and personal messages in notification emails.<br><br>Often, members will reply to the notification email, which in most cases means the webmaster receives the reply.';
Expand Down
2 changes: 2 additions & 0 deletions Languages/en_US/ManageSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@
$txt['cache_memcached_settings'] = 'Memcache/Memcached settings';
$txt['cache_memcached_servers'] = 'Memcache/Memcached servers';
$txt['cache_memcached_servers_subtext'] = 'Example: 127.0.0.1:11211,127.0.0.2';
$txt['cache_sqlite_wal'] = 'Enable SQLite3 WAL';
$txt['cache_sqlite_wal_subtext'] = 'Read <a href="https://www.sqlite.org/wal.html">Write-Ahead Logging</a> documentation prior to using. If you enable then disable this setting, the database will become readonly.';

$txt['loadavg_warning'] = 'Please note: the settings below are to be edited with care. Setting any of them too low may render your forum <strong>unusable</strong>!';
$txt['loadavg_enable'] = 'Enable load balancing by load averages';
Expand Down
101 changes: 88 additions & 13 deletions Sources/Cache/APIs/Sqlite.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use SMF\Cache\CacheApi;
use SMF\Cache\CacheApiInterface;
use SMF\Config;
use SMF\ErrorHandler;
use SMF\Lang;
use SMF\Utils;
use SQLite3;
Expand All @@ -33,6 +34,12 @@
*/
class Sqlite extends CacheApi implements CacheApiInterface
{
/*****************
* Class constants
*****************/

public const CLASS_KEY = 'cache_sqlite';

/*********************
* Internal properties
*********************/
Expand All @@ -47,6 +54,12 @@ class Sqlite extends CacheApi implements CacheApiInterface
*/
private $cacheDB = null;

/**
* Indicates we have logged a error.
* @var bool
*/
private bool $logOnce = false;

/****************
* Public methods
****************/
Expand All @@ -65,15 +78,40 @@ public function __construct()
public function connect(): bool
{
$database = $this->cachedir . '/' . 'SQLite3Cache.db3';
$this->cacheDB = new SQLite3($database);
$this->cacheDB->busyTimeout(1000);

if (filesize($database) == 0) {
$this->cacheDB->exec('CREATE TABLE cache (key text unique, value blob, ttl int);');
$this->cacheDB->exec('CREATE INDEX ttls ON cache(ttl);');
if (!is_writable($database) || !is_writeable($this->cachedir)) {
return false;
}

return true;
try {
// Did we disable WAL? That triggers a read only mode, dump the cache.
if (file_exists($this->cachedir . '/' . 'SQLite3Cache.db3-wal') && empty(Config::$cache_sqlite_wal)) {
unlink($this->cachedir . '/' . 'SQLite3Cache.db3');
}

$this->cacheDB = new SQLite3($database);
$this->cacheDB->busyTimeout(1000);
$this->cacheDB->enableExceptions(true);

// Its a WALuigi!
if (!empty(Config::$cache_sqlite_wal)) {
$this->cacheDB->exec('PRAGMA journal_mode = wal;');
}

if (filesize($database) == 0) {
$this->cacheDB->exec('CREATE TABLE cache (key text unique, value blob, ttl int);');
$this->cacheDB->exec('CREATE INDEX ttls ON cache(ttl);');
}

return true;
} catch (\Exception $ex) {
if (!$this->logOnce) {
$this->logOnce = true;
ErrorHandler::log(self::class . ':' . $ex->getMessage());
}

return false;
}
}

/**
Expand All @@ -96,7 +134,17 @@ public function isSupported(bool $test = false): bool
public function getData(string $key, ?int $ttl = null): mixed
{
$query = 'SELECT value FROM cache WHERE key = \'' . $this->cacheDB->escapeString($key) . '\' AND ttl >= ' . time() . ' LIMIT 1';
$result = $this->cacheDB->query($query);

try {
$result = $this->cacheDB->query($query);
} catch (\Exception $ex) {
if (!$this->logOnce) {
$this->logOnce = true;
ErrorHandler::log(self::class . ':' . $ex->getMessage());
}

return null;
}

$value = null;

Expand All @@ -119,7 +167,17 @@ public function putData(string $key, mixed $value, ?int $ttl = null): mixed
} else {
$query = 'REPLACE INTO cache VALUES (\'' . $this->cacheDB->escapeString($key) . '\', \'' . $this->cacheDB->escapeString(\is_bool($value) ? \strval(\intval($value)) : $value) . '\', ' . $ttl . ');';
}
$result = $this->cacheDB->exec($query);

try {
$result = $this->cacheDB->exec($query);
} catch (\Exception $ex) {
if (!$this->logOnce) {
$this->logOnce = true;
ErrorHandler::log(self::class . ':' . $ex->getMessage());
}

return false;
}

return $result;
}
Expand All @@ -135,10 +193,19 @@ public function cleanCache(string $type = ''): bool
$query = 'DELETE FROM cache;';
}

$result = $this->cacheDB->exec($query);
try {
$result = $this->cacheDB->exec($query);

$query = 'VACUUM;';
$this->cacheDB->exec($query);
} catch (\Exception $ex) {
if (!$this->logOnce) {
$this->logOnce = true;
ErrorHandler::log(self::class . ':' . $ex->getMessage());
}

$query = 'VACUUM;';
$this->cacheDB->exec($query);
$result = false;
}

$this->invalidateCache();

Expand All @@ -153,14 +220,22 @@ public function cacheSettings(array &$config_vars): void
$class_name = $this->getImplementationClassKeyName();
$class_name_txt_key = strtolower($class_name);

$config_vars[] = Lang::getTxt('cache_' . $class_name_txt_key . '_settings', file: 'ManageSettings');
$config_vars[] = Lang::getTxt(self::CLASS_KEY . '_settings', file: 'ManageSettings');
$config_vars[] = [
'cachedir_' . $class_name_txt_key,
Lang::getTxt('cachedir_' . $class_name_txt_key, file: 'ManageSettings'),
'file',
'text',
36,
'cache_' . $class_name_txt_key . '_cachedir',
self::CLASS_KEY . '_cachedir',
];
$config_vars[] = [
self::CLASS_KEY . '_wal',
Lang::getTxt('cache_sqlite_wal', file: 'ManageSettings'),
'file',
'check',
self::CLASS_KEY . '_cachedir',
'subtext' => Lang::getTxt(self::CLASS_KEY . '_wal_subtext', file: 'ManageSettings'),
];

if (!isset(Utils::$context['settings_post_javascript'])) {
Expand Down
20 changes: 20 additions & 0 deletions Sources/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,14 @@ class Config
*/
public static string $cachedir_sqlite;

/**
* @var bool
*
* This is only used for the SQLite3 cache system.
* Whether to enable Write-Ahead Logging.
*/
public static bool $cache_sqlite_wal;

########## Image proxy ##########
/**
* @var bool
Expand Down Expand Up @@ -691,6 +699,18 @@ class Config
'auto_delete' => 2,
'type' => 'string',
],
'cache_sqlite_wal' => [
'text' => <<<'END'
/**
* @var bool
*
* This is only used for the SQLite3 cache system.
* Whether to enable Write-Ahead Logging.
*/
END,
'default' => false,
'type' => 'boolean',
],
'image_proxy_enabled' => [
'text' => <<<'END'

Expand Down