Attempt to fix #121.

This commit is contained in:
Martin Rotter 2017-09-09 14:14:25 +02:00
parent 2d8fbab362
commit 31cd7d5b01
9 changed files with 158 additions and 24 deletions

View File

@ -100,6 +100,40 @@ Message Message::fromSqlRecord(const QSqlRecord& record, bool* result) {
return message; return message;
} }
QDataStream& operator<<(QDataStream& out, const Message& myObj) {
out << myObj.m_accountId
<< myObj.m_customHash
<< myObj.m_customId
<< myObj.m_feedId
<< myObj.m_id
<< myObj.m_isImportant
<< myObj.m_isRead;
return out;
}
QDataStream& operator>>(QDataStream& in, Message& myObj) {
int accountId;
QString customHash;
QString customId;
QString feedId;
int id;
bool isImportant;
bool isRead;
in >> accountId >> customHash >> customId >> feedId >> id >> isImportant >> isRead;
myObj.m_accountId = accountId;
myObj.m_customHash = customHash;
myObj.m_customId = customId;
myObj.m_feedId = feedId;
myObj.m_id = id;
myObj.m_isImportant = isImportant;
myObj.m_isRead = isRead;
return in;
}
uint qHash(Message key, uint seed) { uint qHash(Message key, uint seed) {
Q_UNUSED(seed) Q_UNUSED(seed)
return (key.m_accountId * 10000) + key.m_id; return (key.m_accountId * 10000) + key.m_id;

View File

@ -23,6 +23,7 @@
#include <QDateTime> #include <QDateTime>
#include <QStringList> #include <QStringList>
#include <QSqlRecord> #include <QSqlRecord>
#include <QDataStream>
// Represents single enclosure. // Represents single enclosure.
@ -79,6 +80,11 @@ class Message {
} }
}; };
// Serialize message state.
// NOTE: This is used for persistent caching of message state changes.
QDataStream& operator<<(QDataStream& out, const Message& myObj);
QDataStream& operator>>(QDataStream& in, Message& myObj);
uint qHash(Message key, uint seed); uint qHash(Message key, uint seed);
uint qHash(const Message& key); uint qHash(const Message& key);

View File

