Hello community,

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

Package is "akonadi-server"

Changes:
--------
--- /work/SRC/openSUSE:Factory/akonadi-server/akonadi-server.changes    
2016-12-29 22:43:03.455351682 +0100
+++ /work/SRC/openSUSE:Factory/.akonadi-server.new/akonadi-server.changes       
2017-01-25 23:15:40.576075342 +0100
@@ -1,0 +2,14 @@
+Sun Jan 22 17:10:01 UTC 2017 - hrvoje.sen...@gmail.com
+
+- Add handle-mysql-process-crashes-gracefully.patch from upstream
+
+-------------------------------------------------------------------
+Sat Jan 14 08:48:19 UTC 2017 - lbeltr...@kde.org
+
+- - Update to KDE Applications 16.12.1
+   * KDE Applications 16.12.1 
+   * https://www.kde.org/announcements/announce-applications-16.12.1.php
+
+- Drop upstream patch fix-connect-api.patch
+
+-------------------------------------------------------------------

Old:
----
  akonadi-16.12.0.tar.xz
  fix-connect-api.patch

New:
----
  akonadi-16.12.1.tar.xz
  handle-mysql-process-crashes-gracefully.patch

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

Other differences:
------------------
++++++ akonadi-server.spec ++++++
--- /var/tmp/diff_new_pack.qZneu0/_old  2017-01-25 23:15:41.323962578 +0100
+++ /var/tmp/diff_new_pack.qZneu0/_new  2017-01-25 23:15:41.327961975 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package akonadi-server
 #
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -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.0 in KUA)
+# Latest stable Applications (e.g. 16.08 in KA, but 16.12.1 in KUA)
 %{!?_kapp_version: %global _kapp_version %(echo %{version}| awk -F. '{print 
$1"."$2}')}
 Name:           akonadi-server
-Version:        16.12.0
+Version:        16.12.1
 Release:        0
 Summary:        PIM Storage Service
 License:        LGPL-2.1+
@@ -29,8 +29,8 @@
 Url:            http://akonadi-project.org
 Source:         %{rname}-%{version}.tar.xz
 Source99:       akonadi-server-rpmlintrc
-#PATCH-FIX-UPSTREAM fix-connect-api.patch  mon...@kde.org
-Patch1:         fix-connect-api.patch
+# PATCH-FIX-UPSTREAM handle-mysql-process-crashes-gracefully.patch
+Patch0:         handle-mysql-process-crashes-gracefully.patch
 BuildRequires:  boost-devel
 BuildRequires:  cmake >= 2.8.12
 BuildRequires:  extra-cmake-modules >= %{kf5_version}
@@ -161,7 +161,7 @@
 
 %prep
 %setup -q -n %{rname}-%{version}
-%patch1 -p1
+%patch0 -p1
 
 %build
   %cmake_kf5 -d build -- -DINSTALL_QSQLITE_IN_QT_PREFIX=TRUE 
-DQT_PLUGINS_DIR=%{_kf5_plugindir}

++++++ akonadi-16.12.0.tar.xz -> akonadi-16.12.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/CMakeLists.txt 
new/akonadi-16.12.1/CMakeLists.txt
--- old/akonadi-16.12.0/CMakeLists.txt  2016-12-07 11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/CMakeLists.txt  2017-01-08 16:41:33.000000000 +0100
@@ -22,7 +22,7 @@
 
 include(AkonadiMacros)
 
-set(PIM_VERSION "5.4.0")
+set(PIM_VERSION "5.4.1")
 
 set(QT_REQUIRED_VERSION "5.6.0")
 set(AKONADI_VERSION ${PIM_VERSION})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/core/changerecorder_p.cpp 
new/akonadi-16.12.1/src/core/changerecorder_p.cpp
--- old/akonadi-16.12.0/src/core/changerecorder_p.cpp   2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/core/changerecorder_p.cpp   2017-01-08 
16:41:33.000000000 +0100
@@ -127,11 +127,11 @@
     notificationsLoaded();
 }
 
