Tweak Sqlite connection settings to reduce database locked errors

Related resources:
- https://litestream.io/tips/
- https://unixsheikh.com/articles/sqlite-the-only-database-you-will-ever-need-in-most-cases.html
This commit is contained in:
Frédéric Guillot 2023-07-07 19:00:59 -07:00 committed by Frédéric Guillot
parent e00e2e3789
commit f084cfa7bd
5 changed files with 32 additions and 4 deletions

2
.gitignore vendored
View File

@ -1,5 +1,7 @@
*.sqlite *.sqlite
*.sqlite-journal *.sqlite-journal
*.sqlite-shm
*.sqlite-wal
.buildpath .buildpath
.project .project
/.settings/ /.settings/

View File

@ -20,6 +20,7 @@ class ConfigController extends BaseController
$this->response->html($this->helper->layout->config('config/about', array( $this->response->html($this->helper->layout->config('config/about', array(
'db_size' => $this->configModel->getDatabaseSize(), 'db_size' => $this->configModel->getDatabaseSize(),
'db_version' => $this->db->getDriver()->getDatabaseVersion(), 'db_version' => $this->db->getDriver()->getDatabaseVersion(),
'db_options' => $this->configModel->getDatabaseOptions(),
'user_agent' => $this->request->getServerVariable('HTTP_USER_AGENT'), 'user_agent' => $this->request->getServerVariable('HTTP_USER_AGENT'),
'title' => t('Settings').' > '.t('About'), 'title' => t('Settings').' > '.t('About'),
))); )));

View File

@ -72,6 +72,26 @@ class ConfigModel extends SettingModel
return DB_DRIVER === 'sqlite' ? filesize(DB_FILENAME) : 0; return DB_DRIVER === 'sqlite' ? filesize(DB_FILENAME) : 0;
} }
/**
* Get database extra options
*
* @access public
* @return array
*/
public function getDatabaseOptions()
{
if (DB_DRIVER === 'sqlite') {
return [
'journal_mode' => $this->db->getConnection()->query('PRAGMA journal_mode')->fetchColumn(),
'wal_autocheckpoint' => $this->db->getConnection()->query('PRAGMA wal_autocheckpoint')->fetchColumn(),
'synchronous' => $this->db->getConnection()->query('PRAGMA synchronous')->fetchColumn(),
'busy_timeout' => $this->db->getConnection()->query('PRAGMA busy_timeout')->fetchColumn(),
];
}
return [];
}
/** /**
* Regenerate a token * Regenerate a token
* *

View File

@ -79,6 +79,9 @@
<?= $this->url->link(t('Optimize the database'), 'ConfigController', 'optimizeDb', array(), true) ?>&nbsp; <?= $this->url->link(t('Optimize the database'), 'ConfigController', 'optimizeDb', array(), true) ?>&nbsp;
<?= t('(VACUUM command)') ?> <?= t('(VACUUM command)') ?>
</li> </li>
<?php foreach ($db_options as $option => $value): ?>
<li><strong><?= $this->text->e($option) ?></strong> = <?= $this->text->e($value) ?></li>
<?php endforeach ?>
</ul> </ul>
</div> </div>
<?php endif ?> <?php endif ?>

View File

@ -29,17 +29,19 @@ class Sqlite extends Base
*/ */
public function createConnection(array $settings) public function createConnection(array $settings)
{ {
$options = array(); $options = [];
if (! empty($settings['timeout'])) { // Set a default timeout of 30 seconds to reduce "database is locked" errors.
$options[PDO::ATTR_TIMEOUT] = $settings['timeout']; $options[PDO::ATTR_TIMEOUT] = (! empty($settings['timeout'])) ? $settings['timeout'] : 30;
}
$this->pdo = new PDO('sqlite:'.$settings['filename'], null, null, $options); $this->pdo = new PDO('sqlite:'.$settings['filename'], null, null, $options);
// Enabling WAL mode by default should also reduce the "database is locked" errors.
// Official docs: https://sqlite.org/wal.html // Official docs: https://sqlite.org/wal.html
if (isset($settings['wal_mode']) && $settings['wal_mode'] === true) { if (isset($settings['wal_mode']) && $settings['wal_mode'] === true) {
$this->pdo->exec('PRAGMA journal_mode=wal'); $this->pdo->exec('PRAGMA journal_mode=wal');
$this->pdo->exec('PRAGMA wal_autocheckpoint = 0');
$this->pdo->exec('PRAGMA synchronous=NORMAL');
} }
$this->enableForeignKeys(); $this->enableForeignKeys();