Branch 'kolab/integration/4.13.0' - 3 commits - akonadi/agentbase.cpp akonadi/agentbase.h akonadi/agentbase_p.h akonadi/changerecorder_p.h akonadi/monitor.h akonadi/monitor_p.cpp akonadi/monitor_p.h akonadi/relation.h

Aaron Seigo seigo at kolabsys.com
Tue Oct 14 16:08:47 CEST 2014


 akonadi/agentbase.cpp      |   96 +++++++++++++++++++++++++++++++++++++++++++++
 akonadi/agentbase.h        |   20 +++++++++
 akonadi/agentbase_p.h      |    6 ++
 akonadi/changerecorder_p.h |    3 -
 akonadi/monitor.h          |    2 
 akonadi/monitor_p.cpp      |   13 ++++--
 akonadi/monitor_p.h        |    3 +
 akonadi/relation.h         |    4 -
 8 files changed, 140 insertions(+), 7 deletions(-)

New commits:
commit b46305639ddae54636a159bc813d47d08456ab57
Author: Aaron Seigo <aseigo at kde.org>
Date:   Tue Oct 14 15:59:48 2014 +0200

    implement support for relation handling in agents

diff --git a/akonadi/agentbase.cpp b/akonadi/agentbase.cpp
index 2e3b6c2..df86d0b 100644
--- a/akonadi/agentbase.cpp
+++ b/akonadi/agentbase.cpp
@@ -287,6 +287,46 @@ void AgentBase::ObserverV4::itemsTagsChanged(const Item::List &items, const QSet
     }
 }
 
+void AgentBase::ObserverV4::relationAdded(const Akonadi::Relation &relation)
+{
+    Q_UNUSED(relation)
+
+    if (sAgentBase) {
+        // not implementation, let's disconnect the signal to enable optimization in Monitor
+        QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(relationAdded(Akonadi::Relation)),
+                            sAgentBase->d_ptr, SLOT(relationAdded(Akonadi::Relation)));
+        sAgentBase->d_ptr->changeProcessed();
+    }
+}
+
+void AgentBase::ObserverV4::relationRemoved(const Akonadi::Relation &relation)
+{
+    Q_UNUSED(relation)
+
+    if (sAgentBase) {
+        // not implementation, let's disconnect the signal to enable optimization in Monitor
+        QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(relationRemoved(Akonadi::Relation)),
+                            sAgentBase->d_ptr, SLOT(relationRemoved(Akonadi::Relation)));
+        sAgentBase->d_ptr->changeProcessed();
+    }
+}
+
+void AgentBase::ObserverV4::itemsRelationsChanged(const Akonadi::Item::List &items,
+                                                  const Akonadi::Relation::List &addedRelations,
+                                                  const Akonadi::Relation::List &removedRelations)
+{
+    Q_UNUSED(items)
+    Q_UNUSED(addedRelations)
+    Q_UNUSED(removedRelations)
+
+    if (sAgentBase) {
+        // not implementation, let's disconnect the signal to enable optimization in Monitor
+        QObject::disconnect(sAgentBase->changeRecorder(), SIGNAL(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List)),
+                            sAgentBase, SLOT(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List)));
+        sAgentBase->d_ptr->changeProcessed();
+    }
+}
+
 //@cond PRIVATE
 
 AgentBasePrivate::AgentBasePrivate(AgentBase *parent)
@@ -616,6 +656,50 @@ void AgentBasePrivate::itemsTagsChanged(const Akonadi::Item::List &items, const
     }
 }
 
