From e9de711492bc4036df2ba2cf2010b90761a0f49a Mon Sep 17 00:00:00 2001 From: Josip Medved Date: Sat, 11 Dec 2021 14:45:51 -0800 Subject: [PATCH] Added background save for config (to work better on ZFS) --- CONTRIBUTING.md | 6 ++--- src/medo/config.cpp | 63 +++++++++++++++++++++++++++++++++++++++++---- src/medo/config.h | 24 ++++++++++++++++- 3 files changed, 84 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a2c49d..3f59899 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ Welcome and thank you for your interest in contributing. ### Compiling Code -Project uses Qt 5 and Qt Creator is the preferred development environment. +Project uses Qt 5.12.8 and Qt Creator is the preferred development environment. All code is situated in `src` directory. @@ -56,7 +56,7 @@ all test cases. Fixes can be contributed using pull requests. Do note project is under MIT license and any contribution will inherit the same. -LF line ending is strongly preffered. To have Git check it for you, configure +LF line ending is strongly preferred. To have Git check it for you, configure `core.whitespace` setting: git config core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol @@ -68,7 +68,7 @@ All textual files should be encoded as UTF-8 without BOM. For non code files (xml, etc), use the best judgment. Albeit, do note that `tab` character should be avoided and a number of `space` characters should be used -instead (4 being preffered). +instead (4 being preferred). Code uses K&R coding style. Please do make sure any contribution follows the coding style already in use. diff --git a/src/medo/config.cpp b/src/medo/config.cpp index e6af53b..f716087 100644 --- a/src/medo/config.cpp +++ b/src/medo/config.cpp @@ -15,6 +15,7 @@ Config::PortableStatus Config::_isPortable(PortableStatus::Unknown); bool Config::_immediateSave(true); Config::ConfigFile* Config::_configFile(nullptr); Config::ConfigFile* Config::_stateFile(nullptr); +Config::ConfigSaveThread Config::_configSaveThread{}; void Config::reset() { qDebug().noquote().nospace() << "[Config] reset()"; @@ -130,7 +131,7 @@ bool Config::immediateSave() { void Config::setImmediateSave(bool saveImmediately) { QMutexLocker locker(&_publicAccessMutex); _immediateSave = saveImmediately; - if (_immediateSave) { save(); } //to ensure any pending writes are cleared + if (_immediateSave) { Config::_configSaveThread.requestSave(); } //to ensure any pending writes are cleared } @@ -630,6 +631,58 @@ void Config::resetStateFile() { } +Config::ConfigSaveThread::ConfigSaveThread(void) { + this->setObjectName("ConfigSaveThread"); + this->start(LowPriority); +} + +Config::ConfigSaveThread::~ConfigSaveThread() { + this->requestInterruption(); + this->wait(); +} + +void Config::ConfigSaveThread::requestSave() { + QMutexLocker locker(&_syncRoot); + _saveRequested = true; +} + +void Config::ConfigSaveThread::run() { + while (!this->isInterruptionRequested()) { + QMutexLocker locker(&_syncRoot); + bool saveRequested = _saveRequested; + locker.unlock(); + if (saveRequested) { + qDebug().noquote().nospace() << "[Config] Background save()"; + QElapsedTimer stopwatch; stopwatch.start(); + if (Config::getConfigFile()->save()) { + locker.relock(); + _saveRequested = false; + locker.unlock(); + qDebug().noquote().nospace() << "[Config] Background save() done in " << stopwatch.elapsed() << "ms"; + } else { + qDebug().noquote().nospace() << "[Config] Background save() failed in " << stopwatch.elapsed() << "ms"; + this->msleep(2500); // give it some time + } + } + this->msleep(250); + } + + { // check once more when exiting + QMutexLocker locker(&_syncRoot); + bool saveRequested = _saveRequested; + locker.unlock(); + if (saveRequested) { + qDebug().noquote().nospace() << "[Config] Final background save()"; + QElapsedTimer stopwatch; stopwatch.start(); + if (Config::getConfigFile()->save()) { + qDebug().noquote().nospace() << "[Config] Final background save() done in " << stopwatch.elapsed() << "ms"; + } else { + qDebug().noquote().nospace() << "[Config] Final background save() failed in " << stopwatch.elapsed() << "ms"; + } + } + } +} + Config::ConfigFile::ConfigFile(QString filePath) { QString fileContent; QString lineEnding = QString(); @@ -964,7 +1017,7 @@ void Config::ConfigFile::writeOne(QString key, QString value) { } } - if (_immediateSave) { save(); } + if (_immediateSave) { Config::_configSaveThread.requestSave(); } } void Config::ConfigFile::writeMany(QString key, QStringList values) { @@ -1018,7 +1071,7 @@ void Config::ConfigFile::writeMany(QString key, QStringList values) { } } - if (_immediateSave) { save(); } + if (_immediateSave) { Config::_configSaveThread.requestSave(); } } void Config::ConfigFile::removeMany(QString key) { @@ -1031,7 +1084,7 @@ void Config::ConfigFile::removeMany(QString key) { _lines.removeAt(i); } } - if (_immediateSave) { save(); } + if (_immediateSave) { Config::_configSaveThread.requestSave(); } } void Config::ConfigFile::removeAll() { @@ -1039,7 +1092,7 @@ void Config::ConfigFile::removeAll() { _cache.clear(); //invalidate cache _lines.clear(); - if (_immediateSave) { save(); } + if (_immediateSave) { Config::_configSaveThread.requestSave(); } } diff --git a/src/medo/config.h b/src/medo/config.h index e167f10..0696ea0 100644 --- a/src/medo/config.h +++ b/src/medo/config.h @@ -1,5 +1,6 @@ /* Josip Medved * www.medo64.com * MIT License */ +// 2021-12-10: Added background save // 2020-05-25: Using strongly typed enums // 2020-05-05: Added stateRead/stateWrite for integers, longs, and doubles // Allowing : and = in key name @@ -9,7 +10,7 @@ // 2019-11-01: Fixed readMany implementation // 2019-11-17: Added stateReadMany and stateWriteMany // Added option to set paths manually -// 2020-03-15: If QApplication hasn't bee initializesd, assume installed on Linux +// 2020-03-15: If QApplication hasn't been initialized, assume installed on Linux #pragma once @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -291,6 +293,25 @@ class Config { static QString dataDirectoryPathWhenPortable(); static QString dataDirectoryPathWhenInstalled(); + private: + class ConfigSaveThread : private QThread { + public: + explicit ConfigSaveThread(void); + ~ConfigSaveThread(); + + public: + void requestSave(); + + public: + ConfigSaveThread(const ConfigSaveThread&) = delete; + void operator=(const ConfigSaveThread&) = delete; + + private: + QMutex _syncRoot; + bool _saveRequested = false; + void run(); + }; + private: class ConfigFile { public: @@ -364,5 +385,6 @@ class Config { static ConfigFile* getStateFile(); static void resetStateFile(); static ConfigFile* _stateFile; + static Config::ConfigSaveThread _configSaveThread; };