Significantly reduce impact of FileWatcher hashing (#3724)

* Fix #3699

Reduce file watch hashing of open database files from every second to every 30 seconds. Additionally, only hash the first 1024 bytes of the database file. This is valid since most of the header and the entire encrypted portion are changed significantly on every save.
This commit is contained in:
Jonathan White 2019-10-30 06:40:56 -04:00 committed by Janek Bevendorff
parent 178bea6bbc
commit 36e14157be
3 changed files with 17 additions and 7 deletions

View File

@ -158,7 +158,7 @@ bool Database::open(const QString& filePath, QSharedPointer<const CompositeKey>
m_initialized = true;
emit databaseOpened();
m_fileWatcher->start(canonicalFilePath());
m_fileWatcher->start(canonicalFilePath(), 30, 1);
setEmitModified(true);
return true;
@ -234,7 +234,7 @@ bool Database::saveAs(const QString& filePath, QString* error, bool atomic, bool
bool ok = performSave(canonicalFilePath, error, atomic, backup);
if (ok) {
setFilePath(filePath);
m_fileWatcher->start(canonicalFilePath);
m_fileWatcher->start(canonicalFilePath, 30, 1);
} else {
// Saving failed, don't rewatch file since it does not represent our database
markAsModified();

View File

@ -42,7 +42,7 @@ FileWatcher::FileWatcher(QObject* parent)
m_fileIgnoreDelayTimer.setSingleShot(true);
}
void FileWatcher::start(const QString& filePath, int checksumInterval)
void FileWatcher::start(const QString& filePath, int checksumIntervalSeconds, int checksumSizeKibibytes)
{
stop();
@ -63,8 +63,14 @@ void FileWatcher::start(const QString& filePath, int checksumInterval)
m_fileWatcher.addPath(filePath);
m_filePath = filePath;
// Handle file checksum
m_fileChecksumSizeBytes = checksumSizeKibibytes * 1024;
m_fileChecksum = calculateChecksum();
m_fileChecksumTimer.start(checksumInterval);
if (checksumIntervalSeconds > 0) {
m_fileChecksumTimer.start(checksumIntervalSeconds * 1000);
}
m_ignoreFileChange = false;
}
@ -131,9 +137,12 @@ QByteArray FileWatcher::calculateChecksum()
QFile file(m_filePath);
if (file.open(QFile::ReadOnly)) {
QCryptographicHash hash(QCryptographicHash::Sha256);
if (hash.addData(&file)) {
return hash.result();
if (m_fileChecksumSizeBytes > 0) {
hash.addData(file.read(m_fileChecksumSizeBytes));
} else {
hash.addData(&file);
}
return hash.result();
}
return {};
}

View File

@ -30,7 +30,7 @@ class FileWatcher : public QObject
public:
explicit FileWatcher(QObject* parent = nullptr);
void start(const QString& path, int checksumInterval = 1000);
void start(const QString& path, int checksumIntervalSeconds = 0, int checksumSizeKibibytes = -1);
void stop();
bool hasSameFileChecksum();
@ -56,6 +56,7 @@ private:
QTimer m_fileChangeDelayTimer;
QTimer m_fileIgnoreDelayTimer;
QTimer m_fileChecksumTimer;
int m_fileChecksumSizeBytes;
bool m_ignoreFileChange;
};