Akonadi

aggregatedfetchscope.cpp
1/*
2 SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "aggregatedfetchscope.h"
8#include "shared/akranges.h"
9
10#include <QMutexLocker>
11#include <QRecursiveMutex>
12
13#define LOCKED_D(name) \
14 Q_D(name); \
15 QMutexLocker lock(&d->lock);
16
17namespace Akonadi
18{
19namespace Server
20{
21class AggregatedFetchScopePrivate
22{
23public:
24 AggregatedFetchScopePrivate()
25 : lock() // recursive so that we can call our own getters/setters
26 {
27 }
28
29 inline void addToSet(const QByteArray &value, QSet<QByteArray> &set, QHash<QByteArray, int> &count)
30 {
31 auto it = count.find(value);
32 if (it == count.end()) {
33 it = count.insert(value, 0);
34 set.insert(value);
35 }
36 ++(*it);
37 }
38
39 inline void removeFromSet(const QByteArray &value, QSet<QByteArray> &set, QHash<QByteArray, int> &count)
40 {
41 auto it = count.find(value);
42 if (it == count.end()) {
43 return;
44 }
45
46 if (--(*it) == 0) {
47 count.erase(it);
48 set.remove(value);
49 }
50 }
51
52 inline void updateBool(bool newValue, int &store)
53 {
54 store += newValue ? 1 : -1;
55 }
56
57 inline void applySet(const QSet<QByteArray> &oldSet, const QSet<QByteArray> &newSet, QSet<QByteArray> &set, QHash<QByteArray, int> &count)
58 {
59 const auto added = newSet - oldSet;
60 for (const auto &value : added) {
61 addToSet(value, set, count);
62 }
63 const auto removed = oldSet - newSet;
64 for (const auto &value : removed) {
65 removeFromSet(value, set, count);
66 }
67 }
68
69public:
70 mutable QRecursiveMutex lock;
71};
72
73class AggregatedCollectionFetchScopePrivate : public AggregatedFetchScopePrivate
74{
75public:
76 QSet<QByteArray> attrs;
77 QHash<QByteArray, int> attrsCount;
78 int subscribers = 0;
79 int fetchIdOnly = 0;
80 int fetchStats = 0;
81};
82
83class AggregatedTagFetchScopePrivate : public AggregatedFetchScopePrivate
84{
85public:
86 QSet<QByteArray> attrs;
87 QHash<QByteArray, int> attrsCount;
88 int subscribers = 0;
89 int fetchIdOnly = 0;
90 int fetchRemoteId = 0;
91 int doNotFetchAllAttributes = 0;
92};
93
94class AggregatedItemFetchScopePrivate : public AggregatedFetchScopePrivate
95{
96public:
97 mutable Protocol::ItemFetchScope mCachedScope;
98 mutable bool mCachedScopeValid = false; // use std::optional for mCachedScope
99
100 QSet<QByteArray> parts;
101 QHash<QByteArray, int> partsCount;
102 QSet<QByteArray> tags;
103 QHash<QByteArray, int> tagsCount;
104 int subscribers = 0;
105 int ancestors[3] = {0, 0, 0}; // 3 = size of AncestorDepth enum
106 int cacheOnly = 0;
107 int fullPayload = 0;
108 int allAttributes = 0;
109 int fetchSize = 0;
110 int fetchMTime = 0;
111 int fetchRRev = 0;
112 int ignoreErrors = 0;
113 int fetchFlags = 0;
114 int fetchRID = 0;
115 int fetchGID = 0;
116 int fetchTags = 0;
117 int fetchVRefs = 0;
118};
119
120} // namespace Server
121} // namespace Akonadi
122
123using namespace Akonadi;
124using namespace Akonadi::Protocol;
125using namespace Akonadi::Server;
126
127AggregatedCollectionFetchScope::AggregatedCollectionFetchScope()
128 : d_ptr(new AggregatedCollectionFetchScopePrivate)
129{
130}
131
132AggregatedCollectionFetchScope::~AggregatedCollectionFetchScope() = default;
133
134void AggregatedCollectionFetchScope::apply(const Protocol::CollectionFetchScope &oldScope, const Protocol::CollectionFetchScope &newScope)
135{
136 LOCKED_D(AggregatedCollectionFetchScope)
137
138 if (newScope.includeStatistics() != oldScope.includeStatistics()) {
139 d->updateBool(newScope.includeStatistics(), d->fetchStats);
140 }
141 if (newScope.fetchIdOnly() != oldScope.fetchIdOnly()) {
142 d->updateBool(newScope.fetchIdOnly(), d->fetchIdOnly);
143 }
144 if (newScope.attributes() != oldScope.attributes()) {
145 d->applySet(oldScope.attributes(), newScope.attributes(), d->attrs, d->attrsCount);
146 }
147}
148
149QSet<QByteArray> AggregatedCollectionFetchScope::attributes() const
150{
151 LOCKED_D(const AggregatedCollectionFetchScope)
152 return d->attrs;
153}
154
155bool AggregatedCollectionFetchScope::fetchIdOnly() const
156{
157 LOCKED_D(const AggregatedCollectionFetchScope)
158 // Aggregation: we can return true only if everyone wants fetchIdOnly,
159 // otherwise there's at least one subscriber who wants everything
160 return d->fetchIdOnly == d->subscribers;
161}
162
163bool AggregatedCollectionFetchScope::fetchStatistics() const
164{
165 LOCKED_D(const AggregatedCollectionFetchScope);
166 // Aggregation: return true if at least one subscriber wants stats
167 return d->fetchStats > 0;
168}
169
170void AggregatedCollectionFetchScope::addSubscriber()
171{
172 LOCKED_D(AggregatedCollectionFetchScope)
173 ++d->subscribers;
174}
175
176void AggregatedCollectionFetchScope::removeSubscriber()
177{
178 LOCKED_D(AggregatedCollectionFetchScope)
179 --d->subscribers;
180}
181
182AggregatedItemFetchScope::AggregatedItemFetchScope()
183 : d_ptr(new AggregatedItemFetchScopePrivate)
184{
185}
186
187AggregatedItemFetchScope::~AggregatedItemFetchScope() = default;
188
189void AggregatedItemFetchScope::apply(const Protocol::ItemFetchScope &oldScope, const Protocol::ItemFetchScope &newScope)
190{
191 LOCKED_D(AggregatedItemFetchScope);
192
193 const auto newParts = newScope.requestedParts() | AkRanges::Actions::toQSet;
194 const auto oldParts = oldScope.requestedParts() | AkRanges::Actions::toQSet;
195 if (newParts != oldParts) {
196 d->applySet(oldParts, newParts, d->parts, d->partsCount);
197 }
198 if (newScope.ancestorDepth() != oldScope.ancestorDepth()) {
199 updateAncestorDepth(oldScope.ancestorDepth(), newScope.ancestorDepth());
200 }
201 if (newScope.cacheOnly() != oldScope.cacheOnly()) {
202 d->updateBool(newScope.cacheOnly(), d->cacheOnly);
203 }
204 if (newScope.fullPayload() != oldScope.fullPayload()) {
205 d->updateBool(newScope.fullPayload(), d->fullPayload);
206 }
207 if (newScope.allAttributes() != oldScope.allAttributes()) {
208 d->updateBool(newScope.allAttributes(), d->allAttributes);
209 }
210 if (newScope.fetchSize() != oldScope.fetchSize()) {
211 d->updateBool(newScope.fetchSize(), d->fetchSize);
212 }
213 if (newScope.fetchMTime() != oldScope.fetchMTime()) {
214 d->updateBool(newScope.fetchMTime(), d->fetchMTime);
215 }
216 if (newScope.fetchRemoteRevision() != oldScope.fetchRemoteRevision()) {
217 d->updateBool(newScope.fetchRemoteRevision(), d->fetchRRev);
218 }
219 if (newScope.ignoreErrors() != oldScope.ignoreErrors()) {
220 d->updateBool(newScope.ignoreErrors(), d->ignoreErrors);
221 }
222 if (newScope.fetchFlags() != oldScope.fetchFlags()) {
223 d->updateBool(newScope.fetchFlags(), d->fetchFlags);
224 }
225 if (newScope.fetchRemoteId() != oldScope.fetchRemoteId()) {
226 d->updateBool(newScope.fetchRemoteId(), d->fetchRID);
227 }
228 if (newScope.fetchGID() != oldScope.fetchGID()) {
229 d->updateBool(newScope.fetchGID(), d->fetchGID);
230 }
231 if (newScope.fetchTags() != oldScope.fetchTags()) {
232 d->updateBool(newScope.fetchTags(), d->fetchTags);
233 }
234 if (newScope.fetchVirtualReferences() != oldScope.fetchVirtualReferences()) {
235 d->updateBool(newScope.fetchVirtualReferences(), d->fetchVRefs);
236 }
237
238 d->mCachedScopeValid = false;
239}
240
241ItemFetchScope AggregatedItemFetchScope::toFetchScope() const
242{
243 LOCKED_D(const AggregatedItemFetchScope);
244 if (d->mCachedScopeValid) {
245 return d->mCachedScope;
246 }
247
248 d->mCachedScope = ItemFetchScope();
249 d->mCachedScope.setRequestedParts(d->parts | AkRanges::Actions::toQVector);
250 d->mCachedScope.setAncestorDepth(ancestorDepth());
251
252 d->mCachedScope.setFetch(ItemFetchScope::CacheOnly, cacheOnly());
253 d->mCachedScope.setFetch(ItemFetchScope::FullPayload, fullPayload());
254 d->mCachedScope.setFetch(ItemFetchScope::AllAttributes, allAttributes());
255 d->mCachedScope.setFetch(ItemFetchScope::Size, fetchSize());
256 d->mCachedScope.setFetch(ItemFetchScope::MTime, fetchMTime());
257 d->mCachedScope.setFetch(ItemFetchScope::RemoteRevision, fetchRemoteRevision());
258 d->mCachedScope.setFetch(ItemFetchScope::IgnoreErrors, ignoreErrors());
259 d->mCachedScope.setFetch(ItemFetchScope::Flags, fetchFlags());
260 d->mCachedScope.setFetch(ItemFetchScope::RemoteID, fetchRemoteId());
261 d->mCachedScope.setFetch(ItemFetchScope::GID, fetchGID());
262 d->mCachedScope.setFetch(ItemFetchScope::Tags, fetchTags());
263 d->mCachedScope.setFetch(ItemFetchScope::VirtReferences, fetchVirtualReferences());
264 d->mCachedScopeValid = true;
265 return d->mCachedScope;
266}
267
268QSet<QByteArray> AggregatedItemFetchScope::requestedParts() const
269{
270 LOCKED_D(const AggregatedItemFetchScope)
271 return d->parts;
272}
273
274ItemFetchScope::AncestorDepth AggregatedItemFetchScope::ancestorDepth() const
275{
276 LOCKED_D(const AggregatedItemFetchScope)
277 // Aggregation: return the largest depth with at least one subscriber
278 if (d->ancestors[ItemFetchScope::AllAncestors] > 0) {
279 return ItemFetchScope::AllAncestors;
280 } else if (d->ancestors[ItemFetchScope::ParentAncestor] > 0) {
281 return ItemFetchScope::ParentAncestor;
282 } else {
283 return ItemFetchScope::NoAncestor;
284 }
285}
286
287void AggregatedItemFetchScope::updateAncestorDepth(ItemFetchScope::AncestorDepth oldDepth, ItemFetchScope::AncestorDepth newDepth)
288{
289 LOCKED_D(AggregatedItemFetchScope)
290 if (d->ancestors[oldDepth] > 0) {
291 --d->ancestors[oldDepth];
292 }
293 ++d->ancestors[newDepth];
294}
295
296bool AggregatedItemFetchScope::cacheOnly() const
297{
298 LOCKED_D(const AggregatedItemFetchScope)
299 // Aggregation: we can return true only if everyone wants cached data only,
300 // otherwise there's at least one subscriber who wants uncached data
301 return d->cacheOnly == d->subscribers;
302}
303
304bool AggregatedItemFetchScope::fullPayload() const
305{
306 LOCKED_D(const AggregatedItemFetchScope)
307 // Aggregation: return true if there's at least one subscriber who wants the
308 // full payload
309 return d->fullPayload > 0;
310}
311
312bool AggregatedItemFetchScope::allAttributes() const
313{
314 LOCKED_D(const AggregatedItemFetchScope)
315 // Aggregation: return true if there's at least one subscriber who wants
316 // all attributes
317 return d->allAttributes > 0;
318}
319
320bool AggregatedItemFetchScope::fetchSize() const
321{
322 LOCKED_D(const AggregatedItemFetchScope)
323 // Aggregation: return true if there's at least one subscriber who wants size
324 return d->fetchSize > 0;
325}
326
327bool AggregatedItemFetchScope::fetchMTime() const
328{
329 LOCKED_D(const AggregatedItemFetchScope)
330 // Aggregation: return true if there's at least one subscriber who wants mtime
331 return d->fetchMTime > 0;
332}
333
334bool AggregatedItemFetchScope::fetchRemoteRevision() const
335{
336 LOCKED_D(const AggregatedItemFetchScope)
337 // Aggregation: return true if there's at least one subscriber who wants rrev
338 return d->fetchRRev > 0;
339}
340
341bool AggregatedItemFetchScope::ignoreErrors() const
342{
343 LOCKED_D(const AggregatedItemFetchScope)
344 // Aggregation: return true only if everyone wants to ignore errors, otherwise
345 // there's at least one subscriber who does not want to ignore them
346 return d->ignoreErrors == d->subscribers;
347}
348
349bool AggregatedItemFetchScope::fetchFlags() const
350{
351 LOCKED_D(const AggregatedItemFetchScope)
352 // Aggregation: return true if there's at least one subscriber who wants flags
353 return d->fetchFlags > 0;
354}
355
356bool AggregatedItemFetchScope::fetchRemoteId() const
357{
358 LOCKED_D(const AggregatedItemFetchScope)
359 // Aggregation: return true if there's at least one subscriber who wants RID
360 return d->fetchRID > 0;
361}
362
363bool AggregatedItemFetchScope::fetchGID() const
364{
365 LOCKED_D(const AggregatedItemFetchScope)
366 // Aggregation: return true if there's at least one subscriber who wants GID
367 return d->fetchGID > 0;
368}
369
370bool AggregatedItemFetchScope::fetchTags() const
371{
372 LOCKED_D(const AggregatedItemFetchScope)
373 // Aggregation: return true if there's at least one subscriber who wants tags
374 return d->fetchTags > 0;
375}
376
377bool AggregatedItemFetchScope::fetchVirtualReferences() const
378{
379 LOCKED_D(const AggregatedItemFetchScope)
380 // Aggregation: return true if there's at least one subscriber who wants vrefs
381 return d->fetchVRefs > 0;
382}
383
384void AggregatedItemFetchScope::addSubscriber()
385{
386 LOCKED_D(AggregatedItemFetchScope)
387 ++d->subscribers;
388}
389
390void AggregatedItemFetchScope::removeSubscriber()
391{
392 LOCKED_D(AggregatedItemFetchScope)
393 --d->subscribers;
394}
395
396AggregatedTagFetchScope::AggregatedTagFetchScope()
397 : d_ptr(new AggregatedTagFetchScopePrivate)
398{
399}
400
401AggregatedTagFetchScope::~AggregatedTagFetchScope() = default;
402
403void AggregatedTagFetchScope::apply(const Protocol::TagFetchScope &oldScope, const Protocol::TagFetchScope &newScope)
404{
405 LOCKED_D(AggregatedTagFetchScope)
406
407 if (newScope.fetchIdOnly() != oldScope.fetchIdOnly()) {
408 d->updateBool(newScope.fetchIdOnly(), d->fetchIdOnly);
409 }
410 if (newScope.fetchRemoteID() != oldScope.fetchRemoteID()) {
411 d->updateBool(newScope.fetchRemoteID(), d->fetchRemoteId);
412 }
413 if (newScope.fetchAllAttributes() != oldScope.fetchAllAttributes()) {
414 // Count the number of subscribers who call with false
415 d->updateBool(!newScope.fetchAllAttributes(), d->doNotFetchAllAttributes);
416 }
417 if (newScope.attributes() != oldScope.attributes()) {
418 d->applySet(oldScope.attributes(), newScope.attributes(), d->attrs, d->attrsCount);
419 }
420}
421
422Protocol::TagFetchScope AggregatedTagFetchScope::toFetchScope() const
423{
424 Protocol::TagFetchScope tfs;
425 tfs.setFetchIdOnly(fetchIdOnly());
426 tfs.setFetchRemoteID(fetchRemoteId());
427 tfs.setFetchAllAttributes(fetchAllAttributes());
428 tfs.setAttributes(attributes());
429 return tfs;
430}
431
432bool AggregatedTagFetchScope::fetchIdOnly() const
433{
434 LOCKED_D(const AggregatedTagFetchScope)
435 // Aggregation: we can return true only if everyone wants fetchIdOnly,
436 // otherwise there's at least one subscriber who wants everything
437 return d->fetchIdOnly == d->subscribers;
438}
439
440bool AggregatedTagFetchScope::fetchRemoteId() const
441{
442 LOCKED_D(const AggregatedTagFetchScope)
443 return d->fetchRemoteId > 0;
444}
445
446bool AggregatedTagFetchScope::fetchAllAttributes() const
447{
448 LOCKED_D(const AggregatedTagFetchScope)
449 // The default value for fetchAllAttributes is true, so we return false only if every subscriber said "do not fetch all attributes"
450 return d->doNotFetchAllAttributes != d->subscribers;
451}
452
453QSet<QByteArray> AggregatedTagFetchScope::attributes() const
454{
455 LOCKED_D(const AggregatedTagFetchScope)
456 return d->attrs;
457}
458
459void AggregatedTagFetchScope::addSubscriber()
460{
461 LOCKED_D(AggregatedTagFetchScope)
462 ++d->subscribers;
463}
464
465void AggregatedTagFetchScope::removeSubscriber()
466{
467 LOCKED_D(AggregatedTagFetchScope)
468 --d->subscribers;
469}
470
471#undef LOCKED_D
Specifies which parts of an item should be fetched from the Akonadi storage.
Helper integration between Akonadi and Qt.
iterator end()
iterator erase(const_iterator pos)
iterator find(const Key &key)
iterator insert(const Key &key, const T &value)
iterator insert(const T &value)
bool remove(const T &value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:08:30 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.