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