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

KDE's Doxygen guidelines are available online.