mirror of https://gitee.com/bigwinds/arangodb
honor exclusive locks
This commit is contained in:
parent
9db917bd77
commit
861291da16
|
@ -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());
|
||||
|
|
|
@ -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 --
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue