mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-22 22:34:13 +02:00
2bedfaa394
Every QElectroTech on a computer shares elements_cache.sqlite. The cache set PRAGMA locking_mode = EXCLUSIVE, so a QElectroTech that had read the file once kept it locked until it closed. A second one -- a build in another folder, or a build beside a released version, which SingleApplication lets run because its key includes the program's path and version -- could not write to it: each write waited SQLite's 5 s busy timeout and failed, on the GUI thread, twice for every symbol the collection showed. The report's log is exactly that: an empty QSqlError every 5.0 s for three minutes. Use SQLite's normal locking, which holds a lock only while a statement runs, and give this connection no busy timeout: the cache only saves time, so a busy file is a cache miss, never a wait. Print the failing query's error, not the connection's, which was always empty. Measured with the real program running and a second process writing to its cache: before, the write fails "database is locked" after 5.01 s; after, it succeeds in 0.02 s. tst_elementcachelock opens two caches on one file; it fails before the fix with the report's empty QSqlError. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
50 lines
1.8 KiB
C++
50 lines
1.8 KiB
C++
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
#include <QtTest>
|
|
|
|
#include <QElapsedTimer>
|
|
#include <QTemporaryDir>
|
|
#include <QUuid>
|
|
|
|
#include "elementscollectioncache.h"
|
|
|
|
// Every QElectroTech on a computer shares one elements_cache.sqlite. The cache
|
|
// used PRAGMA locking_mode = EXCLUSIVE, so a QElectroTech that had once read
|
|
// the file kept it locked until it closed, and every write from a second one
|
|
// waited SQLite's 5 s busy timeout and failed -- on the GUI thread, twice per
|
|
// symbol shown in the collection (#1571). Two caches on the same file in one
|
|
// process lock each other exactly as two processes do.
|
|
class tst_elementcachelock : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
QTemporaryDir m_dir;
|
|
const QUuid m_uuid = QUuid::createUuid();
|
|
|
|
private slots:
|
|
void secondCacheWritesWithoutWaiting()
|
|
{
|
|
QVERIFY(m_dir.isValid());
|
|
const QString path = m_dir.filePath(QStringLiteral("elements_cache.sqlite"));
|
|
|
|
ElementsCollectionCache first(path);
|
|
QVERIFY(first.cacheName(QStringLiteral("embed://a.elmt"), m_uuid));
|
|
QVERIFY(first.fetchNameFromCache(QStringLiteral("embed://a.elmt"), m_uuid));
|
|
QVERIFY(!first.fetchNameFromCache(QStringLiteral("embed://missing.elmt"), m_uuid));
|
|
|
|
ElementsCollectionCache second(path);
|
|
QElapsedTimer timer;
|
|
timer.start();
|
|
QVERIFY(second.cacheName(QStringLiteral("embed://b.elmt"), m_uuid));
|
|
QVERIFY(second.cachePixmap(QStringLiteral("embed://b.elmt"), m_uuid));
|
|
QVERIFY2(timer.elapsed() < 1000, qPrintable(QString::number(timer.elapsed()) + " ms"));
|
|
|
|
// and each one sees what the other wrote
|
|
QVERIFY(second.fetchNameFromCache(QStringLiteral("embed://a.elmt"), m_uuid));
|
|
QVERIFY(first.fetchNameFromCache(QStringLiteral("embed://b.elmt"), m_uuid));
|
|
QVERIFY(first.cacheName(QStringLiteral("embed://c.elmt"), m_uuid));
|
|
}
|
|
};
|
|
|
|
QTEST_MAIN(tst_elementcachelock)
|
|
#include "tst_elementcachelock.moc"
|