Akonadi

cachecleaner.cpp
1/*
2 SPDX-FileCopyrightText: 2007 Volker Krause <vkrause@kde.org>
3 SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "cachecleaner.h"
9#include "akonadi.h"
10#include "akonadiserver_debug.h"
11#include "storage/datastore.h"
12#include "storage/entity.h"
13#include "storage/parthelper.h"
14#include "storage/selectquerybuilder.h"
15
16#include "private/protocol_p.h"
17
18#include <QDateTime>
19
20using namespace Akonadi::Server;
21
22QMutex CacheCleanerInhibitor::sLock;
23int CacheCleanerInhibitor::sInhibitCount = 0;
24
25CacheCleanerInhibitor::CacheCleanerInhibitor(AkonadiServer &akonadi, bool doInhibit)
26 : mCleaner(akonadi.cacheCleaner())
27{
28 if (doInhibit) {
29 inhibit();
30 }
31}
32
33CacheCleanerInhibitor::~CacheCleanerInhibitor()
34{
35 if (mInhibited) {
36 uninhibit();
37 }
38}
39
40void CacheCleanerInhibitor::inhibit()
41{
42 if (mInhibited) {
43 qCCritical(AKONADISERVER_LOG) << "Cannot recursively inhibit an inhibitor";
44 return;
45 }
46
47 sLock.lock();
48 if (++sInhibitCount == 1) {
49 if (mCleaner) {
50 mCleaner->inhibit(true);
51 }
52 }
53 sLock.unlock();
54 mInhibited = true;
55}
56
57void CacheCleanerInhibitor::uninhibit()
58{
59 if (!mInhibited) {
60 qCCritical(AKONADISERVER_LOG) << "Cannot uninhibit an uninhibited inhibitor"; // aaaw yeah
61 return;
62 }
63 mInhibited = false;
64
65 sLock.lock();
66 Q_ASSERT(sInhibitCount > 0);
67 if (--sInhibitCount == 0) {
68 if (mCleaner) {
69 mCleaner->inhibit(false);
70 }
71 }
72 sLock.unlock();
73}
74
76 : CollectionScheduler(QStringLiteral("CacheCleaner"), QThread::IdlePriority, parent)
77{
78 setMinimumInterval(5);
79}
80
81CacheCleaner::~CacheCleaner()
82{
83 quitThread();
84}
85
86int CacheCleaner::collectionScheduleInterval(const Collection &collection)
87{
88 return collection.cachePolicyCacheTimeout();
89}
90
91bool CacheCleaner::hasChanged(const Collection &collection, const Collection &changed)
92{
93 return collection.cachePolicyLocalParts() != changed.cachePolicyLocalParts() || collection.cachePolicyCacheTimeout() != changed.cachePolicyCacheTimeout()
94 || collection.cachePolicyInherit() != changed.cachePolicyInherit();
95}
96
97bool CacheCleaner::shouldScheduleCollection(const Collection &collection)
98{
99 return collection.cachePolicyLocalParts() != QLatin1StringView("ALL") && collection.cachePolicyCacheTimeout() >= 0
100 && (collection.enabled() || (collection.displayPref() == Collection::True) || (collection.syncPref() == Collection::True)
101 || (collection.indexPref() == Collection::True))
102 && collection.resourceId() > 0;
103}
104
105void CacheCleaner::collectionExpired(const Collection &collection)
106{
108 qb.addJoin(QueryBuilder::InnerJoin, PimItem::tableName(), Part::pimItemIdColumn(), PimItem::idFullColumnName());
109 qb.addJoin(QueryBuilder::InnerJoin, PartType::tableName(), Part::partTypeIdFullColumnName(), PartType::idFullColumnName());
110 qb.addValueCondition(PimItem::collectionIdFullColumnName(), Query::Equals, collection.id());
111 qb.addValueCondition(PimItem::atimeFullColumnName(), Query::Less, QDateTime::currentDateTimeUtc().addSecs(-60 * collection.cachePolicyCacheTimeout()));
112 qb.addValueCondition(Part::dataFullColumnName(), Query::IsNot, QVariant());
113 qb.addValueCondition(PartType::nsFullColumnName(), Query::Equals, QLatin1StringView("PLD"));
114 qb.addValueCondition(PimItem::dirtyFullColumnName(), Query::Equals, false);
115
116 const QStringList partNames = collection.cachePolicyLocalParts().split(QLatin1Char(' '));
117 for (QString partName : partNames) {
118 if (partName.startsWith(QLatin1StringView(AKONADI_PARAM_PLD))) {
119 partName.remove(0, 4);
120 }
121 qb.addValueCondition(PartType::nameFullColumnName(), Query::NotEquals, partName);
122 }
123 if (qb.exec()) {
124 const Part::List parts = qb.result();
125 if (!parts.isEmpty()) {
126 qCInfo(AKONADISERVER_LOG) << "CacheCleaner found" << parts.count() << "item parts to expire in collection" << collection.name();
127 // clear data field
128 for (Part part : parts) {
129 try {
130 if (!PartHelper::truncate(part)) {
131 qCWarning(AKONADISERVER_LOG) << "CacheCleaner failed to expire item part" << part.id();
132 }
133 } catch (const PartHelperException &e) {
134 qCCritical(AKONADISERVER_LOG) << e.type() << e.what();
135 }
136 }
137 }
138 }
139}
140
141#include "moc_cachecleaner.cpp"
Represents a collection of PIM items.
Definition collection.h:62
CacheCleaner(QObject *parent=nullptr)
Creates a new cache cleaner thread.
void addValueCondition(const QString &column, Query::CompareOperator op, const QVariant &value, ConditionType type=WhereCondition)
Add a WHERE or HAVING condition which compares a column with a given value.
void addJoin(JoinType joinType, const QString &table, const Query::Condition &condition)
Join a table to the query.
bool exec()
Executes the query, returns true on success.
@ InnerJoin
NOTE: only supported for UPDATE and SELECT queries.
Helper class for creating and executing database SELECT queries.
QList< T > result()
Returns the result of this SELECT query.
bool truncate(Part &part)
Truncate the payload of part and update filesystem/database accordingly.
QDateTime currentDateTimeUtc()
void lock()
void unlock()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:01:42 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.