diff --git a/arangod/Utils/AhuacatlTransaction.h b/arangod/Utils/AhuacatlTransaction.h index d739dea795..eaee1df793 100644 --- a/arangod/Utils/AhuacatlTransaction.h +++ b/arangod/Utils/AhuacatlTransaction.h @@ -66,7 +66,7 @@ namespace triagens { TRI_aql_context_t* const context) : Transaction(vocbase, resolver) { - this->addHint(TRI_TRANSACTION_HINT_MANAGE_LOCKS); + this->addHint(TRI_TRANSACTION_HINT_IMPLICIT_LOCK); TRI_vector_pointer_t* collections = &context->_collections; diff --git a/arangod/Utils/Transaction.h b/arangod/Utils/Transaction.h index 4dc631d9f2..808e15234a 100644 --- a/arangod/Utils/Transaction.h +++ b/arangod/Utils/Transaction.h @@ -349,10 +349,7 @@ namespace triagens { return TRI_ERROR_INTERNAL; } - if ((this->status() == TRI_TRANSACTION_RUNNING && ! this->isEmbedded()) || - this->status() == TRI_TRANSACTION_COMMITTED || - this->status() == TRI_TRANSACTION_ABORTED || - this->status() == TRI_TRANSACTION_FINISHED) { + if (this->status() != TRI_TRANSACTION_RUNNING) { return TRI_ERROR_TRANSACTION_INVALID_STATE; } @@ -361,14 +358,7 @@ namespace triagens { return TRI_ERROR_NO_ERROR; } - if (type == TRI_TRANSACTION_READ) { - primary->beginRead(primary); - } - else { - primary->beginWrite(primary); - } - - return TRI_ERROR_NO_ERROR; + return TRI_LockCollectionTransaction(this->_trx, (TRI_transaction_cid_t) primary->base._info._cid, type); } //////////////////////////////////////////////////////////////////////////////// @@ -381,10 +371,7 @@ namespace triagens { return TRI_ERROR_INTERNAL; } - if ((this->status() == TRI_TRANSACTION_RUNNING && ! this->isEmbedded()) || - this->status() == TRI_TRANSACTION_COMMITTED || - this->status() == TRI_TRANSACTION_ABORTED || - this->status() == TRI_TRANSACTION_FINISHED) { + if (this->status() != TRI_TRANSACTION_RUNNING) { return TRI_ERROR_TRANSACTION_INVALID_STATE; } @@ -392,15 +379,8 @@ namespace triagens { // locking is a no-op in embedded transactions return TRI_ERROR_NO_ERROR; } - - if (type == TRI_TRANSACTION_READ) { - primary->endRead(primary); - } - else { - primary->endWrite(primary); - } - - return TRI_ERROR_NO_ERROR; + + return TRI_UnlockCollectionTransaction(this->_trx, (TRI_transaction_cid_t) primary->base._info._cid, type); } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Utils/UserTransaction.h b/arangod/Utils/UserTransaction.h index 53fbd2bb4b..bad24b212b 100644 --- a/arangod/Utils/UserTransaction.h +++ b/arangod/Utils/UserTransaction.h @@ -65,7 +65,7 @@ namespace triagens { const vector& writeCollections) : Transaction(vocbase, resolver) { - this->addHint(TRI_TRANSACTION_HINT_MANAGE_LOCKS); + this->addHint(TRI_TRANSACTION_HINT_IMPLICIT_LOCK); for (size_t i = 0; i < readCollections.size(); ++i) { this->addCollection(readCollections[i], TRI_TRANSACTION_READ); diff --git a/arangod/VocBase/transaction.c b/arangod/VocBase/transaction.c index f2d6a3917f..7c110cf65a 100644 --- a/arangod/VocBase/transaction.c +++ b/arangod/VocBase/transaction.c @@ -533,6 +533,60 @@ static void FreeCollection (TRI_transaction_collection_t* collection) { TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief lock a collection +//////////////////////////////////////////////////////////////////////////////// + +static int LockCollection (TRI_transaction_collection_t* collection, + const TRI_transaction_type_e type) { + TRI_primary_collection_t* primary; + + assert(collection != NULL); + assert(collection->_collection != NULL); + assert(collection->_collection->_collection != NULL); + assert(collection->_locked == false); + + primary = collection->_collection->_collection; + + if (type == TRI_TRANSACTION_READ) { + primary->beginRead(primary); + } + else { + primary->beginWrite(primary); + } + + collection->_locked = true; + + return TRI_ERROR_NO_ERROR; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief unlock a collection +//////////////////////////////////////////////////////////////////////////////// + +static int UnlockCollection (TRI_transaction_collection_t* collection, + const TRI_transaction_type_e type) { + TRI_primary_collection_t* primary; + + assert(collection != NULL); + assert(collection->_collection != NULL); + assert(collection->_collection->_collection != NULL); + assert(collection->_locked == true); + + primary = collection->_collection->_collection; + + if (type == TRI_TRANSACTION_READ) { + primary->endRead(primary); + } + else { + primary->endWrite(primary); + } + + collection->_locked = false; + + return TRI_ERROR_NO_ERROR; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief return a global instance for the collection /// this function will create a global instance if it does not yet exist @@ -599,17 +653,12 @@ static int UseCollections (TRI_transaction_t* const trx) { collection->_globalLock = true; } - if ((trx->_hints & (TRI_transaction_hint_t) TRI_TRANSACTION_HINT_MANAGE_LOCKS) != 0) { - TRI_primary_collection_t* primary = (TRI_primary_collection_t*) collection->_collection->_collection; + if ((trx->_hints & (TRI_transaction_hint_t) TRI_TRANSACTION_HINT_IMPLICIT_LOCK) != 0) { + int res = LockCollection(collection, collection->_type); - if (collection->_type == TRI_TRANSACTION_WRITE) { - primary->beginWrite(primary); + if (res != TRI_ERROR_NO_ERROR) { + return res; } - else if (collection->_type == TRI_TRANSACTION_READ) { - primary->beginRead(primary); - } - - collection->_locked = true; } } @@ -639,18 +688,8 @@ static int ReleaseCollections (TRI_transaction_t* const trx) { continue; } - if (collection->_locked && - (trx->_hints & (TRI_transaction_hint_t) TRI_TRANSACTION_HINT_MANAGE_LOCKS) != 0) { - - TRI_primary_collection_t* primary = (TRI_primary_collection_t*) collection->_collection->_collection; - if (collection->_type == TRI_TRANSACTION_WRITE) { - primary->endWrite(primary); - } - else if (collection->_type == TRI_TRANSACTION_READ) { - primary->endRead(primary); - } - - collection->_locked = false; + if (collection->_locked) { + UnlockCollection(collection, collection->_type); } if (collection->_type == TRI_TRANSACTION_WRITE && collection->_globalLock) { @@ -971,6 +1010,58 @@ void TRI_FreeTransaction (TRI_transaction_t* const trx) { /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief request a lock for a collection +//////////////////////////////////////////////////////////////////////////////// + +int TRI_LockCollectionTransaction (TRI_transaction_t* const trx, + const TRI_transaction_cid_t cid, + const TRI_transaction_type_e type) { + size_t i, n; + + n = trx->_collections._length; + + for (i = 0; i < n; ++i) { + TRI_transaction_collection_t* collection = TRI_AtVectorPointer(&trx->_collections, i); + + if (collection->_collection == NULL) { + continue; + } + + if (collection->_cid == cid) { + return LockCollection(collection, type); + } + } + + return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief request an unlock for a collection +//////////////////////////////////////////////////////////////////////////////// + +int TRI_UnlockCollectionTransaction (TRI_transaction_t* const trx, + const TRI_transaction_cid_t cid, + const TRI_transaction_type_e type) { + size_t i, n; + + n = trx->_collections._length; + + for (i = 0; i < n; ++i) { + TRI_transaction_collection_t* collection = TRI_AtVectorPointer(&trx->_collections, i); + + if (collection->_collection == NULL) { + continue; + } + + if (collection->_cid == cid) { + return UnlockCollection(collection, type); + } + } + + return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief return whether the transaction consists only of a single operation //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/transaction.h b/arangod/VocBase/transaction.h index d8979dade9..11ffd9e82e 100644 --- a/arangod/VocBase/transaction.h +++ b/arangod/VocBase/transaction.h @@ -303,7 +303,7 @@ typedef uint32_t TRI_transaction_hint_t; typedef enum { TRI_TRANSACTION_HINT_NONE = 0, TRI_TRANSACTION_HINT_SINGLE_OPERATION = 1, - TRI_TRANSACTION_HINT_MANAGE_LOCKS = 2 + TRI_TRANSACTION_HINT_IMPLICIT_LOCK = 2 } TRI_transaction_hint_e; @@ -401,6 +401,22 @@ int TRI_AddCollectionTransaction (TRI_transaction_t* const, const TRI_transaction_cid_t, const TRI_transaction_type_e); +//////////////////////////////////////////////////////////////////////////////// +/// @brief request a lock for a collection +//////////////////////////////////////////////////////////////////////////////// + +int TRI_LockCollectionTransaction (TRI_transaction_t* const, + const TRI_transaction_cid_t, + const TRI_transaction_type_e); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief request an unlock for a collection +//////////////////////////////////////////////////////////////////////////////// + +int TRI_UnlockCollectionTransaction (TRI_transaction_t* const, + const TRI_transaction_cid_t, + const TRI_transaction_type_e); + //////////////////////////////////////////////////////////////////////////////// /// @brief start a transaction ////////////////////////////////////////////////////////////////////////////////