diff --git a/autotests/shared/CMakeLists.txt b/autotests/shared/CMakeLists.txt --- a/autotests/shared/CMakeLists.txt +++ b/autotests/shared/CMakeLists.txt @@ -20,3 +20,4 @@ endmacro() add_unit_test(akrangestest.cpp) +add_unit_test(akscopeguardtest.cpp) diff --git a/src/server/storage/transaction.cpp b/autotests/shared/akscopeguardtest.cpp copy from src/server/storage/transaction.cpp copy to autotests/shared/akscopeguardtest.cpp --- a/src/server/storage/transaction.cpp +++ b/autotests/shared/akscopeguardtest.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2006 Volker Krause + Copyright (c) 2018 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 @@ -17,35 +17,27 @@ 02110-1301, USA. */ -#include "transaction.h" -#include "storage/datastore.h" +#include "shared/akscopeguard.h" -using namespace Akonadi::Server; +#include +#include -Transaction::Transaction(DataStore *db, const QString &name, bool beginTransaction) - : mDb(db) - , mName(name) - , mCommitted(false) +class AkScopeGuardTest : public QObject { - if (beginTransaction) { - mDb->beginTransaction(mName); + Q_OBJECT +private Q_SLOTS: + void testGoingOutOfScope() + { + bool callbackCalled = false; + { + AkScopeGuard guard([&callbackCalled]() { + callbackCalled = true; + }); + } + QVERIFY(callbackCalled); } -} +}; -Transaction::~Transaction() -{ - if (!mCommitted) { - mDb->rollbackTransaction(); - } -} +QTEST_GUILESS_MAIN(AkScopeGuardTest) -bool Transaction::commit() -{ - mCommitted = true; - return mDb->commitTransaction(); -} - -void Transaction::begin() -{ - mDb->beginTransaction(mName); -} +#include "akscopeguardtest.moc" diff --git a/src/server/handler/collectionmodifyhandler.cpp b/src/server/handler/collectionmodifyhandler.cpp --- a/src/server/handler/collectionmodifyhandler.cpp +++ b/src/server/handler/collectionmodifyhandler.cpp @@ -32,6 +32,7 @@ #include "storage/collectionqueryhelper.h" #include "search/searchmanager.h" #include "akonadiserver_debug.h" +#include "shared/akscopeguard.h" using namespace Akonadi; using namespace Akonadi::Server; @@ -237,6 +238,16 @@ } } + AkScopeGuard collectionReferencingGuard([&]() noexcept { + // If transaction is not committed and we are going out of scope, then a rollback + // occurred and we need to undo the collection reference change, if any. + if (!transaction.isCommitted()) { + if (referencedChanged && changes.contains(AKONADI_PARAM_REFERENCED)) { + connection()->collectionReferenceManager()->referenceCollection(connection()->sessionId(), collection, false); + } + } + }); + if (cmd.modifiedParts() & Protocol::ModifyCollectionCommand::RemovedAttributes) { Q_FOREACH (const QByteArray &attr, cmd.removedAttributes()) { if (db->removeCollectionAttribute(collection, attr)) { diff --git a/src/server/storage/transaction.h b/src/server/storage/transaction.h --- a/src/server/storage/transaction.h +++ b/src/server/storage/transaction.h @@ -55,6 +55,8 @@ */ ~Transaction(); + bool isCommitted() const; + /** Commits the transaction. Returns true on success. If a global transaction is used, nothing happens, global transactions have diff --git a/src/server/storage/transaction.cpp b/src/server/storage/transaction.cpp --- a/src/server/storage/transaction.cpp +++ b/src/server/storage/transaction.cpp @@ -39,6 +39,11 @@ } } +bool Transaction::isCommitted() const +{ + return mCommitted; +} + bool Transaction::commit() { mCommitted = true; diff --git a/src/server/storage/transaction.cpp b/src/shared/akscopeguard.h copy from src/server/storage/transaction.cpp copy to src/shared/akscopeguard.h --- a/src/server/storage/transaction.cpp +++ b/src/shared/akscopeguard.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2006 Volker Krause + Copyright (C) 2019 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 @@ -17,35 +17,30 @@ 02110-1301, USA. */ -#include "transaction.h" -#include "storage/datastore.h" +#ifndef AKSCOPEGUARD_H_ +#define AKSCOPEGUARD_H_ -using namespace Akonadi::Server; +#include +#include -Transaction::Transaction(DataStore *db, const QString &name, bool beginTransaction) - : mDb(db) - , mName(name) - , mCommitted(false) +class AkScopeGuard { - if (beginTransaction) { - mDb->beginTransaction(mName); +public: + AkScopeGuard(std::function &&func) + : mFunc(func) + {} + + ~AkScopeGuard() noexcept + { + mFunc(); } -} -Transaction::~Transaction() -{ - if (!mCommitted) { - mDb->rollbackTransaction(); - } -} +private: + Q_DISABLE_COPY(AkScopeGuard); + AkScopeGuard(AkScopeGuard &&) = delete; + AkScopeGuard &operator=(AkScopeGuard &&) = delete; -bool Transaction::commit() -{ - mCommitted = true; - return mDb->commitTransaction(); -} + std::function mFunc; +}; -void Transaction::begin() -{ - mDb->beginTransaction(mName); -} +#endif