Fixes for synchronization cache, fixes for cache in TT-RSS, more to come.

This commit is contained in:
Martin Rotter 2020-12-16 13:42:59 +01:00
parent b09d3ecf1e
commit bf0c143938
13 changed files with 109 additions and 88 deletions

View File

@ -1,8 +1,8 @@
--- ---
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
title: '' title: '[BUG]: '
labels: '' labels: Type-Defect
assignees: martinrotter assignees: martinrotter
--- ---
<!--- <!---

View File

@ -1,7 +1,7 @@
--- ---
name: Feature request name: Feature request
about: Suggest an idea for this project about: Suggest an idea for this project
title: '' title: '[FR]: '
labels: Type-Enhancement labels: Type-Enhancement
assignees: martinrotter assignees: martinrotter
--- ---

View File

@ -10,35 +10,43 @@
#include <QDir> #include <QDir>
#include <QSet> #include <QSet>
CacheForServiceRoot::CacheForServiceRoot() : m_cacheSaveMutex(new QMutex()) {} CacheForServiceRoot::CacheForServiceRoot() : m_uniqueId(NO_PARENT_CATEGORY), m_cacheSaveMutex(new QMutex()) {}
void CacheForServiceRoot::addLabelsAssignmentsToCache(const QStringList& ids_of_messages,
const QString& lbl_custom_id,
bool assign) {
if (assign) {
for (const QString& custom_id : ids_of_messages) {
if (m_cachedLabelDeassignments[lbl_custom_id].contains(custom_id)) {
// We want to assign this ID but it was marked for deassignment, remove from deassignment.
m_cachedLabelDeassignments[lbl_custom_id].removeAll(custom_id);
}
else {
m_cachedLabelAssignments[lbl_custom_id].append(custom_id);
m_cachedLabelAssignments[lbl_custom_id].removeDuplicates();
}
}
}
else {
for (const QString& custom_id : ids_of_messages) {
if (m_cachedLabelAssignments[lbl_custom_id].contains(custom_id)) {
// We want to deassign this ID but it was marked for assignment, remove from assignment.
m_cachedLabelAssignments[lbl_custom_id].removeAll(custom_id);
}
else {
m_cachedLabelDeassignments[lbl_custom_id].append(custom_id);
m_cachedLabelDeassignments[lbl_custom_id].removeDuplicates();
}
}
}
saveCacheToFile();
}
void CacheForServiceRoot::addLabelsAssignmentsToCache(const QList<Message>& ids_of_messages, Label* lbl, bool assign) { void CacheForServiceRoot::addLabelsAssignmentsToCache(const QList<Message>& ids_of_messages, Label* lbl, bool assign) {
auto custom_ids = lbl->getParentServiceRoot()->customIDsOfMessages(ids_of_messages); auto custom_ids = lbl->getParentServiceRoot()->customIDsOfMessages(ids_of_messages);
if (assign) { addLabelsAssignmentsToCache(custom_ids, lbl->customId(), assign);
for (const QString& custom_id : custom_ids) {
if (m_cachedLabelDeassignments[lbl->customId()].contains(custom_id)) {
// We want to assign this ID but it was marked for deassignment, remove from deassignment.
m_cachedLabelDeassignments[lbl->customId()].removeAll(custom_id);
}
else {
m_cachedLabelAssignments[lbl->customId()].append(custom_id);
m_cachedLabelAssignments[lbl->customId()].removeDuplicates();
}
}
}
else {
for (const QString& custom_id : custom_ids) {
if (m_cachedLabelAssignments[lbl->customId()].contains(custom_id)) {
// We want to deassign this ID but it was marked for assignment, remove from assignment.
m_cachedLabelAssignments[lbl->customId()].removeAll(custom_id);
}
else {
m_cachedLabelDeassignments[lbl->customId()].append(custom_id);
m_cachedLabelDeassignments[lbl->customId()].removeDuplicates();
}
}
}
} }
void CacheForServiceRoot::addMessageStatesToCache(const QList<Message>& ids_of_messages, RootItem::Importance importance) { void CacheForServiceRoot::addMessageStatesToCache(const QList<Message>& ids_of_messages, RootItem::Importance importance) {
@ -65,6 +73,8 @@ void CacheForServiceRoot::addMessageStatesToCache(const QList<Message>& ids_of_m
list_act.append(set_act.values()); list_act.append(set_act.values());
list_other.clear(); list_other.clear();
list_other.append(set_other.values()); list_other.append(set_other.values());
saveCacheToFile();
} }
void CacheForServiceRoot::addMessageStatesToCache(const QStringList& ids_of_messages, RootItem::ReadStatus read) { void CacheForServiceRoot::addMessageStatesToCache(const QStringList& ids_of_messages, RootItem::ReadStatus read) {
@ -91,13 +101,13 @@ void CacheForServiceRoot::addMessageStatesToCache(const QStringList& ids_of_mess
list_act.append(set_act.values()); list_act.append(set_act.values());
list_other.clear(); list_other.clear();
list_other.append(set_other.values()); list_other.append(set_other.values());
saveCacheToFile();
} }
void CacheForServiceRoot::saveCacheToFile(int acc_id) { void CacheForServiceRoot::saveCacheToFile() {
QMutexLocker lck(m_cacheSaveMutex.data());
// Save to file. // Save to file.
const QString file_cache = qApp->userDataFolder() + QDir::separator() + QString::number(acc_id) + "-cached-msgs.dat"; const QString file_cache = qApp->userDataFolder() + QDir::separator() + QString::number(m_uniqueId) + "-cached-msgs.dat";
if (isEmpty()) { if (isEmpty()) {
QFile::remove(file_cache); QFile::remove(file_cache);
@ -112,8 +122,6 @@ void CacheForServiceRoot::saveCacheToFile(int acc_id) {
file.flush(); file.flush();
file.close(); file.close();
} }
clearCache();
} }
} }
@ -124,28 +132,29 @@ void CacheForServiceRoot::clearCache() {
m_cachedLabelDeassignments.clear(); m_cachedLabelDeassignments.clear();
} }
void CacheForServiceRoot::loadCacheFromFile(int acc_id) { void CacheForServiceRoot::loadCacheFromFile() {
QMutexLocker lck(m_cacheSaveMutex.data()); QMutexLocker lck(m_cacheSaveMutex.data());
clearCache(); clearCache();
// Load from file. // Load from file.
const QString file_cache = qApp->userDataFolder() + QDir::separator() + QString::number(acc_id) + "-cached-msgs.dat"; const QString file_cache = qApp->userDataFolder() + QDir::separator() + QString::number(m_uniqueId) + "-cached-msgs.dat";
QFile file(file_cache); QFile file(file_cache);
if (file.exists()) { if (file.exists()) {
if (file.open(QIODevice::ReadOnly)) { if (file.open(QIODevice::OpenModeFlag::ReadOnly)) {
QDataStream stream(&file); QDataStream stream(&file);
stream >> m_cachedStatesImportant >> m_cachedStatesRead >> m_cachedLabelAssignments >> m_cachedLabelDeassignments; stream >> m_cachedStatesImportant >> m_cachedStatesRead >> m_cachedLabelAssignments >> m_cachedLabelDeassignments;
file.flush();
file.close(); file.close();
} }
file.remove();
} }
} }
void CacheForServiceRoot::setUniqueId(int unique_id) {
m_uniqueId = unique_id;
}
CacheSnapshot CacheForServiceRoot::takeMessageCache() { CacheSnapshot CacheForServiceRoot::takeMessageCache() {
QMutexLocker lck(m_cacheSaveMutex.data()); QMutexLocker lck(m_cacheSaveMutex.data());
@ -165,6 +174,7 @@ CacheSnapshot CacheForServiceRoot::takeMessageCache() {
cached_deass_lbl.detach(); cached_deass_lbl.detach();
clearCache(); clearCache();
saveCacheToFile();
CacheSnapshot c; CacheSnapshot c;

View File

@ -22,20 +22,29 @@ class CacheForServiceRoot {
public: public:
explicit CacheForServiceRoot(); explicit CacheForServiceRoot();
virtual void saveAllCachedData(bool async = true) = 0;
void addLabelsAssignmentsToCache(const QStringList& ids_of_messages, const QString& lbl_custom_id, bool assign);
void addLabelsAssignmentsToCache(const QList<Message>& ids_of_messages, Label* lbl, bool assign); void addLabelsAssignmentsToCache(const QList<Message>& ids_of_messages, Label* lbl, bool assign);
void addMessageStatesToCache(const QList<Message>& ids_of_messages, RootItem::Importance importance); void addMessageStatesToCache(const QList<Message>& ids_of_messages, RootItem::Importance importance);
void addMessageStatesToCache(const QStringList& ids_of_messages, RootItem::ReadStatus read); void addMessageStatesToCache(const QStringList& ids_of_messages, RootItem::ReadStatus read);
// Persistently saves/loads cached changes to/from file. void loadCacheFromFile();
// NOTE: The whole cache is cleared after save is done and before load is done. void setUniqueId(int unique_id);
void saveCacheToFile(int acc_id);
void loadCacheFromFile(int acc_id);
virtual void saveAllCachedData(bool async = true) = 0;
protected: protected:
// Returns all cached data and clears the cache.
// NOTE: If returned data are not successfuly passed back to
// server then caller needs to re-add the data back to cache.
CacheSnapshot takeMessageCache(); CacheSnapshot takeMessageCache();
private:
bool isEmpty() const;
void clearCache();
void saveCacheToFile();
int m_uniqueId;
QScopedPointer<QMutex> m_cacheSaveMutex; QScopedPointer<QMutex> m_cacheSaveMutex;
// Map where key is label's custom ID and value is list of message custom IDs // Map where key is label's custom ID and value is list of message custom IDs
@ -51,10 +60,6 @@ class CacheForServiceRoot {
// Map of cached important/unimportant changes. // Map of cached important/unimportant changes.
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

@ -499,6 +499,12 @@ int ServiceRoot::accountId() const {
void ServiceRoot::setAccountId(int account_id) { void ServiceRoot::setAccountId(int account_id) {
m_accountId = account_id; m_accountId = account_id;
auto* cache = dynamic_cast<CacheForServiceRoot*>(this);
if (cache != nullptr) {
cache->setUniqueId(account_id);
}
} }
bool ServiceRoot::loadMessagesForItem(RootItem* item, MessagesModel* model) { bool ServiceRoot::loadMessagesForItem(RootItem* item, MessagesModel* model) {

View File

@ -184,17 +184,14 @@ void GmailServiceRoot::start(bool freshly_activated) {
Q_UNUSED(freshly_activated) Q_UNUSED(freshly_activated)
loadFromDatabase(); loadFromDatabase();
loadCacheFromFile(accountId()); loadCacheFromFile();
if (childCount() <= 3) { if (childCount() <= 3) {
syncIn(); syncIn();
} }
else {
m_network->oauth()->login(); m_network->oauth()->login();
} }
void GmailServiceRoot::stop() {
saveCacheToFile(accountId());
} }
QString GmailServiceRoot::code() const { QString GmailServiceRoot::code() const {

View File

@ -31,7 +31,6 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual bool supportsFeedAdding() const; virtual bool supportsFeedAdding() const;
virtual bool supportsCategoryAdding() const; virtual bool supportsCategoryAdding() const;
virtual void start(bool freshly_activated); virtual void start(bool freshly_activated);
virtual void stop();
virtual QString code() const; virtual QString code() const;
virtual QString additionalTooltip() const; virtual QString additionalTooltip() const;
virtual void saveAllCachedData(bool async = true); virtual void saveAllCachedData(bool async = true);

View File

@ -108,7 +108,7 @@ void InoreaderServiceRoot::start(bool freshly_activated) {
Q_UNUSED(freshly_activated) Q_UNUSED(freshly_activated)
loadFromDatabase(); loadFromDatabase();
loadCacheFromFile(accountId()); loadCacheFromFile();
if (childCount() <= 3) { if (childCount() <= 3) {
syncIn(); syncIn();
@ -118,10 +118,6 @@ void InoreaderServiceRoot::start(bool freshly_activated) {
} }
} }
void InoreaderServiceRoot::stop() {
saveCacheToFile(accountId());
}
QString InoreaderServiceRoot::code() const { QString InoreaderServiceRoot::code() const {
return InoreaderEntryPoint().code(); return InoreaderEntryPoint().code();
} }

View File

@ -29,7 +29,6 @@ class InoreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual bool supportsFeedAdding() const; virtual bool supportsFeedAdding() const;
virtual bool supportsCategoryAdding() const; virtual bool supportsCategoryAdding() const;
virtual void start(bool freshly_activated); virtual void start(bool freshly_activated);
virtual void stop();
virtual QString code() const; virtual QString code() const;
virtual QString additionalTooltip() const; virtual QString additionalTooltip() const;
virtual void saveAllCachedData(bool async = true); virtual void saveAllCachedData(bool async = true);

View File

@ -65,17 +65,13 @@ bool OwnCloudServiceRoot::supportsCategoryAdding() 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()); loadCacheFromFile();
if (childCount() <= 3) { if (childCount() <= 3) {
syncIn(); syncIn();
} }
} }
void OwnCloudServiceRoot::stop() {
saveCacheToFile(accountId());
}
QString OwnCloudServiceRoot::code() const { QString OwnCloudServiceRoot::code() const {
return OwnCloudServiceEntryPoint().code(); return OwnCloudServiceEntryPoint().code();
} }

View File

@ -18,24 +18,22 @@ class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot {
explicit OwnCloudServiceRoot(RootItem* parent = nullptr); explicit OwnCloudServiceRoot(RootItem* parent = nullptr);
virtual ~OwnCloudServiceRoot(); virtual ~OwnCloudServiceRoot();
bool isSyncable() const; virtual bool isSyncable() const;
bool canBeEdited() const; virtual bool canBeEdited() const;
bool canBeDeleted() const; virtual bool canBeDeleted() const;
bool editViaGui(); virtual bool editViaGui();
bool deleteViaGui(); virtual bool deleteViaGui();
bool supportsFeedAdding() const; virtual bool supportsFeedAdding() const;
bool supportsCategoryAdding() const; virtual bool supportsCategoryAdding() const;
virtual void start(bool freshly_activated);
virtual QString code() const;
virtual void saveAllCachedData(bool async = true);
void start(bool freshly_activated);
void stop();
QString code() const;
OwnCloudNetworkFactory* network() const; OwnCloudNetworkFactory* network() const;
void updateTitle(); void updateTitle();
void saveAccountDataToDatabase(); void saveAccountDataToDatabase();
void saveAllCachedData(bool async = true);
protected: protected:
virtual RootItem* obtainNewTreeForSyncIn() const; virtual RootItem* obtainNewTreeForSyncIn() const;

View File

@ -332,7 +332,8 @@ TtRssResponse TtRssNetworkFactory::setArticleLabel(const QStringList& article_id
TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList& ids, TtRssUpdateArticleResponse TtRssNetworkFactory::updateArticles(const QStringList& ids,
UpdateArticle::OperatingField field, UpdateArticle::OperatingField field,
UpdateArticle::Mode mode, bool async) { UpdateArticle::Mode mode,
bool async) {
Q_UNUSED(async) Q_UNUSED(async)
QJsonObject json; QJsonObject json;
@ -515,6 +516,7 @@ TtRssResponse::TtRssResponse(const QString& raw_content) {
} }
TtRssResponse::~TtRssResponse() = default; TtRssResponse::~TtRssResponse() = default;
bool TtRssResponse::isLoaded() const { bool TtRssResponse::isLoaded() const {
return !m_rawContent.isEmpty(); return !m_rawContent.isEmpty();
} }

View File

@ -39,7 +39,7 @@ ServiceRoot::LabelOperation TtRssServiceRoot::supportedLabelOperations() const {
void TtRssServiceRoot::start(bool freshly_activated) { void TtRssServiceRoot::start(bool freshly_activated) {
Q_UNUSED(freshly_activated) Q_UNUSED(freshly_activated)
loadFromDatabase(); loadFromDatabase();
loadCacheFromFile(accountId()); loadCacheFromFile();
if (childCount() <= 3) { if (childCount() <= 3) {
syncIn(); syncIn();
@ -47,8 +47,6 @@ void TtRssServiceRoot::start(bool freshly_activated) {
} }
void TtRssServiceRoot::stop() { void TtRssServiceRoot::stop() {
saveCacheToFile(accountId());
m_network->logout(); m_network->logout();
qDebugNN << LOGSEC_TTRSS qDebugNN << LOGSEC_TTRSS
<< "Stopping Tiny Tiny RSS account, logging out with result" << "Stopping Tiny Tiny RSS account, logging out with result"
@ -130,12 +128,16 @@ void TtRssServiceRoot::saveAllCachedData(bool async) {
QStringList ids = i.value(); QStringList ids = i.value();
if (!ids.isEmpty()) { if (!ids.isEmpty()) {
network()->updateArticles(ids, auto res = network()->updateArticles(ids,
UpdateArticle::OperatingField::Unread, UpdateArticle::OperatingField::Unread,
key == RootItem::ReadStatus::Unread key == RootItem::ReadStatus::Unread
? UpdateArticle::Mode::SetToTrue ? UpdateArticle::Mode::SetToTrue
: UpdateArticle::Mode::SetToFalse, : UpdateArticle::Mode::SetToFalse,
async); async);
if (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError()) {
addMessageStatesToCache(ids, key);
}
} }
} }
@ -149,13 +151,16 @@ void TtRssServiceRoot::saveAllCachedData(bool async) {
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
QStringList ids = customIDsOfMessages(messages); QStringList ids = customIDsOfMessages(messages);
auto res = network()->updateArticles(ids,
network()->updateArticles(ids,
UpdateArticle::OperatingField::Starred, UpdateArticle::OperatingField::Starred,
key == RootItem::Importance::Important key == RootItem::Importance::Important
? UpdateArticle::Mode::SetToTrue ? UpdateArticle::Mode::SetToTrue
: UpdateArticle::Mode::SetToFalse, : UpdateArticle::Mode::SetToFalse,
async); async);
if (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError()) {
addMessageStatesToCache(messages, key);
}
} }
} }
@ -168,7 +173,11 @@ void TtRssServiceRoot::saveAllCachedData(bool async) {
QStringList messages = k.value(); QStringList messages = k.value();
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
network()->setArticleLabel(messages, label_custom_id, true); auto res = network()->setArticleLabel(messages, label_custom_id, true);
if (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError()) {
addLabelsAssignmentsToCache(messages, label_custom_id, true);
}
} }
} }
@ -181,7 +190,11 @@ void TtRssServiceRoot::saveAllCachedData(bool async) {
QStringList messages = l.value(); QStringList messages = l.value();
if (!messages.isEmpty()) { if (!messages.isEmpty()) {
network()->setArticleLabel(messages, label_custom_id, false); auto res = network()->setArticleLabel(messages, label_custom_id, false);
if (network()->lastError() != QNetworkReply::NetworkError::NoError || res.hasError()) {
addLabelsAssignmentsToCache(messages, label_custom_id, false);
}
} }
} }
} }