Ini file gets empty : QSettings problem ?
-
On our embedded device (with i.MX27 processor, running Linux), we use an ini file to store information. Therefor, we use an object that inherits from QSettings. Sometimes (in fact very rarely), when powering off the device, we notice that the ini file gets empty. First we taught that the ini file was missing, but that's not the case. The file obviously remains available but gets empty. We only write to the file at the very beginning of our application, for the rest we only read it.
Can this be a problem of QSettings ? (maybe the way QSettings implements ini file handling ?). Or would this be more related to the file-system (we are using UBI filesystem) ? Someone experienced similar problems ? -
Did you ever found an answer for this question? I'm struggling with it, both in Embedded and x86 Linux/Windows...
-
[quote author="RazZziel" date="1338665406"] I'm struggling with it, both in Embedded and x86 Linux/Windows...[/quote]
If you can reproduce it under PC linux/Window, I think it will be easy to resolve , even it's a bug of Qt. -
I've found the error a lot of times, usually followed by clients calling us in rage after the data loss, but I can't really tell when this is happening
-
Users of my program also report similar problem which I never noticed myself. I tried to reproduce it with the following program:
cat >empty.cpp <<EOF
@
#include <QCoreApplication>
#include <QSemaphore>
#include <QSettings>
#include <QStringList>
#include <QThread>struct Settings : public QSettings
{
Settings(const QString &_name) : QSettings(_name, QSettings::IniFormat) {}
};static QString getIniName()
{
QStringList args = QCoreApplication::arguments();
return ((args.size() > 1) ? args.at(1) : "/tmp/empty.ini");
}static bool canChangeIni()
{
QStringList args = QCoreApplication::arguments();
return ((args.size() > 2) ? true : false);
}static void initValue(const QString &_iniName, const char *_key, const QVariant &_val)
{
Settings s(_iniName);
if (s.contains(_key))
return;
qWarning("key %s is missing", _key);
s.setValue(_key, _val);
}struct IniThread : public QThread
{
IniThread(const QString &_iniName, bool _changeIni) : QThread(), m_iniName(_iniName), m_changeIni(_changeIni) {}void run() {
Settings s(m_iniName);
while (true) {
if (!m_changeIni) {
volatile int oneVal = s.value("one/val", 1).toInt();
volatile QString twoVal = s.value("two/val", "2").toString();
&oneVal;
&twoVal;
}
else {
s.setValue("one/val", s.value("one/val", 1).toInt()+1);
s.sync();
s.setValue("two/val", nextTwoVal(s.value("two/val", "2").toString()));
s.sync();
}
}
}QString nextTwoVal(const QString &_val) {
return QString::number(_val.toInt() + 1);
}QString m_iniName; bool m_changeIni;
};
int main(int _argc, char *_argv[])
{
QCoreApplication app(_argc, _argv);QString iniName = getIniName(); bool changeIni = canChangeIni(); // fill ini file with default values initValue(iniName, "one/val", 1); initValue(iniName, "two/val", "2"); // start thread to update ini file IniThread thread(iniName, changeIni); thread.start(); // wait a little, then terminate while ini file is accessed QSemaphore sem; sem.tryAcquire(1, 1000); return 0;
}
@
EOFcat >empty.pro <<EOF
@
QT += core
QT -= gui
CONFIG += console
CONFIG += warn_onTARGET = empty
TEMPLATE = appSOURCES += empty.cpp
@EOF
Basically, it runs thread which constantly changes ini file and then process exits without stopping writer thread. Once in 3-5 invocations it produces empty ini file. Might be run as following in sh shell:
while ( true ); do ./empty /tmp/empty.ini 1; if [ ! -s /tmp/empty.ini ]; then break; fi; done
In my program I'm using wrapper around QSettings, so I can just add flag to block writing when program finishes. It might still produce empty ini file if program crashes while ini is updated, so I can write into temporary file and then replace original one, or save original before writing values - at least there will be backup ini file.
-
Did anyone found a solution to this?
-
Quite late but somthing could help,
From past 3 days I was facing the same issue. The problem is qsettings keeps writing file in event loop. Hence this file will be always be present in ur kernel buffer. After writing changes in the next event loop it wll again put file in kernel buffer. And whn ur app crash or power off with out writing buffer kernel makes tht file zero byte. Some system providers will have capacitors to keep system up for tiny amount of time so tht kernel can clear buffer but most small embedded wil not have tht facility.. I actually fixed this problem by using normal qfile read and write function. after write flush i do QProcess::execute("sync"). This will clear buffer. hence ur file is not more in kernel buffer. And safe. But in this case u can lost file whn sync is going on and ur power goes off.. Its not atomic.