Akonadi

aggregatedfetchscope.cpp
1 /*
2  SPDX-FileCopyrightText: 2017 Daniel Vr├ítil <[email protected]>
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 
17 namespace Akonadi
18 {
19 namespace Server
20 {
21 class AggregatedFetchScopePrivate
22 {
23 public:
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 
69 public:
70  mutable QRecursiveMutex lock;
71 };
72 
73 class AggregatedCollectionFetchScopePrivate : public AggregatedFetchScopePrivate
74 {
75 public:
76  QSet<QByteArray> attrs;
77  QHash<QByteArray, int> attrsCount;
78  int subscribers = 0;
79  int fetchIdOnly = 0;
80  int fetchStats = 0;
81 };
82 
83 class AggregatedTagFetchScopePrivate : public AggregatedFetchScopePrivate
84 {
85 public:
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 
94 class AggregatedItemFetchScopePrivate : public AggregatedFetchScopePrivate
95 {
96 public:
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 
124 using namespace Akonadi;
125 using namespace Akonadi::Protocol;
126 using namespace Akonadi::Server;
127 
128 AggregatedCollectionFetchScope::AggregatedCollectionFetchScope()
129  : d_ptr(new AggregatedCollectionFetchScopePrivate)
130 {
131 }
132 
133 AggregatedCollectionFetchScope::~AggregatedCollectionFetchScope() = default;
134 
135 void 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 
150 QSet<QByteArray> AggregatedCollectionFetchScope::attributes() const
151 {
152  LOCKED_D(const AggregatedCollectionFetchScope)
153  return d->attrs;
154 }
155 
156 bool 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 
164 bool 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 
171 void AggregatedCollectionFetchScope::addSubscriber()
172 {
173  LOCKED_D(AggregatedCollectionFetchScope)
174  ++d->subscribers;
175 }
176 
177 void AggregatedCollectionFetchScope::removeSubscriber()
178 {
179  LOCKED_D(AggregatedCollectionFetchScope)
180  --d->subscribers;
181 }
182 
183 AggregatedItemFetchScope::AggregatedItemFetchScope()
184  : d_ptr(new AggregatedItemFetchScopePrivate)
185 {
186 }
187 
188 AggregatedItemFetchScope::~AggregatedItemFetchScope() = default;
189 
190 void 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 
245 ItemFetchScope 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 
273 QSet<QByteArray> AggregatedItemFetchScope::requestedParts() const
274 {
275  LOCKED_D(const AggregatedItemFetchScope)
276  return d->parts;
277 }
278 
279 ItemFetchScope::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 
292 void 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 
301 bool 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 
309 bool 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 
317 bool 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 
325 bool 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 
332 bool 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 
339 bool 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 
346 bool 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 
354 bool 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 
361 bool 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 
368 bool 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 
375 bool 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 
382 bool 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 
389 bool 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 
396 void AggregatedItemFetchScope::addSubscriber()
397 {
398  LOCKED_D(AggregatedItemFetchScope)
399  ++d->subscribers;
400 }
401 
402 void AggregatedItemFetchScope::removeSubscriber()
403 {
404  LOCKED_D(AggregatedItemFetchScope)
405  --d->subscribers;
406 }
407 
408 AggregatedTagFetchScope::AggregatedTagFetchScope()
409  : d_ptr(new AggregatedTagFetchScopePrivate)
410 {
411 }
412 
413 AggregatedTagFetchScope::~AggregatedTagFetchScope() = default;
414 
415 void 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 
434 Protocol::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 
444 bool 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 
452 bool AggregatedTagFetchScope::fetchRemoteId() const
453 {
454  LOCKED_D(const AggregatedTagFetchScope)
455  return d->fetchRemoteId > 0;
456 }
457 
458 bool 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 
465 QSet<QByteArray> AggregatedTagFetchScope::attributes() const
466 {
467  LOCKED_D(const AggregatedTagFetchScope)
468  return d->attrs;
469 }
470 
471 void AggregatedTagFetchScope::addSubscriber()
472 {
473  LOCKED_D(AggregatedTagFetchScope)
474  ++d->subscribers;
475 }
476 
477 void AggregatedTagFetchScope::removeSubscriber()
478 {
479  LOCKED_D(AggregatedTagFetchScope)
480  --d->subscribers;
481 }
482 
483 #undef LOCKED_D
bool remove(const T &value)
QHash::iterator erase(QHash::iterator pos)
QHash::iterator find(const Key &key)
QHash::iterator insert(const Key &key, const T &value)
QSet::iterator insert(const T &value)
QHash::iterator end()
Specifies which parts of an item should be fetched from the Akonadi storage.
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jun 30 2022 03:51:45 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.