Skip to content

Commit 469cbaa

Browse files
committed
If WOL was disabled, it causes readonly mode to occur.
PHP offers no way to determine that, so sniff for the file to guess. Additionally to fix issues with errors occurring, enabled exceptions for sqlite3 and used that to handle silently logging the error.
1 parent df56d1b commit 469cbaa

File tree

2 files changed

+72
-16
lines changed

2 files changed

+72
-16
lines changed

Languages/en_US/ManageSettings.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@
152152
$txt['cache_memcached_servers'] = 'Memcache/Memcached servers';
153153
$txt['cache_memcached_servers_subtext'] = 'Example: 127.0.0.1:11211,127.0.0.2';
154154
$txt['cache_sqlite_wal'] = 'Enable SQLite3 WAL';
155-
$txt['cache_sqlite_wal_subtext'] = 'Read <a href="https://www.sqlite.org/wal.html">Write-Ahead Logging</a> documentation prior to using.';
155+
$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.';
156156

157157
$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>!';
158158
$txt['loadavg_enable'] = 'Enable load balancing by load averages';

Sources/Cache/APIs/Sqlite.php

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use SMF\Cache\CacheApi;
1919
use SMF\Cache\CacheApiInterface;
2020
use SMF\Config;
21+
use SMF\ErrorHandler;
2122
use SMF\Lang;
2223
use SMF\Utils;
2324
use SQLite3;
@@ -53,6 +54,12 @@ class Sqlite extends CacheApi implements CacheApiInterface
5354
*/
5455
private $cacheDB = null;
5556

57+
/**
58+
* Indicates we have logged a error.
59+
* @var bool
60+
*/
61+
private bool $logOnce = false;
62+
5663
/****************
5764
* Public methods
5865
****************/
@@ -71,20 +78,40 @@ public function __construct()
7178
public function connect(): bool
7279
{
7380
$database = $this->cachedir . '/' . 'SQLite3Cache.db3';
74-
$this->cacheDB = new SQLite3($database);
75-
$this->cacheDB->busyTimeout(1000);
7681

77-
// Its a WALuigi!
78-
if (!empty(Config::$cache_sqlite_wal)) {
79-
$this->cacheDB->exec('PRAGMA journal_mode = wal;');
82+
if (!is_writable($database) || !is_writeable($this->cachedir)) {
83+
return false;
8084
}
8185

82-
if (filesize($database) == 0) {
83-
$this->cacheDB->exec('CREATE TABLE cache (key text unique, value blob, ttl int);');
84-
$this->cacheDB->exec('CREATE INDEX ttls ON cache(ttl);');
85-
}
86+
try {
87+
// Did we disable WAL? That triggers a read only mode, dump the cache.
88+
if (file_exists($this->cachedir . '/' . 'SQLite3Cache.db3-wal') && empty(Config::$modSettings['cache_sqlite_wal'])) {
89+
unlink($this->cachedir . '/' . 'SQLite3Cache.db3');
90+
}
91+
92+
$this->cacheDB = new SQLite3($database);
93+
$this->cacheDB->busyTimeout(1000);
94+
$this->cacheDB->enableExceptions(true);
95+
96+
// Its a WALuigi!
97+
if (!empty(Config::$cache_sqlite_wal)) {
98+
$this->cacheDB->exec('PRAGMA journal_mode = wal;');
99+
}
100+
101+
if (filesize($database) == 0) {
102+
$this->cacheDB->exec('CREATE TABLE cache (key text unique, value blob, ttl int);');
103+
$this->cacheDB->exec('CREATE INDEX ttls ON cache(ttl);');
104+
}
105+
106+
return true;
107+
} catch (\Exception $ex) {
108+
if (!$this->logOnce) {
109+
$this->logOnce = true;
110+
ErrorHandler::log(self::class . ':' . $ex->getMessage());
111+
}
86112

87-
return true;
113+
return false;
114+
}
88115
}
89116

90117
/**
@@ -107,7 +134,17 @@ public function isSupported(bool $test = false): bool
107134
public function getData(string $key, ?int $ttl = null): mixed
108135
{
109136
$query = 'SELECT value FROM cache WHERE key = \'' . $this->cacheDB->escapeString($key) . '\' AND ttl >= ' . time() . ' LIMIT 1';
110-
$result = $this->cacheDB->query($query);
137+
138+
try {
139+
$result = $this->cacheDB->query($query);
140+
} catch (\Exception $ex) {
141+
if (!$this->logOnce) {
142+
$this->logOnce = true;
143+
ErrorHandler::log(self::class . ':' . $ex->getMessage());
144+
}
145+
146+
return null;
147+
}
111148

112149
$value = null;
113150

@@ -130,7 +167,17 @@ public function putData(string $key, mixed $value, ?int $ttl = null): mixed
130167
} else {
131168
$query = 'REPLACE INTO cache VALUES (\'' . $this->cacheDB->escapeString($key) . '\', \'' . $this->cacheDB->escapeString(\is_bool($value) ? \strval(\intval($value)) : $value) . '\', ' . $ttl . ');';
132169
}
133-
$result = $this->cacheDB->exec($query);
170+
171+
try {
172+
$result = $this->cacheDB->exec($query);
173+
} catch (\Exception $ex) {
174+
if (!$this->logOnce) {
175+
$this->logOnce = true;
176+
ErrorHandler::log(self::class . ':' . $ex->getMessage());
177+
}
178+
179+
return false;
180+
}
134181

135182
return $result;
136183
}
@@ -146,10 +193,19 @@ public function cleanCache(string $type = ''): bool
146193
$query = 'DELETE FROM cache;';
147194
}
148195

149-
$result = $this->cacheDB->exec($query);
196+
try {
197+
$result = $this->cacheDB->exec($query);
150198

151-
$query = 'VACUUM;';
152-
$this->cacheDB->exec($query);
199+
$query = 'VACUUM;';
200+
$this->cacheDB->exec($query);
201+
} catch (\Exception $ex) {
202+
if (!$this->logOnce) {
203+
$this->logOnce = true;
204+
ErrorHandler::log(self::class . ':' . $ex->getMessage());
205+
}
206+
207+
$result = false;
208+
}
153209

154210
$this->invalidateCache();
155211

0 commit comments

Comments
 (0)