diff --git a/arangod/Transaction/Manager.cpp b/arangod/Transaction/Manager.cpp index d2d71784b7..4c27f33939 100644 --- a/arangod/Transaction/Manager.cpp +++ b/arangod/Transaction/Manager.cpp @@ -98,30 +98,88 @@ void Manager::shutdown () { /// @brief create a transaction object //////////////////////////////////////////////////////////////////////////////// -Transaction* Manager::createTransaction (TRI_vocbase_t* vocbase) { +Transaction* Manager::createTransaction (TRI_vocbase_t* vocbase, + bool singleOperation) { Transaction::IdType id = _generator.next(); - Transaction* transaction = new Transaction(this, id, vocbase); + Transaction* transaction = new Transaction(this, id, vocbase, singleOperation); + + WRITE_LOCKER(_lock); + auto it = _transactions.insert(make_pair(id, transaction)); + + if (it.first == _transactions.end()) { + // couldn't insert transaction + delete transaction; + + return nullptr; + } return transaction; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief return the status of a transaction +//////////////////////////////////////////////////////////////////////////////// + +Transaction::StateType Manager::statusTransaction (Transaction::IdType id) { + READ_LOCKER(_lock); + + auto it = _transactions.find(id); + if (it != _transactions.end()) { + return (*it).second->state(); + } + + // unknown transaction. probably already committed + return Transaction::StateType::STATE_COMMITTED; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get oldest still running transaction +//////////////////////////////////////////////////////////////////////////////// + +TransactionInfo Manager::getOldestRunning () { + READ_LOCKER(_lock); + + for (auto it = _transactions.begin(); it != _transactions.end(); ++it) { + Transaction* transaction = (*it).second; + + if (transaction->state() == Transaction::StateType::STATE_BEGUN) { + return TransactionInfo(transaction->id(), transaction->elapsedTime()); + } + } + + return TransactionInfo(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief remove failed transactions from the failed list +//////////////////////////////////////////////////////////////////////////////// + +int Manager::removeFailed (vector const& ids) { + WRITE_LOCKER(_lock); + + for (auto it = ids.begin(); it != ids.end(); ++it) { + _transactions.erase(*it); + } + + return TRI_ERROR_NO_ERROR; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief begin a transaction //////////////////////////////////////////////////////////////////////////////// int Manager::beginTransaction (Transaction* transaction) { - double startTime = TRI_microtime(); - Transaction::IdType id = transaction->id(); - WRITE_LOCKER(_lock); - auto it = _transactions.insert(make_pair(id, Transaction::StateType::STATE_BEGUN)); - - if (it.first == _transactions.end()) { - return TRI_ERROR_INTERNAL; + + // check the transaction state first + if (transaction->state() != Transaction::StateType::STATE_UNINITIALISED) { + transaction->setAborted(); + return TRI_ERROR_TRANSACTION_INTERNAL; } - transaction->setStartTime(startTime); + // sets status and start time stamp + transaction->setBegun(); return TRI_ERROR_NO_ERROR; } @@ -134,13 +192,25 @@ int Manager::commitTransaction (Transaction* transaction) { Transaction::IdType id = transaction->id(); WRITE_LOCKER(_lock); + + if (transaction->state() != Transaction::StateType::STATE_BEGUN) { + // set it to aborted + transaction->setAborted(); + return TRI_ERROR_TRANSACTION_INTERNAL; + } + + transaction->setCommitted(); + auto it = _transactions.find(id); if (it == _transactions.end()) { - return TRI_ERROR_INTERNAL; + // not found + return TRI_ERROR_TRANSACTION_INTERNAL; } + // erase it in the list of transactions _transactions.erase(id); + return TRI_ERROR_NO_ERROR; } @@ -149,33 +219,19 @@ int Manager::commitTransaction (Transaction* transaction) { //////////////////////////////////////////////////////////////////////////////// int Manager::abortTransaction (Transaction* transaction) { - Transaction::IdType id = transaction->id(); - WRITE_LOCKER(_lock); - auto it = _transactions.find(id); - if (it == _transactions.end()) { - return TRI_ERROR_INTERNAL; + if (transaction->state() != Transaction::StateType::STATE_BEGUN) { + // TODO: set it to aborted + return TRI_ERROR_TRANSACTION_INTERNAL; } - (*it).second = Transaction::StateType::STATE_ABORTED; + transaction->setAborted(); + + // leave it in the list of transactions return TRI_ERROR_NO_ERROR; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief return the status of a transaction -//////////////////////////////////////////////////////////////////////////////// - -Transaction::StateType Manager::statusTransaction (Transaction::IdType id) { - READ_LOCKER(_lock); - - auto it = _transactions.find(id); - if (it == _transactions.end()) { - return Transaction::StateType::STATE_COMMITTED; - } - - return (*it).second; -} // mode: outline-minor // outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}" diff --git a/arangod/Transaction/Manager.h b/arangod/Transaction/Manager.h index f35530b4a1..b77b3c58ed 100644 --- a/arangod/Transaction/Manager.h +++ b/arangod/Transaction/Manager.h @@ -84,7 +84,26 @@ namespace triagens { /// @brief create a transaction object //////////////////////////////////////////////////////////////////////////////// - Transaction* createTransaction (struct TRI_vocbase_s*); + Transaction* createTransaction (struct TRI_vocbase_s*, + bool); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief abort a transaction +//////////////////////////////////////////////////////////////////////////////// + + Transaction::StateType statusTransaction (Transaction::IdType); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get oldest still running transaction +//////////////////////////////////////////////////////////////////////////////// + + TransactionInfo getOldestRunning (); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief remove failed transactions from the failed list +//////////////////////////////////////////////////////////////////////////////// + + int removeFailed (std::vector const&); //////////////////////////////////////////////////////////////////////////////// /// @brief begin a transaction @@ -104,12 +123,6 @@ namespace triagens { int abortTransaction (Transaction*); -//////////////////////////////////////////////////////////////////////////////// -/// @brief abort a transaction -//////////////////////////////////////////////////////////////////////////////// - - Transaction::StateType statusTransaction (Transaction::IdType); - // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- @@ -132,7 +145,7 @@ namespace triagens { /// @brief all running or aborted transactions //////////////////////////////////////////////////////////////////////////////// - map _transactions; + map _transactions; }; diff --git a/arangod/Transaction/Transaction.cpp b/arangod/Transaction/Transaction.cpp index 16caf72604..b5958a5940 100644 --- a/arangod/Transaction/Transaction.cpp +++ b/arangod/Transaction/Transaction.cpp @@ -41,11 +41,13 @@ using namespace triagens::transaction; Transaction::Transaction (Manager* manager, IdType id, - TRI_vocbase_t* vocbase) + TRI_vocbase_t* vocbase, + bool singleOperation) : _manager(manager), _id(id), _state(StateType::STATE_UNINITIALISED), _vocbase(vocbase), + _singleOperation(singleOperation), _operations(), _startTime() { } @@ -70,15 +72,7 @@ Transaction::~Transaction () { //////////////////////////////////////////////////////////////////////////////// int Transaction::begin () { - if (state() == StateType::STATE_UNINITIALISED && - _manager->beginTransaction(this)) { - _state = StateType::STATE_BEGUN; - - return TRI_ERROR_NO_ERROR; - } - - this->abort(); - return TRI_ERROR_TRANSACTION_INTERNAL; + return _manager->beginTransaction(this); } //////////////////////////////////////////////////////////////////////////////// @@ -86,15 +80,7 @@ int Transaction::begin () { //////////////////////////////////////////////////////////////////////////////// int Transaction::commit () { - if (state() == StateType::STATE_BEGUN && - _manager->commitTransaction(this)) { - _state = StateType::STATE_COMMITTED; - - return TRI_ERROR_NO_ERROR; - } - - this->abort(); - return TRI_ERROR_TRANSACTION_INTERNAL; + return _manager->commitTransaction(this); } //////////////////////////////////////////////////////////////////////////////// @@ -102,15 +88,7 @@ int Transaction::commit () { //////////////////////////////////////////////////////////////////////////////// int Transaction::abort () { - if (state() == StateType::STATE_BEGUN && - _manager->abortTransaction(this)) { - _state = StateType::STATE_ABORTED; - - return TRI_ERROR_NO_ERROR; - } - - _state = StateType::STATE_ABORTED; - return TRI_ERROR_TRANSACTION_INTERNAL; + return _manager->abortTransaction(this); } // Local Variables: diff --git a/arangod/Transaction/Transaction.h b/arangod/Transaction/Transaction.h index 0ada2907cf..8640e440f7 100644 --- a/arangod/Transaction/Transaction.h +++ b/arangod/Transaction/Transaction.h @@ -44,6 +44,8 @@ namespace triagens { class Transaction { + friend class Manager; + // ----------------------------------------------------------------------------- // --SECTION-- typedefs // ----------------------------------------------------------------------------- @@ -87,7 +89,8 @@ namespace triagens { Transaction (Manager*, IdType, - struct TRI_vocbase_s*); + struct TRI_vocbase_s*, + bool); //////////////////////////////////////////////////////////////////////////////// /// @brief destroy a transaction @@ -118,11 +121,30 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief set the transaction start time stamp +/// @brief is single operation? //////////////////////////////////////////////////////////////////////////////// - inline void setStartTime (double s) { - _startTime = s; + inline bool singleOperation () const { + return _singleOperation; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the transaction start time stamp +//////////////////////////////////////////////////////////////////////////////// + + inline double startTime () const { + return _startTime; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief get the time since transaction start +//////////////////////////////////////////////////////////////////////////////// + + inline double elapsedTime () const { + if (state() == Transaction::StateType::STATE_BEGUN) { + return TRI_microtime() - _startTime; + } + return 0.0; } //////////////////////////////////////////////////////////////////////////////// @@ -149,6 +171,31 @@ namespace triagens { private: +//////////////////////////////////////////////////////////////////////////////// +/// @brief set a transaction to committed +//////////////////////////////////////////////////////////////////////////////// + + void setBegun () { + _startTime = TRI_microtime(); + _state = StateType::STATE_BEGUN; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set a transaction to committed +//////////////////////////////////////////////////////////////////////////////// + + void setCommitted () { + _state = StateType::STATE_COMMITTED; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set a transaction to aborted +//////////////////////////////////////////////////////////////////////////////// + + void setAborted () { + _state = StateType::STATE_ABORTED; + } + // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- @@ -179,6 +226,12 @@ namespace triagens { struct TRI_vocbase_s* _vocbase; +//////////////////////////////////////////////////////////////////////////////// +/// @brief whether or not the transaction consists of a single operation +//////////////////////////////////////////////////////////////////////////////// + + bool const _singleOperation; + //////////////////////////////////////////////////////////////////////////////// /// @brief transaction operations, per collection //////////////////////////////////////////////////////////////////////////////// @@ -193,6 +246,26 @@ namespace triagens { }; +// ----------------------------------------------------------------------------- +// --SECTION-- TransactionInfo +// ----------------------------------------------------------------------------- + + struct TransactionInfo { + TransactionInfo (Transaction::IdType id, + double elapsedTime) + : _id(id), + _elapsedTime(elapsedTime) { + } + + TransactionInfo () + : _id(0), + _elapsedTime(0.0) { + } + + Transaction::IdType const _id; + double const _elapsedTime; + }; + } } diff --git a/js/apps/system/aardvark/frontend/js/bootstrap/errors.js b/js/apps/system/aardvark/frontend/js/bootstrap/errors.js index a9842301e6..572a2674d2 100644 --- a/js/apps/system/aardvark/frontend/js/bootstrap/errors.js +++ b/js/apps/system/aardvark/frontend/js/bootstrap/errors.js @@ -169,6 +169,7 @@ "ERROR_TRANSACTION_NESTED" : { "code" : 1651, "message" : "nested transactions detected" }, "ERROR_TRANSACTION_UNREGISTERED_COLLECTION" : { "code" : 1652, "message" : "unregistered collection used in transaction" }, "ERROR_TRANSACTION_DISALLOWED_OPERATION" : { "code" : 1653, "message" : "disallowed operation inside transaction" }, + "ERROR_TRANSACTION_ABORTED" : { "code" : 1654, "message" : "transaction aborted" }, "ERROR_USER_INVALID_NAME" : { "code" : 1700, "message" : "invalid user name" }, "ERROR_USER_INVALID_PASSWORD" : { "code" : 1701, "message" : "invalid password" }, "ERROR_USER_DUPLICATE" : { "code" : 1702, "message" : "duplicate user" }, diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js index a9842301e6..572a2674d2 100644 --- a/js/common/bootstrap/errors.js +++ b/js/common/bootstrap/errors.js @@ -169,6 +169,7 @@ "ERROR_TRANSACTION_NESTED" : { "code" : 1651, "message" : "nested transactions detected" }, "ERROR_TRANSACTION_UNREGISTERED_COLLECTION" : { "code" : 1652, "message" : "unregistered collection used in transaction" }, "ERROR_TRANSACTION_DISALLOWED_OPERATION" : { "code" : 1653, "message" : "disallowed operation inside transaction" }, + "ERROR_TRANSACTION_ABORTED" : { "code" : 1654, "message" : "transaction aborted" }, "ERROR_USER_INVALID_NAME" : { "code" : 1700, "message" : "invalid user name" }, "ERROR_USER_INVALID_PASSWORD" : { "code" : 1701, "message" : "invalid password" }, "ERROR_USER_DUPLICATE" : { "code" : 1702, "message" : "duplicate user" }, diff --git a/lib/BasicsC/errors.dat b/lib/BasicsC/errors.dat index 38cfaf6c67..537d087849 100755 --- a/lib/BasicsC/errors.dat +++ b/lib/BasicsC/errors.dat @@ -224,6 +224,7 @@ ERROR_TRANSACTION_INTERNAL,1650,"internal transaction error","Will be raised whe ERROR_TRANSACTION_NESTED,1651,"nested transactions detected","Will be raised when transactions are nested." ERROR_TRANSACTION_UNREGISTERED_COLLECTION,1652,"unregistered collection used in transaction","Will be raised when a collection is used in the middle of a transaction but was not registered at transaction start." ERROR_TRANSACTION_DISALLOWED_OPERATION,1653,"disallowed operation inside transaction","Will be raised when a disallowed operation is carried out in a transaction." +ERROR_TRANSACTION_ABORTED,1654,"transaction aborted","Will be raised when a transaction was aborted." ################################################################################ ## User management diff --git a/lib/BasicsC/voc-errors.c b/lib/BasicsC/voc-errors.c index ca7e7f5469..74babe10c3 100644 --- a/lib/BasicsC/voc-errors.c +++ b/lib/BasicsC/voc-errors.c @@ -165,6 +165,7 @@ void TRI_InitialiseErrorMessages (void) { REG_ERROR(ERROR_TRANSACTION_NESTED, "nested transactions detected"); REG_ERROR(ERROR_TRANSACTION_UNREGISTERED_COLLECTION, "unregistered collection used in transaction"); REG_ERROR(ERROR_TRANSACTION_DISALLOWED_OPERATION, "disallowed operation inside transaction"); + REG_ERROR(ERROR_TRANSACTION_ABORTED, "transaction aborted"); REG_ERROR(ERROR_USER_INVALID_NAME, "invalid user name"); REG_ERROR(ERROR_USER_INVALID_PASSWORD, "invalid password"); REG_ERROR(ERROR_USER_DUPLICATE, "duplicate user"); diff --git a/lib/BasicsC/voc-errors.h b/lib/BasicsC/voc-errors.h index b105ea150d..6a1628313a 100644 --- a/lib/BasicsC/voc-errors.h +++ b/lib/BasicsC/voc-errors.h @@ -394,6 +394,8 @@ extern "C" { /// - 1653: @LIT{disallowed operation inside transaction} /// Will be raised when a disallowed operation is carried out in a /// transaction. +/// - 1654: @LIT{transaction aborted} +/// Will be raised when a transaction was aborted. /// - 1700: @LIT{invalid user name} /// Will be raised when an invalid user name is used. /// - 1701: @LIT{invalid password} @@ -2111,6 +2113,16 @@ void TRI_InitialiseErrorMessages (void); #define TRI_ERROR_TRANSACTION_DISALLOWED_OPERATION (1653) +//////////////////////////////////////////////////////////////////////////////// +/// @brief 1654: ERROR_TRANSACTION_ABORTED +/// +/// transaction aborted +/// +/// Will be raised when a transaction was aborted. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_TRANSACTION_ABORTED (1654) + //////////////////////////////////////////////////////////////////////////////// /// @brief 1700: ERROR_USER_INVALID_NAME ///