+void AgentBasePrivate::relationAdded(const Akonadi::Relation &relation)
+{
+    if (!mObserver) {
+        return;
+    }
+
+    AgentBase::ObserverV4 *observer4 = dynamic_cast<AgentBase::ObserverV4 *>(mObserver);
+    if (observer4) {
+        observer4->relationAdded(relation);
+    } else {
+        changeProcessed();
+    }
+}
+
+void AgentBasePrivate::relationRemoved(const Akonadi::Relation &relation)
+{
+    if (!mObserver) {
+        return;
+    }
+
+    AgentBase::ObserverV4 *observer4 = dynamic_cast<AgentBase::ObserverV4 *>(mObserver);
+    if (observer4) {
+        observer4->relationRemoved(relation);
+    } else {
+        changeProcessed();
+    }
+}
+
+void AgentBasePrivate::itemsRelationsChanged(const Akonadi::Item::List &items,
+                                             const Akonadi::Relation::List &addedRelations,
+                                             const Akonadi::Relation::List &removedRelations)
+{
+    if (!mObserver) {
+        return;
+    }
+
+    AgentBase::ObserverV4 *observer4 = dynamic_cast<AgentBase::ObserverV4 *>(mObserver);
+    if (observer4) {
+        observer4->itemsRelationsChanged(items, addedRelations, removedRelations);
+    } else {
+        changeProcessed();
+    }
+}
+
 void AgentBasePrivate::collectionAdded(const Akonadi::Collection &collection, const Akonadi::Collection &parent)
 {
     if (mObserver != 0) {
@@ -1092,6 +1176,12 @@ void AgentBase::registerObserver(Observer *observer)
                d_ptr, SLOT(itemLinked(Akonadi::Item,Akonadi::Collection)));
     disconnect(d_ptr->mChangeRecorder, SIGNAL(itemUnlinked(Akonadi::Item,Akonadi::Collection)),
                d_ptr, SLOT(itemUnlinked(Akonadi::Item,Akonadi::Collection)));
+    disconnect(d_ptr->mChangeRecorder, SIGNAL(relationAdded(Akonadi::Relation)),
+               d_ptr, SLOT(relationAdded(Akonadi::Relation)));
+    disconnect(d_ptr->mChangeRecorder, SIGNAL(relationRemoved(Akonadi::Relation)),
+               d_ptr, SLOT(relationRemoved(Akonadi::Relation)));
+    disconnect(d_ptr->mChangeRecorder, SIGNAL(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List)),
+               d_ptr, SLOT(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List)));
 
     if (hasObserverV4) {
         connect(d_ptr->mChangeRecorder, SIGNAL(tagAdded(Akonadi::Tag)),
@@ -1102,6 +1192,12 @@ void AgentBase::registerObserver(Observer *observer)
                 d_ptr, SLOT(tagRemoved(Akonadi::Tag)));
         connect(d_ptr->mChangeRecorder, SIGNAL(itemsTagsChanged(Akonadi::Item::List,QSet<Akonadi::Tag>,QSet<Akonadi::Tag>)),
                 d_ptr, SLOT(itemsTagsChanged(Akonadi::Item::List,QSet<Akonadi::Tag>,QSet<Akonadi::Tag>)));
+        connect(d_ptr->mChangeRecorder, SIGNAL(relationAdded(Akonadi::Relation)),
+                d_ptr, SLOT(relationAdded(Akonadi::Relation)));
+        connect(d_ptr->mChangeRecorder, SIGNAL(relationRemoved(Akonadi::Relation)),
+                d_ptr, SLOT(relationRemoved(Akonadi::Relation)));
+        connect(d_ptr->mChangeRecorder, SIGNAL(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List)),
+                d_ptr, SLOT(itemsRelationsChanged(Akonadi::Item::List,Akonadi::Relation::List,Akonadi::Relation::List)));
     }
 
     if (hasObserverV3) {
diff --git a/akonadi/agentbase.h b/akonadi/agentbase.h
index 2b2826d..8d2b72d 100644
--- a/akonadi/agentbase.h
+++ b/akonadi/agentbase.h
@@ -402,6 +402,26 @@ public:
          * @param removedTags Set of tags that were removed from all @p items
          */
         virtual void itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags);