@ -83,14 +83,17 @@ void FeedReader::updateFeeds(const QList<Feed*>& feeds) {
if (m_feedDownloader == nullptr) { if (m_feedDownloader == nullptr) {
m_feedDownloader = new FeedDownloader(); m_feedDownloader = new FeedDownloader();
m_feedDownloaderThread = new QThread(); m_feedDownloaderThread = new QThread();
// Downloader setup. // Downloader setup.
qRegisterMetaType<QList<Feed*>>("QList<Feed*>"); qRegisterMetaType<QList<Feed*>>("QList<Feed*>");
m_feedDownloader->moveToThread(m_feedDownloaderThread); m_feedDownloader->moveToThread(m_feedDownloaderThread);
connect(m_feedDownloaderThread, &QThread::finished, m_feedDownloaderThread, &QThread::deleteLater); connect(m_feedDownloaderThread, &QThread::finished, m_feedDownloaderThread, &QThread::deleteLater);
connect(m_feedDownloader, &FeedDownloader::updateFinished, this, &FeedReader::feedUpdatesFinished); connect(m_feedDownloader, &FeedDownloader::updateFinished, this, &FeedReader::feedUpdatesFinished);
connect(m_feedDownloader, &FeedDownloader::updateProgress, this, &FeedReader::feedUpdatesProgress); connect(m_feedDownloader, &FeedDownloader::updateProgress, this, &FeedReader::feedUpdatesProgress);
connect(m_feedDownloader, &FeedDownloader::updateStarted, this, &FeedReader::feedUpdatesStarted); connect(m_feedDownloader, &FeedDownloader::updateStarted, this, &FeedReader::feedUpdatesStarted);
connect(m_feedDownloader, &FeedDownloader::updateFinished, qApp->feedUpdateLock(), &Mutex::unlock); connect(m_feedDownloader, &FeedDownloader::updateFinished, qApp->feedUpdateLock(), &Mutex::unlock);
// Connections are made, start the feed downloader thread. // Connections are made, start the feed downloader thread.
m_feedDownloaderThread->start(); m_feedDownloaderThread->start();
} }
@ -149,10 +152,12 @@ DatabaseCleaner* FeedReader::databaseCleaner() {
if (m_dbCleaner == nullptr) { if (m_dbCleaner == nullptr) {
m_dbCleaner = new DatabaseCleaner(); m_dbCleaner = new DatabaseCleaner();
m_dbCleanerThread = new QThread(); m_dbCleanerThread = new QThread();
// Downloader setup. // Downloader setup.
qRegisterMetaType<CleanerOrders>("CleanerOrders"); qRegisterMetaType<CleanerOrders>("CleanerOrders");
m_dbCleaner->moveToThread(m_dbCleanerThread); m_dbCleaner->moveToThread(m_dbCleanerThread);
connect(m_dbCleanerThread, SIGNAL(finished()), m_dbCleanerThread, SLOT(deleteLater())); connect(m_dbCleanerThread, SIGNAL(finished()), m_dbCleanerThread, SLOT(deleteLater()));
// Connections are made, start the feed downloader thread. // Connections are made, start the feed downloader thread.
m_dbCleanerThread->start(); m_dbCleanerThread->start();
} }
@ -211,8 +216,8 @@ void FeedReader::checkServicesForAsyncOperations() {
checkServicesForAsyncOperations(false); checkServicesForAsyncOperations(false);
} }
void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) { void FeedReader::checkServicesForAsyncOperations(bool wait_for_future, bool do_on_this_thread) {
if (m_cacheSaveFutureWatcher->future().isRunning()) { if (!do_on_this_thread && m_cacheSaveFutureWatcher->future().isRunning()) {
qDebug("Previous future is still running."); qDebug("Previous future is still running.");
// If we want to wait for future synchronously, we want to make sure that // If we want to wait for future synchronously, we want to make sure that
@ -223,11 +228,19 @@ void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) {
} }
else { else {
qWarning("Some cached service data are being saved now, so aborting this saving cycle."); qWarning("Some cached service data are being saved now, so aborting this saving cycle.");
// Some cache saving is now running. // Some cache saving is now running.
return; return;
} }
} }
if (do_on_this_thread) {
foreach (ServiceRoot* service, m_feedsModel->serviceRoots()) {
// Store any cached data.
service->saveAllCachedData();
}
}
else {
QFuture<void> future = QtConcurrent::run([&] { QFuture<void> future = QtConcurrent::run([&] {
foreach (ServiceRoot* service, m_feedsModel->serviceRoots()) { foreach (ServiceRoot* service, m_feedsModel->serviceRoots()) {
// Store any cached data. // Store any cached data.
@ -242,6 +255,7 @@ void FeedReader::checkServicesForAsyncOperations(bool wait_for_future) {
else { else {
m_cacheSaveFutureWatcher->setFuture(future); m_cacheSaveFutureWatcher->setFuture(future);
} }
}
} }
void FeedReader::asyncCacheSaveFinished() { void FeedReader::asyncCacheSaveFinished() {
@ -257,7 +271,7 @@ void FeedReader::quit() {
m_autoUpdateTimer->stop(); m_autoUpdateTimer->stop();
} }
checkServicesForAsyncOperations(true); checkServicesForAsyncOperations(false, true);
// Close worker threads. // Close worker threads.
if (m_feedDownloaderThread != nullptr && m_feedDownloaderThread->isRunning()) { if (m_feedDownloaderThread != nullptr && m_feedDownloaderThread->isRunning()) {

View File

@ -79,7 +79,7 @@ class FeedReader : public QObject {
// Is executed when next auto-update round could be done. // Is executed when next auto-update round could be done.
void executeNextAutoUpdate(); void executeNextAutoUpdate();
void checkServicesForAsyncOperations(); void checkServicesForAsyncOperations();
void checkServicesForAsyncOperations(bool wait_for_future); void checkServicesForAsyncOperations(bool wait_for_future, bool do_on_this_thread = false);
void asyncCacheSaveFinished(); void asyncCacheSaveFinished();
signals: signals:

View File

@ -17,9 +17,11 @@
#include "services/abstract/cacheforserviceroot.h" #include "services/abstract/cacheforserviceroot.h"
#include "miscellaneous/application.h"
#include "miscellaneous/mutex.h" #include "miscellaneous/mutex.h"
#include <QSet> #include <QSet>
#include <QDir>
CacheForServiceRoot::CacheForServiceRoot() : m_cacheSaveMutex(new Mutex(QMutex::NonRecursive, nullptr)), CacheForServiceRoot::CacheForServiceRoot() : m_cacheSaveMutex(new Mutex(QMutex::NonRecursive, nullptr)),
@ -77,10 +79,24 @@ void CacheForServiceRoot::saveCacheToFile(int accId) {
m_cacheSaveMutex->lock(); m_cacheSaveMutex->lock();
// Save to file. // Save to file.
const QString file_cache = qApp->userDataPath() + QDir::separator() + QString::number(accId) + "-cached-msgs.dat";
if (isEmpty()) {
QFile::remove(file_cache);
}
else {
QFile file(file_cache);
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QDataStream stream(&file);
stream << m_cachedStatesImportant << m_cachedStatesRead;
file.flush();
file.close();
}
clearCache(); clearCache();
}
m_cacheSaveMutex->unlock(); m_cacheSaveMutex->unlock();
} }
@ -94,6 +110,22 @@ void CacheForServiceRoot::loadCacheFromFile(int accId) {
clearCache(); clearCache();
// Load from file. // Load from file.
const QString file_cache = qApp->userDataPath() + QDir::separator() + QString::number(accId) + "-cached-msgs.dat";
QFile file(file_cache);
if (file.exists()) {
if (file.open(QIODevice::ReadOnly)) {
QDataStream stream(&file);
stream >> m_cachedStatesImportant >> m_cachedStatesRead;
file.flush();
file.close();
}
file.remove();
}
// TODO: TODO
m_cacheSaveMutex->unlock(); m_cacheSaveMutex->unlock();
} }
@ -101,7 +133,7 @@ void CacheForServiceRoot::loadCacheFromFile(int accId) {
QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> CacheForServiceRoot::takeMessageCache() { QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> CacheForServiceRoot::takeMessageCache() {
m_cacheSaveMutex->lock(); m_cacheSaveMutex->lock();
if (m_cachedStatesRead.isEmpty() && m_cachedStatesImportant.isEmpty()) { if (isEmpty()) {
// No cached changes. // No cached changes.
m_cacheSaveMutex->unlock(); m_cacheSaveMutex->unlock();
@ -120,3 +152,7 @@ QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<
return QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>>(cached_data_read, cached_data_imp); return QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>>(cached_data_read, cached_data_imp);
} }
bool CacheForServiceRoot::isEmpty() const {
return m_cachedStatesRead.isEmpty() && m_cachedStatesImportant.isEmpty();
}

View File

@ -46,6 +46,10 @@ class CacheForServiceRoot {
Mutex* m_cacheSaveMutex; Mutex* m_cacheSaveMutex;
QMap<RootItem::ReadStatus, QStringList> m_cachedStatesRead; QMap<RootItem::ReadStatus, QStringList> m_cachedStatesRead;
QMap<RootItem::Importance, QList<Message>> m_cachedStatesImportant; QMap<RootItem::Importance, QList<Message>> m_cachedStatesImportant;
private:
bool isEmpty() const;
void clearCache();
}; };
#endif // CACHEFORSERVICEROOT_H #endif // CACHEFORSERVICEROOT_H

View File

@ -473,3 +473,33 @@ bool RootItem::removeChild(int index) {
return false; return false;
} }
} }
QDataStream& operator>>(QDataStream& in, RootItem::ReadStatus& myObj) {
int obj;
in >> obj;
myObj = (RootItem::ReadStatus)obj;
return in;
}
QDataStream& operator<<(QDataStream& out, const RootItem::ReadStatus& myObj) {
out << (int)myObj;
return out;
}
QDataStream& operator>>(QDataStream& in, RootItem::Importance& myObj) {
int obj;
in >> obj;
myObj = (RootItem::Importance)obj;
return in;
}
QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj) {
out << (int)myObj;
return out;
}

View File

@ -236,4 +236,12 @@ class RootItem : public QObject {
RootItem* m_parentItem; RootItem* m_parentItem;
}; };
QDataStream& operator<<(QDataStream& out, const RootItem::Importance& myObj);
QDataStream& operator>>(QDataStream& in, RootItem::Importance& myObj);
QDataStream& operator<<(QDataStream& out, const RootItem::ReadStatus& myObj);
QDataStream& operator>>(QDataStream& in, RootItem::ReadStatus& myObj);
#endif // ROOTITEM_H #endif // ROOTITEM_H

View File

@ -92,6 +92,7 @@ RecycleBin* OwnCloudServiceRoot::recycleBin() const {
void OwnCloudServiceRoot::start(bool freshly_activated) { void OwnCloudServiceRoot::start(bool freshly_activated) {
Q_UNUSED(freshly_activated) Q_UNUSED(freshly_activated)
loadFromDatabase(); loadFromDatabase();
//loadCacheFromFile(accountId());
if (qApp->isFirstRun(QSL("3.1.1")) || (childCount() == 1 && child(0)->kind() == RootItemKind::Bin)) { if (qApp->isFirstRun(QSL("3.1.1")) || (childCount() == 1 && child(0)->kind() == RootItemKind::Bin)) {
syncIn(); syncIn();
@ -99,6 +100,7 @@ void OwnCloudServiceRoot::start(bool freshly_activated) {
} }
void OwnCloudServiceRoot::stop() { void OwnCloudServiceRoot::stop() {
//saveCacheToFile(accountId());
} }
QString OwnCloudServiceRoot::code() const { QString OwnCloudServiceRoot::code() const {