-static const quint64 s_currentVersion = Q_UINT64_C(0x000500000000);
+static const quint64 s_currentVersion = Q_UINT64_C(0x000600000000);
 static const quint64 s_versionMask    = Q_UINT64_C(0xFFFF00000000);
 static const quint64 s_sizeMask       = Q_UINT64_C(0x0000FFFFFFFF);
 
-QQueue<Protocol::ChangeNotification> ChangeRecorderPrivate::loadFrom(QIODevice 
*device, bool &needsFullSave) const
+QQueue<Protocol::ChangeNotification> ChangeRecorderPrivate::loadFrom(QFile 
*device, bool &needsFullSave) const
 {
     QDataStream stream(device);
     stream.setVersion(QDataStream::Qt_4_6);
@@ -161,6 +161,11 @@
         stream >> sessionId;
         stream >> type;
 
+        if (stream.status() != QDataStream::Ok) {
+            qCWarning(AKONADICORE_LOG) << "Error reading saved notifications! 
Aborting. Corrupt file:" << device->fileName();
+            break;
+        }
+
         switch (static_cast<LegacyType>(type)) {
         case Item:
             msg = loadItemNotification(stream, version);
@@ -463,6 +468,10 @@
             stream >> remoteId;
             stream >> remoteRevision;
             stream >> mimeType;
+            if (stream.status() != QDataStream::Ok) {
+                qCWarning(AKONADICORE_LOG) << "Error reading saved 
notifications! Aborting";
+                return msg;
+            }
             msg.addItem(uid, remoteId, remoteRevision, mimeType);
         }
         stream >> resource;
@@ -558,6 +567,10 @@
             stream >> remoteId;
             stream >> remoteRevision;
             stream >> dummyString;
+            if (stream.status() != QDataStream::Ok) {
+                qCWarning(AKONADICORE_LOG) << "Error reading saved 
notifications! Aborting";
+                return msg;
+            }
             msg.setId(uid);
             msg.setRemoteId(remoteId);
             msg.setRemoteRevision(remoteRevision);
@@ -637,6 +650,10 @@
             stream >> remoteId;
             stream >> dummyString;
             stream >> dummyString;
+            if (stream.status() != QDataStream::Ok) {
+                qCWarning(AKONADICORE_LOG) << "Error reading saved 
notifications! Aborting";
+                return msg;
+            }
             msg.setId(uid);
             msg.setRemoteId(remoteId);
         }
@@ -702,9 +719,20 @@
             stream >> dummyString;
             stream >> dummyString;
             stream >> dummyString;
+            if (stream.status() != QDataStream::Ok) {
+                qCWarning(AKONADICORE_LOG) << "Error reading saved 
notifications! Aborting";
+                return msg;
+            }
         }
         stream >> dummyBa;
-        stream >> dummyBa;
+        if (version == 5) {
+            // there was a bug in version 5 serializer that serialized this
+            // field as qint64 (8 bytes) instead of empty QByteArray (which is
+            // 4 bytes)
+            stream >> dummyI;
+        } else {
+            stream >> dummyBa;
+        }
         stream >> dummyI;
         stream >> dummyI;
         stream >> itemParts;
@@ -754,7 +782,7 @@
     stream << QString();
     stream << QString();
     stream << QByteArray();
-    stream << qint64(0);
+    stream << QByteArray();
     stream << qint64(0);
     stream << qint64(0);
     stream << rv;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/core/changerecorder_p.h 
new/akonadi-16.12.1/src/core/changerecorder_p.h
--- old/akonadi-16.12.0/src/core/changerecorder_p.h     2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/core/changerecorder_p.h     2017-01-08 
16:41:33.000000000 +0100
@@ -51,7 +51,7 @@
     QString notificationsFileName() const;
 
     void loadNotifications();
-    QQueue<Protocol::ChangeNotification> loadFrom(QIODevice *device, bool 
&needsFullSave) const;
+    QQueue<Protocol::ChangeNotification> loadFrom(QFile *device, bool 
&needsFullSave) const;
     QString dumpNotificationListToString() const;
     void addToStream(QDataStream &stream, const Protocol::ChangeNotification 
&msg);
     void saveNotifications();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/core/monitor_p.cpp 
