mirror of https://gitee.com/bigwinds/arangodb
clean up write lockers a bit
This commit is contained in:
parent
af17235242
commit
3e7432ccd6
|
@ -1614,7 +1614,7 @@ int MMFilesEngine::insertCompactionBlocker(TRI_vocbase_t* vocbase, double ttl,
|
|||
CompactionBlocker blocker(TRI_NewTickServer(), TRI_microtime() + ttl);
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock);
|
||||
|
||||
auto it = _compactionBlockers.find(vocbase);
|
||||
|
||||
|
@ -1637,7 +1637,7 @@ int MMFilesEngine::extendCompactionBlocker(TRI_vocbase_t* vocbase, TRI_voc_tick_
|
|||
return TRI_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock);
|
||||
|
||||
auto it = _compactionBlockers.find(vocbase);
|
||||
|
||||
|
@ -1658,7 +1658,7 @@ int MMFilesEngine::extendCompactionBlocker(TRI_vocbase_t* vocbase, TRI_voc_tick_
|
|||
/// @brief remove an existing compaction blocker
|
||||
int MMFilesEngine::removeCompactionBlocker(TRI_vocbase_t* vocbase,
|
||||
TRI_voc_tick_t id) {
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock);
|
||||
|
||||
auto it = _compactionBlockers.find(vocbase);
|
||||
|
||||
|
@ -1686,7 +1686,7 @@ int MMFilesEngine::removeCompactionBlocker(TRI_vocbase_t* vocbase,
|
|||
|
||||
void MMFilesEngine::preventCompaction(TRI_vocbase_t* vocbase,
|
||||
std::function<void(TRI_vocbase_t*)> const& callback) {
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock, 5000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock);
|
||||
callback(vocbase);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ retry:
|
|||
|
||||
// reset failed connects
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
_applier->_state._failedConnects = 0;
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ retry:
|
|||
connectRetries++;
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
_applier->_state._failedConnects = connectRetries;
|
||||
_applier->_state._totalRequests++;
|
||||
_applier->_state._totalFailedConnects++;
|
||||
|
@ -163,7 +163,7 @@ retry:
|
|||
LOG_TOPIC(WARN, Logger::REPLICATION) << "requireFromPresent feature is not supported on master server < ArangoDB 2.7";
|
||||
}
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
res = getLocalState(errorMsg);
|
||||
|
||||
_applier->_state._failedConnects = 0;
|
||||
|
@ -199,7 +199,7 @@ retry:
|
|||
TRI_RemoveStateReplicationApplier(_vocbase);
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
|
||||
LOG_TOPIC(DEBUG, Logger::REPLICATION) << "stopped replication applier for database '" << _vocbase->name() << "' with lastProcessedContinuousTick: " << _applier->_state._lastProcessedContinuousTick << ", lastAppliedContinuousTick: " << _applier->_state._lastAppliedContinuousTick << ", safeResumeTick: " << _applier->_state._safeResumeTick;
|
||||
|
||||
|
@ -808,7 +808,7 @@ int ContinuousSyncer::applyLogMarker(VPackSlice const& slice,
|
|||
TRI_voc_tick_t newTick = static_cast<TRI_voc_tick_t>(
|
||||
StringUtils::uint64(tick.c_str(), tick.size()));
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
|
||||
if (newTick >= firstRegularTick &&
|
||||
newTick > _applier->_state._lastProcessedContinuousTick) {
|
||||
|
@ -960,7 +960,7 @@ int ContinuousSyncer::applyLog(SimpleHttpResult* response,
|
|||
}
|
||||
|
||||
// update tick value
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
|
||||
if (_applier->_state._lastProcessedContinuousTick >
|
||||
_applier->_state._lastAppliedContinuousTick) {
|
||||
|
@ -996,7 +996,7 @@ int ContinuousSyncer::runContinuousSync(std::string& errorMsg) {
|
|||
TRI_voc_tick_t safeResumeTick = 0;
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
|
||||
if (_useTick) {
|
||||
// use user-defined tick
|
||||
|
@ -1079,7 +1079,7 @@ int ContinuousSyncer::runContinuousSync(std::string& errorMsg) {
|
|||
connectRetries++;
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
|
||||
_applier->_state._failedConnects = connectRetries;
|
||||
_applier->_state._totalRequests++;
|
||||
|
@ -1094,7 +1094,7 @@ int ContinuousSyncer::runContinuousSync(std::string& errorMsg) {
|
|||
connectRetries = 0;
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
|
||||
_applier->_state._failedConnects = connectRetries;
|
||||
_applier->_state._totalRequests++;
|
||||
|
@ -1397,7 +1397,7 @@ int ContinuousSyncer::followMasterLog(std::string& errorMsg,
|
|||
if (found) {
|
||||
tick = StringUtils::uint64(header);
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
_applier->_state._lastAvailableContinuousTick = tick;
|
||||
}
|
||||
}
|
||||
|
@ -1426,7 +1426,7 @@ int ContinuousSyncer::followMasterLog(std::string& errorMsg,
|
|||
TRI_voc_tick_t lastAppliedTick;
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
lastAppliedTick = _applier->_state._lastAppliedContinuousTick;
|
||||
}
|
||||
|
||||
|
@ -1438,7 +1438,7 @@ int ContinuousSyncer::followMasterLog(std::string& errorMsg,
|
|||
if (processedMarkers > 0) {
|
||||
worked = true;
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
_applier->_state._totalEvents += processedMarkers;
|
||||
|
||||
if (_applier->_state._lastAppliedContinuousTick != lastAppliedTick) {
|
||||
|
@ -1451,7 +1451,7 @@ int ContinuousSyncer::followMasterLog(std::string& errorMsg,
|
|||
// write state at least once so the start tick gets saved
|
||||
_hasWrittenState = true;
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLocker, _applier->_statusLock);
|
||||
|
||||
_applier->_state._lastAppliedContinuousTick = firstRegularTick;
|
||||
_applier->_state._lastProcessedContinuousTick = firstRegularTick;
|
||||
|
|
|
@ -325,7 +325,7 @@ int RocksDBEngine::insertCompactionBlocker(TRI_vocbase_t* vocbase, double ttl,
|
|||
CompactionBlocker blocker(TRI_NewTickServer(), TRI_microtime() + ttl);
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock);
|
||||
|
||||
auto it = _compactionBlockers.find(vocbase);
|
||||
|
||||
|
@ -348,7 +348,7 @@ int RocksDBEngine::extendCompactionBlocker(TRI_vocbase_t* vocbase, TRI_voc_tick_
|
|||
return TRI_ERROR_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock);
|
||||
|
||||
auto it = _compactionBlockers.find(vocbase);
|
||||
|
||||
|
@ -369,7 +369,7 @@ int RocksDBEngine::extendCompactionBlocker(TRI_vocbase_t* vocbase, TRI_voc_tick_
|
|||
/// @brief remove an existing compaction blocker
|
||||
int RocksDBEngine::removeCompactionBlocker(TRI_vocbase_t* vocbase,
|
||||
TRI_voc_tick_t id) {
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock);
|
||||
|
||||
auto it = _compactionBlockers.find(vocbase);
|
||||
|
||||
|
@ -397,7 +397,7 @@ int RocksDBEngine::removeCompactionBlocker(TRI_vocbase_t* vocbase,
|
|||
|
||||
void RocksDBEngine::preventCompaction(TRI_vocbase_t* vocbase,
|
||||
std::function<void(TRI_vocbase_t*)> const& callback) {
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock, 5000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _compactionBlockersLock);
|
||||
callback(vocbase);
|
||||
}
|
||||
|
||||
|
|
|
@ -860,7 +860,7 @@ int LogicalCollection::rename(std::string const& newName) {
|
|||
// Otherwise caching is destroyed.
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator()); // NOT YET IMPLEMENTED
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(locker, _lock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, _lock);
|
||||
|
||||
// Check for illeagal states.
|
||||
switch (_status) {
|
||||
|
|
|
@ -193,7 +193,7 @@ bool TRI_vocbase_t::unregisterCollection(arangodb::LogicalCollection* collection
|
|||
bool TRI_vocbase_t::UnloadCollectionCallback(LogicalCollection* collection) {
|
||||
TRI_ASSERT(collection != nullptr);
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(locker, collection->_lock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, collection->_lock);
|
||||
|
||||
if (collection->status() != TRI_VOC_COL_STATUS_UNLOADING) {
|
||||
return false;
|
||||
|
@ -235,7 +235,7 @@ bool TRI_vocbase_t::DropCollectionCallback(arangodb::LogicalCollection* collecti
|
|||
std::string const name(collection->name());
|
||||
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(statusLock, collection->_lock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(statusLock, collection->_lock);
|
||||
|
||||
if (collection->status() != TRI_VOC_COL_STATUS_DELETED) {
|
||||
LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "someone resurrected the collection '" << name << "'";
|
||||
|
@ -288,7 +288,7 @@ arangodb::LogicalCollection* TRI_vocbase_t::createCollectionWorker(
|
|||
}
|
||||
|
||||
arangodb::LogicalCollection* collection =
|
||||
registerCollection(ConditionalWriteLocker<ReadWriteLock>::DoNotLock(), parameters);
|
||||
registerCollection(basics::ConditionalLocking::DoNotLock, parameters);
|
||||
|
||||
// Register collection cannot return a nullptr.
|
||||
// If it would return a nullptr it should have thrown instead
|
||||
|
@ -351,7 +351,7 @@ int TRI_vocbase_t::loadCollection(arangodb::LogicalCollection* collection,
|
|||
// write lock
|
||||
// .............................................................................
|
||||
|
||||
WRITE_LOCKER_EVENTUAL(locker, collection->_lock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, collection->_lock);
|
||||
|
||||
// someone else loaded the collection, release the WRITE lock and try again
|
||||
if (collection->status() == TRI_VOC_COL_STATUS_LOADED) {
|
||||
|
@ -451,7 +451,7 @@ int TRI_vocbase_t::loadCollection(arangodb::LogicalCollection* collection,
|
|||
}
|
||||
|
||||
// lock again to adjust the status
|
||||
locker.lockEventual(1000);
|
||||
locker.lockEventual();
|
||||
|
||||
// no one else must have changed the status
|
||||
TRI_ASSERT(collection->status() == TRI_VOC_COL_STATUS_LOADING);
|
||||
|
@ -478,8 +478,8 @@ int TRI_vocbase_t::dropCollectionWorker(arangodb::LogicalCollection* collection,
|
|||
std::string const colName(collection->name());
|
||||
|
||||
// do not acquire these locks instantly
|
||||
CONDITIONAL_WRITE_LOCKER(writeLocker, _collectionsLock, false);
|
||||
CONDITIONAL_WRITE_LOCKER(locker, collection->_lock, false);
|
||||
CONDITIONAL_WRITE_LOCKER(writeLocker, _collectionsLock, basics::ConditionalLocking::DoNotLock);
|
||||
CONDITIONAL_WRITE_LOCKER(locker, collection->_lock, basics::ConditionalLocking::DoNotLock);
|
||||
|
||||
while (true) {
|
||||
TRI_ASSERT(!writeLocker.isLocked());
|
||||
|
@ -684,7 +684,7 @@ std::shared_ptr<VPackBuilder> TRI_vocbase_t::inventory(TRI_voc_tick_t maxTick,
|
|||
std::vector<arangodb::LogicalCollection*> collections;
|
||||
|
||||
// cycle on write-lock
|
||||
WRITE_LOCKER_EVENTUAL(writeLock, _inventoryLock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(writeLock, _inventoryLock);
|
||||
|
||||
// copy collection pointers into vector so we can work with the copy without
|
||||
// the global lock
|
||||
|
@ -844,7 +844,7 @@ arangodb::LogicalCollection* TRI_vocbase_t::createCollection(
|
|||
int TRI_vocbase_t::unloadCollection(arangodb::LogicalCollection* collection, bool force) {
|
||||
TRI_voc_cid_t cid = collection->cid();
|
||||
{
|
||||
WRITE_LOCKER_EVENTUAL(locker, collection->_lock, 1000);
|
||||
WRITE_LOCKER_EVENTUAL(locker, collection->_lock);
|
||||
|
||||
// cannot unload a corrupted collection
|
||||
if (collection->status() == TRI_VOC_COL_STATUS_CORRUPTED) {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
||||
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef ARANGODB_BASICS_LOCKING_H
|
||||
#define ARANGODB_BASICS_LOCKING_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
|
||||
namespace arangodb {
|
||||
namespace basics {
|
||||
|
||||
enum class LockerType {
|
||||
BLOCKING, // always lock, blocking if the lock cannot be acquired instantly
|
||||
EVENTUAL, // always lock, sleeping while the lock is not acquired
|
||||
TRY // try to acquire the lock and give up instantly if it cannot be acquired
|
||||
};
|
||||
|
||||
namespace ConditionalLocking {
|
||||
static constexpr bool DoLock = true;
|
||||
static constexpr bool DoNotLock = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -326,9 +326,6 @@ class ConditionalReadLocker {
|
|||
return false;
|
||||
}
|
||||
|
||||
static constexpr bool DoLock() { return true; }
|
||||
static constexpr bool DoNotLock() { return false; }
|
||||
|
||||
private:
|
||||
/// @brief the read-write lock
|
||||
LockType* _readWriteLock;
|
||||
|
|
|
@ -26,39 +26,30 @@
|
|||
#define ARANGODB_BASICS_WRITE_LOCKER_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/Locking.h"
|
||||
#include "Basics/ReadWriteLock.h"
|
||||
|
||||
#ifdef TRI_SHOW_LOCK_TIME
|
||||
#include "Logger/Logger.h"
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief construct locker with file and line information
|
||||
///
|
||||
/// Ones needs to use macros twice to get a unique variable based on the line
|
||||
/// number.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef TRI_SHOW_LOCK_TIME
|
||||
|
||||
#define WRITE_LOCKER(obj, lock) \
|
||||
arangodb::basics::WriteLocker<std::decay<decltype (lock)>::type> obj(&lock, __FILE__, __LINE__)
|
||||
arangodb::basics::WriteLocker<std::decay<decltype (lock)>::type> obj(&lock, arangodb::basics::LockerType::BLOCKING, true, __FILE__, __LINE__)
|
||||
|
||||
#define WRITE_LOCKER_EVENTUAL(obj, lock, t) \
|
||||
arangodb::basics::WriteLocker<std::decay<decltype (lock)>::type> obj(&lock, t, __FILE__, __LINE__)
|
||||
#define WRITE_LOCKER_EVENTUAL(obj, lock) \
|
||||
arangodb::basics::WriteLocker<std::decay<decltype (lock)>::type> obj(&lock, arangodb::basics::LockerType::EVENTUAL, true, __FILE__, __LINE__)
|
||||
|
||||
#else
|
||||
#define TRY_WRITE_LOCKER(obj, lock) \
|
||||
arangodb::basics::WriteLocker<std::decay<decltype (lock)>::type> obj(&lock, arangodb::basics::LockerType::TRY, true, __FILE__, __LINE__)
|
||||
|
||||
#define WRITE_LOCKER(obj, lock) arangodb::basics::WriteLocker<std::decay<decltype (lock)>::type> obj(&lock)
|
||||
|
||||
#define WRITE_LOCKER_EVENTUAL(obj, lock, t) \
|
||||
arangodb::basics::WriteLocker<std::decay<decltype (lock)>::type> obj(&lock, t)
|
||||
|
||||
#endif
|
||||
|
||||
#define TRY_WRITE_LOCKER(obj, lock) arangodb::basics::TryWriteLocker<std::decay<decltype (lock)>::type> obj(&lock)
|
||||
|
||||
#define CONDITIONAL_WRITE_LOCKER(obj, lock, condition) arangodb::basics::ConditionalWriteLocker<std::decay<decltype (lock)>::type> obj(&lock, (condition))
|
||||
#define CONDITIONAL_WRITE_LOCKER(obj, lock, condition) \
|
||||
arangodb::basics::WriteLocker<std::decay<decltype (lock)>::type> obj(&lock, arangodb::basics::LockerType::BLOCKING, (condition), __FILE__, __LINE__)
|
||||
|
||||
namespace arangodb {
|
||||
namespace basics {
|
||||
|
@ -72,46 +63,40 @@ class WriteLocker {
|
|||
WriteLocker& operator=(WriteLocker const&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
/// @brief aquires a write-lock
|
||||
/// The constructors acquire a write lock, the destructor unlocks the lock.
|
||||
WriteLocker(LockType* readWriteLock, LockerType type, bool condition, char const* file, int line)
|
||||
: _readWriteLock(readWriteLock), _file(file), _line(line),
|
||||
#ifdef TRI_SHOW_LOCK_TIME
|
||||
|
||||
/// @brief aquires a write-lock
|
||||
/// The constructors acquire a write lock, the destructor unlocks the lock.
|
||||
WriteLocker(LockType* readWriteLock, char const* file, int line)
|
||||
: _readWriteLock(readWriteLock), _file(file), _line(line), _isLocked(false) {
|
||||
double t = TRI_microtime();
|
||||
lock();
|
||||
_time = TRI_microtime() - t;
|
||||
}
|
||||
|
||||
/// @brief aquires a write-lock, with periodic sleeps while not acquired
|
||||
/// sleep time is specified in nanoseconds
|
||||
WriteLocker(LockType* readWriteLock, uint64_t sleepTime,
|
||||
char const* file, int line)
|
||||
: _readWriteLock(readWriteLock), _file(file), _line(line), _isLocked(false) {
|
||||
double t = TRI_microtime();
|
||||
lockEventual(sleepTime);
|
||||
_time = TRI_microtime() - t;
|
||||
}
|
||||
|
||||
_isLocked(false), _time(0.0) {
|
||||
#else
|
||||
|
||||
/// @brief aquires a write-lock
|
||||
/// The constructors acquire a write lock, the destructor unlocks the lock.
|
||||
explicit WriteLocker(LockType* readWriteLock)
|
||||
: _readWriteLock(readWriteLock), _isLocked(false) {
|
||||
lock();
|
||||
}
|
||||
|
||||
/// @brief aquires a write-lock, with periodic sleeps while not acquired
|
||||
/// sleep time is specified in nanoseconds
|
||||
WriteLocker(LockType* readWriteLock, uint64_t sleepTime)
|
||||
: _readWriteLock(readWriteLock), _isLocked(false) {
|
||||
lockEventual(sleepTime);
|
||||
_isLocked = true;
|
||||
}
|
||||
|
||||
_isLocked(false) {
|
||||
#endif
|
||||
|
||||
#ifdef TRI_SHOW_LOCK_TIME
|
||||
// fetch current time
|
||||
double t = TRI_microtime();
|
||||
#endif
|
||||
|
||||
if (condition) {
|
||||
if (type == LockerType::BLOCKING) {
|
||||
lock();
|
||||
TRI_ASSERT(_isLocked);
|
||||
} else if (type == LockerType::EVENTUAL) {
|
||||
lockEventual();
|
||||
TRI_ASSERT(_isLocked);
|
||||
} else if (type == LockerType::TRY) {
|
||||
_isLocked = tryLock();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TRI_SHOW_LOCK_TIME
|
||||
// add elapsed time to time tracker
|
||||
_time = TRI_microtime() - t;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief releases the write-lock
|
||||
~WriteLocker() {
|
||||
if (_isLocked) {
|
||||
|
@ -120,28 +105,33 @@ class WriteLocker {
|
|||
|
||||
#ifdef TRI_SHOW_LOCK_TIME
|
||||
if (_time > TRI_SHOW_LOCK_THRESHOLD) {
|
||||
LOG_TOPIC(WARN, arangodb::Logger::FIXME) << "WriteLocker " << _file << ":" << _line << " took " << _time << " s";
|
||||
LOG_TOPIC(WARN, arangodb::Logger::PERFORMANCE) << "WriteLocker " << _file << ":" << _line << " took " << _time << " s";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief whether or not we acquired the lock
|
||||
bool isLocked() const { return _isLocked; }
|
||||
bool isLocked() const noexcept { return _isLocked; }
|
||||
|
||||
/// @brief eventually acquire the write lock
|
||||
void lockEventual(uint64_t sleepTime) {
|
||||
void lockEventual() {
|
||||
while (!_readWriteLock->tryWriteLock()) {
|
||||
#ifdef _WIN32
|
||||
usleep((unsigned long)sleepTime);
|
||||
#else
|
||||
usleep((useconds_t)sleepTime);
|
||||
#endif
|
||||
std::this_thread::yield();
|
||||
}
|
||||
_isLocked = true;
|
||||
}
|
||||
|
||||
bool tryLock() {
|
||||
TRI_ASSERT(!_isLocked);
|
||||
if (_readWriteLock->tryWriteLock()) {
|
||||
_isLocked = true;
|
||||
}
|
||||
return _isLocked;
|
||||
}
|
||||
|
||||
/// @brief acquire the write lock, blocking
|
||||
void lock() {
|
||||
TRI_ASSERT(!_isLocked);
|
||||
_readWriteLock->writeLock();
|
||||
_isLocked = true;
|
||||
}
|
||||
|
@ -169,172 +159,19 @@ class WriteLocker {
|
|||
/// @brief the read-write lock
|
||||
LockType* _readWriteLock;
|
||||
|
||||
#ifdef TRI_SHOW_LOCK_TIME
|
||||
|
||||
/// @brief file
|
||||
char const* _file;
|
||||
|
||||
/// @brief line number
|
||||
int _line;
|
||||
|
||||
/// @brief lock time
|
||||
double _time;
|
||||
|
||||
#endif
|
||||
|
||||
/// @brief whether or not the lock was acquired
|
||||
bool _isLocked;
|
||||
};
|
||||
|
||||
template<class LockType>
|
||||
class TryWriteLocker {
|
||||
TryWriteLocker(TryWriteLocker const&) = delete;
|
||||
TryWriteLocker& operator=(TryWriteLocker const&) = delete;
|
||||
|
||||
public:
|
||||
/// @brief tries to acquire a write-lock
|
||||
/// The constructor tries to aquire a write lock, the destructors unlocks the
|
||||
/// lock if we acquired it in the constructor
|
||||
explicit TryWriteLocker(LockType* readWriteLock)
|
||||
: _readWriteLock(readWriteLock), _isLocked(false) {
|
||||
_isLocked = _readWriteLock->tryWriteLock();
|
||||
}
|
||||
|
||||
/// @brief releases the write-lock
|
||||
~TryWriteLocker() {
|
||||
if (_isLocked) {
|
||||
_readWriteLock->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief whether or not we acquired the lock
|
||||
bool isLocked() const { return _isLocked; }
|
||||
|
||||
/// @brief eventually acquire the write lock
|
||||
void lockEventual(uint64_t sleepTime) {
|
||||
while (!_readWriteLock->tryWriteLock()) {
|
||||
#ifdef _WIN32
|
||||
usleep((unsigned long)sleepTime);
|
||||
#else
|
||||
usleep((useconds_t)sleepTime);
|
||||
#ifdef TRI_SHOW_LOCK_TIME
|
||||
/// @brief lock time
|
||||
double _time;
|
||||
#endif
|
||||
}
|
||||
_isLocked = true;
|
||||
}
|
||||
|
||||
/// @brief acquire the write lock, blocking
|
||||
void lock() {
|
||||
_readWriteLock->writeLock();
|
||||
_isLocked = true;
|
||||
}
|
||||
|
||||
/// @brief unlocks the read-write lock
|
||||
bool unlock() {
|
||||
if (_isLocked) {
|
||||
_readWriteLock->unlock();
|
||||
_isLocked = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief steals the lock, but does not unlock it
|
||||
bool steal() {
|
||||
if (_isLocked) {
|
||||
_isLocked = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief the read-write lock
|
||||
LockType* _readWriteLock;
|
||||
|
||||
/// @brief whether or not we acquired the lock
|
||||
bool _isLocked;
|
||||
};
|
||||
|
||||
template<class LockType>
|
||||
class ConditionalWriteLocker {
|
||||
ConditionalWriteLocker(ConditionalWriteLocker const&) = delete;
|
||||
ConditionalWriteLocker& operator=(ConditionalWriteLocker const&) = delete;
|
||||
|
||||
public:
|
||||
/// @brief acquire a write-lock
|
||||
/// The constructor tries to write-lock the lock, the destructor unlocks the
|
||||
/// lock if it was acquired in the constructor
|
||||
ConditionalWriteLocker(LockType* readWriteLock, bool condition)
|
||||
: _readWriteLock(readWriteLock), _isLocked(false) {
|
||||
if (condition) {
|
||||
_readWriteLock->writeLock();
|
||||
_isLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief releases the write-lock
|
||||
~ConditionalWriteLocker() {
|
||||
if (_isLocked) {
|
||||
_readWriteLock->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief whether or not we acquired the lock
|
||||
bool isLocked() const { return _isLocked; }
|
||||
|
||||
/// @brief eventually acquire the write lock
|
||||
void lockEventual(uint64_t sleepTime) {
|
||||
while (!_readWriteLock->tryWriteLock()) {
|
||||
#ifdef _WIN32
|
||||
usleep((unsigned long)sleepTime);
|
||||
#else
|
||||
usleep((useconds_t)sleepTime);
|
||||
#endif
|
||||
}
|
||||
_isLocked = true;
|
||||
}
|
||||
|
||||
bool tryLock() {
|
||||
if (!_isLocked && _readWriteLock->tryWriteLock()) {
|
||||
_isLocked = true;
|
||||
}
|
||||
return _isLocked;
|
||||
}
|
||||
|
||||
/// @brief acquire the write lock, blocking
|
||||
void lock() {
|
||||
_readWriteLock->writeLock();
|
||||
_isLocked = true;
|
||||
}
|
||||
|
||||
/// @brief unlocks the read-write lock
|
||||
bool unlock() {
|
||||
if (_isLocked) {
|
||||
_readWriteLock->unlock();
|
||||
_isLocked = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief steals the lock, but does not unlock it
|
||||
bool steal() {
|
||||
if (_isLocked) {
|
||||
_isLocked = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr bool DoLock() { return true; }
|
||||
static constexpr bool DoNotLock() { return false; }
|
||||
|
||||
private:
|
||||
/// @brief the read-write lock
|
||||
LockType* _readWriteLock;
|
||||
|
||||
/// @brief whether or not we acquired the lock
|
||||
bool _isLocked;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue