Akonadi

cachecleaner.cpp
1 /*
2  SPDX-FileCopyrightText: 2007 Volker Krause <[email protected]>
3  SPDX-FileCopyrightText: 2014 Daniel Vrátil <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "cachecleaner.h"
9 #include "storage/parthelper.h"
10 #include "storage/datastore.h"
11 #include "storage/selectquerybuilder.h"
12 #include "storage/entity.h"
13 #include "akonadi.h"
14 #include "akonadiserver_debug.h"
15 
16 #include <private/protocol_p.h>
17 
18 #include <QDateTime>
19 
20 using namespace Akonadi::Server;
21 
22 QMutex CacheCleanerInhibitor::sLock;
23 int CacheCleanerInhibitor::sInhibitCount = 0;
24 
25 CacheCleanerInhibitor::CacheCleanerInhibitor(AkonadiServer &akonadi, bool doInhibit)
26  : mCleaner(akonadi.cacheCleaner())
27 {
28  if (doInhibit) {
29  inhibit();
30  }
31 }
32 
33 CacheCleanerInhibitor::~CacheCleanerInhibitor()
34 {
35  if (mInhibited) {
36  uninhibit();
37  }
38 }
39 
40 void 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 
57 void 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 
75 CacheCleaner::CacheCleaner(QObject *parent)
76  : CollectionScheduler(QStringLiteral("CacheCleaner"), QThread::IdlePriority, parent)
77 {
78  setMinimumInterval(5);
79 }
80 
81 CacheCleaner::~CacheCleaner()
82 {
83  quitThread();
84 }
85 
86 int CacheCleaner::collectionScheduleInterval(const Collection &collection)
87 {
88  return collection.cachePolicyCacheTimeout();
89 }
90 
91 bool CacheCleaner::hasChanged(const Collection &collection, const Collection &changed)
92 {
93  return collection.cachePolicyLocalParts() != changed.cachePolicyLocalParts()
94  || collection.cachePolicyCacheTimeout() != changed.cachePolicyCacheTimeout()
95  || collection.cachePolicyInherit() != changed.cachePolicyInherit();
96 }
97 
98 bool CacheCleaner::shouldScheduleCollection(const Collection &collection)
99 {
100  return collection.cachePolicyLocalParts() != QLatin1String("ALL")
101  && collection.cachePolicyCacheTimeout() >= 0
102  && (collection.enabled() || (collection.displayPref() == Collection::True) || (collection.syncPref() == Collection::True) || (collection.indexPref() == Collection::True))
103  && collection.resourceId() > 0;
104 }
105 
106 void CacheCleaner::collectionExpired(const Collection &collection)
107 {
109  qb.addJoin(QueryBuilder::InnerJoin, PimItem::tableName(), Part::pimItemIdColumn(), PimItem::idFullColumnName());
110  qb.addJoin(QueryBuilder::InnerJoin, PartType::tableName(), Part::partTypeIdFullColumnName(), PartType::idFullColumnName());
111  qb.addValueCondition(PimItem::collectionIdFullColumnName(), Query::Equals, collection.id());
112  qb.addValueCondition(PimItem::atimeFullColumnName(), Query::Less, QDateTime::currentDateTimeUtc().addSecs(-60 * collection.cachePolicyCacheTimeout()));
113  qb.addValueCondition(Part::dataFullColumnName(), Query::IsNot, QVariant());
114  qb.addValueCondition(PartType::nsFullColumnName(), Query::Equals, QLatin1String("PLD"));
115  qb.addValueCondition(PimItem::dirtyFullColumnName(), Query::Equals, false);
116 
117  const QStringList partNames = collection.cachePolicyLocalParts().split(QLatin1Char(' '));
118  for (QString partName : partNames) {
119  if (partName.startsWith(QLatin1String(AKONADI_PARAM_PLD))) {
120  partName.remove(0, 4);
121  }
122  qb.addValueCondition(PartType::nameFullColumnName(), Query::NotEquals, partName);
123  }
124  if (qb.exec()) {
125  const Part::List parts = qb.result();
126  if (!parts.isEmpty()) {
127  qCInfo(AKONADISERVER_LOG) << "CacheCleaner found" << parts.count() << "item parts to expire in collection" << collection.name();
128  // clear data field
129  for (Part part : parts) {
130  try {
131  if (!PartHelper::truncate(part)) {
132  qCWarning(AKONADISERVER_LOG) << "CacheCleaner failed to expire item part" << part.id();
133  }
134  } catch (const PartHelperException &e) {
135  qCCritical(AKONADISERVER_LOG) << e.type() << e.what();
136  }
137  }
138  }
139  }
140 }
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.
QString name() const
Returns the i18n&#39;ed name of the collection.
Definition: collection.cpp:211
Represents a collection of PIM items.
Definition: collection.h:63
NOTE: only supported for UPDATE and SELECT queries.
Definition: querybuilder.h:49
void addJoin(JoinType joinType, const QString &table, const Query::Condition &condition)
Join a table to the query.
bool truncate(Part &part)
Truncate the payload of part and update filesystem/database accordingly.
Definition: parthelper.cpp:152
QVector< T > result()
Returns the result of this SELECT query.
Helper class for creating and executing database SELECT queries.
Id id() const
Returns the unique identifier of the collection.
Definition: collection.cpp:98
bool enabled() const
Returns the collection&#39;s enabled state.
Definition: collection.cpp:366
QDateTime currentDateTimeUtc()
bool exec()
Executes the query, returns true on success.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Jan 19 2021 23:20:39 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.