new/akonadi-16.12.1/src/core/monitor_p.cpp
--- old/akonadi-16.12.0/src/core/monitor_p.cpp  2016-12-07 11:27:47.000000000 
+0100
+++ new/akonadi-16.12.1/src/core/monitor_p.cpp  2017-01-08 16:41:33.000000000 
+0100
@@ -953,6 +953,13 @@
                 it.setRemoteId(msgItem.remoteId);
                 it.setRemoteRevision(msgItem.remoteRevision);
                 it.setMimeType(msgItem.mimeType);
+            } else if (msg.operation() == 
Protocol::ItemChangeNotification::Move) {
+                // For moves we remove the RID from the PimItemTable to prevent
+                // RID conflict during merge (see T3904 in Phab), so restore 
the
+                // RID from notification.
+                // TODO: Should we do this for all items with empty RID? Right 
now
+                // I only know about this usecase.
+                it.setRemoteId(msgItem.remoteId);
             }
 
             if (!it.parentCollection().isValid()) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/server/collectionscheduler.cpp 
new/akonadi-16.12.1/src/server/collectionscheduler.cpp
--- old/akonadi-16.12.0/src/server/collectionscheduler.cpp      2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/server/collectionscheduler.cpp      2017-01-08 
16:41:33.000000000 +0100
@@ -66,12 +66,7 @@
 
     Q_INVOKABLE void pause()
     {
-        if (!isActive()) {
-            qCCritical(AKONADISERVER_LOG) << "Cannot pause an inactive timer";
-            return;
-        }
-        if (isPaused()) {
-            qCCritical(AKONADISERVER_LOG) << "Cannot pause an already paused 
timer";
+        if (!isActive() || isPaused()) {
             return;
         }
 
@@ -82,7 +77,6 @@
     Q_INVOKABLE void resume()
     {
         if (!isPaused()) {
-            qCCritical(AKONADISERVER_LOG) << "Cannot resume a timer that is 
not paused.";
             return;
         }
 
@@ -128,14 +122,12 @@
 
 void CollectionScheduler::inhibit(bool inhibit)
 {
-    if (inhibit && mScheduler->isActive() && !mScheduler->isPaused()) {
+    if (inhibit) {
         const bool success = QMetaObject::invokeMethod(mScheduler, "pause", 
Qt::QueuedConnection);
-        Q_ASSERT(success);
-        Q_UNUSED(success);
-    } else if (!inhibit && mScheduler->isPaused()) {
+        Q_ASSERT(success); Q_UNUSED(success);
+    } else {
         const bool success = QMetaObject::invokeMethod(mScheduler, "resume", 
Qt::QueuedConnection);
-        Q_ASSERT(success);
-        Q_UNUSED(success);
+        Q_ASSERT(success); Q_UNUSED(success);
     }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/server/connection.cpp 
new/akonadi-16.12.1/src/server/connection.cpp
--- old/akonadi-16.12.0/src/server/connection.cpp       2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/server/connection.cpp       2017-01-08 
16:41:33.000000000 +0100
@@ -96,7 +96,7 @@
     connect(socket, &QIODevice::readyRead,
             this, &Connection::slotNewData);
     connect(socket, &QLocalSocket::disconnected,
-            this, &Connection::disconnected);
+            this, &Connection::slotSocketDisconnected);
 
     m_idleTimer = new QTimer(this);
     connect(m_idleTimer, &QTimer::timeout,
@@ -169,8 +169,23 @@
     }
 }
 
+void Connection::slotSocketDisconnected()
+{
+    // If we have active handler, wait for it to finish, then we emit the 
signal
+    // from slotNewDate()
+    if (m_currentHandler) {
+        return;
+    }
+
+    Q_EMIT disconnected();
+}
+
 void Connection::slotNewData()
 {
+    if (m_socket->state() != QLocalSocket::ConnectedState) {
+        return;
+    }
+
     m_idleTimer->stop();
 
     // will only open() a previously idle backend.
@@ -251,6 +266,11 @@
         }
         delete m_currentHandler;
         m_currentHandler = 0;
+
+        if (m_socket->state() != QLocalSocket::ConnectedState) {
+            Q_EMIT disconnected();
+            return;
+        }
     }
 
     // reset, arm the timer
@@ -394,7 +414,7 @@
 {
     while (m_socket->bytesAvailable() < (int) sizeof(qint64)) {
         if (m_socket->state() == QLocalSocket::UnconnectedState) {
-            return Protocol::Command();
+            throw ProtocolException("Socket disconnected");
         }
         m_socket->waitForReadyRead(500);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/server/connection.h 
new/akonadi-16.12.1/src/server/connection.h
--- old/akonadi-16.12.0/src/server/connection.h 2016-12-07 11:27:47.000000000 
+0100
+++ new/akonadi-16.12.1/src/server/connection.h 2017-01-08 16:41:33.000000000 
+0100
@@ -85,7 +85,7 @@
     void slotNewData();
     void slotConnectionStateChange(ConnectionState state);
     void slotConnectionIdle();
-
+    void slotSocketDisconnected();
     void slotSendHello();
 
 protected:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/server/handler/akappend.cpp 
new/akonadi-16.12.1/src/server/handler/akappend.cpp
--- old/akonadi-16.12.0/src/server/handler/akappend.cpp 2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/server/handler/akappend.cpp 2017-01-08 
16:41:33.000000000 +0100
@@ -82,14 +82,14 @@
 bool AkAppend::insertItem(const Protocol::CreateItemCommand &cmd, PimItem 
&item,
                           const Collection &parentCol)
 {
-    if (!item.insert()) {
-        return failureResponse("Failed to append item");
-    }
-
     if (!item.datetime().isValid()) {
         item.setDatetime(QDateTime::currentDateTimeUtc());
     }
 
+    if (!item.insert()) {
+        return failureResponse("Failed to append item");
+    }
+
     // set message flags
     const QSet<QByteArray> flags = cmd.mergeModes() == 
Protocol::CreateItemCommand::None ? cmd.flags() : cmd.addedFlags();
     if (!flags.isEmpty()) {
@@ -179,6 +179,7 @@
         currentItem.setDatetime(newItem.datetime());
         needsUpdate = true;
     }
+
     if (newItem.size() > 0 && newItem.size() != currentItem.size()) {
         currentItem.setSize(newItem.size());
         needsUpdate = true;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/server/handler/modify.cpp 
new/akonadi-16.12.1/src/server/handler/modify.cpp
--- old/akonadi-16.12.0/src/server/handler/modify.cpp   2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/server/handler/modify.cpp   2017-01-08 
16:41:33.000000000 +0100
@@ -189,7 +189,7 @@
         cols.reserve(cmd.persistentSearchCollections().size());
         QVector<qint64> inCols = cmd.persistentSearchCollections();
         qSort(inCols);
-        Q_FOREACH (qint64 col, cmd.persistentSearchCollections()) {
+        Q_FOREACH (qint64 col, inCols) {
             cols.append(QString::number(col));
         }
         const QString colStr = cols.join(QLatin1Char(' '));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/server/handler/move.cpp 
new/akonadi-16.12.1/src/server/handler/move.cpp
--- old/akonadi-16.12.0/src/server/handler/move.cpp     2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/server/handler/move.cpp     2017-01-08 
16:41:33.000000000 +0100
@@ -56,6 +56,7 @@
     // Split the list by source collection
     QMap<Entity::Id /* collection */, PimItem> toMove;
     QMap<Entity::Id /* collection */, Collection> sources;
+    ImapSet toMoveIds;
     Q_FOREACH (/*sic!*/ PimItem item, items) {  //krazy:exclude=foreach
         if (!item.isValid()) {
             failureResponse("Invalid item in result set!?");
@@ -87,6 +88,7 @@
         }
 
         toMove.insertMulti(source.id(), item);
+        toMoveIds.add(QVector<qint64>{ item.id() });
     }
 
     if (!transaction.commit()) {
@@ -94,8 +96,18 @@
         return;
     }
 
+    // Batch-reset RID
+    // The item should have an empty RID in the destination collection to avoid
+    // RID conflicts with existing items (see T3904 in Phab).
+    QueryBuilder qb2(PimItem::tableName(), QueryBuilder::Update);
+    qb2.setColumnValue(PimItem::remoteIdColumn(), QString());
+    ItemQueryHelper::itemSetToQuery(toMoveIds, connection()->context(), qb2);
+    if (!qb2.exec()) {
+        failureResponse("Unable to update RID");
+        return;
+    }
+
     // Emit notification for each source collection separately
-    QVector<PimItem::Id> itemsToResetRID;
     Collection source;
     PimItem::List itemsToMove;
     for (auto it = toMove.cbegin(), end = toMove.cend(); it != end; ++it) {
@@ -108,29 +120,11 @@
         }
 
         itemsToMove.push_back(*it);
-
-        // reset RID on inter-resource moves, but only after generating the 
change notification
-        // so that this still contains the old one for the source resource
-        const bool isInterResourceMove = it->collection().resource().id() != 
source.resource().id();
-        if (isInterResourceMove) {
-            itemsToResetRID.push_back(it->id());
-        }
     }
 
     if (!itemsToMove.isEmpty()) {
         store->notificationCollector()->itemsMoved(itemsToMove, source, 
mDestination);
     }
-
-    // Batch-reset RID for all inter-resource moves
-    if (!itemsToResetRID.isEmpty()) {
-        QueryBuilder qb(PimItem::tableName(), QueryBuilder::Update);
-        qb.setColumnValue(PimItem::remoteIdColumn(), QString());
-        ItemQueryHelper::itemSetToQuery(itemsToResetRID, 
connection()->context(), qb);
-        if (!qb.exec()) {
-            failureResponse("Unable to update RID");
-            return;
-        }
-    }
 }
 
 bool Move::parseStream()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/server/search/searchmanager.cpp 
new/akonadi-16.12.1/src/server/search/searchmanager.cpp
--- old/akonadi-16.12.0/src/server/search/searchmanager.cpp     2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/server/search/searchmanager.cpp     2017-01-08 
16:41:33.000000000 +0100
@@ -427,35 +427,54 @@
     qCDebug(AKONADISERVER_LOG) << "Got" << newMatches.count() << "results, out 
of which" << existingMatches.count() << "are already in the collection";
 
     newMatches = newMatches - existingMatches;
+    if (newMatches.isEmpty()) {
+        qCDebug(AKONADISERVER_LOG) << "Added results: 0 (fast path)";
+        return;
+    }
 
     const bool existingTransaction = DataStore::self()->inTransaction();
     if (!existingTransaction) {
         DataStore::self()->beginTransaction();
     }
 
+    // First query all the IDs we got from search plugin/agent against the DB.
+    // This will remove IDs that no longer exist in the DB.
     QVariantList newMatchesVariant;
     newMatchesVariant.reserve(newMatches.count());
     Q_FOREACH (qint64 id, newMatches) {
         newMatchesVariant << id;
-        Collection::addPimItem(collection.id(), id);
     }
 
-    qCDebug(AKONADISERVER_LOG) << "Added" << newMatches.count();
+    SelectQueryBuilder<PimItem> qb;
+    qb.addValueCondition(PimItem::idFullColumnName(), Query::In, 
newMatchesVariant);
+    if (!qb.exec()) {
+        return;
+    }
+
+    const auto items = qb.result();
+    if (items.count() != newMatches.count()) {
+        qCDebug(AKONADISERVER_LOG) << "Search backend returned" << 
(newMatches.count() - items.count()) << "results that no longer exist in 
Akonadi.";
+        qCDebug(AKONADISERVER_LOG) << "Please reindex collection" << 
collection.id();
+        // TODO: Request the reindexing directly from here
+    }
+
+    if (items.isEmpty()) {
+        qCDebug(AKONADISERVER_LOG) << "Added results: 0";
+        return;
+    }
+
+    for (const auto item : items) {
+        Collection::addPimItem(collection.id(), item.id());
+    }
 
     if (!existingTransaction && !DataStore::self()->commitTransaction()) {
         qCDebug(AKONADISERVER_LOG) << "Failed to commit transaction";
         return;
     }
 
-    if (!newMatchesVariant.isEmpty()) {
-        SelectQueryBuilder<PimItem> qb;
-        qb.addValueCondition(PimItem::idFullColumnName(), Query::In, 
newMatchesVariant);
-        if (!qb.exec()) {
-            return ;
-        }
-        const QVector<PimItem> newItems = qb.result();
-        DataStore::self()->notificationCollector()->itemsLinked(newItems, 
collection);
-        // Force collector to dispatch the notification now
-        DataStore::self()->notificationCollector()->dispatchNotifications();
-    }
+    DataStore::self()->notificationCollector()->itemsLinked(items, collection);
+    // Force collector to dispatch the notification now
+    DataStore::self()->notificationCollector()->dispatchNotifications();
+
+    qCDebug(AKONADISERVER_LOG) << "Added results:" << items.count();
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/server/storage/partstreamer.cpp 
new/akonadi-16.12.1/src/server/storage/partstreamer.cpp
--- old/akonadi-16.12.0/src/server/storage/partstreamer.cpp     2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/server/storage/partstreamer.cpp     2017-01-08 
16:41:33.000000000 +0100
@@ -64,13 +64,13 @@
 {
     Q_EMIT responseAvailable(Protocol::StreamPayloadCommand(partName, 
Protocol::StreamPayloadCommand::MetaData));
 
-    Protocol::StreamPayloadResponse response = mConnection->readCommand();
-    if (response.isError() || !response.isValid()) {
+    const auto cmd = mConnection->readCommand();
+    if (!cmd.isValid() || Protocol::Response(cmd).isError()) {
         mError = QStringLiteral("Client failed to provide part metadata");
         return Protocol::PartMetaData();
     }
 
-    return response.metaData();
+    return Protocol::StreamPayloadResponse(cmd).metaData();
 }
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/akonadi-16.12.0/src/widgets/subscriptiondialog.cpp 
new/akonadi-16.12.1/src/widgets/subscriptiondialog.cpp
--- old/akonadi-16.12.0/src/widgets/subscriptiondialog.cpp      2016-12-07 
11:27:47.000000000 +0100
+++ new/akonadi-16.12.1/src/widgets/subscriptiondialog.cpp      2017-01-08 
16:41:33.000000000 +0100
@@ -223,7 +223,7 @@
     mainLayout->addWidget(buttonBox);
 
     connect(d->model, SIGNAL(loaded()), SLOT(modelLoaded()));
-    connect(d->mOkButton, &QAbstractButton::clicked, this, &QDialog::done);
+    connect(d->mOkButton, SIGNAL(clicked(bool)), this, SLOT(done()));
     connect(buttonBox->button(QDialogButtonBox::Cancel), 
&QPushButton::clicked, this, &SubscriptionDialog::deleteLater);
     ControlGui::widgetNeedsAkonadi(mainWidget);
     d->readConfig();

++++++ handle-mysql-process-crashes-gracefully.patch ++++++
>From 4c5ca9bf32e5a9d569e83f66a439c65d8939a540 Mon Sep 17 00:00:00 2001
From: Martin Koller <kol...@aon.at>
Date: Sat, 21 Jan 2017 12:11:14 +0100
Subject: handle mysql process crashes gracefully

This patch checks if the mysqld stops unexpectedly when it was started
from akonadiserver and tells the latter to quit when a
stopped mysqld was discovered.
Also in this case the local socket file is removed so that
a restart can work without problem.
REVIEW: 129264
---
 src/server/storage/dbconfigmysql.cpp | 69 +++++++++++++++++++++++++++++++++---
 src/server/storage/dbconfigmysql.h   | 11 ++++--
 2 files changed, 72 insertions(+), 8 deletions(-)

diff --git a/src/server/storage/dbconfigmysql.cpp 
b/src/server/storage/dbconfigmysql.cpp
index 0962ccb..7631890 100644
--- a/src/server/storage/dbconfigmysql.cpp
+++ b/src/server/storage/dbconfigmysql.cpp
@@ -32,6 +32,7 @@
 #include <QSqlDriver>
 #include <QSqlError>
 #include <QSqlQuery>
+#include <QCoreApplication>
 
 using namespace Akonadi;
 using namespace Akonadi::Server;
@@ -190,6 +191,8 @@ bool DbConfigMysql::startInternalServer()
     const QString dataDir = StandardDirs::saveDir("data", 
QStringLiteral("db_data"));
 #ifndef Q_OS_WIN
     const QString socketDirectory = 
Utils::preferredSocketDirectory(StandardDirs::saveDir("data", 
QStringLiteral("db_misc")));
+    const QString socketFile = 
QStringLiteral("%1/mysql.socket").arg(socketDirectory);
+    const QString pidFileName = 
QStringLiteral("%1/mysql.pid").arg(socketDirectory);
 #endif
 
     // generate config file
@@ -289,6 +292,39 @@ bool DbConfigMysql::startInternalServer()
         qCCritical(AKONADISERVER_LOG) << "MySQL cannot deal with a socket path 
this long. Path was: " << socketDirectory;
         return false;
     }
+
+    // If mysql.socket file exists, check if also the server process is still 
running,
+    // else we can safely remove the socket file (cleanup after a system 
crash, etc.)
+    QFile pidFile(pidFileName);
+    if (QFile::exists(socketFile) && pidFile.open(QIODevice::ReadOnly)) {
+        qCDebug(AKONADISERVER_LOG) << "Found a mysqld pid file, checking 
whether the server is still running...";
+        QByteArray pid = pidFile.readLine().trimmed();
+        QFile proc(QString::fromLatin1("/proc/" + pid + "/stat"));
+        // Check whether the process with the PID from pidfile still exists 
and whether
+        // it's actually still mysqld or, whether the PID has been recycled in 
the meanwhile.
+        bool serverIsRunning = false;
+        if (proc.open(QIODevice::ReadOnly)) {
+            const QByteArray stat = proc.readAll();
+            const QList<QByteArray> stats = stat.split(' ');
+            if (stats.count() > 1) {
+                // Make sure the PID actually belongs to mysql process
+                if (stats[1] == "(mysqld)") {
+                    // Yup, our mysqld is actually running, so pretend we 
started the server
+                    // and try to connect to it
+                    qCWarning(AKONADISERVER_LOG) << "mysqld for Akonadi is 
already running, trying to connect to it.";
+                    serverIsRunning = true;
+                }
+            }
+            proc.close();
+        }
+
+        if (!serverIsRunning) {
+            qCDebug(AKONADISERVER_LOG) << "No mysqld process with specified 
PID is running. Removing the pidfile and starting a new instance...";
+            pidFile.close();
+            pidFile.remove();
+            QFile::remove(socketFile);
+        }
+    }
 #endif
 
     // synthesize the mysqld command
@@ -296,14 +332,15 @@ bool DbConfigMysql::startInternalServer()
     arguments << QStringLiteral("--defaults-file=%1/mysql.conf").arg(akDir);
     arguments << QStringLiteral("--datadir=%1/").arg(dataDir);
 #ifndef Q_OS_WIN
-    arguments << 
QStringLiteral("--socket=%1/mysql.socket").arg(socketDirectory);
+    arguments << QStringLiteral("--socket=%1").arg(socketFile);
+    arguments << QStringLiteral("--pid-file=%1").arg(pidFileName);
 #else
     arguments << QString::fromLatin1("--shared-memory");
 #endif
 
     // If mysql.socket file does not exists, then we must start the server,
     // otherwise we reconnect to it
-    if 
(!QFile::exists(QStringLiteral("%1/mysql.socket").arg(socketDirectory))) {
+    if (!QFile::exists(socketFile)) {
         // move mysql error log file out of the way
         const QFileInfo errorLog(dataDir + QDir::separator() + 
QLatin1String("mysql.err"));
         if (errorLog.exists()) {
@@ -348,9 +385,11 @@ bool DbConfigMysql::startInternalServer()
             return false;
         }
 
-    #ifndef Q_OS_WIN
+        connect(mDatabaseProcess, 
static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
+                this, &DbConfigMysql::processFinished);
+
+#ifndef Q_OS_WIN
         // wait until mysqld has created the socket file (workaround for 
QTBUG-47475 in Qt5.5.0)
-        QString socketFile = 
QStringLiteral("%1/mysql.socket").arg(socketDirectory);
         int counter = 50;  // avoid an endless loop in case mysqld terminated
         while ((counter-- > 0) && !QFileInfo::exists(socketFile)) {
             QThread::msleep(100);
@@ -358,7 +397,6 @@ bool DbConfigMysql::startInternalServer()
     #endif
     } else {
         qCDebug(AKONADISERVER_LOG) << "Found mysql.socket file, reconnecting 
to the database";
-        mDatabaseProcess = new QProcess();
     }
 
     const QLatin1String initCon("initConnection");
@@ -378,7 +416,7 @@ bool DbConfigMysql::startInternalServer()
             if (opened) {
                 break;
             }
-            if (mDatabaseProcess->waitForFinished(500)) {
+            if (mDatabaseProcess && mDatabaseProcess->waitForFinished(500)) {
                 qCCritical(AKONADISERVER_LOG) << "Database process exited 
unexpectedly during initial connection!";
                 qCCritical(AKONADISERVER_LOG) << "executable:" << mMysqldPath;
                 qCCritical(AKONADISERVER_LOG) << "arguments:" << arguments;
@@ -459,12 +497,33 @@ bool DbConfigMysql::startInternalServer()
     return success;
 }
 
+void DbConfigMysql::processFinished(int exitCode, QProcess::ExitStatus 
exitStatus)
+{
+    Q_UNUSED(exitCode);
+    Q_UNUSED(exitStatus);
+
+    qCCritical(AKONADISERVER_LOG) << "database server stopped unexpectedly";
+
+#ifndef Q_OS_WIN
+    // when the server stopped unexpectedly, make sure to remove the stale 
socket file since otherwise
+    // it can not be started again
+    const QString socketDirectory = 
Utils::preferredSocketDirectory(StandardDirs::saveDir("data", 
QStringLiteral("db_misc")));
+    const QString socketFile = 
QStringLiteral("%1/mysql.socket").arg(socketDirectory);
+    QFile::remove(socketFile);
+#endif
+
+    QCoreApplication::quit();
+}
+
 void DbConfigMysql::stopInternalServer()
 {
     if (!mDatabaseProcess) {
         return;
     }
 
+    disconnect(mDatabaseProcess, 
static_cast<void(QProcess::*)(int,QProcess::ExitStatus)>(&QProcess::finished),
+               this, &DbConfigMysql::processFinished);
+
     // first, try the nicest approach
     if (!mCleanServerShutdownCommand.isEmpty()) {
         QProcess::execute(mCleanServerShutdownCommand);
diff --git a/src/server/storage/dbconfigmysql.h 
b/src/server/storage/dbconfigmysql.h
index 27841e8..a25f28b 100644
--- a/src/server/storage/dbconfigmysql.h
+++ b/src/server/storage/dbconfigmysql.h
@@ -21,14 +21,16 @@
 #define DBCONFIGMYSQL_H
 
 #include "dbconfig.h"
-
-class QProcess;
+#include <QObject>
+#include <QProcess>
 
 namespace Akonadi {
 namespace Server {
 
-class DbConfigMysql : public DbConfig
+class DbConfigMysql : public QObject, public DbConfig
 {
+    Q_OBJECT
+
 public:
     DbConfigMysql();
 
@@ -75,6 +77,9 @@ public:
     /// reimpl
     void initSession(const QSqlDatabase &database) Q_DECL_OVERRIDE;
 
+private Q_SLOTS:
+    void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
+
 private:
     int parseCommandLineToolsVersion() const;
 
-- 
cgit v0.11.2

Reply via email to