mirror of https://gitee.com/bigwinds/arangodb
added exclusive locks
This commit is contained in:
parent
f2360e1039
commit
c2cbce507f
|
@ -11,6 +11,7 @@ in progress
|
|||
|
||||
to do
|
||||
-----
|
||||
- move engine-specific parts of transaction.cpp into engine
|
||||
- check for illegal includes
|
||||
- fix includes during API conversion
|
||||
- concept "collection locks"
|
||||
|
@ -18,3 +19,5 @@ to do
|
|||
- transaction API
|
||||
- DDL API
|
||||
- index API
|
||||
- add new serialization RW lock to LogicalCollection. all DML ops must acquire it in read mode, the explicit lock command must acquire it in write mode.
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
namespace arangodb {
|
||||
|
||||
class AqlTransaction : public Transaction {
|
||||
class AqlTransaction final : public Transaction {
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the transaction and add all collections from the query
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
namespace arangodb {
|
||||
|
||||
class ExplicitTransaction : public Transaction {
|
||||
class ExplicitTransaction final : public Transaction {
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create the transaction
|
||||
|
@ -42,6 +42,7 @@ class ExplicitTransaction : public Transaction {
|
|||
ExplicitTransaction(std::shared_ptr<V8TransactionContext> transactionContext,
|
||||
std::vector<std::string> const& readCollections,
|
||||
std::vector<std::string> const& writeCollections,
|
||||
std::vector<std::string> const& exclusiveCollections,
|
||||
double lockTimeout, bool waitForSync,
|
||||
bool allowImplicitCollections)
|
||||
: Transaction(transactionContext) {
|
||||
|
@ -54,6 +55,10 @@ class ExplicitTransaction : public Transaction {
|
|||
if (waitForSync) {
|
||||
this->setWaitForSync();
|
||||
}
|
||||
|
||||
for (auto const& it : exclusiveCollections) {
|
||||
this->addCollection(it, TRI_TRANSACTION_EXCLUSIVE);
|
||||
}
|
||||
|
||||
for (auto const& it : writeCollections) {
|
||||
this->addCollection(it, TRI_TRANSACTION_WRITE);
|
||||
|
|
|
@ -209,6 +209,7 @@ static void JS_Transaction(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
bool isValid = true;
|
||||
std::vector<std::string> readCollections;
|
||||
std::vector<std::string> writeCollections;
|
||||
std::vector<std::string> exclusiveCollections;
|
||||
|
||||
bool allowImplicitCollections = true;
|
||||
if (collections->Has(TRI_V8_ASCII_STRING("allowImplicit"))) {
|
||||
|
@ -261,6 +262,29 @@ static void JS_Transaction(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// collections.exclusive
|
||||
if (collections->Has(TRI_V8_ASCII_STRING("exclusive"))) {
|
||||
if (collections->Get(TRI_V8_ASCII_STRING("exclusive"))->IsArray()) {
|
||||
v8::Handle<v8::Array> names = v8::Handle<v8::Array>::Cast(
|
||||
collections->Get(TRI_V8_ASCII_STRING("exclusive")));
|
||||
|
||||
for (uint32_t i = 0; i < names->Length(); ++i) {
|
||||
v8::Handle<v8::Value> collection = names->Get(i);
|
||||
if (!collection->IsString()) {
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
exclusiveCollections.emplace_back(TRI_ObjectToString(collection));
|
||||
}
|
||||
} else if (collections->Get(TRI_V8_ASCII_STRING("exclusive"))->IsString()) {
|
||||
exclusiveCollections.emplace_back(
|
||||
TRI_ObjectToString(collections->Get(TRI_V8_ASCII_STRING("exclusive"))));
|
||||
} else {
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
TRI_V8_THROW_EXCEPTION_PARAMETER(collectionError);
|
||||
|
@ -342,7 +366,7 @@ static void JS_Transaction(v8::FunctionCallbackInfo<v8::Value> const& args) {
|
|||
std::make_shared<V8TransactionContext>(vocbase, embed);
|
||||
|
||||
// start actual transaction
|
||||
ExplicitTransaction trx(transactionContext, readCollections, writeCollections,
|
||||
ExplicitTransaction trx(transactionContext, readCollections, writeCollections, exclusiveCollections,
|
||||
lockTimeout, waitForSync, allowImplicitCollections);
|
||||
|
||||
int res = trx.begin();
|
||||
|
|
|
@ -53,52 +53,38 @@
|
|||
#endif
|
||||
|
||||
using namespace arangodb;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns whether the collection is currently locked
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool IsWrite(TRI_transaction_type_e type) {
|
||||
return (type == TRI_TRANSACTION_WRITE || type == TRI_TRANSACTION_EXCLUSIVE);
|
||||
}
|
||||
|
||||
/// @brief returns whether the collection is currently locked
|
||||
static inline bool IsLocked(TRI_transaction_collection_t const* trxCollection) {
|
||||
return (trxCollection->_lockType != TRI_TRANSACTION_NONE);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the logfile manager
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline MMFilesLogfileManager* GetMMFilesLogfileManager() {
|
||||
return MMFilesLogfileManager::instance();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a transaction is read-only
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline bool IsReadOnlyTransaction(TRI_transaction_t const* trx) {
|
||||
return (trx->_type == TRI_TRANSACTION_READ);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a specific hint is set for the transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline bool HasHint(TRI_transaction_t const* trx,
|
||||
TRI_transaction_hint_e hint) {
|
||||
return ((trx->_hints & (TRI_transaction_hint_t)hint) != 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a transaction consists of a single operation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline bool IsSingleOperationTransaction(TRI_transaction_t const* trx) {
|
||||
return HasHint(trx, TRI_TRANSACTION_HINT_SINGLE_OPERATION);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a marker needs to be written
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline bool NeedWriteMarker(TRI_transaction_t const* trx,
|
||||
bool isBeginMarker) {
|
||||
if (isBeginMarker) {
|
||||
|
@ -109,11 +95,8 @@ static inline bool NeedWriteMarker(TRI_transaction_t const* trx,
|
|||
!IsReadOnlyTransaction(trx) && !IsSingleOperationTransaction(trx));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief clear the query cache for all collections that were modified by
|
||||
/// the transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClearQueryCache(TRI_transaction_t* trx) {
|
||||
if (trx->_collections.empty()) {
|
||||
return;
|
||||
|
@ -122,7 +105,7 @@ void ClearQueryCache(TRI_transaction_t* trx) {
|
|||
try {
|
||||
std::vector<std::string> collections;
|
||||
for (auto& trxCollection : trx->_collections) {
|
||||
if (trxCollection->_accessType != TRI_TRANSACTION_WRITE ||
|
||||
if (!IsWrite(trxCollection->_accessType) ||
|
||||
trxCollection->_operations == nullptr ||
|
||||
trxCollection->_operations->empty()) {
|
||||
// we're only interested in collections that may have been modified
|
||||
|
@ -143,10 +126,7 @@ void ClearQueryCache(TRI_transaction_t* trx) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the status of the transaction as a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef ARANGODB_ENABLE_MAINTAINER_MODE
|
||||
static char const* StatusTransaction(const TRI_transaction_status_e status) {
|
||||
switch (status) {
|
||||
|
@ -167,10 +147,7 @@ static char const* StatusTransaction(const TRI_transaction_status_e status) {
|
|||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief free all operations for a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void FreeOperations(arangodb::Transaction* activeTrx, TRI_transaction_t* trx) {
|
||||
bool const mustRollback = (trx->_status == TRI_TRANSACTION_ABORTED);
|
||||
bool const isSingleOperation = IsSingleOperationTransaction(trx);
|
||||
|
@ -216,10 +193,7 @@ static void FreeOperations(arangodb::Transaction* activeTrx, TRI_transaction_t*
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief find a collection in the transaction's list of collections
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static TRI_transaction_collection_t* FindCollection(
|
||||
TRI_transaction_t const* trx, TRI_voc_cid_t cid,
|
||||
size_t* position) {
|
||||
|
@ -250,10 +224,7 @@ static TRI_transaction_collection_t* FindCollection(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lock a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int LockCollection(TRI_transaction_collection_t* trxCollection,
|
||||
TRI_transaction_type_e type, int nestingLevel) {
|
||||
TRI_ASSERT(trxCollection != nullptr);
|
||||
|
@ -291,10 +262,10 @@ static int LockCollection(TRI_transaction_collection_t* trxCollection,
|
|||
bool const useDeadlockDetector = !IsSingleOperationTransaction(trx);
|
||||
|
||||
int res;
|
||||
if (type == TRI_TRANSACTION_READ) {
|
||||
if (!IsWrite(type)) {
|
||||
LOG_TRX(trx, nestingLevel) << "read-locking collection " << trxCollection->_cid;
|
||||
res = collection->beginReadTimed(useDeadlockDetector, timeout);
|
||||
} else {
|
||||
} else { // WRITE or EXCLUSIVE
|
||||
LOG_TRX(trx, nestingLevel) << "write-locking collection "
|
||||
<< trxCollection->_cid;
|
||||
res = collection->beginWriteTimed(useDeadlockDetector, timeout);
|
||||
|
@ -307,10 +278,7 @@ static int LockCollection(TRI_transaction_collection_t* trxCollection,
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief unlock a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int UnlockCollection(TRI_transaction_collection_t* trxCollection,
|
||||
TRI_transaction_type_e type, int nestingLevel) {
|
||||
TRI_ASSERT(trxCollection != nullptr);
|
||||
|
@ -340,12 +308,10 @@ static int UnlockCollection(TRI_transaction_collection_t* trxCollection,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
if (type == TRI_TRANSACTION_READ &&
|
||||
trxCollection->_lockType == TRI_TRANSACTION_WRITE) {
|
||||
if (!IsWrite(type) && IsWrite(trxCollection->_lockType)) {
|
||||
// do not remove a write-lock if a read-unlock was requested!
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
} else if (type == TRI_TRANSACTION_WRITE &&
|
||||
trxCollection->_lockType == TRI_TRANSACTION_READ) {
|
||||
} else if (IsWrite(type) && !IsWrite(trxCollection->_lockType)) {
|
||||
// we should never try to write-unlock a collection that we have only
|
||||
// read-locked
|
||||
LOG(ERR) << "logic error in UnlockCollection";
|
||||
|
@ -358,10 +324,10 @@ static int UnlockCollection(TRI_transaction_collection_t* trxCollection,
|
|||
|
||||
LogicalCollection* collection = trxCollection->_collection;
|
||||
TRI_ASSERT(collection != nullptr);
|
||||
if (trxCollection->_lockType == TRI_TRANSACTION_READ) {
|
||||
if (!IsWrite(trxCollection->_lockType)) {
|
||||
LOG_TRX(trxCollection->_transaction, nestingLevel) << "read-unlocking collection " << trxCollection->_cid;
|
||||
collection->endRead(useDeadlockDetector);
|
||||
} else {
|
||||
} else { // WRITE or EXCLUSIVE
|
||||
LOG_TRX(trxCollection->_transaction, nestingLevel) << "write-unlocking collection " << trxCollection->_cid;
|
||||
collection->endWrite(useDeadlockDetector);
|
||||
}
|
||||
|
@ -371,10 +337,7 @@ static int UnlockCollection(TRI_transaction_collection_t* trxCollection,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief use all participating collections of a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int UseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
||||
// process collections in forward order
|
||||
for (auto& trxCollection : trx->_collections) {
|
||||
|
@ -411,7 +374,7 @@ static int UseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
|||
return res;
|
||||
}
|
||||
|
||||
if (trxCollection->_accessType == TRI_TRANSACTION_WRITE &&
|
||||
if (IsWrite(trxCollection->_accessType) &&
|
||||
TRI_GetOperationModeServer() == TRI_VOCBASE_MODE_NO_CREATE &&
|
||||
!LogicalCollection::IsSystemName(
|
||||
trxCollection->_collection->name())) {
|
||||
|
@ -426,7 +389,7 @@ static int UseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
|||
TRI_ASSERT(trxCollection->_collection != nullptr);
|
||||
|
||||
if (nestingLevel == 0 &&
|
||||
trxCollection->_accessType == TRI_TRANSACTION_WRITE) {
|
||||
IsWrite(trxCollection->_accessType)) {
|
||||
// read-lock the compaction lock
|
||||
if (!HasHint(trx, TRI_TRANSACTION_HINT_NO_COMPACTION_LOCK)) {
|
||||
if (!trxCollection->_compactionLocked) {
|
||||
|
@ -436,7 +399,7 @@ static int UseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
|||
}
|
||||
}
|
||||
|
||||
if (trxCollection->_accessType == TRI_TRANSACTION_WRITE &&
|
||||
if (IsWrite(trxCollection->_accessType) &&
|
||||
trxCollection->_originalRevision == 0) {
|
||||
// store original revision at transaction start
|
||||
trxCollection->_originalRevision =
|
||||
|
@ -446,8 +409,7 @@ static int UseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
|||
bool shouldLock = HasHint(trx, TRI_TRANSACTION_HINT_LOCK_ENTIRELY);
|
||||
|
||||
if (!shouldLock) {
|
||||
shouldLock = (trxCollection->_accessType == TRI_TRANSACTION_WRITE) &&
|
||||
(!IsSingleOperationTransaction(trx));
|
||||
shouldLock = (IsWrite(trxCollection->_accessType) && !IsSingleOperationTransaction(trx));
|
||||
}
|
||||
|
||||
if (shouldLock && !IsLocked(trxCollection)) {
|
||||
|
@ -464,10 +426,7 @@ static int UseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief release collection locks for a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int UnuseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
||||
int res = TRI_ERROR_NO_ERROR;
|
||||
|
||||
|
@ -484,8 +443,7 @@ static int UnuseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
|||
// the top level transaction releases all collections
|
||||
if (nestingLevel == 0 && trxCollection->_collection != nullptr) {
|
||||
if (!HasHint(trx, TRI_TRANSACTION_HINT_NO_COMPACTION_LOCK)) {
|
||||
if (trxCollection->_accessType == TRI_TRANSACTION_WRITE &&
|
||||
trxCollection->_compactionLocked) {
|
||||
if (IsWrite(trxCollection->_accessType) && trxCollection->_compactionLocked) {
|
||||
// read-unlock the compaction lock
|
||||
trxCollection->_collection->allowCompaction();
|
||||
trxCollection->_compactionLocked = false;
|
||||
|
@ -499,10 +457,7 @@ static int UnuseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief release collection locks for a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int ReleaseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
||||
TRI_ASSERT(nestingLevel == 0);
|
||||
if (HasHint(trx, TRI_TRANSACTION_HINT_LOCK_NEVER) ||
|
||||
|
@ -527,10 +482,7 @@ static int ReleaseCollections(TRI_transaction_t* trx, int nestingLevel) {
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief write WAL begin marker
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int WriteBeginMarker(TRI_transaction_t* trx) {
|
||||
if (!NeedWriteMarker(trx, true)) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -573,10 +525,7 @@ static int WriteBeginMarker(TRI_transaction_t* trx) {
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief write WAL abort marker
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int WriteAbortMarker(TRI_transaction_t* trx) {
|
||||
if (!NeedWriteMarker(trx, false)) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -617,10 +566,7 @@ static int WriteAbortMarker(TRI_transaction_t* trx) {
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief write WAL commit marker
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int WriteCommitMarker(TRI_transaction_t* trx) {
|
||||
if (!NeedWriteMarker(trx, false)) {
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
|
@ -668,10 +614,7 @@ static int WriteCommitMarker(TRI_transaction_t* trx) {
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief update the status of a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void UpdateTransactionStatus(TRI_transaction_t* const trx,
|
||||
TRI_transaction_status_e status) {
|
||||
TRI_ASSERT(trx->_status == TRI_TRANSACTION_CREATED ||
|
||||
|
@ -688,10 +631,7 @@ static void UpdateTransactionStatus(TRI_transaction_t* const trx,
|
|||
trx->_status = status;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the transaction type from a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_transaction_type_e TRI_GetTransactionTypeFromStr(char const* s) {
|
||||
if (strcmp(s, "read") == 0) {
|
||||
return TRI_TRANSACTION_READ;
|
||||
|
@ -699,14 +639,14 @@ TRI_transaction_type_e TRI_GetTransactionTypeFromStr(char const* s) {
|
|||
if (strcmp(s, "write") == 0) {
|
||||
return TRI_TRANSACTION_WRITE;
|
||||
}
|
||||
if (strcmp(s, "exclusive") == 0) {
|
||||
return TRI_TRANSACTION_EXCLUSIVE;
|
||||
}
|
||||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
|
||||
"invalid transaction type");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the collection from a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_transaction_collection_t* TRI_GetCollectionTransaction(
|
||||
TRI_transaction_t const* trx, TRI_voc_cid_t cid,
|
||||
TRI_transaction_type_e accessType) {
|
||||
|
@ -731,8 +671,7 @@ TRI_transaction_collection_t* TRI_GetCollectionTransaction(
|
|||
}
|
||||
|
||||
// check if access type matches
|
||||
if (accessType == TRI_TRANSACTION_WRITE &&
|
||||
trxCollection->_accessType == TRI_TRANSACTION_READ) {
|
||||
if (IsWrite(accessType) && !IsWrite(trxCollection->_accessType)) {
|
||||
// type doesn't match. probably also a mistake by the caller
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -740,10 +679,7 @@ TRI_transaction_collection_t* TRI_GetCollectionTransaction(
|
|||
return trxCollection;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a collection to a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_AddCollectionTransaction(TRI_transaction_t* trx, TRI_voc_cid_t cid,
|
||||
TRI_transaction_type_e accessType,
|
||||
int nestingLevel, bool force,
|
||||
|
@ -764,8 +700,7 @@ int TRI_AddCollectionTransaction(TRI_transaction_t* trx, TRI_voc_cid_t cid,
|
|||
TRI_ASSERT(trx->_status == TRI_TRANSACTION_CREATED);
|
||||
}
|
||||
|
||||
if (accessType == TRI_TRANSACTION_WRITE &&
|
||||
trx->_type == TRI_TRANSACTION_READ) {
|
||||
if (IsWrite(accessType) && !IsWrite(trx->_type)) {
|
||||
// if one collection is written to, the whole transaction becomes a
|
||||
// write-transaction
|
||||
trx->_type = TRI_TRANSACTION_WRITE;
|
||||
|
@ -780,8 +715,7 @@ int TRI_AddCollectionTransaction(TRI_transaction_t* trx, TRI_voc_cid_t cid,
|
|||
if (trxCollection != nullptr) {
|
||||
// collection is already contained in vector
|
||||
|
||||
if (accessType == TRI_TRANSACTION_WRITE &&
|
||||
trxCollection->_accessType != accessType) {
|
||||
if (IsWrite(accessType) && !IsWrite(trxCollection->_accessType)) {
|
||||
if (nestingLevel > 0) {
|
||||
// trying to write access a collection that is only marked with
|
||||
// read-access
|
||||
|
@ -791,7 +725,7 @@ int TRI_AddCollectionTransaction(TRI_transaction_t* trx, TRI_voc_cid_t cid,
|
|||
TRI_ASSERT(nestingLevel == 0);
|
||||
|
||||
// upgrade collection type to write-access
|
||||
trxCollection->_accessType = TRI_TRANSACTION_WRITE;
|
||||
trxCollection->_accessType = accessType;
|
||||
}
|
||||
|
||||
if (nestingLevel < trxCollection->_nestingLevel) {
|
||||
|
@ -804,12 +738,12 @@ int TRI_AddCollectionTransaction(TRI_transaction_t* trx, TRI_voc_cid_t cid,
|
|||
|
||||
// collection not found.
|
||||
|
||||
if (nestingLevel > 0 && accessType == TRI_TRANSACTION_WRITE) {
|
||||
if (nestingLevel > 0 && IsWrite(accessType)) {
|
||||
// trying to write access a collection in an embedded transaction
|
||||
return TRI_ERROR_TRANSACTION_UNREGISTERED_COLLECTION;
|
||||
}
|
||||
|
||||
if (accessType == TRI_TRANSACTION_READ && !allowImplicitCollections) {
|
||||
if (!IsWrite(accessType) && !allowImplicitCollections) {
|
||||
return TRI_ERROR_TRANSACTION_UNREGISTERED_COLLECTION;
|
||||
}
|
||||
|
||||
|
@ -835,23 +769,16 @@ int TRI_AddCollectionTransaction(TRI_transaction_t* trx, TRI_voc_cid_t cid,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief make sure all declared collections are used & locked
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_EnsureCollectionsTransaction(TRI_transaction_t* trx, int nestingLevel) {
|
||||
return UseCollections(trx, nestingLevel);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request a lock for a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_LockCollectionTransaction(TRI_transaction_collection_t* trxCollection,
|
||||
TRI_transaction_type_e accessType,
|
||||
int nestingLevel) {
|
||||
if (accessType == TRI_TRANSACTION_WRITE &&
|
||||
trxCollection->_accessType != TRI_TRANSACTION_WRITE) {
|
||||
if (IsWrite(accessType) && !IsWrite(trxCollection->_accessType)) {
|
||||
// wrong lock type
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
@ -864,15 +791,11 @@ int TRI_LockCollectionTransaction(TRI_transaction_collection_t* trxCollection,
|
|||
return LockCollection(trxCollection, accessType, nestingLevel);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request an unlock for a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_UnlockCollectionTransaction(TRI_transaction_collection_t* trxCollection,
|
||||
TRI_transaction_type_e accessType,
|
||||
int nestingLevel) {
|
||||
if (accessType == TRI_TRANSACTION_WRITE &&
|
||||
trxCollection->_accessType != TRI_TRANSACTION_WRITE) {
|
||||
if (IsWrite(accessType) && !IsWrite(trxCollection->_accessType)) {
|
||||
// wrong lock type: write-unlock requested but collection is read-only
|
||||
return TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
@ -885,17 +808,13 @@ int TRI_UnlockCollectionTransaction(TRI_transaction_collection_t* trxCollection,
|
|||
return UnlockCollection(trxCollection, accessType, nestingLevel);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check if a collection is locked in a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_IsLockedCollectionTransaction(
|
||||
TRI_transaction_collection_t const* trxCollection,
|
||||
TRI_transaction_type_e accessType, int nestingLevel) {
|
||||
TRI_ASSERT(trxCollection != nullptr);
|
||||
|
||||
if (accessType == TRI_TRANSACTION_WRITE &&
|
||||
trxCollection->_accessType != TRI_TRANSACTION_WRITE) {
|
||||
if (IsWrite(accessType) && !IsWrite(trxCollection->_accessType)) {
|
||||
// wrong lock type
|
||||
LOG(WARN) << "logic error. checking wrong lock type";
|
||||
return false;
|
||||
|
@ -904,20 +823,14 @@ bool TRI_IsLockedCollectionTransaction(
|
|||
return IsLocked(trxCollection);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check if a collection is locked in a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_IsLockedCollectionTransaction(
|
||||
TRI_transaction_collection_t const* trxCollection) {
|
||||
TRI_ASSERT(trxCollection != nullptr);
|
||||
return IsLocked(trxCollection);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether a collection is used in a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_IsContainedCollectionTransaction(TRI_transaction_t* trx,
|
||||
TRI_voc_cid_t cid) {
|
||||
for (auto& trxCollection : trx->_collections) {
|
||||
|
@ -929,10 +842,7 @@ bool TRI_IsContainedCollectionTransaction(TRI_transaction_t* trx,
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a WAL operation for a transaction collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_AddOperationTransaction(TRI_transaction_t* trx,
|
||||
TRI_voc_rid_t revisionId,
|
||||
MMFilesDocumentOperation& operation,
|
||||
|
@ -1081,13 +991,10 @@ int TRI_AddOperationTransaction(TRI_transaction_t* trx,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief start a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_BeginTransaction(TRI_transaction_t* trx, TRI_transaction_hint_t hints,
|
||||
int nestingLevel) {
|
||||
LOG_TRX(trx, nestingLevel) << "beginning " << (trx->_type == TRI_TRANSACTION_READ ? "read" : "write") << " transaction";
|
||||
LOG_TRX(trx, nestingLevel) << "beginning " << (IsWrite(trx->_type) ? "write" : "read") << " transaction";
|
||||
|
||||
if (nestingLevel == 0) {
|
||||
TRI_ASSERT(trx->_status == TRI_TRANSACTION_CREATED);
|
||||
|
@ -1095,7 +1002,7 @@ int TRI_BeginTransaction(TRI_transaction_t* trx, TRI_transaction_hint_t hints,
|
|||
auto logfileManager = MMFilesLogfileManager::instance();
|
||||
|
||||
if (!HasHint(trx, TRI_TRANSACTION_HINT_NO_THROTTLING) &&
|
||||
trx->_type == TRI_TRANSACTION_WRITE &&
|
||||
IsWrite(trx->_type) &&
|
||||
logfileManager->canBeThrottled()) {
|
||||
// write-throttling?
|
||||
static uint64_t const WaitTime = 50000;
|
||||
|
@ -1151,12 +1058,9 @@ int TRI_BeginTransaction(TRI_transaction_t* trx, TRI_transaction_hint_t hints,
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief commit a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_CommitTransaction(arangodb::Transaction* activeTrx, TRI_transaction_t* trx, int nestingLevel) {
|
||||
LOG_TRX(trx, nestingLevel) << "committing " << (trx->_type == TRI_TRANSACTION_READ ? "read" : "write") << " transaction";
|
||||
LOG_TRX(trx, nestingLevel) << "committing " << (IsWrite(trx->_type) ? "write" : "read") << " transaction";
|
||||
|
||||
TRI_ASSERT(trx->_status == TRI_TRANSACTION_RUNNING);
|
||||
|
||||
|
@ -1186,7 +1090,7 @@ int TRI_CommitTransaction(arangodb::Transaction* activeTrx, TRI_transaction_t* t
|
|||
UpdateTransactionStatus(trx, TRI_TRANSACTION_COMMITTED);
|
||||
|
||||
// if a write query, clear the query cache for the participating collections
|
||||
if (trx->_type == TRI_TRANSACTION_WRITE &&
|
||||
if (IsWrite(trx->_type) &&
|
||||
!trx->_collections.empty() &&
|
||||
arangodb::aql::QueryCache::instance()->mayBeActive()) {
|
||||
ClearQueryCache(trx);
|
||||
|
@ -1200,12 +1104,9 @@ int TRI_CommitTransaction(arangodb::Transaction* activeTrx, TRI_transaction_t* t
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief abort and rollback a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_AbortTransaction(arangodb::Transaction* activeTrx, TRI_transaction_t* trx, int nestingLevel) {
|
||||
LOG_TRX(trx, nestingLevel) << "aborting " << (trx->_type == TRI_TRANSACTION_READ ? "read" : "write") << " transaction";
|
||||
LOG_TRX(trx, nestingLevel) << "aborting " << (IsWrite(trx->_type) ? "write" : "read") << " transaction";
|
||||
|
||||
TRI_ASSERT(trx->_status == TRI_TRANSACTION_RUNNING);
|
||||
|
||||
|
@ -1224,18 +1125,12 @@ int TRI_AbortTransaction(arangodb::Transaction* activeTrx, TRI_transaction_t* tr
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a transaction consists of a single operation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_IsSingleOperationTransaction(TRI_transaction_t const* trx) {
|
||||
return HasHint(trx, TRI_TRANSACTION_HINT_SINGLE_OPERATION);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief transaction type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_transaction_t::TRI_transaction_t(TRI_vocbase_t* vocbase, double timeout, bool waitForSync)
|
||||
: _vocbase(vocbase),
|
||||
_id(0),
|
||||
|
@ -1257,10 +1152,7 @@ TRI_transaction_t::TRI_transaction_t(TRI_vocbase_t* vocbase, double timeout, boo
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief free a transaction container
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_transaction_t::~TRI_transaction_t() {
|
||||
TRI_ASSERT(_status != TRI_TRANSACTION_RUNNING);
|
||||
|
||||
|
|
|
@ -42,26 +42,18 @@ class Transaction;
|
|||
struct TRI_transaction_collection_t;
|
||||
struct TRI_vocbase_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief time (in µs) that is spent waiting for a lock
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_TRANSACTION_DEFAULT_LOCK_TIMEOUT 30.0
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief transaction type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum TRI_transaction_type_e {
|
||||
TRI_TRANSACTION_NONE = 0,
|
||||
TRI_TRANSACTION_READ = 1,
|
||||
TRI_TRANSACTION_WRITE = 2
|
||||
TRI_TRANSACTION_WRITE = 2,
|
||||
TRI_TRANSACTION_EXCLUSIVE = 4
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief transaction statuses
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum TRI_transaction_status_e {
|
||||
TRI_TRANSACTION_UNDEFINED = 0,
|
||||
TRI_TRANSACTION_CREATED = 1,
|
||||
|
@ -70,16 +62,10 @@ enum TRI_transaction_status_e {
|
|||
TRI_TRANSACTION_ABORTED = 4
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief typedef for transaction hints
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef uint32_t TRI_transaction_hint_t;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief hints that can be used for transactions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum TRI_transaction_hint_e {
|
||||
TRI_TRANSACTION_HINT_NONE = 0,
|
||||
TRI_TRANSACTION_HINT_SINGLE_OPERATION = 1,
|
||||
|
@ -94,10 +80,7 @@ enum TRI_transaction_hint_e {
|
|||
TRI_TRANSACTION_HINT_RECOVERY = 512
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief transaction type
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TRI_transaction_t {
|
||||
TRI_transaction_t(TRI_vocbase_t* vocbase, double timeout, bool waitForSync);
|
||||
~TRI_transaction_t();
|
||||
|
@ -122,10 +105,7 @@ struct TRI_transaction_t {
|
|||
double _timeout; // timeout for lock acquisition
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief collection used in a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TRI_transaction_collection_t {
|
||||
TRI_transaction_collection_t(TRI_transaction_t* trx, TRI_voc_cid_t cid, TRI_transaction_type_e accessType, int nestingLevel)
|
||||
: _transaction(trx), _cid(cid), _accessType(accessType), _nestingLevel(nestingLevel), _collection(nullptr), _operations(nullptr),
|
||||
|
@ -144,32 +124,25 @@ struct TRI_transaction_collection_t {
|
|||
bool _waitForSync; // whether or not the collection has waitForSync
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the type of the transaction as a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline char const* TRI_TransactionTypeGetStr(TRI_transaction_type_e t) {
|
||||
switch (t) {
|
||||
case TRI_TRANSACTION_NONE:
|
||||
return "none";
|
||||
case TRI_TRANSACTION_READ:
|
||||
return "read";
|
||||
case TRI_TRANSACTION_WRITE:
|
||||
return "write";
|
||||
case TRI_TRANSACTION_NONE: {
|
||||
}
|
||||
case TRI_TRANSACTION_EXCLUSIVE:
|
||||
return "exclusive";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the transaction type from a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_transaction_type_e TRI_GetTransactionTypeFromStr(char const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get the transaction id for usage in a marker
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline TRI_voc_tid_t TRI_MarkerIdTransaction(
|
||||
TRI_transaction_t const* trx) {
|
||||
if ((trx->_hints &
|
||||
|
@ -180,81 +153,45 @@ static inline TRI_voc_tid_t TRI_MarkerIdTransaction(
|
|||
return trx->_id;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the collection from a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_transaction_collection_t* TRI_GetCollectionTransaction(
|
||||
TRI_transaction_t const*, TRI_voc_cid_t, TRI_transaction_type_e);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a collection to a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_AddCollectionTransaction(TRI_transaction_t*, TRI_voc_cid_t,
|
||||
TRI_transaction_type_e, int, bool, bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief make sure all declared collections are used & locked
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_EnsureCollectionsTransaction(TRI_transaction_t*, int = 0);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request a lock for a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_LockCollectionTransaction(TRI_transaction_collection_t*,
|
||||
TRI_transaction_type_e, int);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief request an unlock for a collection
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_UnlockCollectionTransaction(TRI_transaction_collection_t*,
|
||||
TRI_transaction_type_e, int);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether a collection is locked in a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_IsLockedCollectionTransaction(TRI_transaction_collection_t const*,
|
||||
TRI_transaction_type_e, int);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether a collection is locked in a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_IsLockedCollectionTransaction(TRI_transaction_collection_t const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether a collection is contained in a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_IsContainedCollectionTransaction(TRI_transaction_t*, TRI_voc_cid_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief begin a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_BeginTransaction(TRI_transaction_t*, TRI_transaction_hint_t, int);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief commit a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_CommitTransaction(arangodb::Transaction*, TRI_transaction_t*, int);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief abort a transaction
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_AbortTransaction(arangodb::Transaction*, TRI_transaction_t*, int);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief whether or not a transaction consists of a single operation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_IsSingleOperationTransaction(TRI_transaction_t const*);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue