Merge pull request #14082 from Ondsel-Development/issue_13522_fix_read_lock
Core: Add read lock to fix for possible race conditions reading/writing config files
This commit is contained in:
@@ -1674,19 +1674,29 @@ void Application::cleanupUnits()
|
||||
void Application::destruct()
|
||||
{
|
||||
// saving system parameter
|
||||
Base::Console().Log("Saving system parameter...\n");
|
||||
_pcSysParamMngr->SaveDocument();
|
||||
if (_pcSysParamMngr->IgnoreSave()) {
|
||||
Base::Console().Warning("Discard system parameter\n");
|
||||
}
|
||||
else {
|
||||
Base::Console().Log("Saving system parameter...\n");
|
||||
_pcSysParamMngr->SaveDocument();
|
||||
Base::Console().Log("Saving system parameter...done\n");
|
||||
}
|
||||
// saving the User parameter
|
||||
Base::Console().Log("Saving system parameter...done\n");
|
||||
Base::Console().Log("Saving user parameter...\n");
|
||||
_pcUserParamMngr->SaveDocument();
|
||||
Base::Console().Log("Saving user parameter...done\n");
|
||||
if (_pcUserParamMngr->IgnoreSave()) {
|
||||
Base::Console().Warning("Discard user parameter\n");
|
||||
}
|
||||
else {
|
||||
Base::Console().Log("Saving user parameter...\n");
|
||||
_pcUserParamMngr->SaveDocument();
|
||||
Base::Console().Log("Saving user parameter...done\n");
|
||||
}
|
||||
|
||||
// now save all other parameter files
|
||||
auto& paramMgr = _pcSingleton->mpcPramManager;
|
||||
for (auto it : paramMgr) {
|
||||
if ((it.second != _pcSysParamMngr) && (it.second != _pcUserParamMngr)) {
|
||||
if (it.second->HasSerializer()) {
|
||||
if (it.second->HasSerializer() && !it.second->IgnoreSave()) {
|
||||
Base::Console().Log("Saving %s...\n", it.first.c_str());
|
||||
it.second->SaveDocument();
|
||||
Base::Console().Log("Saving %s...done\n", it.first.c_str());
|
||||
|
||||
@@ -1617,6 +1617,7 @@ ParameterManager::ParameterManager()
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// NOLINTBEGIN
|
||||
gIgnoreSave = false;
|
||||
gDoNamespaces = false;
|
||||
gDoSchema = false;
|
||||
gSchemaFullChecking = false;
|
||||
@@ -1723,14 +1724,28 @@ void ParameterManager::SaveDocument() const
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterManager::SetIgnoreSave(bool value)
|
||||
{
|
||||
gIgnoreSave = value;
|
||||
}
|
||||
|
||||
bool ParameterManager::IgnoreSave() const
|
||||
{
|
||||
return gIgnoreSave;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void waitForFileAccess(const Base::FileInfo& file)
|
||||
QString getLockFile(const Base::FileInfo& file)
|
||||
{
|
||||
QFileInfo fi(QDir::tempPath(), QString::fromStdString(file.fileName() + ".lock"));
|
||||
QLockFile lock(fi.absoluteFilePath());
|
||||
const int waitOneSecond = 1000;
|
||||
lock.tryLock(waitOneSecond);
|
||||
return fi.absoluteFilePath();
|
||||
}
|
||||
|
||||
int getTimeout()
|
||||
{
|
||||
const int timeout = 5000;
|
||||
return timeout;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -1753,7 +1768,14 @@ int ParameterManager::LoadDocument(const char* sFileName)
|
||||
{
|
||||
try {
|
||||
Base::FileInfo file(sFileName);
|
||||
waitForFileAccess(file);
|
||||
QLockFile lock(getLockFile(file));
|
||||
if (!lock.tryLock(getTimeout())) {
|
||||
// Continue with empty config
|
||||
CreateDocument();
|
||||
SetIgnoreSave(true);
|
||||
std::cerr << "Failed to access file for reading: " << sFileName << std::endl;
|
||||
return 1;
|
||||
}
|
||||
#if defined(FC_OS_WIN32)
|
||||
std::wstring name = file.toStdWString();
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
@@ -1845,7 +1867,11 @@ void ParameterManager::SaveDocument(const char* sFileName) const
|
||||
{
|
||||
try {
|
||||
Base::FileInfo file(sFileName);
|
||||
waitForFileAccess(file);
|
||||
QLockFile lock(getLockFile(file));
|
||||
if (!lock.tryLock(getTimeout())) {
|
||||
std::cerr << "Failed to access file for writing: " << sFileName << std::endl;
|
||||
return;
|
||||
}
|
||||
//
|
||||
// Plug in a format target to receive the resultant
|
||||
// XML stream from the serializer.
|
||||
|
||||
@@ -434,12 +434,15 @@ public:
|
||||
bool LoadOrCreateDocument();
|
||||
/// Saves an XML document by calling the serializer's save method.
|
||||
void SaveDocument() const;
|
||||
void SetIgnoreSave(bool value);
|
||||
bool IgnoreSave() const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* _pDocument {nullptr};
|
||||
ParameterSerializer* paramSerializer {nullptr};
|
||||
|
||||
bool gIgnoreSave;
|
||||
bool gDoNamespaces;
|
||||
bool gDoSchema;
|
||||
bool gSchemaFullChecking;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "MainWindow.h"
|
||||
#include "Language/Translator.h"
|
||||
#include <App/Application.h>
|
||||
#include <Base/Console.h>
|
||||
|
||||
|
||||
using namespace Gui;
|
||||
@@ -233,6 +234,7 @@ void StartupPostProcess::execute()
|
||||
setBranding();
|
||||
showMainWindow();
|
||||
activateWorkbench();
|
||||
checkParameters();
|
||||
}
|
||||
|
||||
void StartupPostProcess::setWindowTitle()
|
||||
@@ -545,3 +547,15 @@ void StartupPostProcess::autoloadModules(const QStringList& wb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StartupPostProcess::checkParameters()
|
||||
{
|
||||
if (App::GetApplication().GetSystemParameter().IgnoreSave()) {
|
||||
Base::Console().Warning("System parameter file couldn't be opened.\n"
|
||||
"Continue with an empty configuration that won't be saved.\n");
|
||||
}
|
||||
if (App::GetApplication().GetUserParameter().IgnoreSave()) {
|
||||
Base::Console().Warning("User parameter file couldn't be opened.\n"
|
||||
"Continue with an empty configuration that won't be saved.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ private:
|
||||
bool hiddenMainWindow() const;
|
||||
void showMainWindow();
|
||||
void activateWorkbench();
|
||||
void checkParameters();
|
||||
|
||||
private:
|
||||
bool loadFromPythonModule = false;
|
||||
|
||||
Reference in New Issue
Block a user