diff --git a/autotests/server/aggregatedfetchscopetest.cpp b/autotests/server/aggregatedfetchscopetest.cpp index eaeaa4aa4..45eca3200 100644 --- a/autotests/server/aggregatedfetchscopetest.cpp +++ b/autotests/server/aggregatedfetchscopetest.cpp @@ -1,163 +1,168 @@ /* Copyright (c) 2019 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "aggregatedfetchscope.h" #include using namespace Akonadi; using namespace Akonadi::Server; class AggregatedFetchScopeTest : public QObject { Q_OBJECT private Q_SLOTS: void testTagApply() { AggregatedTagFetchScope scope; // first subscriber, A scope.addSubscriber(); Protocol::TagFetchScope oldTagScope, tagScopeA; QSet attrs = {"FOO"}; tagScopeA.setAttributes(attrs); tagScopeA.setFetchIdOnly(true); + tagScopeA.setFetchAllAttributes(false); scope.apply(oldTagScope, tagScopeA); QCOMPARE(scope.attributes(), attrs); QVERIFY(scope.fetchIdOnly()); + QVERIFY(!scope.fetchAllAttributes()); // second subscriber, B Protocol::TagFetchScope tagScopeB = tagScopeA; tagScopeB.setFetchIdOnly(false); + tagScopeB.setFetchAllAttributes(true); scope.addSubscriber(); scope.apply(oldTagScope, tagScopeB); QCOMPARE(scope.attributes(), attrs); QVERIFY(!scope.fetchIdOnly()); + QVERIFY(scope.fetchAllAttributes()); // then B goes away scope.apply(tagScopeB, oldTagScope); scope.removeSubscriber(); QCOMPARE(scope.attributes(), attrs); QVERIFY(scope.fetchIdOnly()); + QVERIFY(!scope.fetchAllAttributes()); // A goes away scope.apply(tagScopeA, oldTagScope); scope.removeSubscriber(); QCOMPARE(scope.attributes(), QSet()); } void testCollectionApply() { AggregatedCollectionFetchScope scope; // first subscriber, A scope.addSubscriber(); Protocol::CollectionFetchScope oldCollectionScope, collectionScopeA; QSet attrs = {"FOO"}; collectionScopeA.setAttributes(attrs); collectionScopeA.setFetchIdOnly(true); scope.apply(oldCollectionScope, collectionScopeA); QCOMPARE(scope.attributes(), attrs); QVERIFY(scope.fetchIdOnly()); // second subscriber, B Protocol::CollectionFetchScope collectionScopeB = collectionScopeA; collectionScopeB.setFetchIdOnly(false); scope.addSubscriber(); scope.apply(oldCollectionScope, collectionScopeB); QCOMPARE(scope.attributes(), attrs); QVERIFY(!scope.fetchIdOnly()); // then B goes away scope.apply(collectionScopeB, oldCollectionScope); scope.removeSubscriber(); QCOMPARE(scope.attributes(), attrs); QVERIFY(scope.fetchIdOnly()); // A goes away scope.apply(collectionScopeA, oldCollectionScope); scope.removeSubscriber(); QCOMPARE(scope.attributes(), QSet()); } void testItemApply() { AggregatedItemFetchScope scope; QCOMPARE(scope.ancestorDepth(), Protocol::ItemFetchScope::NoAncestor); // first subscriber, A scope.addSubscriber(); Protocol::ItemFetchScope oldItemScope, itemScopeA; QVector parts = {"FOO"}; QSet partsSet = {"FOO"}; itemScopeA.setRequestedParts(parts); itemScopeA.setAncestorDepth(Protocol::ItemFetchScope::ParentAncestor); itemScopeA.setFetch(Protocol::ItemFetchScope::CacheOnly); itemScopeA.setFetch(Protocol::ItemFetchScope::IgnoreErrors); scope.apply(oldItemScope, itemScopeA); QCOMPARE(scope.requestedParts(), partsSet); QCOMPARE(scope.ancestorDepth(), Protocol::ItemFetchScope::ParentAncestor); QVERIFY(scope.cacheOnly()); QVERIFY(scope.ignoreErrors()); // second subscriber, B Protocol::ItemFetchScope itemScopeB = itemScopeA; itemScopeB.setAncestorDepth(Protocol::ItemFetchScope::AllAncestors); scope.addSubscriber(); QVERIFY(!scope.cacheOnly()); // they don't agree so: false QVERIFY(!scope.ignoreErrors()); scope.apply(oldItemScope, itemScopeB); QCOMPARE(scope.requestedParts(), partsSet); QCOMPARE(scope.ancestorDepth(), Protocol::ItemFetchScope::AllAncestors); // subscriber C with ParentAncestor - but that won't make change it Protocol::ItemFetchScope itemScopeC = itemScopeA; scope.addSubscriber(); scope.apply(oldItemScope, itemScopeC); QCOMPARE(scope.requestedParts(), partsSet); QCOMPARE(scope.ancestorDepth(), Protocol::ItemFetchScope::AllAncestors); // no change // then C goes away scope.apply(itemScopeC, oldItemScope); scope.removeSubscriber(); QCOMPARE(scope.requestedParts(), partsSet); QCOMPARE(scope.ancestorDepth(), Protocol::ItemFetchScope::AllAncestors); // then B goes away scope.apply(itemScopeB, oldItemScope); scope.removeSubscriber(); QCOMPARE(scope.requestedParts(), partsSet); QCOMPARE(scope.ancestorDepth(), Protocol::ItemFetchScope::ParentAncestor); // A goes away scope.apply(itemScopeA, oldItemScope); scope.removeSubscriber(); QCOMPARE(scope.requestedParts(), QSet()); QCOMPARE(scope.ancestorDepth(), Protocol::ItemFetchScope::NoAncestor); } }; QTEST_MAIN(AggregatedFetchScopeTest) #include "aggregatedfetchscopetest.moc" diff --git a/autotests/server/notificationmanagertest.cpp b/autotests/server/notificationmanagertest.cpp index ea340f921..6d2e4ce98 100644 --- a/autotests/server/notificationmanagertest.cpp +++ b/autotests/server/notificationmanagertest.cpp @@ -1,157 +1,164 @@ /* Copyright (c) 2019 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "aggregatedfetchscope.h" #include "entities.h" #include "notificationmanager.h" #include "notificationsubscriber.h" #include #include using namespace Akonadi; using namespace Akonadi::Server; class TestableNotificationSubscriber : public NotificationSubscriber { public: TestableNotificationSubscriber(NotificationManager *manager) : NotificationSubscriber(manager) { mSubscriber = "TestSubscriber"; } using NotificationSubscriber::registerSubscriber; using NotificationSubscriber::modifySubscription; using NotificationSubscriber::disconnectSubscriber; }; class NotificationManagerTest : public QObject { Q_OBJECT private Q_SLOTS: void testAggregatedFetchScope() { NotificationManager manager(AkThread::NoThread); QMetaObject::invokeMethod(&manager, "init", Qt::DirectConnection); // first subscriber, A TestableNotificationSubscriber subscriberA(&manager); Protocol::CreateSubscriptionCommand createCmd; createCmd.setSession("session1"); subscriberA.registerSubscriber(createCmd); QVERIFY(!manager.tagFetchScope()->fetchIdOnly()); + QVERIFY(manager.tagFetchScope()->fetchAllAttributes()); // default is true QVERIFY(!manager.collectionFetchScope()->fetchIdOnly()); QVERIFY(!manager.collectionFetchScope()->fetchStatistics()); // set A's subscription settings Protocol::ModifySubscriptionCommand modifyCmd; { Protocol::TagFetchScope tagFetchScope; tagFetchScope.setFetchIdOnly(true); + tagFetchScope.setFetchAllAttributes(false); modifyCmd.setTagFetchScope(tagFetchScope); Protocol::CollectionFetchScope collectionFetchScope; collectionFetchScope.setFetchIdOnly(true); collectionFetchScope.setIncludeStatistics(true); modifyCmd.setCollectionFetchScope(collectionFetchScope); Protocol::ItemFetchScope itemFetchScope; itemFetchScope.setFetch(Protocol::ItemFetchScope::FullPayload); itemFetchScope.setFetch(Protocol::ItemFetchScope::AllAttributes); itemFetchScope.setFetch(Protocol::ItemFetchScope::Size); itemFetchScope.setFetch(Protocol::ItemFetchScope::MTime); itemFetchScope.setFetch(Protocol::ItemFetchScope::RemoteRevision); itemFetchScope.setFetch(Protocol::ItemFetchScope::Flags); itemFetchScope.setFetch(Protocol::ItemFetchScope::RemoteID); itemFetchScope.setFetch(Protocol::ItemFetchScope::GID); itemFetchScope.setFetch(Protocol::ItemFetchScope::Tags); itemFetchScope.setFetch(Protocol::ItemFetchScope::Relations); itemFetchScope.setFetch(Protocol::ItemFetchScope::VirtReferences); modifyCmd.setItemFetchScope(itemFetchScope); } subscriberA.modifySubscription(modifyCmd); QVERIFY(manager.tagFetchScope()->fetchIdOnly()); + QVERIFY(!manager.tagFetchScope()->fetchAllAttributes()); QVERIFY(manager.collectionFetchScope()->fetchIdOnly()); QVERIFY(manager.collectionFetchScope()->fetchStatistics()); QVERIFY(manager.itemFetchScope()->fullPayload()); QVERIFY(manager.itemFetchScope()->allAttributes()); // second subscriber, B TestableNotificationSubscriber subscriberB(&manager); subscriberB.registerSubscriber(createCmd); QVERIFY(!manager.tagFetchScope()->fetchIdOnly()); // A and B don't agree, so: false + QVERIFY(manager.tagFetchScope()->fetchAllAttributes()); QVERIFY(!manager.collectionFetchScope()->fetchIdOnly()); QVERIFY(manager.collectionFetchScope()->fetchStatistics()); // at least one - so still true QVERIFY(manager.itemFetchScope()->fullPayload()); QVERIFY(manager.itemFetchScope()->allAttributes()); QVERIFY(manager.itemFetchScope()->fetchSize()); QVERIFY(manager.itemFetchScope()->fetchMTime()); QVERIFY(manager.itemFetchScope()->fetchRemoteRevision()); QVERIFY(manager.itemFetchScope()->fetchFlags()); QVERIFY(manager.itemFetchScope()->fetchRemoteId()); QVERIFY(manager.itemFetchScope()->fetchGID()); QVERIFY(manager.itemFetchScope()->fetchTags()); QVERIFY(manager.itemFetchScope()->fetchRelations()); QVERIFY(manager.itemFetchScope()->fetchVirtualReferences()); // give it the same settings subscriberB.modifySubscription(modifyCmd); QVERIFY(manager.tagFetchScope()->fetchIdOnly()); // now they agree + QVERIFY(!manager.tagFetchScope()->fetchAllAttributes()); QVERIFY(manager.collectionFetchScope()->fetchIdOnly()); QVERIFY(manager.collectionFetchScope()->fetchStatistics()); // no change for the "at least one" settings // revert B's settings, so we can check what happens when disconnecting modifyCmd.setTagFetchScope(Protocol::TagFetchScope()); modifyCmd.setCollectionFetchScope(Protocol::CollectionFetchScope()); subscriberB.modifySubscription(modifyCmd); QVERIFY(!manager.tagFetchScope()->fetchIdOnly()); + QVERIFY(manager.tagFetchScope()->fetchAllAttributes()); QVERIFY(!manager.collectionFetchScope()->fetchIdOnly()); QVERIFY(manager.collectionFetchScope()->fetchStatistics()); // B goes away subscriberB.disconnectSubscriber(); QVERIFY(manager.tagFetchScope()->fetchIdOnly()); // B cleaned up after itself, so A can have id-only again + QVERIFY(!manager.tagFetchScope()->fetchAllAttributes()); QVERIFY(manager.collectionFetchScope()->fetchIdOnly()); QVERIFY(manager.collectionFetchScope()->fetchStatistics()); // A goes away subscriberA.disconnectSubscriber(); QVERIFY(!manager.collectionFetchScope()->fetchStatistics()); QVERIFY(!manager.itemFetchScope()->fullPayload()); QVERIFY(!manager.itemFetchScope()->allAttributes()); QVERIFY(!manager.itemFetchScope()->fetchSize()); QVERIFY(!manager.itemFetchScope()->fetchMTime()); QVERIFY(!manager.itemFetchScope()->fetchRemoteRevision()); QVERIFY(!manager.itemFetchScope()->fetchFlags()); QVERIFY(!manager.itemFetchScope()->fetchRemoteId()); QVERIFY(!manager.itemFetchScope()->fetchGID()); QVERIFY(!manager.itemFetchScope()->fetchTags()); QVERIFY(!manager.itemFetchScope()->fetchRelations()); QVERIFY(!manager.itemFetchScope()->fetchVirtualReferences()); } }; AKTEST_MAIN(NotificationManagerTest) #include "notificationmanagertest.moc" diff --git a/src/server/aggregatedfetchscope.cpp b/src/server/aggregatedfetchscope.cpp index e449c8ee5..ce48f3086 100644 --- a/src/server/aggregatedfetchscope.cpp +++ b/src/server/aggregatedfetchscope.cpp @@ -1,657 +1,659 @@ /* Copyright (c) 2017 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "aggregatedfetchscope.h" #include #include #include #include #define LOCKED_D(name) \ Q_D(name); \ QMutexLocker lock(&d->lock); namespace Akonadi { namespace Server { class AggregatedFetchScopePrivate { public: AggregatedFetchScopePrivate() : lock(QMutex::Recursive) // recursive so that we can call our own getters/setters {} inline void addToSet(const QByteArray &value, QSet &set, QHash &count) { auto it = count.find(value); if (it == count.end()) { it = count.insert(value, 0); set.insert(value); } ++(*it); } inline void removeFromSet(const QByteArray &value, QSet &set, QHash &count) { auto it = count.find(value); if (it == count.end()) { return; } if (--(*it) == 0) { count.erase(it); set.remove(value); } } inline void updateBool(bool newValue, int &store) { store += newValue ? 1 : -1; } inline void applySet(const QSet &oldSet, const QSet &newSet, QSet &set, QHash &count) { const auto added = newSet - oldSet; for (const auto &value : added) { addToSet(value, set, count); } const auto removed = oldSet - newSet; for (const auto &value : removed) { removeFromSet(value, set, count); } } public: mutable QMutex lock; }; class AggregatedCollectionFetchScopePrivate : public AggregatedFetchScopePrivate { public: QSet attrs; QHash attrsCount; int subscribers = 0; int fetchIdOnly = 0; int fetchStats = 0; }; class AggregatedTagFetchScopePrivate : public AggregatedFetchScopePrivate { public: QSet attrs; QHash attrsCount; int subscribers = 0; int fetchIdOnly = 0; int fetchRemoteId = 0; - int fetchAllAttributes = 0; + int doNotFetchAllAttributes = 0; }; class AggregatedItemFetchScopePrivate : public AggregatedFetchScopePrivate { public: mutable Protocol::ItemFetchScope mCachedScope; mutable bool mCachedScopeValid = false; // use std::optional for mCachedScope QSet parts; QHash partsCount; QSet tags; QHash tagsCount; int subscribers = 0; int ancestors[3] = { 0, 0, 0 }; // 3 = size of AncestorDepth enum int cacheOnly = 0; int fullPayload = 0; int allAttributes = 0; int fetchSize = 0; int fetchMTime = 0; int fetchRRev = 0; int ignoreErrors = 0; int fetchFlags = 0; int fetchRID = 0; int fetchGID = 0; int fetchTags = 0; int fetchRelations = 0; int fetchVRefs = 0; }; } // namespace Server } // namespace Akonadi using namespace Akonadi; using namespace Akonadi::Protocol; using namespace Akonadi::Server; AggregatedCollectionFetchScope::AggregatedCollectionFetchScope() : d_ptr(new AggregatedCollectionFetchScopePrivate) { } AggregatedCollectionFetchScope::~AggregatedCollectionFetchScope() { delete d_ptr; } void AggregatedCollectionFetchScope::apply(const Protocol::CollectionFetchScope &oldScope, const Protocol::CollectionFetchScope &newScope) { LOCKED_D(AggregatedCollectionFetchScope) if (newScope.includeStatistics() != oldScope.includeStatistics()) { setFetchStatistics(newScope.includeStatistics()); } if (newScope.fetchIdOnly() != oldScope.fetchIdOnly()) { setFetchIdOnly(newScope.fetchIdOnly()); } if (newScope.attributes() != oldScope.attributes()) { d->applySet(oldScope.attributes(), newScope.attributes(), d->attrs, d->attrsCount); } } QSet AggregatedCollectionFetchScope::attributes() const { LOCKED_D(const AggregatedCollectionFetchScope) return d->attrs; } void AggregatedCollectionFetchScope::addAttribute(const QByteArray &attribute) { LOCKED_D(AggregatedCollectionFetchScope) d->addToSet(attribute, d->attrs, d->attrsCount); } void AggregatedCollectionFetchScope::removeAttribute(const QByteArray &attribute) { LOCKED_D(AggregatedCollectionFetchScope) d->removeFromSet(attribute, d->attrs, d->attrsCount); } bool AggregatedCollectionFetchScope::fetchIdOnly() const { LOCKED_D(const AggregatedCollectionFetchScope) // Aggregation: we can return true only if everyone wants fetchIdOnly, // otherwise there's at least one subscriber who wants everything return d->fetchIdOnly == d->subscribers; } void AggregatedCollectionFetchScope::setFetchIdOnly(bool fetchIdOnly) { LOCKED_D(AggregatedCollectionFetchScope) d->updateBool(fetchIdOnly, d->fetchIdOnly); } bool AggregatedCollectionFetchScope::fetchStatistics() const { LOCKED_D(const AggregatedCollectionFetchScope); // Aggregation: return true if at least one subscriber wants stats return d->fetchStats > 0; } void AggregatedCollectionFetchScope::setFetchStatistics(bool fetchStats) { LOCKED_D(AggregatedCollectionFetchScope); d->updateBool(fetchStats, d->fetchStats); } void AggregatedCollectionFetchScope::addSubscriber() { LOCKED_D(AggregatedCollectionFetchScope) ++d->subscribers; } void AggregatedCollectionFetchScope::removeSubscriber() { LOCKED_D(AggregatedCollectionFetchScope) --d->subscribers; } AggregatedItemFetchScope::AggregatedItemFetchScope() : d_ptr(new AggregatedItemFetchScopePrivate) { } AggregatedItemFetchScope::~AggregatedItemFetchScope() { delete d_ptr; } void AggregatedItemFetchScope::apply(const Protocol::ItemFetchScope &oldScope, const Protocol::ItemFetchScope &newScope) { LOCKED_D(AggregatedItemFetchScope); const auto newParts = vectorToSet(newScope.requestedParts()); const auto oldParts = vectorToSet(oldScope.requestedParts()); if (newParts != oldParts) { d->applySet(oldParts, newParts, d->parts, d->partsCount); } if (newScope.ancestorDepth() != oldScope.ancestorDepth()) { updateAncestorDepth(oldScope.ancestorDepth(), newScope.ancestorDepth()); } if (newScope.cacheOnly() != oldScope.cacheOnly()) { setCacheOnly(newScope.cacheOnly()); } if (newScope.fullPayload() != oldScope.fullPayload()) { setFullPayload(newScope.fullPayload()); } if (newScope.allAttributes() != oldScope.allAttributes()) { setAllAttributes(newScope.allAttributes()); } if (newScope.fetchSize() != oldScope.fetchSize()) { setFetchSize(newScope.fetchSize()); } if (newScope.fetchMTime() != oldScope.fetchMTime()) { setFetchMTime(newScope.fetchMTime()); } if (newScope.fetchRemoteRevision() != oldScope.fetchRemoteRevision()) { setFetchRemoteRevision(newScope.fetchRemoteRevision()); } if (newScope.ignoreErrors() != oldScope.ignoreErrors()) { setIgnoreErrors(newScope.ignoreErrors()); } if (newScope.fetchFlags() != oldScope.fetchFlags()) { setFetchFlags(newScope.fetchFlags()); } if (newScope.fetchRemoteId() != oldScope.fetchRemoteId()) { setFetchRemoteId(newScope.fetchRemoteId()); } if (newScope.fetchGID() != oldScope.fetchGID()) { setFetchGID(newScope.fetchGID()); } if (newScope.fetchTags() != oldScope.fetchTags()) { setFetchTags(newScope.fetchTags()); } if (newScope.fetchRelations() != oldScope.fetchRelations()) { setFetchRelations(newScope.fetchRelations()); } if (newScope.fetchVirtualReferences() != oldScope.fetchVirtualReferences()) { setFetchVirtualReferences(newScope.fetchVirtualReferences()); } d->mCachedScopeValid = false; } ItemFetchScope AggregatedItemFetchScope::toFetchScope() const { LOCKED_D(const AggregatedItemFetchScope); if (d->mCachedScopeValid) { return d->mCachedScope; } d->mCachedScope = ItemFetchScope(); d->mCachedScope.setRequestedParts(setToVector(d->parts)); d->mCachedScope.setAncestorDepth(ancestorDepth()); d->mCachedScope.setFetch(ItemFetchScope::CacheOnly, cacheOnly()); d->mCachedScope.setFetch(ItemFetchScope::FullPayload, fullPayload()); d->mCachedScope.setFetch(ItemFetchScope::AllAttributes, allAttributes()); d->mCachedScope.setFetch(ItemFetchScope::Size, fetchSize()); d->mCachedScope.setFetch(ItemFetchScope::MTime, fetchMTime()); d->mCachedScope.setFetch(ItemFetchScope::RemoteRevision, fetchRemoteRevision()); d->mCachedScope.setFetch(ItemFetchScope::IgnoreErrors, ignoreErrors()); d->mCachedScope.setFetch(ItemFetchScope::Flags, fetchFlags()); d->mCachedScope.setFetch(ItemFetchScope::RemoteID, fetchRemoteId()); d->mCachedScope.setFetch(ItemFetchScope::GID, fetchGID()); d->mCachedScope.setFetch(ItemFetchScope::Tags, fetchTags()); d->mCachedScope.setFetch(ItemFetchScope::Relations, fetchRelations()); d->mCachedScope.setFetch(ItemFetchScope::VirtReferences, fetchVirtualReferences()); d->mCachedScopeValid = true; return d->mCachedScope; } QSet AggregatedItemFetchScope::requestedParts() const { LOCKED_D(const AggregatedItemFetchScope) return d->parts; } void AggregatedItemFetchScope::addRequestedPart(const QByteArray &part) { LOCKED_D(AggregatedItemFetchScope) d->addToSet(part, d->parts, d->partsCount); } void AggregatedItemFetchScope::removeRequestedPart(const QByteArray &part) { LOCKED_D(AggregatedItemFetchScope) d->removeFromSet(part, d->parts, d->partsCount); } ItemFetchScope::AncestorDepth AggregatedItemFetchScope::ancestorDepth() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return the largest depth with at least one subscriber if (d->ancestors[ItemFetchScope::AllAncestors] > 0) { return ItemFetchScope::AllAncestors; } else if (d->ancestors[ItemFetchScope::ParentAncestor] > 0) { return ItemFetchScope::ParentAncestor; } else { return ItemFetchScope::NoAncestor; } } void AggregatedItemFetchScope::updateAncestorDepth(ItemFetchScope::AncestorDepth oldDepth, ItemFetchScope::AncestorDepth newDepth) { LOCKED_D(AggregatedItemFetchScope) if (d->ancestors[oldDepth] > 0) { --d->ancestors[oldDepth]; } ++d->ancestors[newDepth]; } bool AggregatedItemFetchScope::cacheOnly() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: we can return true only if everyone wants cached data only, // otherwise there's at least one subscriber who wants uncached data return d->cacheOnly == d->subscribers; } void AggregatedItemFetchScope::setCacheOnly(bool cacheOnly) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(cacheOnly, d->cacheOnly); } bool AggregatedItemFetchScope::fullPayload() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants the // full payload return d->fullPayload > 0; } void AggregatedItemFetchScope::setFullPayload(bool fullPayload) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fullPayload, d->fullPayload); } bool AggregatedItemFetchScope::allAttributes() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants // all attributes return d->allAttributes > 0; } void AggregatedItemFetchScope::setAllAttributes(bool allAttributes) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(allAttributes, d->allAttributes); } bool AggregatedItemFetchScope::fetchSize() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants size return d->fetchSize > 0; } void AggregatedItemFetchScope::setFetchSize(bool fetchSize) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fetchSize, d->fetchSize); } bool AggregatedItemFetchScope::fetchMTime() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants mtime return d->fetchMTime > 0; } void AggregatedItemFetchScope::setFetchMTime(bool fetchMTime) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fetchMTime, d->fetchMTime); } bool AggregatedItemFetchScope::fetchRemoteRevision() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants rrev return d->fetchRRev > 0; } void AggregatedItemFetchScope::setFetchRemoteRevision(bool remoteRevision) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(remoteRevision, d->fetchRRev); } bool AggregatedItemFetchScope::ignoreErrors() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true only if everyone wants to ignore errors, otherwise // there's at least one subscriber who does not want to ignore them return d->ignoreErrors == d->subscribers; } void AggregatedItemFetchScope::setIgnoreErrors(bool ignoreErrors) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(ignoreErrors, d->ignoreErrors); } bool AggregatedItemFetchScope::fetchFlags() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants flags return d->fetchFlags > 0; } void AggregatedItemFetchScope::setFetchFlags(bool fetchFlags) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fetchFlags, d->fetchFlags); } bool AggregatedItemFetchScope::fetchRemoteId() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants RID return d->fetchRID > 0; } void AggregatedItemFetchScope::setFetchRemoteId(bool fetchRemoteId) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fetchRemoteId, d->fetchRID); } bool AggregatedItemFetchScope::fetchGID() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants GID return d->fetchGID > 0; } void AggregatedItemFetchScope::setFetchGID(bool fetchGid) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fetchGid, d->fetchGID); } bool AggregatedItemFetchScope::fetchTags() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants tags return d->fetchTags > 0; } void AggregatedItemFetchScope::setFetchTags(bool fetchTags) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fetchTags, d->fetchTags); } bool AggregatedItemFetchScope::fetchRelations() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants relations return d->fetchRelations > 0; } void AggregatedItemFetchScope::setFetchRelations(bool fetchRelations) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fetchRelations, d->fetchRelations); } bool AggregatedItemFetchScope::fetchVirtualReferences() const { LOCKED_D(const AggregatedItemFetchScope) // Aggregation: return true if there's at least one subscriber who wants vrefs return d->fetchVRefs > 0; } void AggregatedItemFetchScope::setFetchVirtualReferences(bool fetchVRefs) { LOCKED_D(AggregatedItemFetchScope) d->updateBool(fetchVRefs, d->fetchVRefs); } void AggregatedItemFetchScope::addSubscriber() { LOCKED_D(AggregatedItemFetchScope) ++d->subscribers; } void AggregatedItemFetchScope::removeSubscriber() { LOCKED_D(AggregatedItemFetchScope) --d->subscribers; } AggregatedTagFetchScope::AggregatedTagFetchScope() : d_ptr(new AggregatedTagFetchScopePrivate) { } AggregatedTagFetchScope::~AggregatedTagFetchScope() { delete d_ptr; } void AggregatedTagFetchScope::apply(const Protocol::TagFetchScope &oldScope, const Protocol::TagFetchScope &newScope) { LOCKED_D(AggregatedTagFetchScope) if (newScope.fetchIdOnly() != oldScope.fetchIdOnly()) { setFetchIdOnly(newScope.fetchIdOnly()); } if (newScope.fetchRemoteID() != oldScope.fetchRemoteID()) { setFetchRemoteId(newScope.fetchRemoteID()); } if (newScope.fetchAllAttributes() != oldScope.fetchAllAttributes()) { setFetchAllAttributes(newScope.fetchAllAttributes()); } if (newScope.attributes() != oldScope.attributes()) { d->applySet(oldScope.attributes(), newScope.attributes(), d->attrs, d->attrsCount); } } Protocol::TagFetchScope AggregatedTagFetchScope::toFetchScope() const { Protocol::TagFetchScope tfs; tfs.setFetchIdOnly(fetchIdOnly()); tfs.setFetchRemoteID(fetchRemoteId()); tfs.setFetchAllAttributes(fetchAllAttributes()); tfs.setAttributes(attributes()); return tfs; } bool AggregatedTagFetchScope::fetchIdOnly() const { LOCKED_D(const AggregatedTagFetchScope) // Aggregation: we can return true only if everyone wants fetchIdOnly, // otherwise there's at least one subscriber who wants everything return d->fetchIdOnly == d->subscribers; } void AggregatedTagFetchScope::setFetchIdOnly(bool fetchIdOnly) { LOCKED_D(AggregatedTagFetchScope) d->updateBool(fetchIdOnly, d->fetchIdOnly); } bool AggregatedTagFetchScope::fetchRemoteId() const { LOCKED_D(const AggregatedTagFetchScope) return d->fetchRemoteId > 0; } void AggregatedTagFetchScope::setFetchRemoteId(bool fetchRemoteId) { LOCKED_D(AggregatedTagFetchScope) d->updateBool(fetchRemoteId, d->fetchRemoteId); } bool AggregatedTagFetchScope::fetchAllAttributes() const { LOCKED_D(const AggregatedTagFetchScope) - return d->fetchAllAttributes > 0; + // The default value for fetchAllAttributes is true, so we return false only if every subscriber said "do not fetch all attributes" + return d->doNotFetchAllAttributes != d->subscribers; } void AggregatedTagFetchScope::setFetchAllAttributes(bool fetchAllAttributes) { LOCKED_D(AggregatedTagFetchScope) - d->updateBool(fetchAllAttributes, d->fetchAllAttributes); + // Count the number of subscribers who call with false + d->updateBool(!fetchAllAttributes, d->doNotFetchAllAttributes); } QSet AggregatedTagFetchScope::attributes() const { LOCKED_D(const AggregatedTagFetchScope) return d->attrs; } void AggregatedTagFetchScope::addAttribute(const QByteArray &attribute) { LOCKED_D(AggregatedTagFetchScope) d->addToSet(attribute, d->attrs, d->attrsCount); } void AggregatedTagFetchScope::removeAttribute(const QByteArray &attribute) { LOCKED_D(AggregatedTagFetchScope) d->removeFromSet(attribute, d->attrs, d->attrsCount); } void AggregatedTagFetchScope::addSubscriber() { LOCKED_D(AggregatedTagFetchScope) ++d->subscribers; } void AggregatedTagFetchScope::removeSubscriber() { LOCKED_D(AggregatedTagFetchScope) --d->subscribers; } #undef LOCKED_D