refs #884 Protect filesystem race in settings using QLockFile.

This commit is contained in:
Mathew Sutcliffe
2017-03-15 18:36:45 +00:00
parent 0d0e2cf9e0
commit 70520d44c3
3 changed files with 42 additions and 3 deletions

View File

@@ -511,9 +511,6 @@ namespace BlackCore
{ {
return this->getIContextApplication()->saveSettingsByKey(keys); return this->getIContextApplication()->saveSettingsByKey(keys);
} }
//! \todo If contexts have shut down then we already missed the opportunity to save settings.
//! Saving without contexts is not safe.
BLACK_VERIFY(false);
return CSettingsCache::instance()->saveToStore(keys); return CSettingsCache::instance()->saveToStore(keys);
} }

View File

@@ -30,13 +30,41 @@ namespace BlackMisc
return dir; return dir;
} }
const QString &CSettingsCache::lockFileName()
{
static const QString file = CFileUtils::appendFilePaths(persistentStore(), ".lock");
return file;
}
CStatusMessage CSettingsCache::lockFile(QLockFile &lock)
{
Q_ASSERT(!lock.isLocked());
if (!QDir::root().mkpath(persistentStore()))
{
return CStatusMessage(this).error("Failed to create %1") << persistentStore();
}
if (!lock.lock())
{
return CStatusMessage(this).error("Failed to lock %1: %2") << lockFileName() << CFileUtils::lockFileError(lock);
}
return {};
}
BlackMisc::CStatusMessage CSettingsCache::saveToStore(const QString &keyPrefix) BlackMisc::CStatusMessage CSettingsCache::saveToStore(const QString &keyPrefix)
{ {
QLockFile lock(lockFileName());
const CStatusMessage lockStatus = lockFile(lock);
if (lockStatus.isFailure()) { return lockStatus; }
return saveToFiles(persistentStore(), keyPrefix); return saveToFiles(persistentStore(), keyPrefix);
} }
BlackMisc::CStatusMessage CSettingsCache::saveToStore(const QStringList &keys) BlackMisc::CStatusMessage CSettingsCache::saveToStore(const QStringList &keys)
{ {
QLockFile lock(lockFileName());
const CStatusMessage lockStatus = lockFile(lock);
if (lockStatus.isFailure()) { return lockStatus; }
return saveToFiles(persistentStore(), keys); return saveToFiles(persistentStore(), keys);
} }
@@ -47,12 +75,24 @@ namespace BlackMisc
void CSettingsCache::saveToStoreByPacket(const CValueCachePacket &values) void CSettingsCache::saveToStoreByPacket(const CValueCachePacket &values)
{ {
QLockFile lock(lockFileName());
const CStatusMessage lockStatus = lockFile(lock);
if (lockStatus.isFailure())
{
CLogMessage::preformatted(lockStatus);
return;
}
CStatusMessage status = saveToFiles(persistentStore(), values.toVariantMap()); CStatusMessage status = saveToFiles(persistentStore(), values.toVariantMap());
CLogMessage::preformatted(status); CLogMessage::preformatted(status);
} }
BlackMisc::CStatusMessage CSettingsCache::loadFromStore() BlackMisc::CStatusMessage CSettingsCache::loadFromStore()
{ {
QLockFile lock(lockFileName());
const CStatusMessage lockStatus = lockFile(lock);
if (lockStatus.isFailure()) { return lockStatus; }
return loadFromFiles(persistentStore()); return loadFromFiles(persistentStore());
} }

View File

@@ -62,6 +62,8 @@ namespace BlackMisc
private: private:
CSettingsCache(); CSettingsCache();
void saveToStoreByPacket(const CValueCachePacket &values); void saveToStoreByPacket(const CValueCachePacket &values);
static const QString &lockFileName();
CStatusMessage lockFile(QLockFile &);
}; };
/*! /*!