+
+        /**
+         * Reimplement to handle relations being added
+         */
+        virtual void relationAdded(const Akonadi::Relation &relation);
+
+        /**
+         * Reimplement to handle relations being removed
+         */
+        virtual void relationRemoved(const Akonadi::Relation &relation);
+
+        /**
+         * Reimplement to handled relations changing on items
+         * @param items Items that had relations added/removed from them
+         * @param addedRelations the list of relations that were added to all @p items
+         * @param removedRelations the list of relations that were removed from all @p items
+         */
+        virtual void itemsRelationsChanged(const Akonadi::Item::List &items,
+                                           const Akonadi::Relation::List &addedRelations,
+                                           const Akonadi::Relation::List &removedRelations);
     };
 
     /**
diff --git a/akonadi/agentbase_p.h b/akonadi/agentbase_p.h
index e47bcac..d5c4444 100644
--- a/akonadi/agentbase_p.h
+++ b/akonadi/agentbase_p.h
@@ -143,6 +143,12 @@ public:
     virtual void tagChanged(const Akonadi::Tag &tag);
     virtual void tagRemoved(const Akonadi::Tag &tag);
     virtual void itemsTagsChanged(const Akonadi::Item::List &items, const QSet<Akonadi::Tag> &addedTags, const QSet<Akonadi::Tag> &removedTags);
+
+    virtual void relationAdded(const Akonadi::Relation &relation);
+    virtual void relationRemoved(const Akonadi::Relation &relation);
+    virtual void itemsRelationsChanged(const Akonadi::Item::List &items,
+                                       const Akonadi::Relation::List &addedRelations,
+                                       const Akonadi::Relation::List &removedRelations);
 };
 
 }


commit 9e6cd3b431632fd7c5dfbeb39f1b4bb5003fb69b
Author: Aaron Seigo <aseigo at kde.org>
Date:   Tue Oct 14 15:57:38 2014 +0200

    protect against replaying notifications on bad data
    
    Remove operations indeed will reference UIDs that no loner exist in the
    database. However, it is possible to have notifications saved to disk (e.g.)
    by a ChangeRecorder which, on next start, reference UIDs that no longer exist.
    In that case, we need to drop the message on the ground otherwise we end up
    stuck with a notification that never gets cleared every time the resource
    is started.

diff --git a/akonadi/changerecorder_p.h b/akonadi/changerecorder_p.h
index d25b6ff..0ffd8d5 100644
--- a/akonadi/changerecorder_p.h
+++ b/akonadi/changerecorder_p.h
@@ -52,8 +52,9 @@ public:
     void addToStream(QDataStream &stream, const NotificationMessageV3 &msg);
     void saveNotifications();
     void saveTo(QIODevice *device);
-private:
     void dequeueNotification();
+
+private:
     void notificationsLoaded();
     void writeStartOffset();
 
diff --git a/akonadi/monitor.h b/akonadi/monitor.h
index 3f5526a..f296722 100644
--- a/akonadi/monitor.h
+++ b/akonadi/monitor.h
@@ -440,7 +440,7 @@ Q_SIGNALS:
      * @since 4.15
      */
     void itemsRelationsChanged(const Akonadi::Item::List &items, const Akonadi::Relation::List &addedRelations,
-                          const Akonadi::Relation::List &removedRelations);
+                               const Akonadi::Relation::List &removedRelations);
 
     /**
      * This signal is emitted if a monitored item has been moved between two collections
diff --git a/akonadi/monitor_p.cpp b/akonadi/monitor_p.cpp
index 9eb1686..4d1ea2f 100644
--- a/akonadi/monitor_p.cpp
+++ b/akonadi/monitor_p.cpp
@@ -430,6 +430,7 @@ bool MonitorPrivate::ensureDataAvailable(const NotificationMessageV3 &msg)
         }
         return true;
     }
+
     if (msg.type() == NotificationMessageV2::Relations) {
         return true;
     }
@@ -480,9 +481,9 @@ bool MonitorPrivate::ensureDataAvailable(const NotificationMessageV3 &msg)
                 }
             }
         }
+
         if (!itemCache->ensureCached(msg.uids(), scope)) {
             allCached = false;
-
         }
 
         // Make sure all tags for ModifyTags operation are in cache too
@@ -549,12 +550,16 @@ bool MonitorPrivate::emitNotification(const NotificationMessageV3 &msg)
                 }
             }
         } else if (msg.type() == NotificationMessageV2::Items) {
-            //In case of a Remove notification this will return a list of invalid entities (we'll deal later with them)
             const Item::List items = itemCache->retrieve(msg.uids());
             if (!items.isEmpty()) {
                 someoneWasListening = emitItemsNotification(msg, items, parent, destParent);
             } else {
-                someoneWasListening = true;
+                // In case of a Remove notification this will return a list of invalid entities (we'll deal later with them)
+                // Of course, we may end up with an inconsistency in the database and have a pending notification that has
+                // been (e.g.) written out to a log for later replay (such as in a ChangeRecorder) and now references uids
+                // that no longer exist. In *that* case we want to just drop the notification, otherwise we get stuck on it
+                // forever
+                someoneWasListening = msg.operation() == NotificationMessageV2::Remove;
             }
         }
     }
@@ -696,6 +701,7 @@ void MonitorPrivate::slotNotify(const NotificationMessageV3::List &msgs)
     int appendedMessages = 0;
     int modifiedMessages = 0;
     int erasedMessages = 0;
+
     Q_FOREACH (const NotificationMessageV3 &msg, msgs) {
         invalidateCaches(msg);
         updatePendingStatistics(msg);
@@ -763,6 +769,7 @@ void MonitorPrivate::flushPipeline()
             // dequeue should be before emit, otherwise stuff might happen (like dataAvailable
             // being called again) and we end up dequeuing an empty pipeline
             pipeline.dequeue();
+            dequeueNotification();
             emitNotification(msg);
         } else {
             break;
diff --git a/akonadi/monitor_p.h b/akonadi/monitor_p.h
index f3789ac..04c9076 100644
--- a/akonadi/monitor_p.h
+++ b/akonadi/monitor_p.h
@@ -102,6 +102,9 @@ public:
     virtual void notificationsErased()
     {
     }
+    virtual void dequeueNotification()
+    {
+    }
 
     // Virtual so it can be overridden in FakeMonitor.
     virtual bool connectToNotificationManager();


commit c3fc3ff265af5f4ca0a97697ccb2c787bc9f10aa
Author: Aaron Seigo <aseigo at kde.org>
Date:   Thu Oct 9 16:01:15 2014 +0200

    dox fix

diff --git a/akonadi/relation.h b/akonadi/relation.h
index 7d2a78a..13d3c31 100644
--- a/akonadi/relation.h
+++ b/akonadi/relation.h
@@ -106,12 +106,12 @@ public:
     QByteArray type() const;
 
     /**
-     * Sets the type of the relation.
+     * Sets the remote id of the relation.
      */
     void setRemoteId(const QByteArray &type) const;
 
     /**
-     * Returns the type of the relation.
+     * Returns the remote idof the relation.
      */
     QByteArray remoteId() const;
 




More information about the commits mailing list