Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorckieschnick <christian.kieschnick@hicknhack-software.com>2019-04-12 20:59:50 +0300
committerJanek Bevendorff <janek@jbev.net>2019-04-12 20:59:50 +0300
commit2eb82c83560844f32f38d17d9ecbd719aed12acb (patch)
tree2ca936712fb5b152edf69f404ae5970088fac771 /src/core/FileWatcher.cpp
parente7815787c72d3f97f79321b764196eeaf57b9fa9 (diff)
Improve file tracking in BulkFileWatcher (#2978)
Introduce modification-based change tracking in BulkFileWatcher to reduce emitted signals caused by file changes within the same directory. Resolves #2895.
Diffstat (limited to 'src/core/FileWatcher.cpp')
-rw-r--r--src/core/FileWatcher.cpp56
1 files changed, 31 insertions, 25 deletions
diff --git a/src/core/FileWatcher.cpp b/src/core/FileWatcher.cpp
index 64e86c3fa..ae7878191 100644
--- a/src/core/FileWatcher.cpp
+++ b/src/core/FileWatcher.cpp
@@ -120,9 +120,9 @@ BulkFileWatcher::BulkFileWatcher(QObject* parent)
{
connect(&m_fileWatcher, SIGNAL(fileChanged(QString)), SLOT(handleFileChanged(QString)));
connect(&m_fileWatcher, SIGNAL(directoryChanged(QString)), SLOT(handleDirectoryChanged(QString)));
- connect(&m_fileWatchUnblockTimer, SIGNAL(timeout()), this, SLOT(observeFileChanges()));
+ connect(&m_watchedFilesIgnoreTimer, SIGNAL(timeout()), this, SLOT(observeFileChanges()));
connect(&m_pendingSignalsTimer, SIGNAL(timeout()), this, SLOT(emitSignals()));
- m_fileWatchUnblockTimer.setSingleShot(true);
+ m_watchedFilesIgnoreTimer.setSingleShot(true);
m_pendingSignalsTimer.setSingleShot(true);
}
@@ -135,7 +135,7 @@ void BulkFileWatcher::clear()
}
m_watchedPaths.clear();
m_watchedFilesInDirectory.clear();
- m_ignoreFilesChangess.clear();
+ m_watchedFilesIgnored.clear();
}
void BulkFileWatcher::removePath(const QString& path)
@@ -166,7 +166,7 @@ void BulkFileWatcher::addPath(const QString& path)
const bool directorySuccess = m_fileWatcher.addPath(directoryPath);
m_watchedPaths[directoryPath] = directorySuccess;
}
- m_watchedFilesInDirectory[directoryPath][filePath] = info.exists();
+ m_watchedFilesInDirectory[directoryPath][filePath] = info.exists() ? info.lastModified().toMSecsSinceEpoch() : 0;
}
void BulkFileWatcher::handleFileChanged(const QString& path)
@@ -174,13 +174,15 @@ void BulkFileWatcher::handleFileChanged(const QString& path)
const QFileInfo info(path);
const QString filePath = info.absoluteFilePath();
const QString directoryPath = info.absolutePath();
- const QMap<QString, bool>& watchedFiles = m_watchedFilesInDirectory[directoryPath];
- const bool created = !watchedFiles[filePath] && info.exists();
- const bool deleted = watchedFiles[filePath] && !info.exists();
- const bool changed = !created && !deleted;
+ const QMap<QString, qint64>& watchedFiles = m_watchedFilesInDirectory[directoryPath];
+ const qint64 lastModificationTime = info.lastModified().toMSecsSinceEpoch();
+ const bool created = watchedFiles[filePath] == 0 && info.exists();
+ const bool deleted = watchedFiles[filePath] != 0 && !info.exists();
+ const bool changed = !created && !deleted && lastModificationTime != watchedFiles[filePath];
+
addPath(path);
- if (m_ignoreFilesChangess[info.canonicalFilePath()] > Clock::currentDateTimeUtc()) {
+ if (m_watchedFilesIgnored[info.canonicalFilePath()] > Clock::currentDateTimeUtc()) {
// changes are blocked
return;
}
@@ -203,35 +205,36 @@ void BulkFileWatcher::handleDirectoryChanged(const QString& path)
qDebug("Directory changed %s", qPrintable(path));
const QFileInfo directoryInfo(path);
const QString directoryPath = directoryInfo.absoluteFilePath();
- QMap<QString, bool>& watchedFiles = m_watchedFilesInDirectory[directoryPath];
+ QMap<QString, qint64>& watchedFiles = m_watchedFilesInDirectory[directoryPath];
for (const QString& filename : watchedFiles.keys()) {
const QFileInfo fileInfo(filename);
const QString filePath = fileInfo.absoluteFilePath();
- const bool existed = watchedFiles[filePath];
- if (!fileInfo.exists() && existed) {
- qDebug("Remove watch file %s", qPrintable(filePath));
+ const qint64 previousModificationTime = watchedFiles[filePath];
+ const qint64 lastModificationTime = fileInfo.lastModified().toMSecsSinceEpoch();
+ if (!fileInfo.exists() && previousModificationTime != 0) {
+ qDebug("Remove watch file %s", qPrintable(fileInfo.absoluteFilePath()));
m_fileWatcher.removePath(filePath);
m_watchedPaths.remove(filePath);
watchedFiles.remove(filePath);
scheduleSignal(Removed, filePath);
}
- if (!existed && fileInfo.exists()) {
- qDebug("Add watch file %s", qPrintable(filePath));
+ if (previousModificationTime == 0 && fileInfo.exists()) {
+ qDebug("Add watch file %s", qPrintable(fileInfo.absoluteFilePath()));
if (!m_watchedPaths.value(filePath)) {
const bool success = m_fileWatcher.addPath(filePath);
m_watchedPaths[filePath] = success;
- watchedFiles[filePath] = fileInfo.exists();
+ watchedFiles[filePath] = lastModificationTime;
}
scheduleSignal(Created, filePath);
}
- if (existed && fileInfo.exists()) {
+ if (fileInfo.exists() && previousModificationTime != lastModificationTime) {
// this case is handled using
qDebug("Refresh watch file %s", qPrintable(fileInfo.absoluteFilePath()));
m_fileWatcher.removePath(fileInfo.absolutePath());
m_fileWatcher.addPath(fileInfo.absolutePath());
scheduleSignal(Updated, filePath);
}
- m_watchedFilesInDirectory[directoryPath][filePath] = fileInfo.exists();
+ m_watchedFilesInDirectory[directoryPath][filePath] = fileInfo.exists() ? lastModificationTime : 0;
}
}
@@ -242,13 +245,16 @@ void BulkFileWatcher::emitSignals()
for (const auto& path : queued.keys()) {
const auto& signal = queued[path];
if (signal.last() == Removed) {
+ qDebug("Emit %s removed", qPrintable(path));
emit fileRemoved(path);
continue;
}
if (signal.first() == Created) {
+ qDebug("Emit %s created", qPrintable(path));
emit fileCreated(path);
continue;
}
+ qDebug("Emit %s changed", qPrintable(path));
emit fileChanged(path);
}
}
@@ -268,7 +274,7 @@ void BulkFileWatcher::scheduleSignal(Signal signal, const QString& path)
void BulkFileWatcher::ignoreFileChanges(const QString& path)
{
const QFileInfo info(path);
- m_ignoreFilesChangess[info.canonicalFilePath()] = Clock::currentDateTimeUtc().addMSecs(FileChangeDelay);
+ m_watchedFilesIgnored[info.canonicalFilePath()] = Clock::currentDateTimeUtc().addMSecs(FileChangeDelay);
}
void BulkFileWatcher::observeFileChanges(bool delayed)
@@ -278,19 +284,19 @@ void BulkFileWatcher::observeFileChanges(bool delayed)
timeout = TimerResolution;
} else {
const QDateTime current = Clock::currentDateTimeUtc();
- for (const QString& key : m_ignoreFilesChangess.keys()) {
- if (m_ignoreFilesChangess[key] < current) {
+ for (const QString& key : m_watchedFilesIgnored.keys()) {
+ if (m_watchedFilesIgnored[key] < current) {
// We assume that there was no concurrent change of the database
// during our block - so no need to reimport
qDebug("Remove block from %s", qPrintable(key));
- m_ignoreFilesChangess.remove(key);
+ m_watchedFilesIgnored.remove(key);
continue;
}
qDebug("Keep block from %s", qPrintable(key));
- timeout = static_cast<int>(current.msecsTo(m_ignoreFilesChangess[key]));
+ timeout = qMin(timeout, static_cast<int>(current.msecsTo(m_watchedFilesIgnored[key])));
}
}
- if (timeout > 0 && !m_fileWatchUnblockTimer.isActive()) {
- m_fileWatchUnblockTimer.start(timeout);
+ if (timeout > 0 && !m_watchedFilesIgnoreTimer.isActive()) {
+ m_watchedFilesIgnoreTimer.start(timeout);
}
}