mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-26 23:28:14 +03:00
Journal: Second attempt at journal mode fallback #5723
Some filesystems, vms or other limitations make using the WAL journal mode impossible. We are notified of this problem through an sqlite IOERR for SHMMAP. In that case We want to attempt to fall back to the DELETE journal mode.
This commit is contained in:
parent
e05f5fc50d
commit
0b4fd52d63
2 changed files with 43 additions and 40 deletions
|
@ -35,11 +35,34 @@ namespace OCC {
|
|||
|
||||
Q_LOGGING_CATEGORY(lcDb, "sync.database", QtInfoMsg)
|
||||
|
||||
static QString defaultJournalMode(const QString &dbPath)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
// See #2693: Some exFAT file systems seem unable to cope with the
|
||||
// WAL journaling mode. They work fine with DELETE.
|
||||
QString fileSystem = FileSystem::fileSystemForPath(dbPath);
|
||||
qCInfo(lcDb) << "Detected filesystem" << fileSystem << "for" << dbPath;
|
||||
if (fileSystem.contains("FAT")) {
|
||||
qCInfo(lcDb) << "Filesystem contains FAT - using DELETE journal mode";
|
||||
return "DELETE";
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(dbPath)
|
||||
#endif
|
||||
return "WAL";
|
||||
}
|
||||
|
||||
SyncJournalDb::SyncJournalDb(const QString &dbFilePath, QObject *parent)
|
||||
: QObject(parent)
|
||||
, _dbFile(dbFilePath)
|
||||
, _transaction(0)
|
||||
{
|
||||
// Allow forcing the journal mode for debugging
|
||||
static QString envJournalMode = QString::fromLocal8Bit(qgetenv("OWNCLOUD_SQLITE_JOURNAL_MODE"));
|
||||
_journalMode = envJournalMode;
|
||||
if (_journalMode.isEmpty()) {
|
||||
_journalMode = defaultJournalMode(_dbFile);
|
||||
}
|
||||
}
|
||||
|
||||
QString SyncJournalDb::makeDbName(const QString &localPath,
|
||||
|
@ -215,23 +238,6 @@ bool SyncJournalDb::sqlFail(const QString &log, const SqlQuery &query)
|
|||
return false;
|
||||
}
|
||||
|
||||
static QString defaultJournalMode(const QString &dbPath)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
// See #2693: Some exFAT file systems seem unable to cope with the
|
||||
// WAL journaling mode. They work fine with DELETE.
|
||||
QString fileSystem = FileSystem::fileSystemForPath(dbPath);
|
||||
qCInfo(lcDb) << "Detected filesystem" << fileSystem << "for" << dbPath;
|
||||
if (fileSystem.contains("FAT")) {
|
||||
qCInfo(lcDb) << "Filesystem contains FAT - using DELETE journal mode";
|
||||
return "DELETE";
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(dbPath)
|
||||
#endif
|
||||
return "WAL";
|
||||
}
|
||||
|
||||
bool SyncJournalDb::checkConnect()
|
||||
{
|
||||
if (_db.isOpen()) {
|
||||
|
@ -264,13 +270,7 @@ bool SyncJournalDb::checkConnect()
|
|||
qCInfo(lcDb) << "sqlite3 version" << pragma1.stringValue(0);
|
||||
}
|
||||
|
||||
// Allow forcing the journal mode for debugging
|
||||
static QString env_journal_mode = QString::fromLocal8Bit(qgetenv("OWNCLOUD_SQLITE_JOURNAL_MODE"));
|
||||
QString journal_mode = env_journal_mode;
|
||||
if (journal_mode.isEmpty()) {
|
||||
journal_mode = defaultJournalMode(_dbFile);
|
||||
}
|
||||
pragma1.prepare(QString("PRAGMA journal_mode=%1;").arg(journal_mode));
|
||||
pragma1.prepare(QString("PRAGMA journal_mode=%1;").arg(_journalMode));
|
||||
if (!pragma1.exec()) {
|
||||
return sqlFail("Set PRAGMA journal_mode", pragma1);
|
||||
} else {
|
||||
|
@ -323,25 +323,21 @@ bool SyncJournalDb::checkConnect()
|
|||
");");
|
||||
|
||||
if (!createQuery.exec()) {
|
||||
bool fail = true;
|
||||
|
||||
// In certain situations the io error can be avoided by switching
|
||||
// to the DELETE journal mode, see #5723
|
||||
if (createQuery.errorId() == SQLITE_IOERR) {
|
||||
qCWarning(lcDb) << "IO error on table creation, attempting with DELETE journal mode";
|
||||
if (_journalMode != "DELETE"
|
||||
&& createQuery.errorId() == SQLITE_IOERR
|
||||
&& sqlite3_extended_errcode(_db.sqliteDb()) == SQLITE_IOERR_SHMMAP) {
|
||||
qCWarning(lcDb) << "IO error SHMMAP on table creation, attempting with DELETE journal mode";
|
||||
|
||||
pragma1.prepare(QString("PRAGMA journal_mode=DELETE;"));
|
||||
if (!pragma1.exec()) {
|
||||
return sqlFail("Set PRAGMA journal_mode", pragma1);
|
||||
_journalMode = "DELETE";
|
||||
createQuery.finish();
|
||||
pragma1.finish();
|
||||
commitTransaction();
|
||||
_db.close();
|
||||
return checkConnect();
|
||||
}
|
||||
pragma1.next();
|
||||
qCInfo(lcDb) << "sqlite3 journal_mode=" << pragma1.stringValue(0);
|
||||
|
||||
if (createQuery.exec()) {
|
||||
fail = false;
|
||||
}
|
||||
}
|
||||
if (fail)
|
||||
return sqlFail("Create table metadata", createQuery);
|
||||
}
|
||||
|
||||
|
|
|
@ -256,6 +256,13 @@ private:
|
|||
* that would write the etag and would void the purpose of avoidReadFromDbOnNextSync
|
||||
*/
|
||||
QList<QString> _avoidReadFromDbOnNextSyncFilter;
|
||||
|
||||
/** The journal mode to use for the db.
|
||||
*
|
||||
* Typically WAL initially, but may be set to other modes via environment
|
||||
* variable, for specific filesystems, or when WAL fails in a particular way.
|
||||
*/
|
||||
QString _journalMode;
|
||||
};
|
||||
|
||||
bool OWNCLOUDSYNC_EXPORT
|
||||
|
|
Loading…
Reference in a new issue