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

KDE's Doxygen guidelines are available online.