diff --git a/arangod/Transaction/Methods.cpp b/arangod/Transaction/Methods.cpp index 457a361d3d..9d7888e384 100644 --- a/arangod/Transaction/Methods.cpp +++ b/arangod/Transaction/Methods.cpp @@ -741,6 +741,8 @@ Result transaction::Methods::commit() { // transaction not created or not running return TRI_ERROR_TRANSACTION_INTERNAL; } + + CallbackInvoker invoker(this); if (_state->isCoordinator()) { if (_state->isTopLevelTransaction()) { @@ -759,6 +761,8 @@ Result transaction::Methods::abort() { return TRI_ERROR_TRANSACTION_INTERNAL; } + CallbackInvoker invoker(this); + if (_state->isCoordinator()) { if (_state->isTopLevelTransaction()) { _state->updateStatus(transaction::Status::ABORTED); @@ -2885,3 +2889,16 @@ Result transaction::Methods::resolveId(char const* handle, size_t length, return TRI_ERROR_NO_ERROR; } + +/// @brief invoke a callback method when a transaction has finished +void transaction::CallbackInvoker::invoke() noexcept { + if (!_trx->_onFinish) { + return; + } + + try { + _trx->_onFinish(_trx); + } catch (...) { + // we must not propagate exceptions from here + } +} diff --git a/arangod/Transaction/Methods.h b/arangod/Transaction/Methods.h index fbf9ec5816..c70cdefd4c 100644 --- a/arangod/Transaction/Methods.h +++ b/arangod/Transaction/Methods.h @@ -64,6 +64,7 @@ class BaseEngine; } namespace transaction { +class CallbackInvoker; class Context; } @@ -81,6 +82,7 @@ namespace transaction { class Methods { friend class traverser::BaseEngine; + friend class CallbackInvoker; public: @@ -141,6 +143,9 @@ class Methods { ANY }; + /// @brief register a callback for transaction commit or abort + void registerCallback(std::function const& onFinish) { _onFinish = onFinish; } + /// @brief return database of transaction TRI_vocbase_t* vocbase() const; inline std::string const& databaseName() const { return vocbase()->name(); } @@ -167,6 +172,9 @@ class Methods { /// @brief get the status of the transaction Status status() const; + + /// @brief get the status of the transaction, as a string + char const* statusString() const { return transaction::statusString(status()); } /// @brief begin the transaction Result begin(); @@ -556,11 +564,29 @@ class Methods { /// @brief transaction hints transaction::Hints _localHints; + /// @brief name-to-cid lookup cache for last collection seen struct { TRI_voc_cid_t cid = 0; std::string name; } _collectionCache; + + /// @brief optional callback function that will be called on transaction + /// commit or abort + std::function _onFinish; +}; + +class CallbackInvoker { + public: + explicit CallbackInvoker(transaction::Methods* trx) : _trx(trx) {} + ~CallbackInvoker() { + invoke(); + } + + void invoke() noexcept; + + private: + transaction::Methods* _trx; }; }