1
0
Fork 0

honor exclusive locks

This commit is contained in:
jsteemann 2017-04-25 12:56:56 +02:00
parent 9db917bd77
commit 861291da16
11 changed files with 144 additions and 169 deletions

View File

@ -2346,8 +2346,7 @@ void MMFilesCollection::invokeOnAllElements(
}
/// @brief read locks a collection, with a timeout (in µseconds)
int MMFilesCollection::beginReadTimed(bool useDeadlockDetector,
double timeout) {
int MMFilesCollection::lockRead(bool useDeadlockDetector, double timeout) {
if (CollectionLockState::_noLockHeaders != nullptr) {
auto it =
CollectionLockState::_noLockHeaders->find(_logicalCollection->name());
@ -2462,8 +2461,7 @@ int MMFilesCollection::beginReadTimed(bool useDeadlockDetector,
}
/// @brief write locks a collection, with a timeout
int MMFilesCollection::beginWriteTimed(bool useDeadlockDetector,
double timeout) {
int MMFilesCollection::lockWrite(bool useDeadlockDetector, double timeout) {
if (CollectionLockState::_noLockHeaders != nullptr) {
auto it =
CollectionLockState::_noLockHeaders->find(_logicalCollection->name());
@ -2576,7 +2574,7 @@ int MMFilesCollection::beginWriteTimed(bool useDeadlockDetector,
}
/// @brief read unlocks a collection
int MMFilesCollection::endRead(bool useDeadlockDetector) {
int MMFilesCollection::unlockRead(bool useDeadlockDetector) {
if (CollectionLockState::_noLockHeaders != nullptr) {
auto it =
CollectionLockState::_noLockHeaders->find(_logicalCollection->name());
@ -2605,7 +2603,7 @@ int MMFilesCollection::endRead(bool useDeadlockDetector) {
}
/// @brief write unlocks a collection
int MMFilesCollection::endWrite(bool useDeadlockDetector) {
int MMFilesCollection::unlockWrite(bool useDeadlockDetector) {
if (CollectionLockState::_noLockHeaders != nullptr) {
auto it =
CollectionLockState::_noLockHeaders->find(_logicalCollection->name());

View File

@ -303,13 +303,13 @@ class MMFilesCollection final : public PhysicalCollection {
// -- SECTION Locking --
///////////////////////////////////
int beginReadTimed(bool useDeadlockDetector, double timeout = 0.0);
int lockRead(bool useDeadlockDetector, double timeout = 0.0);
int beginWriteTimed(bool useDeadlockDetector, double timeout = 0.0);
int lockWrite(bool useDeadlockDetector, double timeout = 0.0);
int endRead(bool useDeadlockDetector);
int unlockRead(bool useDeadlockDetector);
int endWrite(bool useDeadlockDetector);
int unlockWrite(bool useDeadlockDetector);
////////////////////////////////////
// -- SECTION DML Operations --

View File

@ -43,7 +43,7 @@ class MMFilesCollectionReadLocker {
_useDeadlockDetector(useDeadlockDetector),
_doLock(false) {
if (doLock) {
int res = _collection->beginReadTimed(_useDeadlockDetector);
int res = _collection->lockRead(_useDeadlockDetector);
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
@ -59,7 +59,7 @@ class MMFilesCollectionReadLocker {
/// @brief release the lock
inline void unlock() {
if (_doLock) {
_collection->endRead(_useDeadlockDetector);
_collection->unlockRead(_useDeadlockDetector);
_doLock = false;
}
}

View File

@ -42,7 +42,7 @@ class MMFilesCollectionWriteLocker {
_useDeadlockDetector(useDeadlockDetector),
_doLock(false) {
if (doLock) {
int res = _collection->beginWriteTimed(_useDeadlockDetector);
int res = _collection->lockWrite(_useDeadlockDetector);
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
@ -58,7 +58,7 @@ class MMFilesCollectionWriteLocker {
/// @brief release the lock
inline void unlock() {
if (_doLock) {
_collection->endWrite(_useDeadlockDetector);
_collection->unlockWrite(_useDeadlockDetector);
_doLock = false;
}
}

View File

@ -323,7 +323,7 @@ MMFilesCompactorThread::CompactionInitialContext MMFilesCompactorThread::getComp
auto physical = static_cast<MMFilesCollection*>(context._collection->getPhysical());
TRI_ASSERT(physical != nullptr);
bool const useDeadlockDetector = false;
int res = physical->beginReadTimed(useDeadlockDetector, 86400.0);
int res = physical->lockRead(useDeadlockDetector, 86400.0);
if (res != TRI_ERROR_NO_ERROR) {
ok = false;
@ -334,7 +334,7 @@ MMFilesCompactorThread::CompactionInitialContext MMFilesCompactorThread::getComp
} catch (...) {
ok = false;
}
physical->endRead(useDeadlockDetector);
physical->unlockRead(useDeadlockDetector);
}
}

View File

@ -55,7 +55,7 @@ int MMFilesTransactionCollection::lock() {
/// @brief request a lock for a collection
int MMFilesTransactionCollection::lock(AccessMode::Type accessType,
int nestingLevel) {
if (isWrite(accessType) && !isWrite(_accessType)) {
if (AccessMode::isWriteOrExclusive(accessType) && !AccessMode::isWriteOrExclusive(_accessType)) {
// wrong lock type
return TRI_ERROR_INTERNAL;
}
@ -71,7 +71,7 @@ int MMFilesTransactionCollection::lock(AccessMode::Type accessType,
/// @brief request an unlock for a collection
int MMFilesTransactionCollection::unlock(AccessMode::Type accessType,
int nestingLevel) {
if (isWrite(accessType) && !isWrite(_accessType)) {
if (AccessMode::isWriteOrExclusive(accessType) && !AccessMode::isWriteOrExclusive(_accessType)) {
// wrong lock type: write-unlock requested but collection is read-only
return TRI_ERROR_INTERNAL;
}
@ -86,7 +86,7 @@ int MMFilesTransactionCollection::unlock(AccessMode::Type accessType,
/// @brief check if a collection is locked in a specific mode in a transaction
bool MMFilesTransactionCollection::isLocked(AccessMode::Type accessType, int nestingLevel) const {
if (isWrite(accessType) && !isWrite(_accessType)) {
if (AccessMode::isWriteOrExclusive(accessType) && !AccessMode::isWriteOrExclusive(_accessType)) {
// wrong lock type
LOG_TOPIC(WARN, arangodb::Logger::FIXME) << "logic error. checking wrong lock type";
return false;
@ -163,8 +163,8 @@ bool MMFilesTransactionCollection::canAccess(AccessMode::Type accessType) const
}
// check if access type matches
if (AccessMode::isWriteOrExclusive(accessType) &&
!AccessMode::isWriteOrExclusive(_accessType)) {
if (AccessMode::AccessMode::isWriteOrExclusive(accessType) &&
!AccessMode::AccessMode::isWriteOrExclusive(_accessType)) {
// type doesn't match. probably also a mistake by the caller
return false;
}
@ -173,8 +173,8 @@ bool MMFilesTransactionCollection::canAccess(AccessMode::Type accessType) const
}
int MMFilesTransactionCollection::updateUsage(AccessMode::Type accessType, int nestingLevel) {
if (AccessMode::isWriteOrExclusive(accessType) &&
!AccessMode::isWriteOrExclusive(_accessType)) {
if (AccessMode::AccessMode::isWriteOrExclusive(accessType) &&
!AccessMode::AccessMode::isWriteOrExclusive(_accessType)) {
if (nestingLevel > 0) {
// trying to write access a collection that is only marked with
// read-access
@ -229,7 +229,7 @@ int MMFilesTransactionCollection::use(int nestingLevel) {
return res;
}
if (AccessMode::isWriteOrExclusive(_accessType) &&
if (AccessMode::AccessMode::isWriteOrExclusive(_accessType) &&
TRI_GetOperationModeServer() == TRI_VOCBASE_MODE_NO_CREATE &&
!LogicalCollection::IsSystemName(_collection->name())) {
return TRI_ERROR_ARANGO_READ_ONLY;
@ -244,7 +244,7 @@ int MMFilesTransactionCollection::use(int nestingLevel) {
TRI_ASSERT(physical != nullptr);
if (nestingLevel == 0 &&
AccessMode::isWriteOrExclusive(_accessType)) {
AccessMode::AccessMode::isWriteOrExclusive(_accessType)) {
// read-lock the compaction lock
if (!_transaction->hasHint(transaction::Hints::Hint::NO_COMPACTION_LOCK)) {
if (!_compactionLocked) {
@ -254,7 +254,7 @@ int MMFilesTransactionCollection::use(int nestingLevel) {
}
}
if (AccessMode::isWriteOrExclusive(_accessType) && _originalRevision == 0) {
if (AccessMode::AccessMode::isWriteOrExclusive(_accessType) && _originalRevision == 0) {
// store original revision at transaction start
_originalRevision = physical->revision();
}
@ -262,7 +262,7 @@ int MMFilesTransactionCollection::use(int nestingLevel) {
bool shouldLock = _transaction->hasHint(transaction::Hints::Hint::LOCK_ENTIRELY);
if (!shouldLock) {
shouldLock = (AccessMode::isWriteOrExclusive(_accessType) && !_transaction->hasHint(transaction::Hints::Hint::SINGLE_OPERATION));
shouldLock = (AccessMode::AccessMode::isWriteOrExclusive(_accessType) && !_transaction->hasHint(transaction::Hints::Hint::SINGLE_OPERATION));
}
if (shouldLock && !isLocked()) {
@ -287,7 +287,7 @@ void MMFilesTransactionCollection::unuse(int nestingLevel) {
// the top level transaction releases all collections
if (nestingLevel == 0 && _collection != nullptr) {
if (!_transaction->hasHint(transaction::Hints::Hint::NO_COMPACTION_LOCK)) {
if (AccessMode::isWriteOrExclusive(_accessType) && _compactionLocked) {
if (AccessMode::AccessMode::isWriteOrExclusive(_accessType) && _compactionLocked) {
auto physical = static_cast<MMFilesCollection*>(_collection->getPhysical());
TRI_ASSERT(physical != nullptr);
// read-unlock the compaction lock
@ -325,8 +325,6 @@ int MMFilesTransactionCollection::doLock(AccessMode::Type type, int nestingLevel
auto it = CollectionLockState::_noLockHeaders->find(collName);
if (it != CollectionLockState::_noLockHeaders->end()) {
// do not lock by command
// LOCKING-DEBUG
// std::cout << "LockCollection blocked: " << collName << std::endl;
return TRI_ERROR_NO_ERROR;
}
}
@ -348,12 +346,12 @@ int MMFilesTransactionCollection::doLock(AccessMode::Type type, int nestingLevel
bool const useDeadlockDetector = !_transaction->hasHint(transaction::Hints::Hint::SINGLE_OPERATION);
int res;
if (!isWrite(type)) {
if (!AccessMode::isWriteOrExclusive(type)) {
LOG_TRX(_transaction, nestingLevel) << "read-locking collection " << _cid;
res = physical->beginReadTimed(useDeadlockDetector, timeout);
res = physical->lockRead(useDeadlockDetector, timeout);
} else { // WRITE or EXCLUSIVE
LOG_TRX(_transaction, nestingLevel) << "write-locking collection " << _cid;
res = physical->beginWriteTimed(useDeadlockDetector, timeout);
res = physical->lockWrite(useDeadlockDetector, timeout);
}
if (res == TRI_ERROR_NO_ERROR) {
@ -394,13 +392,14 @@ int MMFilesTransactionCollection::doUnlock(AccessMode::Type type, int nestingLev
return TRI_ERROR_NO_ERROR;
}
if (!isWrite(type) && isWrite(_lockType)) {
if (!AccessMode::isWriteOrExclusive(type) && AccessMode::isWriteOrExclusive(_lockType)) {
// do not remove a write-lock if a read-unlock was requested!
return TRI_ERROR_NO_ERROR;
} else if (isWrite(type) && !isWrite(_lockType)) {
}
if (AccessMode::isWriteOrExclusive(type) && !AccessMode::isWriteOrExclusive(_lockType)) {
// we should never try to write-unlock a collection that we have only
// read-locked
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "logic error in UnlockCollection";
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "logic error in doUnlock";
TRI_ASSERT(false);
return TRI_ERROR_INTERNAL;
}
@ -413,12 +412,12 @@ int MMFilesTransactionCollection::doUnlock(AccessMode::Type type, int nestingLev
auto physical = static_cast<MMFilesCollection*>(collection->getPhysical());
TRI_ASSERT(physical != nullptr);
if (!isWrite(_lockType)) {
if (!AccessMode::isWriteOrExclusive(_lockType)) {
LOG_TRX(_transaction, nestingLevel) << "read-unlocking collection " << _cid;
physical->endRead(useDeadlockDetector);
physical->unlockRead(useDeadlockDetector);
} else { // WRITE or EXCLUSIVE
LOG_TRX(_transaction, nestingLevel) << "write-unlocking collection " << _cid;
physical->endWrite(useDeadlockDetector);
physical->unlockWrite(useDeadlockDetector);
}
_lockType = AccessMode::Type::NONE;

View File

@ -23,6 +23,7 @@
#include "RocksDBCollection.h"
#include "Aql/PlanCache.h"
#include "Basics/ReadLocker.h"
#include "Basics/Result.h"
#include "Basics/StaticStrings.h"
#include "Basics/VelocyPackHelper.h"
@ -1248,85 +1249,19 @@ void RocksDBCollection::adjustNumberDocuments(int64_t adjustment) {
}
/// @brief write locks a collection, with a timeout
int RocksDBCollection::beginWriteTimed(bool useDeadlockDetector,
double timeout) {
if (CollectionLockState::_noLockHeaders != nullptr) {
auto it =
CollectionLockState::_noLockHeaders->find(_logicalCollection->name());
if (it != CollectionLockState::_noLockHeaders->end()) {
// do not lock by command
// LOCKING-DEBUG
// std::cout << "BeginWriteTimed blocked: " << _name <<
// std::endl;
return TRI_ERROR_NO_ERROR;
}
}
// LOCKING-DEBUG
// std::cout << "BeginWriteTimed: " << document->_info._name << std::endl;
int iterations = 0;
bool wasBlocked = false;
uint64_t waitTime = 0; // indicate that times uninitialized
int RocksDBCollection::lockWrite(double timeout) {
uint64_t waitTime = 0; // indicates that time is uninitialized
double startTime = 0.0;
while (true) {
TRY_WRITE_LOCKER(locker, _exclusiveLock);
if (locker.isLocked()) {
// register writer
if (useDeadlockDetector) {
_logicalCollection->vocbase()->_deadlockDetector.addWriter(
_logicalCollection, wasBlocked);
}
// keep lock and exit loop
locker.steal();
return TRI_ERROR_NO_ERROR;
}
if (useDeadlockDetector) {
try {
if (!wasBlocked) {
// insert writer
wasBlocked = true;
if (_logicalCollection->vocbase()->_deadlockDetector.setWriterBlocked(
_logicalCollection) == TRI_ERROR_DEADLOCK) {
// deadlock
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
<< "deadlock detected while trying to acquire "
"write-lock on collection '"
<< _logicalCollection->name() << "'";
return TRI_ERROR_DEADLOCK;
}
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
<< "waiting for write-lock on collection '"
<< _logicalCollection->name() << "'";
} else if (++iterations >= 5) {
// periodically check for deadlocks
TRI_ASSERT(wasBlocked);
iterations = 0;
if (_logicalCollection->vocbase()->_deadlockDetector.detectDeadlock(
_logicalCollection, true) == TRI_ERROR_DEADLOCK) {
// deadlock
_logicalCollection->vocbase()->_deadlockDetector.unsetWriterBlocked(
_logicalCollection);
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
<< "deadlock detected while trying to acquire "
"write-lock on collection '"
<< _logicalCollection->name() << "'";
return TRI_ERROR_DEADLOCK;
}
}
} catch (...) {
// clean up!
if (wasBlocked) {
_logicalCollection->vocbase()->_deadlockDetector.unsetWriterBlocked(
_logicalCollection);
}
// always exit
return TRI_ERROR_OUT_OF_MEMORY;
}
}
double now = TRI_microtime();
if (waitTime == 0) { // initialize times
@ -1339,10 +1274,6 @@ int RocksDBCollection::beginWriteTimed(bool useDeadlockDetector,
}
if (now > startTime + timeout) {
if (useDeadlockDetector) {
_logicalCollection->vocbase()->_deadlockDetector.unsetWriterBlocked(
_logicalCollection);
}
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
<< "timed out after " << timeout
<< " s waiting for write-lock on collection '"
@ -1362,32 +1293,59 @@ int RocksDBCollection::beginWriteTimed(bool useDeadlockDetector,
}
/// @brief write unlocks a collection
int RocksDBCollection::endWrite(bool useDeadlockDetector) {
if (CollectionLockState::_noLockHeaders != nullptr) {
auto it =
CollectionLockState::_noLockHeaders->find(_logicalCollection->name());
if (it != CollectionLockState::_noLockHeaders->end()) {
// do not lock by command
// LOCKING-DEBUG
// std::cout << "EndWrite blocked: " << _name <<
// std::endl;
return TRI_ERROR_NO_ERROR;
}
}
if (useDeadlockDetector) {
// unregister writer
try {
_logicalCollection->vocbase()->_deadlockDetector.unsetWriter(
_logicalCollection);
} catch (...) {
// must go on here to unlock the lock
}
}
// LOCKING-DEBUG
// std::cout << "EndWrite: " << _name << std::endl;
int RocksDBCollection::unlockWrite() {
_exclusiveLock.unlockWrite();
return TRI_ERROR_NO_ERROR;
}
/// @brief read locks a collection, with a timeout
int RocksDBCollection::lockRead(double timeout) {
uint64_t waitTime = 0; // indicates that time is uninitialized
double startTime = 0.0;
while (true) {
TRY_READ_LOCKER(locker, _exclusiveLock);
if (locker.isLocked()) {
// keep lock and exit loop
locker.steal();
return TRI_ERROR_NO_ERROR;
}
double now = TRI_microtime();
if (waitTime == 0) { // initialize times
// set end time for lock waiting
if (timeout <= 0.0) {
timeout = defaultLockTimeout;
}
startTime = now;
waitTime = 1;
}
if (now > startTime + timeout) {
LOG_TOPIC(TRACE, arangodb::Logger::FIXME)
<< "timed out after " << timeout
<< " s waiting for read-lock on collection '"
<< _logicalCollection->name() << "'";
return TRI_ERROR_LOCK_TIMEOUT;
}
if (now - startTime < 0.001) {
std::this_thread::yield();
} else {
usleep(static_cast<TRI_usleep_t>(waitTime));
if (waitTime < 500000) {
waitTime *= 2;
}
}
}
}
/// @brief read unlocks a collection
int RocksDBCollection::unlockRead() {
_exclusiveLock.unlockRead();
return TRI_ERROR_NO_ERROR;
}

View File

@ -186,9 +186,10 @@ class RocksDBCollection final : public PhysicalCollection {
Result lookupDocumentToken(transaction::Methods* trx, arangodb::StringRef key,
RocksDBToken& token) const;
int beginWriteTimed(bool useDeadlockDetector, double timeout = 0.0);
int endWrite(bool useDeadlockDetector);
int lockWrite(double timeout = 0.0);
int unlockWrite();
int lockRead(double timeout = 0.0);
int unlockRead();
private:
/// @brief return engine-specific figures

View File

@ -55,7 +55,7 @@ int RocksDBTransactionCollection::lock() { return lock(_accessType, 0); }
/// @brief request a lock for a collection
int RocksDBTransactionCollection::lock(AccessMode::Type accessType,
int nestingLevel) {
if (isWrite(accessType) && !isWrite(_accessType)) {
if (AccessMode::isWriteOrExclusive(accessType) && !AccessMode::isWriteOrExclusive(_accessType)) {
// wrong lock type
return TRI_ERROR_INTERNAL;
}
@ -71,7 +71,7 @@ int RocksDBTransactionCollection::lock(AccessMode::Type accessType,
/// @brief request an unlock for a collection
int RocksDBTransactionCollection::unlock(AccessMode::Type accessType,
int nestingLevel) {
if (isWrite(accessType) && !isWrite(_accessType)) {
if (AccessMode::isWriteOrExclusive(accessType) && !AccessMode::isWriteOrExclusive(_accessType)) {
// wrong lock type: write-unlock requested but collection is read-only
return TRI_ERROR_INTERNAL;
}
@ -87,7 +87,7 @@ int RocksDBTransactionCollection::unlock(AccessMode::Type accessType,
/// @brief check if a collection is locked in a specific mode in a transaction
bool RocksDBTransactionCollection::isLocked(AccessMode::Type accessType,
int nestingLevel) const {
if (isWrite(accessType) && !isWrite(_accessType)) {
if (AccessMode::isWriteOrExclusive(accessType) && !AccessMode::isWriteOrExclusive(_accessType)) {
// wrong lock type
LOG_TOPIC(WARN, arangodb::Logger::FIXME)
<< "logic error. checking wrong lock type";
@ -178,7 +178,7 @@ int RocksDBTransactionCollection::use(int nestingLevel) {
static_cast<RocksDBCollection*>(_collection->getPhysical())->revision();
}
if (isExclusive(_accessType) && !isLocked()) {
if (AccessMode::isWriteOrExclusive(_accessType) && !isLocked()) {
// r/w lock the collection
int res = doLock(_accessType, nestingLevel);
@ -245,7 +245,12 @@ void RocksDBTransactionCollection::addOperation(
/// @brief lock a collection
int RocksDBTransactionCollection::doLock(AccessMode::Type type, int nestingLevel) {
if (!isExclusive(type)) {
if (!AccessMode::isWriteOrExclusive(type)) {
return TRI_ERROR_NO_ERROR;
}
if (_transaction->hasHint(transaction::Hints::Hint::LOCK_NEVER)) {
// never lock
return TRI_ERROR_NO_ERROR;
}
@ -256,8 +261,6 @@ int RocksDBTransactionCollection::doLock(AccessMode::Type type, int nestingLevel
auto it = CollectionLockState::_noLockHeaders->find(collName);
if (it != CollectionLockState::_noLockHeaders->end()) {
// do not lock by command
// LOCKING-DEBUG
// std::cout << "LockCollection blocked: " << collName << std::endl;
return TRI_ERROR_NO_ERROR;
}
}
@ -276,25 +279,28 @@ int RocksDBTransactionCollection::doLock(AccessMode::Type type, int nestingLevel
timeout = 0.00000001;
}
bool const useDeadlockDetector = !_transaction->hasHint(transaction::Hints::Hint::SINGLE_OPERATION);
LOG_TRX(_transaction, nestingLevel) << "write-locking collection " << _cid;
int res = physical->beginWriteTimed(useDeadlockDetector, timeout);
int res;
if (AccessMode::isExclusive(type)) {
// exclusive locking means we'll be acquiring the collection's RW lock in write mode
res = physical->lockWrite(timeout);
} else {
// write locking means we'll be acquiring the collection's RW lock in read mode
res = physical->lockRead(timeout);
}
if (res == TRI_ERROR_NO_ERROR) {
_lockType = type;
} else if (res == TRI_ERROR_LOCK_TIMEOUT && timeout >= 0.1) {
LOG_TOPIC(WARN, Logger::QUERIES) << "timed out after " << timeout << " s waiting for " << AccessMode::typeString(type) << "-lock on collection '" << _collection->name() << "'";
} else if (res == TRI_ERROR_DEADLOCK) {
LOG_TOPIC(WARN, Logger::QUERIES) << "deadlock detected while trying to acquire " << AccessMode::typeString(type) << "-lock on collection '" << _collection->name() << "'";
}
}
return res;
}
/// @brief unlock a collection
int RocksDBTransactionCollection::doUnlock(AccessMode::Type type, int nestingLevel) {
if (!isExclusive(type) || !isExclusive(_lockType)) {
if (!AccessMode::isWriteOrExclusive(type) || !AccessMode::isWriteOrExclusive(_lockType)) {
return TRI_ERROR_NO_ERROR;
}
@ -310,8 +316,6 @@ int RocksDBTransactionCollection::doUnlock(AccessMode::Type type, int nestingLev
auto it = CollectionLockState::_noLockHeaders->find(collName);
if (it != CollectionLockState::_noLockHeaders->end()) {
// do not lock by command
// LOCKING-DEBUG
// std::cout << "UnlockCollection blocked: " << collName << std::endl;
return TRI_ERROR_NO_ERROR;
}
}
@ -322,8 +326,18 @@ int RocksDBTransactionCollection::doUnlock(AccessMode::Type type, int nestingLev
// only process our own collections
return TRI_ERROR_NO_ERROR;
}
bool const useDeadlockDetector = !_transaction->hasHint(transaction::Hints::Hint::SINGLE_OPERATION);
if (!AccessMode::isWriteOrExclusive(type) && AccessMode::isWriteOrExclusive(_lockType)) {
// do not remove a write-lock if a read-unlock was requested!
return TRI_ERROR_NO_ERROR;
}
if (AccessMode::isWriteOrExclusive(type) && !AccessMode::isWriteOrExclusive(_lockType)) {
// we should never try to write-unlock a collection that we have only
// read-locked
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "logic error in doUnlock";
TRI_ASSERT(false);
return TRI_ERROR_INTERNAL;
}
LogicalCollection* collection = _collection;
TRI_ASSERT(collection != nullptr);
@ -332,7 +346,13 @@ int RocksDBTransactionCollection::doUnlock(AccessMode::Type type, int nestingLev
TRI_ASSERT(physical != nullptr);
LOG_TRX(_transaction, nestingLevel) << "write-unlocking collection " << _cid;
physical->endWrite(useDeadlockDetector);
if (!AccessMode::isExclusive(type)) {
// exclusive locking means we'll be releasing the collection's RW lock in write mode
physical->unlockWrite();
} else {
// write locking means we'll be releasing the collection's RW lock in read mode
physical->unlockRead();
}
_lockType = AccessMode::Type::NONE;

View File

@ -81,15 +81,6 @@ class TransactionCollection {
virtual void unuse(int nestingLevel) = 0;
virtual void release() = 0;
protected:
inline bool isExclusive(AccessMode::Type type) const {
return (type == AccessMode::Type::EXCLUSIVE);
}
inline bool isWrite(AccessMode::Type type) const {
return (type == AccessMode::Type::WRITE || type == AccessMode::Type::EXCLUSIVE);
}
protected:
TransactionState* _transaction; // the transaction state
TRI_voc_cid_t const _cid; // collection id

View File

@ -36,9 +36,17 @@ struct AccessMode {
WRITE = 2,
EXCLUSIVE = 4
};
static inline bool isWrite(Type type) {
return (type == Type::WRITE);
}
static inline bool isExclusive(Type type) {
return (type == Type::EXCLUSIVE);
}
static bool isWriteOrExclusive(Type type) {
return (type == Type::WRITE || type == Type::EXCLUSIVE);
static inline bool isWriteOrExclusive(Type type) {
return (isWrite(type) || isExclusive(type));
}
/// @brief get the transaction type from a string