1 | /* |
2 | Copyright (c) 2007 Volker Krause <vkrause@kde.org> |
3 | Copyright (C) 2014 Daniel Vrátil <dvratil@redhat.com> |
4 | |
5 | This library is free software; you can redistribute it and/or modify it |
6 | under the terms of the GNU Library General Public License as published by |
7 | the Free Software Foundation; either version 2 of the License, or (at your |
8 | option) any later version. |
9 | |
10 | This library is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
13 | License for more details. |
14 | |
15 | You should have received a copy of the GNU Library General Public License |
16 | along with this library; see the file COPYING.LIB. If not, write to the |
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
18 | 02110-1301, USA. |
19 | */ |
20 | |
21 | #include "cachecleaner.h" |
22 | #include "akdebug.h" |
23 | #include "storage/parthelper.h" |
24 | #include "storage/datastore.h" |
25 | #include "storage/selectquerybuilder.h" |
26 | #include "storage/entity.h" |
27 | #include "akonadi.h" |
28 | #include "libs/protocol_p.h" |
29 | |
30 | using namespace Akonadi::Server; |
31 | |
32 | QMutex CacheCleanerInhibitor::sLock; |
33 | int CacheCleanerInhibitor::sInhibitCount = 0; |
34 | |
35 | CacheCleanerInhibitor::CacheCleanerInhibitor(bool doInhibit) |
36 | : mInhibited(false) |
37 | { |
38 | if (doInhibit) { |
39 | inhibit(); |
40 | } |
41 | } |
42 | |
43 | CacheCleanerInhibitor::~CacheCleanerInhibitor() |
44 | { |
45 | if (mInhibited) { |
46 | uninhibit(); |
47 | } |
48 | } |
49 | |
50 | void CacheCleanerInhibitor::inhibit() |
51 | { |
52 | if (mInhibited) { |
53 | akError() << "Cannot recursively inhibit an inhibitor" ; |
54 | return; |
55 | } |
56 | |
57 | sLock.lock(); |
58 | if (++sInhibitCount == 1) { |
59 | if (AkonadiServer::instance()->cacheCleaner()) { |
60 | AkonadiServer::instance()->cacheCleaner()->inhibit(true); |
61 | } |
62 | } |
63 | sLock.unlock(); |
64 | mInhibited = true; |
65 | } |
66 | |
67 | void CacheCleanerInhibitor::uninhibit() |
68 | { |
69 | if (!mInhibited) { |
70 | akError() << "Cannot uninhibit an uninhibited inhibitor" ; // aaaw yeah |
71 | return; |
72 | } |
73 | mInhibited = false; |
74 | |
75 | sLock.lock(); |
76 | Q_ASSERT(sInhibitCount > 0); |
77 | if (--sInhibitCount == 0) { |
78 | if (AkonadiServer::instance()->cacheCleaner()) { |
79 | AkonadiServer::instance()->cacheCleaner()->inhibit(false); |
80 | } |
81 | } |
82 | sLock.unlock(); |
83 | } |
84 | |
85 | CacheCleaner::CacheCleaner(QObject *parent) |
86 | : CollectionScheduler(parent) |
87 | { |
88 | setMinimumInterval(5); |
89 | } |
90 | |
91 | CacheCleaner::~CacheCleaner() |
92 | { |
93 | } |
94 | |
95 | int CacheCleaner::collectionScheduleInterval(const Collection &collection) |
96 | { |
97 | return collection.cachePolicyCacheTimeout(); |
98 | } |
99 | |
100 | bool CacheCleaner::hasChanged(const Collection &collection, const Collection &changed) |
101 | { |
102 | return collection.cachePolicyLocalParts() != changed.cachePolicyLocalParts() |
103 | || collection.cachePolicyCacheTimeout() != changed.cachePolicyCacheTimeout() |
104 | || collection.cachePolicyInherit() != changed.cachePolicyInherit(); |
105 | } |
106 | |
107 | bool CacheCleaner::shouldScheduleCollection(const Collection &collection) |
108 | { |
109 | return collection.cachePolicyLocalParts() != QLatin1String("ALL" ) |
110 | && collection.cachePolicyCacheTimeout() >= 0 |
111 | && (collection.enabled() || (collection.displayPref() == Tristate::True) || (collection.syncPref() == Tristate::True) || (collection.indexPref() == Tristate::True)) |
112 | && collection.resourceId() > 0; |
113 | } |
114 | |
115 | void CacheCleaner::collectionExpired(const Collection &collection) |
116 | { |
117 | SelectQueryBuilder<Part> qb; |
118 | qb.addJoin(QueryBuilder::InnerJoin, PimItem::tableName(), Part::pimItemIdColumn(), PimItem::idFullColumnName()); |
119 | qb.addJoin(QueryBuilder::InnerJoin, PartType::tableName(), Part::partTypeIdFullColumnName(), PartType::idFullColumnName()); |
120 | qb.addValueCondition(PimItem::collectionIdFullColumnName(), Query::Equals, collection.id()); |
121 | qb.addValueCondition(PimItem::atimeFullColumnName(), Query::Less, QDateTime::currentDateTime().addSecs(-60 * collection.cachePolicyCacheTimeout())); |
122 | qb.addValueCondition(Part::dataFullColumnName(), Query::IsNot, QVariant()); |
123 | qb.addValueCondition(PartType::nsFullColumnName(), Query::Equals, QLatin1String("PLD" )); |
124 | qb.addValueCondition(PimItem::dirtyFullColumnName(), Query::Equals, false); |
125 | |
126 | QStringList localParts; |
127 | Q_FOREACH (QString partName, collection.cachePolicyLocalParts().split(QLatin1String(" " ))) { |
128 | if (partName.startsWith(QLatin1String(AKONADI_PARAM_PLD))) { |
129 | partName = partName.mid(4); |
130 | } |
131 | qb.addValueCondition(PartType::nameFullColumnName(), Query::NotEquals, partName); |
132 | } |
133 | if (qb.exec()) { |
134 | const Part::List parts = qb.result(); |
135 | if (!parts.isEmpty()) { |
136 | akDebug() << "found" << parts.count() << "item parts to expire in collection" << collection.name(); |
137 | // clear data field |
138 | Q_FOREACH (Part part, parts) { |
139 | try { |
140 | if (!PartHelper::truncate(part)) { |
141 | akDebug() << "failed to update item part" << part.id(); |
142 | } |
143 | } catch (const PartHelperException &e) { |
144 | akError() << e.type() << e.what(); |
145 | } |
146 | } |
147 | } |
148 | } |
149 | } |
150 | |