File indexing completed on 2025-01-05 04:47:02
0001 /* 0002 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org> 0003 SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "cachecleaner.h" 0009 #include "akonadi.h" 0010 #include "akonadiserver_debug.h" 0011 #include "storage/datastore.h" 0012 #include "storage/entity.h" 0013 #include "storage/parthelper.h" 0014 #include "storage/selectquerybuilder.h" 0015 0016 #include "private/protocol_p.h" 0017 0018 #include <QDateTime> 0019 0020 using namespace Akonadi::Server; 0021 0022 QMutex CacheCleanerInhibitor::sLock; 0023 int CacheCleanerInhibitor::sInhibitCount = 0; 0024 0025 CacheCleanerInhibitor::CacheCleanerInhibitor(AkonadiServer &akonadi, bool doInhibit) 0026 : mCleaner(akonadi.cacheCleaner()) 0027 { 0028 if (doInhibit) { 0029 inhibit(); 0030 } 0031 } 0032 0033 CacheCleanerInhibitor::~CacheCleanerInhibitor() 0034 { 0035 if (mInhibited) { 0036 uninhibit(); 0037 } 0038 } 0039 0040 void CacheCleanerInhibitor::inhibit() 0041 { 0042 if (mInhibited) { 0043 qCCritical(AKONADISERVER_LOG) << "Cannot recursively inhibit an inhibitor"; 0044 return; 0045 } 0046 0047 sLock.lock(); 0048 if (++sInhibitCount == 1) { 0049 if (mCleaner) { 0050 mCleaner->inhibit(true); 0051 } 0052 } 0053 sLock.unlock(); 0054 mInhibited = true; 0055 } 0056 0057 void CacheCleanerInhibitor::uninhibit() 0058 { 0059 if (!mInhibited) { 0060 qCCritical(AKONADISERVER_LOG) << "Cannot uninhibit an uninhibited inhibitor"; // aaaw yeah 0061 return; 0062 } 0063 mInhibited = false; 0064 0065 sLock.lock(); 0066 Q_ASSERT(sInhibitCount > 0); 0067 if (--sInhibitCount == 0) { 0068 if (mCleaner) { 0069 mCleaner->inhibit(false); 0070 } 0071 } 0072 sLock.unlock(); 0073 } 0074 0075 CacheCleaner::CacheCleaner(QObject *parent) 0076 : CollectionScheduler(QStringLiteral("CacheCleaner"), QThread::IdlePriority, parent) 0077 { 0078 setMinimumInterval(5); 0079 } 0080 0081 CacheCleaner::~CacheCleaner() 0082 { 0083 quitThread(); 0084 } 0085 0086 int CacheCleaner::collectionScheduleInterval(const Collection &collection) 0087 { 0088 return collection.cachePolicyCacheTimeout(); 0089 } 0090 0091 bool CacheCleaner::hasChanged(const Collection &collection, const Collection &changed) 0092 { 0093 return collection.cachePolicyLocalParts() != changed.cachePolicyLocalParts() || collection.cachePolicyCacheTimeout() != changed.cachePolicyCacheTimeout() 0094 || collection.cachePolicyInherit() != changed.cachePolicyInherit(); 0095 } 0096 0097 bool CacheCleaner::shouldScheduleCollection(const Collection &collection) 0098 { 0099 return collection.cachePolicyLocalParts() != QLatin1StringView("ALL") && collection.cachePolicyCacheTimeout() >= 0 0100 && (collection.enabled() || (collection.displayPref() == Collection::True) || (collection.syncPref() == Collection::True) 0101 || (collection.indexPref() == Collection::True)) 0102 && collection.resourceId() > 0; 0103 } 0104 0105 void CacheCleaner::collectionExpired(const Collection &collection) 0106 { 0107 SelectQueryBuilder<Part> qb; 0108 qb.addJoin(QueryBuilder::InnerJoin, PimItem::tableName(), Part::pimItemIdColumn(), PimItem::idFullColumnName()); 0109 qb.addJoin(QueryBuilder::InnerJoin, PartType::tableName(), Part::partTypeIdFullColumnName(), PartType::idFullColumnName()); 0110 qb.addValueCondition(PimItem::collectionIdFullColumnName(), Query::Equals, collection.id()); 0111 qb.addValueCondition(PimItem::atimeFullColumnName(), Query::Less, QDateTime::currentDateTimeUtc().addSecs(-60 * collection.cachePolicyCacheTimeout())); 0112 qb.addValueCondition(Part::dataFullColumnName(), Query::IsNot, QVariant()); 0113 qb.addValueCondition(PartType::nsFullColumnName(), Query::Equals, QLatin1StringView("PLD")); 0114 qb.addValueCondition(PimItem::dirtyFullColumnName(), Query::Equals, false); 0115 0116 const QStringList partNames = collection.cachePolicyLocalParts().split(QLatin1Char(' ')); 0117 for (QString partName : partNames) { 0118 if (partName.startsWith(QLatin1StringView(AKONADI_PARAM_PLD))) { 0119 partName.remove(0, 4); 0120 } 0121 qb.addValueCondition(PartType::nameFullColumnName(), Query::NotEquals, partName); 0122 } 0123 if (qb.exec()) { 0124 const Part::List parts = qb.result(); 0125 if (!parts.isEmpty()) { 0126 qCInfo(AKONADISERVER_LOG) << "CacheCleaner found" << parts.count() << "item parts to expire in collection" << collection.name(); 0127 // clear data field 0128 for (Part part : parts) { 0129 try { 0130 if (!PartHelper::truncate(part)) { 0131 qCWarning(AKONADISERVER_LOG) << "CacheCleaner failed to expire item part" << part.id(); 0132 } 0133 } catch (const PartHelperException &e) { 0134 qCCritical(AKONADISERVER_LOG) << e.type() << e.what(); 0135 } 0136 } 0137 } 0138 } 0139 } 0140 0141 #include "moc_cachecleaner.cpp"