Hello community,

here is the log from the commit of package akonadi-server for openSUSE:Factory 
checked in at 2017-03-15 00:50:22
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/akonadi-server (Old)
 and      /work/SRC/openSUSE:Factory/.akonadi-server.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "akonadi-server"

Wed Mar 15 00:50:22 2017 rev:26 rq:478097 version:16.12.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/akonadi-server/akonadi-server.changes    
2017-02-26 17:08:22.871864525 +0100
+++ /work/SRC/openSUSE:Factory/.akonadi-server.new/akonadi-server.changes       
2017-03-15 00:50:22.957941005 +0100
@@ -1,0 +2,28 @@
+Thu Mar  9 18:07:28 UTC 2017 - [email protected]
+
+- Drop fix-itemretriever-in-case-of-concurrent-requests.patch, it's
+  already merged upstream 
+
+-------------------------------------------------------------------
+Thu Mar  9 12:33:17 CET 2017 - [email protected]
+
+- Update to 16.12.3
+  * New bugfix release
+  * For more details please see:
+  * https://www.kde.org/announcements/announce-applications-16.12.3.php
+- Changes since 16.12.2:
+  * Fix ServerManager going into Broken state when called before going to the 
event loop.
+  * Fix crash when Connection is closed while ItemRetriever is running 
(kde#374734)
+  * DataStream: throw exception if device is null (kde#376385)
+  * Don't export internal classes when not building autotests.
+  * Remove unused included cpp file from autotest.
+  * Fix ItemRetriever in case of concurrent requests for the same item(s)
+  * no need to generate the header twice, we can use the one from src/server 
here
+  * Revert unwanted changes in previous commit
+  * Implement "TODO: Qt 5: Use QDir::removeRecursively"
+  * Fix runtime warning at the end of itemretrievertest.
+  * Show collection id if collection is valid
+  * Add more debug
+
+
+-------------------------------------------------------------------

Old:
----
  akonadi-16.12.2.tar.xz
  fix-itemretriever-in-case-of-concurrent-requests.patch

New:
----
  akonadi-16.12.3.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ akonadi-server.spec ++++++
--- /var/tmp/diff_new_pack.WhOnA9/_old  2017-03-15 00:50:24.085781418 +0100
+++ /var/tmp/diff_new_pack.WhOnA9/_new  2017-03-15 00:50:24.085781418 +0100
@@ -18,10 +18,10 @@
 
 %define rname   akonadi
 %define kf5_version 5.26.0
-# Latest stable Applications (e.g. 16.08 in KA, but 16.12.2 in KUA)
+# Latest stable Applications (e.g. 16.08 in KA, but 16.12.3 in KUA)
 %{!?_kapp_version: %global _kapp_version %(echo %{version}| awk -F. '{print 
$1"."$2}')}
 Name:           akonadi-server
-Version:        16.12.2
+Version:        16.12.3
 Release:        0
 Summary:        PIM Storage Service
 License:        LGPL-2.1+
@@ -31,8 +31,6 @@
 Source99:       akonadi-server-rpmlintrc
 # PATCH-FIX-UPSTREAM handle-mysql-process-crashes-gracefully.patch
 Patch0:         handle-mysql-process-crashes-gracefully.patch
-# PATCH-FIX-UPSTREAM fix-itemretriever-in-case-of-concurrent-requests.patch - 
Fixes hangs when accessing folders
-Patch1:         fix-itemretriever-in-case-of-concurrent-requests.patch
 %if 0%{?suse_version} > 1325
 BuildRequires:  libboost_headers-devel
 %else
@@ -172,7 +170,6 @@
 %prep
 %setup -q -n %{rname}-%{version}
 %patch0 -p1
-%patch1 -p1
 
 %build
   %cmake_kf5 -d build -- -DINSTALL_QSQLITE_IN_QT_PREFIX=TRUE 
-DQT_PLUGINS_DIR=%{_kf5_plugindir}

++++++ akonadi-16.12.2.tar.xz -> akonadi-16.12.3.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/CMakeLists.txt 
new/akonadi-16.12.3/CMakeLists.txt
--- old/akonadi-16.12.2/CMakeLists.txt  2017-01-19 13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/CMakeLists.txt  2017-03-04 15:02:02.000000000 +0100
@@ -22,7 +22,7 @@
 
 include(AkonadiMacros)
 
-set(PIM_VERSION "5.4.2")
+set(PIM_VERSION "5.4.3")
 
 set(QT_REQUIRED_VERSION "5.6.0")
 set(AKONADI_VERSION ${PIM_VERSION})
@@ -79,7 +79,9 @@
 add_definitions(-DQT_STRICT_ITERATORS)
 
 
-set(AKONADI_TESTS_EXPORT AKONADICORE_EXPORT)
+if(BUILD_TESTING)
+    set(AKONADI_TESTS_EXPORT AKONADICORE_EXPORT)
+endif()
 configure_file(akonaditests_export.h.in 
"${CMAKE_CURRENT_BINARY_DIR}/akonaditests_export.h")
 
 # Make sure the KF5Akonadi_DATA_DIR is absolute before passing it to 
KF5AkonadiConfig.cmake.in
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/akonadi-16.12.2/autotests/libs/actionstatemanagertest.cpp 
new/akonadi-16.12.3/autotests/libs/actionstatemanagertest.cpp
--- old/akonadi-16.12.2/autotests/libs/actionstatemanagertest.cpp       
2017-01-19 13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/autotests/libs/actionstatemanagertest.cpp       
2017-03-04 15:02:02.000000000 +0100
@@ -27,8 +27,6 @@
 #include "../src/widgets/actionstatemanager.cpp"
 #undef QT_NO_CLIPBOARD
 
-#include "../src/core/pastehelper.cpp"
-
 typedef QHash<Akonadi::StandardActionManager::Type, bool> StateMap;
 Q_DECLARE_METATYPE(StateMap)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/autotests/server/CMakeLists.txt 
new/akonadi-16.12.3/autotests/server/CMakeLists.txt
--- old/akonadi-16.12.2/autotests/server/CMakeLists.txt 2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/autotests/server/CMakeLists.txt 2017-03-04 
15:02:02.000000000 +0100
@@ -34,7 +34,6 @@
     dbinitializer.cpp
     ${CMAKE_CURRENT_BINARY_DIR}/dbpopulator.cpp
 )
-ecm_qt_declare_logging_category(common_SRCS HEADER akonadiserver_debug.h 
IDENTIFIER AKONADISERVER_LOG CATEGORY_NAME org.kde.pim.akonadiserver)
 
 add_library(akonadi_unittest_common STATIC ${common_SRCS})
 target_link_libraries(akonadi_unittest_common
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/akonadi-16.12.2/autotests/server/fakeakonadiserver.cpp 
new/akonadi-16.12.3/autotests/server/fakeakonadiserver.cpp
--- old/akonadi-16.12.2/autotests/server/fakeakonadiserver.cpp  2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/autotests/server/fakeakonadiserver.cpp  2017-03-04 
15:02:02.000000000 +0100
@@ -243,29 +243,6 @@
     return true;
 }
 
-bool FakeAkonadiServer::deleteDirectory(const QString &path)
-{
-    // TODO: Qt 5: Use QDir::removeRecursively
-
-    Q_ASSERT(path.startsWith(basePath()));
-    QDir dir(path);
-    dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | 
QDir::Hidden);
-
-    const QFileInfoList list = dir.entryInfoList();
-    for (int i = 0; i < list.size(); ++i) {
-        if (list.at(i).isDir() && !list.at(i).isSymLink()) {
-            deleteDirectory(list.at(i).absoluteFilePath());
-            const QDir tmpDir(list.at(i).absoluteDir());
-            tmpDir.rmdir(list.at(i).fileName());
-        } else {
-            QFile::remove(list.at(i).absoluteFilePath());
-        }
-    }
-    dir.cdUp();
-    dir.rmdir(path);
-    return true;
-}
-
 bool FakeAkonadiServer::quit()
 {
     qDebug() << "==== Fake Akonadi Server shutting down ====";
@@ -277,8 +254,8 @@
 
     const QCommandLineParser &args = 
AkApplicationBase::instance()->commandLineArguments();
     if (!args.isSet(QLatin1String("no-cleanup"))) {
-        deleteDirectory(basePath());
-        qDebug() << "Cleaned up" << basePath();
+        bool ok = QDir(basePath()).removeRecursively();
+        qDebug() << "Cleaned up" << basePath() << "success=" << ok;
     } else {
         qDebug() << "Skipping clean up of" << basePath();
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/autotests/server/fakeakonadiserver.h 
new/akonadi-16.12.3/autotests/server/fakeakonadiserver.h
--- old/akonadi-16.12.2/autotests/server/fakeakonadiserver.h    2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/autotests/server/fakeakonadiserver.h    2017-03-04 
15:02:02.000000000 +0100
@@ -118,8 +118,6 @@
 private:
     explicit FakeAkonadiServer();
 
-    bool deleteDirectory(const QString &path);
-
     FakeDataStore *mDataStore;
     FakeSearchManager *mSearchManager;
     FakeConnection *mConnection;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/akonadi-16.12.2/autotests/server/itemretrievertest.cpp 
new/akonadi-16.12.3/autotests/server/itemretrievertest.cpp
--- old/akonadi-16.12.2/autotests/server/itemretrievertest.cpp  2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/autotests/server/itemretrievertest.cpp  2017-03-04 
15:02:02.000000000 +0100
@@ -20,6 +20,7 @@
 #include <QObject>
 #include <QTest>
 #include <QTimer>
+#include <QMutex>
 
 #include "storage/itemretriever.h"
 #include "storage/itemretrievaljob.h"
@@ -144,6 +145,52 @@
     QMultiHash<qint64, JobResult> mJobResults;
 };
 
+using RequestedParts = QVector<QByteArray /* FQ name */>;
+
+class ClientThread : public QThread
+{
+public:
+    ClientThread(Entity::Id itemId, const RequestedParts &requestedParts)
+        : m_itemId(itemId), m_requestedParts(requestedParts)
+    {}
+
+    void run() Q_DECL_OVERRIDE
+    {
+        // ItemRetriever should...
+        ItemRetriever retriever;
+        retriever.setItem(m_itemId);
+        retriever.setRetrieveParts(m_requestedParts);
+        QSignalSpy spy(&retriever, &ItemRetriever::itemsRetrieved);
+
+        const bool success = retriever.exec();
+
+        QMutexLocker lock(&m_mutex);
+        m_results.success = success;
+        m_results.signalsCount = spy.count();
+        if (m_results.signalsCount > 0) {
+            m_results.emittedItems = spy.at(0).at(0).value<QList<qint64>>();
+        }
+    }
+
+    struct Results
+    {
+        bool success;
+        int signalsCount;
+        QList<qint64> emittedItems;
+    };
+    Results results() const {
+        QMutexLocker lock(&m_mutex);
+        return m_results;
+    }
+
+private:
+    const Entity::Id m_itemId;
+    const RequestedParts m_requestedParts;
+
+    mutable QMutex m_mutex; // protects results below
+    Results m_results;
+};
+
 class ItemRetrieverTest : public QObject
 {
     Q_OBJECT
@@ -151,7 +198,6 @@
 
     using ExistingParts = QVector<QPair<QByteArray /* name */, QByteArray /* 
data */>>;
     using AvailableParts = QVector<QPair<QByteArray /* name */, QByteArray /* 
data */>>;
-    using RequestedParts = QVector<QByteArray /* FQ name */>;
 
 public:
     ItemRetrieverTest()
@@ -252,63 +298,89 @@
 
 
         // Setup
-        DbInitializer dbInitializer;
-        FakeItemRetrievalJobFactory factory(dbInitializer);
-        ItemRetrievalManager mgr(&factory);
-        QTest::qWait(100);
-
-        // Given a PimItem with existing parts
-        Resource res = dbInitializer.createResource("testresource");
-        Collection col = dbInitializer.createCollection("col1");
-        PimItem item = dbInitializer.createItem("1", col);
-        Q_FOREACH (const auto &existingPart, existingParts) {
-            dbInitializer.createPart(item.id(), existingPart.first, 
existingPart.second);
-        }
+        for (int step = 0; step < 2; ++step) {
+            DbInitializer dbInitializer;
+            FakeItemRetrievalJobFactory factory(dbInitializer);
+            ItemRetrievalManager mgr(&factory);
+            QTest::qWait(100);
+
+            // Given a PimItem with existing parts
+            Resource res = dbInitializer.createResource("testresource");
+            Collection col = dbInitializer.createCollection("col1");
+
+            // step 0: do it in the main thread, for easier debugging
+            PimItem item = dbInitializer.createItem("1", col);
+            Q_FOREACH (const auto &existingPart, existingParts) {
+                dbInitializer.createPart(item.id(), existingPart.first, 
existingPart.second);
+            }
 
-        Q_FOREACH (const auto &availablePart, availableParts) {
-            factory.addJobResult(item.id(), availablePart.first, 
availablePart.second);
-        }
+            Q_FOREACH (const auto &availablePart, availableParts) {
+                factory.addJobResult(item.id(), availablePart.first, 
availablePart.second);
+            }
 
-        // ItemRetriever should...
-        ItemRetriever retriever;
-        retriever.setItem(item.id());
-        retriever.setRetrieveParts(requestedParts);
-        QSignalSpy spy(&retriever, &ItemRetriever::itemsRetrieved);
+            if (step == 0) {
+                ClientThread thread(item.id(), requestedParts);
+                thread.run();
+
+                const ClientThread::Results results = thread.results();
+                // ItemRetriever should ... succeed
+                QVERIFY(results.success);
+                // Emit exactly one signal ...
+                QCOMPARE(results.signalsCount, expectedSignals);
+                // ... with that one item
+                if (expectedSignals > 0) {
+                    QCOMPARE(results.emittedItems, QList<qint64>{ item.id() });
+                }
 
-        // Succeed
-        QVERIFY(retriever.exec());
-        // Run exactly one retrieval job
-        QCOMPARE(factory.jobsCount(), expectedRetrievalJobs);
-        // Emit exactly one signal ...
-        QCOMPARE(spy.count(), expectedSignals);
-        // ... with that one item
-        if (expectedSignals > 0) {
-            QCOMPARE(spy.at(0).at(0).value<QList<qint64>>(), QList<qint64>{ 
item.id() });
-        }
+                // Check that the factory had exactly one retrieval job
+                QCOMPARE(factory.jobsCount(), expectedRetrievalJobs);
 
-        // and the part exists in the DB
-        const auto parts = item.parts();
-        QCOMPARE(parts.count(), expectedParts);
-        Q_FOREACH (const Part &dbPart, item.parts()) {
-            const QString fqname = dbPart.partType().ns() + QLatin1Char(':') + 
dbPart.partType().name();
-            if (!requestedParts.contains(fqname.toLatin1())) {
-                continue;
+            } else {
+                QVector<ClientThread *> threads;
+                for (int i = 0; i < 20; ++i) {
+                    threads.append(new ClientThread(item.id(), 
requestedParts));
+                }
+                for (int i = 0; i < threads.size(); ++i) {
+                    threads.at(i)->start();
+                }
+                for (int i = 0; i < threads.size(); ++i) {
+                    threads.at(i)->wait();
+                }
+                for (int i = 0; i < threads.size(); ++i) {
+                    const ClientThread::Results results = 
threads.at(i)->results();
+                    QVERIFY(results.success);
+                    QCOMPARE(results.signalsCount, expectedSignals);
+                    if (expectedSignals > 0) {
+                        QCOMPARE(results.emittedItems, QList<qint64>{ 
item.id() });
+                    }
+                }
+                qDeleteAll(threads);
             }
 
-            auto it = std::find_if(availableParts.constBegin(), 
availableParts.constEnd(),
-                                   [dbPart](const QPair<QByteArray, 
QByteArray> &p) {
-                                       return 
dbPart.partType().name().toLatin1() == p.first;
-                                   });
-            if (it == availableParts.constEnd()) {
-                it = std::find_if(existingParts.constBegin(), 
existingParts.constEnd(),
-                                  [fqname](const QPair<QByteArray, QByteArray> 
&p) {
-                                      return fqname.toLatin1() == p.first;
-                                  });
-                QVERIFY(it != existingParts.constEnd());
-            }
+            // Check that the parts now exist in the DB
+            const auto parts = item.parts();
+            QCOMPARE(parts.count(), expectedParts);
+            Q_FOREACH (const Part &dbPart, item.parts()) {
+                const QString fqname = dbPart.partType().ns() + 
QLatin1Char(':') + dbPart.partType().name();
+                if (!requestedParts.contains(fqname.toLatin1())) {
+                    continue;
+                }
+
+                auto it = std::find_if(availableParts.constBegin(), 
availableParts.constEnd(),
+                        [dbPart](const QPair<QByteArray, QByteArray> &p) {
+                        return dbPart.partType().name().toLatin1() == p.first;
+                        });
+                if (it == availableParts.constEnd()) {
+                    it = std::find_if(existingParts.constBegin(), 
existingParts.constEnd(),
+                            [fqname](const QPair<QByteArray, QByteArray> &p) {
+                            return fqname.toLatin1() == p.first;
+                            });
+                    QVERIFY(it != existingParts.constEnd());
+                }
 
-            QCOMPARE(dbPart.data(), it->second);
-            QCOMPARE(dbPart.datasize(), it->second.size());
+                QCOMPARE(dbPart.data(), it->second);
+                QCOMPARE(dbPart.datasize(), it->second.size());
+            }
         }
     }
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/core/agentmanager.cpp 
new/akonadi-16.12.3/src/core/agentmanager.cpp
--- old/akonadi-16.12.2/src/core/agentmanager.cpp       2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/src/core/agentmanager.cpp       2017-03-04 
15:02:02.000000000 +0100
@@ -383,6 +383,11 @@
 
 AgentType::List AgentManager::types() const
 {
+    // Maybe the Control process is up and ready but we haven't been to the 
event loop yet so serviceOwnerChanged wasn't called yet.
+    // In that case make sure to do it here, to avoid going into Broken state.
+    if (d->mTypes.isEmpty()) {
+        d->readAgentTypes();
+    }
     return Akonadi::valuesToVector(d->mTypes);
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/core/jobs/itemfetchjob.cpp 
new/akonadi-16.12.3/src/core/jobs/itemfetchjob.cpp
--- old/akonadi-16.12.2/src/core/jobs/itemfetchjob.cpp  2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/src/core/jobs/itemfetchjob.cpp  2017-03-04 
15:02:02.000000000 +0100
@@ -89,7 +89,22 @@
 
         } else {
             try {
-                return QString(); 
//QString::fromLatin1(ProtocolHelper::entitySetToScope(mRequestedItems));
+                QString itemStr = QStringLiteral("items id: ");
+                bool firstItem = true;
+                Q_FOREACH(const Akonadi::Item &item, mRequestedItems) {
+                    if (firstItem) {
+                        firstItem = false;
+                    } else {
+                        itemStr += QStringLiteral(", ");
+                    }
+                    itemStr += QString::number(item.id());
+                    const Akonadi::Collection parentCollection = 
item.parentCollection();
+                    if (parentCollection.isValid()) {
+                        itemStr += QStringLiteral(" from collection 
%1").arg(parentCollection.id());
+                    }
+                }
+                return itemStr;
+                //return QString(); 
//QString::fromLatin1(ProtocolHelper::entitySetToScope(mRequestedItems));
             } catch (const Exception &e) {
                 return QString::fromUtf8(e.what());
             }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/private/datastream_p.cpp 
new/akonadi-16.12.3/src/private/datastream_p.cpp
--- old/akonadi-16.12.2/src/private/datastream_p.cpp    2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/src/private/datastream_p.cpp    2017-03-04 
15:02:02.000000000 +0100
@@ -59,6 +59,8 @@
 
 void DataStream::waitForData(quint32 size)
 {
+    checkDevice();
+
     while (mDev->bytesAvailable() < size) {
         if (!mDev->waitForReadyRead(mWaitTimeout)) {
             throw ProtocolException("Timeout while waiting for data");
@@ -68,7 +70,7 @@
 
 void DataStream::writeRawData(const char *data, int len)
 {
-    Q_ASSERT(mDev);
+    checkDevice();
 
     int ret = mDev->write(data, len);
     if (ret != len) {
@@ -87,6 +89,7 @@
 
 int DataStream::readRawData(char *buffer, int len)
 {
-    Q_ASSERT(mDev);
+    checkDevice();
+
     return mDev->read(buffer, len);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/private/datastream_p_p.h 
new/akonadi-16.12.3/src/private/datastream_p_p.h
--- old/akonadi-16.12.2/src/private/datastream_p_p.h    2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/src/private/datastream_p_p.h    2017-03-04 
15:02:02.000000000 +0100
@@ -75,10 +75,15 @@
 
     void waitForData(quint32 size);
 private:
-
-
     Q_DISABLE_COPY(DataStream)
 
+    inline void checkDevice() const
+    {
+        if (Q_UNLIKELY(!mDev)) {
+            throw ProtocolException("Device does not exist");
+        }
+    }
+
     QIODevice *mDev;
     int mWaitTimeout;
 };
@@ -87,7 +92,7 @@
 inline typename std::enable_if<std::is_integral<T>::value, DataStream>::type
 &DataStream::operator<<(T val)
 {
-    Q_ASSERT(mDev);
+    checkDevice();
     if (mDev->write((char *)&val, sizeof(T)) != sizeof(T)) {
         throw Akonadi::ProtocolException("Failed to write data to stream");
     }
@@ -103,7 +108,6 @@
 
 inline DataStream &DataStream::operator<<(const QString &str)
 {
-    Q_ASSERT(mDev);
     if (str.isNull()) {
         *this << (quint32) 0xffffffff;
     } else {
@@ -114,7 +118,6 @@
 
 inline DataStream &DataStream::operator<<(const QByteArray &data)
 {
-    Q_ASSERT(mDev);
     if (data.isNull()) {
         *this << (quint32) 0xffffffff;
     } else {
@@ -143,7 +146,8 @@
 inline typename std::enable_if<std::is_integral<T>::value, DataStream>::type
 &DataStream::operator>>(T &val)
 {
-    Q_ASSERT(mDev);
+    checkDevice();
+
     waitForData(sizeof(T));
 
     if (mDev->read((char *)&val, sizeof(T)) != sizeof(T)) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/server/connection.cpp 
new/akonadi-16.12.3/src/server/connection.cpp
--- old/akonadi-16.12.2/src/server/connection.cpp       2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/src/server/connection.cpp       2017-03-04 
15:02:02.000000000 +0100
@@ -31,7 +31,8 @@
 #include "tracer.h"
 #include "collectionreferencemanager.h"
 
-#include <assert.h>
+#include <cassert>
+#include <cxxabi.h>
 
 #include <private/protocol_p.h>
 #include <private/datastream_p_p.h>
@@ -53,6 +54,7 @@
     , m_verifyCacheOnRetrieval(false)
     , m_idleTimer(Q_NULLPTR)
     , m_totalTime( 0 )
+    , m_connectionClosing(false)
     , m_reportTime( false )
 {
 }
@@ -107,6 +109,12 @@
 
 void Connection::quit()
 {
+    if (QThread::currentThread()->loopLevel() > 1) {
+        m_connectionClosing = true;
+        Q_EMIT connectionClosing();
+        return;
+    }
+
     Tracer::self()->endConnection(m_identifier, QString());
     collectionReferenceManager()->removeSession(m_sessionId);
 
@@ -255,6 +263,15 @@
             if (m_currentHandler) {
                 m_currentHandler->failureResponse(QString::fromUtf8(e.type()) 
+ QLatin1String(": ") + QString::fromUtf8(e.what()));
             }
+        } catch (abi::__forced_unwind&) {
+            // HACK: NPTL throws __forced_unwind during thread cancellation and
+            // we *must* rethrow it otherwise the program aborts. Due to the 
issue
+            // described in #376385 we might end up destroying (cancelling) the
+            // thread from a nested loop executed inside parseStream() above,
+            // so the exception raised in there gets caught by this try..catch
+            // statement and it must be rethrown at all cost. Remove this hack
+            // once the root problem is fixed.
+            throw;
         } catch (...) {
             qCCritical(AKONADISERVER_LOG) << "Unknown exception caught in 
Connection for session" << m_sessionId;
             if (m_currentHandler) {
@@ -271,6 +288,12 @@
             Q_EMIT disconnected();
             return;
         }
+
+        if (m_connectionClosing) {
+            m_socket->disconnect(this);
+            QTimer::singleShot(0, this, &Connection::quit);
+            return;
+        }
     }
 
     // reset, arm the timer
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/server/connection.h 
new/akonadi-16.12.3/src/server/connection.h
--- old/akonadi-16.12.2/src/server/connection.h 2017-01-19 13:12:42.000000000 
+0100
+++ new/akonadi-16.12.3/src/server/connection.h 2017-03-04 15:02:02.000000000 
+0100
@@ -77,6 +77,7 @@
 
 Q_SIGNALS:
     void disconnected();
+    void connectionClosing();
 
 protected Q_SLOTS:
     /**
@@ -114,6 +115,8 @@
     QHash<QString, qint64> m_totalTimeByHandler;
     QHash<QString, qint64> m_executionsByHandler;
 
+    bool m_connectionClosing;
+
 private:
     void sendResponse(qint64 tag, const Protocol::Command &response);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/server/storage/datastore.cpp 
new/akonadi-16.12.3/src/server/storage/datastore.cpp
--- old/akonadi-16.12.2/src/server/storage/datastore.cpp        2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/src/server/storage/datastore.cpp        2017-03-04 
15:02:02.000000000 +0100
@@ -160,6 +160,7 @@
     QueryCache::clear();
     m_database.close();
     m_database = QSqlDatabase();
+    m_transactionQueries.clear();
     QSqlDatabase::removeDatabase(m_connectionName);
 
     m_dbOpened = false;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/akonadi-16.12.2/src/server/storage/itemretrievalmanager.cpp 
new/akonadi-16.12.3/src/server/storage/itemretrievalmanager.cpp
--- old/akonadi-16.12.2/src/server/storage/itemretrievalmanager.cpp     
2017-01-19 13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/src/server/storage/itemretrievalmanager.cpp     
2017-03-04 15:02:02.000000000 +0100
@@ -232,6 +232,7 @@
             qCDebug(AKONADISERVER_LOG) << "someone else requested item" << 
request->ids << "as well, marking as processed";
             (*it)->errorMsg = errorMsg;
             (*it)->processed = true;
+            Q_EMIT requestFinished(*it);
             it = mPendingRequests[request->resourceId].erase(it);
         } else {
             ++it;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/server/storage/itemretriever.cpp 
new/akonadi-16.12.3/src/server/storage/itemretriever.cpp
--- old/akonadi-16.12.2/src/server/storage/itemretriever.cpp    2017-01-19 
13:12:42.000000000 +0100
+++ new/akonadi-16.12.3/src/server/storage/itemretriever.cpp    2017-03-04 
15:02:02.000000000 +0100
@@ -317,17 +317,20 @@
     QEventLoop eventLoop;
     connect(ItemRetrievalManager::instance(), 
&ItemRetrievalManager::requestFinished,
             this, [&](ItemRetrievalRequest *finishedRequest) {
-                if (!finishedRequest->errorMsg.isEmpty()) {
-                    mLastError = finishedRequest->errorMsg.toUtf8();
-                    eventLoop.exit(1);
-                } else {
-                    requests.removeOne(finishedRequest);
-                    Q_EMIT itemsRetrieved(finishedRequest->ids);
-                    if (requests.isEmpty()) {
-                        eventLoop.quit();
-                    }
+        if (requests.removeOne(finishedRequest)) {
+            if (!finishedRequest->errorMsg.isEmpty()) {
+                mLastError = finishedRequest->errorMsg.toUtf8();
+                eventLoop.exit(1);
+            } else {
+                Q_EMIT itemsRetrieved(finishedRequest->ids);
+                if (requests.isEmpty()) {
+                    eventLoop.quit();
                 }
-            }, Qt::UniqueConnection);
+            }
+        }
+    }, Qt::UniqueConnection);
+    connect(mConnection, &Connection::connectionClosing,
+            &eventLoop, [&eventLoop]() { eventLoop.exit(1); });
 
     auto it = requests.begin();
     while (it != requests.end()) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.2/src/shared/aktest.h 
new/akonadi-16.12.3/src/shared/aktest.h
--- old/akonadi-16.12.2/src/shared/aktest.h     2017-01-19 13:12:42.000000000 
+0100
+++ new/akonadi-16.12.3/src/shared/aktest.h     2017-03-04 15:02:02.000000000 
+0100
@@ -46,6 +46,7 @@
     AkCoreApplication app(argc, argv); \
     app.addCommandLineOptions(QCommandLineOption( \
         QLatin1String("no-cleanup"), QLatin1String("Don't clean up the 
temporary runtime environment"))); \
+    app.parseCommandLine(); \
     TestObject tc; \
     return QTest::qExec(&tc, argc, argv); \
 }


Reply via email to