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 fetchRelations = 0;
118 int fetchVRefs = 0;
119};
120
121} // namespace Server
122} // namespace Akonadi
123
124using namespace Akonadi;
125using namespace Akonadi::Protocol;
126using namespace Akonadi::Server;
127
128AggregatedCollectionFetchScope::AggregatedCollectionFetchScope()
129 : d_ptr(new AggregatedCollectionFetchScopePrivate)
130{
131}
132
133AggregatedCollectionFetchScope::~AggregatedCollectionFetchScope() = default;
134
135void AggregatedCollectionFetchScope::apply(const Protocol::CollectionFetchScope &oldScope, const Protocol::CollectionFetchScope &newScope)
136{
137 LOCKED_D(AggregatedCollectionFetchScope)
138
139 if (newScope.includeStatistics() != oldScope.includeStatistics()) {
140 d->updateBool(newScope.includeStatistics(), d->fetchStats);
141 }
142 if (newScope.fetchIdOnly() != oldScope.fetchIdOnly()) {
143 d->updateBool(newScope.fetchIdOnly(), d->fetchIdOnly);
144 }
145 if (newScope.attributes() != oldScope.attributes()) {
146 d->applySet(oldScope.attributes(), newScope.attributes(), d->attrs, d->attrsCount);
147 }
148}
149
150QSet<QByteArray> AggregatedCollectionFetchScope::attributes() const
151{
152 LOCKED_D(const AggregatedCollectionFetchScope)
153 return d->attrs;
154}
155
156bool AggregatedCollectionFetchScope::fetchIdOnly() const
157{
158 LOCKED_D(const AggregatedCollectionFetchScope)
159 // Aggregation: we can return true only if everyone wants fetchIdOnly,
160 // otherwise there's at least one subscriber who wants everything
161 return d->fetchIdOnly == d->subscribers;
162}
163
164bool AggregatedCollectionFetchScope::fetchStatistics() const
165{
166 LOCKED_D(const AggregatedCollectionFetchScope);
167 // Aggregation: return true if at least one subscriber wants stats
168 return d->fetchStats > 0;
169}
170
171void AggregatedCollectionFetchScope::addSubscriber()
172{
173 LOCKED_D(AggregatedCollectionFetchScope)
174 ++d->subscribers;
175}
176
177void AggregatedCollectionFetchScope::removeSubscriber()
178{
179 LOCKED_D(AggregatedCollectionFetchScope)
180 --d->subscribers;
181}
182
183AggregatedItemFetchScope::AggregatedItemFetchScope()
184 : d_ptr(new AggregatedItemFetchScopePrivate)
185{
186}
187
188AggregatedItemFetchScope::~AggregatedItemFetchScope() = default;
189
190void AggregatedItemFetchScope::apply(const Protocol::ItemFetchScope &oldScope, const Protocol::ItemFetchScope &newScope)
191{
192 LOCKED_D(AggregatedItemFetchScope);
193
194 const auto newParts = newScope.requestedParts() | AkRanges::Actions::toQSet;
195 const auto oldParts = oldScope.requestedParts() | AkRanges::Actions::toQSet;
196 if (newParts != oldParts) {
197 d->applySet(oldParts, newParts, d->parts, d->partsCount);
198 }
199 if (newScope.ancestorDepth() != oldScope.ancestorDepth()) {
200 updateAncestorDepth(oldScope.ancestorDepth(), newScope.ancestorDepth());
201 }
202 if (newScope.cacheOnly() != oldScope.cacheOnly()) {
203 d->updateBool(newScope.cacheOnly(), d->cacheOnly);
204 }
205 if (newScope.fullPayload() != oldScope.fullPayload()) {
206 d->updateBool(newScope.fullPayload(), d->fullPayload);
207 }
208 if (newScope.allAttributes() != oldScope.allAttributes()) {
209 d->updateBool(newScope.allAttributes(), d->allAttributes);
210 }
211 if (newScope.fetchSize() != oldScope.fetchSize()) {
212 d->updateBool(newScope.fetchSize(), d->fetchSize);
213 }
214 if (newScope.fetchMTime() != oldScope.fetchMTime()) {
215 d->updateBool(newScope.fetchMTime(), d->fetchMTime);
216 }
217 if (newScope.fetchRemoteRevision() != oldScope.fetchRemoteRevision()) {
218 d->updateBool(newScope.fetchRemoteRevision(), d->fetchRRev);
219 }
220 if (newScope.ignoreErrors() != oldScope.ignoreErrors()) {
221 d->updateBool(newScope.ignoreErrors(), d->ignoreErrors);
222 }
223 if (newScope.fetchFlags() != oldScope.fetchFlags()) {
224 d->updateBool(newScope.fetchFlags(), d->fetchFlags);
225 }
226 if (newScope.fetchRemoteId() != oldScope.fetchRemoteId()) {
227 d->updateBool(newScope.fetchRemoteId(), d->fetchRID);
228 }
229 if (newScope.fetchGID() != oldScope.fetchGID()) {
230 d->updateBool(newScope.fetchGID(), d->fetchGID);
231 }
232 if (newScope.fetchTags() != oldScope.fetchTags()) {
233 d->updateBool(newScope.fetchTags(), d->fetchTags);
234 }
235 if (newScope.fetchRelations() != oldScope.fetchRelations()) {
236 d->updateBool(newScope.fetchRelations(), d->fetchRelations);
237 }
238 if (newScope.fetchVirtualReferences() != oldScope.fetchVirtualReferences()) {
239 d->updateBool(newScope.fetchVirtualReferences(), d->fetchVRefs);
240 }
241
242 d->mCachedScopeValid = false;
243}
244
245ItemFetchScope AggregatedItemFetchScope::toFetchScope() const
246{
247 LOCKED_D(const AggregatedItemFetchScope);
248 if (d->mCachedScopeValid) {
249 return d->mCachedScope;
250 }
251
252 d->mCachedScope = ItemFetchScope();
253 d->mCachedScope.setRequestedParts(d->parts | AkRanges::Actions::toQVector);
254 d->mCachedScope.setAncestorDepth(ancestorDepth());
255
256 d->mCachedScope.setFetch(ItemFetchScope::CacheOnly, cacheOnly());
257 d->mCachedScope.setFetch(ItemFetchScope::FullPayload, fullPayload());
258 d->mCachedScope.setFetch(ItemFetchScope::AllAttributes, allAttributes());
259 d->mCachedScope.setFetch(ItemFetchScope::Size, fetchSize());
260 d->mCachedScope.setFetch(ItemFetchScope::MTime, fetchMTime());
261 d->mCachedScope.setFetch(ItemFetchScope::RemoteRevision, fetchRemoteRevision());
262 d->mCachedScope.setFetch(ItemFetchScope::IgnoreErrors, ignoreErrors());
263 d->mCachedScope.setFetch(ItemFetchScope::Flags, fetchFlags());
264 d->mCachedScope.setFetch(ItemFetchScope::RemoteID, fetchRemoteId());
265 d->mCachedScope.setFetch(ItemFetchScope::GID, fetchGID());
266 d->mCachedScope.setFetch(ItemFetchScope::Tags, fetchTags());
267 d->mCachedScope.setFetch(ItemFetchScope::Relations, fetchRelations());
268 d->mCachedScope.setFetch(ItemFetchScope::VirtReferences, fetchVirtualReferences());
269 d->mCachedScopeValid = true;
270 return d->mCachedScope;
271}
272
273QSet<QByteArray> AggregatedItemFetchScope::requestedParts() const
274{
275 LOCKED_D(const AggregatedItemFetchScope)
276 return d->parts;
277}
278
279ItemFetchScope::AncestorDepth AggregatedItemFetchScope::ancestorDepth() const
280{
281 LOCKED_D(const AggregatedItemFetchScope)
282 // Aggregation: return the largest depth with at least one subscriber
283 if (d->ancestors[ItemFetchScope::AllAncestors] > 0) {
284 return ItemFetchScope::AllAncestors;
285 } else if (d->ancestors[ItemFetchScope::ParentAncestor] > 0) {
286 return ItemFetchScope::ParentAncestor;
287 } else {
288 return ItemFetchScope::NoAncestor;
289 }
290}
291
292void AggregatedItemFetchScope::updateAncestorDepth(ItemFetchScope::AncestorDepth oldDepth, ItemFetchScope::AncestorDepth newDepth)
293{
294 LOCKED_D(AggregatedItemFetchScope)
295 if (d->ancestors[oldDepth] > 0) {
296 --d->ancestors[oldDepth];
297 }
298 ++d->ancestors[newDepth];
299}
300
301bool AggregatedItemFetchScope::cacheOnly() const
302{
303 LOCKED_D(const AggregatedItemFetchScope)
304 // Aggregation: we can return true only if everyone wants cached data only,
305 // otherwise there's at least one subscriber who wants uncached data
306 return d->cacheOnly == d->subscribers;
307}
308
309bool AggregatedItemFetchScope::fullPayload() const
310{
311 LOCKED_D(const AggregatedItemFetchScope)
312 // Aggregation: return true if there's at least one subscriber who wants the
313 // full payload
314 return d->fullPayload > 0;
315}
316
317bool AggregatedItemFetchScope::allAttributes() const
318{
319 LOCKED_D(const AggregatedItemFetchScope)
320 // Aggregation: return true if there's at least one subscriber who wants
321 // all attributes
322 return d->allAttributes > 0;
323}
324
325bool AggregatedItemFetchScope::fetchSize() const
326{
327 LOCKED_D(const AggregatedItemFetchScope)
328 // Aggregation: return true if there's at least one subscriber who wants size
329 return d->fetchSize > 0;
330}
331
332bool AggregatedItemFetchScope::fetchMTime() const
333{
334 LOCKED_D(const AggregatedItemFetchScope)
335 // Aggregation: return true if there's at least one subscriber who wants mtime
336 return d->fetchMTime > 0;
337}
338
339bool AggregatedItemFetchScope::fetchRemoteRevision() const
340{
341 LOCKED_D(const AggregatedItemFetchScope)
342 // Aggregation: return true if there's at least one subscriber who wants rrev
343 return d->fetchRRev > 0;
344}
345
346bool AggregatedItemFetchScope::ignoreErrors() const
347{
348 LOCKED_D(const AggregatedItemFetchScope)
349 // Aggregation: return true only if everyone wants to ignore errors, otherwise
350 // there's at least one subscriber who does not want to ignore them
351 return d->ignoreErrors == d->subscribers;
352}
353
354bool AggregatedItemFetchScope::fetchFlags() const
355{
356 LOCKED_D(const AggregatedItemFetchScope)
357 // Aggregation: return true if there's at least one subscriber who wants flags
358 return d->fetchFlags > 0;
359}
360
361bool AggregatedItemFetchScope::fetchRemoteId() const
362{
363 LOCKED_D(const AggregatedItemFetchScope)
364 // Aggregation: return true if there's at least one subscriber who wants RID
365 return d->fetchRID > 0;
366}
367
368bool AggregatedItemFetchScope::fetchGID() const
369{
370 LOCKED_D(const AggregatedItemFetchScope)
371 // Aggregation: return true if there's at least one subscriber who wants GID
372 return d->fetchGID > 0;
373}
374
375bool AggregatedItemFetchScope::fetchTags() const
376{
377 LOCKED_D(const AggregatedItemFetchScope)
378 // Aggregation: return true if there's at least one subscriber who wants tags
379 return d->fetchTags > 0;
380}
381
382bool AggregatedItemFetchScope::fetchRelations() const
383{
384 LOCKED_D(const AggregatedItemFetchScope)
385 // Aggregation: return true if there's at least one subscriber who wants relations
386 return d->fetchRelations > 0;
387}
388
389bool AggregatedItemFetchScope::fetchVirtualReferences() const
390{
391 LOCKED_D(const AggregatedItemFetchScope)
392 // Aggregation: return true if there's at least one subscriber who wants vrefs
393 return d->fetchVRefs > 0;
394}
395
396void AggregatedItemFetchScope::addSubscriber()
397{
398 LOCKED_D(AggregatedItemFetchScope)
399 ++d->subscribers;
400}
401
402void AggregatedItemFetchScope::removeSubscriber()
403{
404 LOCKED_D(AggregatedItemFetchScope)
405 --d->subscribers;
406}
407
408AggregatedTagFetchScope::AggregatedTagFetchScope()
409 : d_ptr(new AggregatedTagFetchScopePrivate)
410{
411}
412
413AggregatedTagFetchScope::~AggregatedTagFetchScope() = default;
414
415void AggregatedTagFetchScope::apply(const Protocol::TagFetchScope &oldScope, const Protocol::TagFetchScope &newScope)
416{
417 LOCKED_D(AggregatedTagFetchScope)
418
419 if (newScope.fetchIdOnly() != oldScope.fetchIdOnly()) {
420 d->updateBool(newScope.fetchIdOnly(), d->fetchIdOnly);
421 }
422 if (newScope.fetchRemoteID() != oldScope.fetchRemoteID()) {
423 d->updateBool(newScope.fetchRemoteID(), d->fetchRemoteId);
424 }
425 if (newScope.fetchAllAttributes() != oldScope.fetchAllAttributes()) {
426 // Count the number of subscribers who call with false
427 d->updateBool(!newScope.fetchAllAttributes(), d->doNotFetchAllAttributes);
428 }
429 if (newScope.attributes() != oldScope.attributes()) {
430 d->applySet(oldScope.attributes(), newScope.attributes(), d->attrs, d->attrsCount);
431 }
432}
433
434Protocol::TagFetchScope AggregatedTagFetchScope::toFetchScope() const
435{
436 Protocol::TagFetchScope tfs;
437 tfs.setFetchIdOnly(fetchIdOnly());
438 tfs.setFetchRemoteID(fetchRemoteId());
439 tfs.setFetchAllAttributes(fetchAllAttributes());
440 tfs.setAttributes(attributes());
441 return tfs;
442}
443
444bool AggregatedTagFetchScope::fetchIdOnly() const
445{
446 LOCKED_D(const AggregatedTagFetchScope)
447 // Aggregation: we can return true only if everyone wants fetchIdOnly,
448 // otherwise there's at least one subscriber who wants everything
449 return d->fetchIdOnly == d->subscribers;
450}
451
452bool AggregatedTagFetchScope::fetchRemoteId() const
453{
454 LOCKED_D(const AggregatedTagFetchScope)
455 return d->fetchRemoteId > 0;
456}
457
458bool AggregatedTagFetchScope::fetchAllAttributes() const
459{
460 LOCKED_D(const AggregatedTagFetchScope)
461 // The default value for fetchAllAttributes is true, so we return false only if every subscriber said "do not fetch all attributes"
462 return d->doNotFetchAllAttributes != d->subscribers;
463}
464
465QSet<QByteArray> AggregatedTagFetchScope::attributes() const
466{
467 LOCKED_D(const AggregatedTagFetchScope)
468 return d->attrs;
469}
470
471void AggregatedTagFetchScope::addSubscriber()
472{
473 LOCKED_D(AggregatedTagFetchScope)
474 ++d->subscribers;
475}
476
477void AggregatedTagFetchScope::removeSubscriber()
478{
479 LOCKED_D(AggregatedTagFetchScope)
480 --d->subscribers;
481}
482
483#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 Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.