diff options
Diffstat (limited to 'src/mongo/db/d_concurrency.h')
| -rw-r--r-- | src/mongo/db/d_concurrency.h | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/src/mongo/db/d_concurrency.h b/src/mongo/db/d_concurrency.h new file mode 100644 index 00000000000..b4588145088 --- /dev/null +++ b/src/mongo/db/d_concurrency.h @@ -0,0 +1,250 @@ +// @file d_concurrency.h + +/** +* Copyright (C) 2008 10gen Inc. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License, version 3, +* as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +// only used by mongod, thus the name ('d') +// (also used by dbtests test binary, which is running mongod test code) + +#pragma once + +#include "mongo/bson/stringdata.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/lockstat.h" +#include "mongo/util/concurrency/mutex.h" +#include "mongo/util/concurrency/rwlock.h" + +namespace mongo { + + class WrapperForRWLock; + class LockState; + + class Lock : boost::noncopyable { + public: + enum Nestable { notnestable=0, local, admin }; + static int isLocked(); // true if *anything* is locked (by us) + static int isReadLocked(); // r or R + static int somethingWriteLocked(); // w or W + static bool isW(); // W + static bool isR(); + static bool isRW(); // R or W. i.e., we are write-exclusive + static bool nested(); + static bool isWriteLocked(const StringData& ns); + static bool atLeastReadLocked(const StringData& ns); // true if this db is locked + static void assertAtLeastReadLocked(const StringData& ns); + static void assertWriteLocked(const StringData& ns); + + static bool dbLevelLockingEnabled(); + + static LockStat* globalLockStat(); + static LockStat* nestableLockStat( Nestable db ); + + class ScopedLock; + + // note: avoid TempRelease when possible. not a good thing. + struct TempRelease { + TempRelease(); + ~TempRelease(); + const bool cant; // true if couldn't because of recursive locking + ScopedLock *scopedLk; + }; + + /** turn on "parallel batch writer mode". blocks all other threads. this mode is off + by default. note only one thread creates a ParallelBatchWriterMode object; the rest just + call iAmABatchParticipant(). Note that this lock is not released on a temprelease, just + the normal lock things below. + */ + class ParallelBatchWriterMode : boost::noncopyable { + RWLockRecursive::Exclusive _lk; + public: + ParallelBatchWriterMode() : _lk(_batchLock) {} + static void iAmABatchParticipant(); + static RWLockRecursive &_batchLock; + }; + + private: + class ParallelBatchWriterSupport : boost::noncopyable { + public: + ParallelBatchWriterSupport(); + + private: + void tempRelease(); + void relock(); + + scoped_ptr<RWLockRecursive::Shared> _lk; + friend class ScopedLock; + }; + + public: + class ScopedLock : boost::noncopyable { + public: + virtual ~ScopedLock(); + + /** @return micros since we started acquiring */ + long long acquireFinished( LockStat* stat ); + + // Accrue elapsed lock time since last we called reset + void recordTime(); + // Start recording a new period, starting now() + void resetTime(); + + protected: + explicit ScopedLock( char type ); + + private: + friend struct TempRelease; + void tempRelease(); // TempRelease class calls these + void relock(); + + protected: + virtual void _tempRelease() = 0; + virtual void _relock() = 0; + + private: + ParallelBatchWriterSupport _pbws_lk; + + void _recordTime( long long micros ); + Timer _timer; + char _type; // 'r','w','R','W' + LockStat* _stat; // the stat for the relevant lock to increment when we're done + }; + + // note that for these classes recursive locking is ok if the recursive locking "makes sense" + // i.e. you could grab globalread after globalwrite. + + class GlobalWrite : public ScopedLock { + bool noop; + protected: + void _tempRelease(); + void _relock(); + public: + // stopGreed is removed and does NOT work + // timeoutms is only for writelocktry -- deprecated -- do not use + GlobalWrite(bool stopGreed = false, int timeoutms = -1 ); + virtual ~GlobalWrite(); + void downgrade(); // W -> R + void upgrade(); // caution see notes + }; + class GlobalRead : public ScopedLock { // recursive is ok + public: + bool noop; + protected: + void _tempRelease(); + void _relock(); + public: + // timeoutms is only for readlocktry -- deprecated -- do not use + GlobalRead( int timeoutms = -1 ); + virtual ~GlobalRead(); + }; + + // lock this database. do not shared_lock globally first, that is handledin herein. + class DBWrite : public ScopedLock { + /** + * flow + * 1) lockDB + * a) lockTop + * b) lockNestable or lockOther + * 2) unlockDB + */ + + void lockTop(LockState&); + void lockNestable(Nestable db); + void lockOther(const string& db); + void lockDB(const string& ns); + void unlockDB(); + + protected: + void _tempRelease(); + void _relock(); + + public: + DBWrite(const StringData& dbOrNs); + virtual ~DBWrite(); + + class UpgradeToExclusive : private boost::noncopyable { + public: + UpgradeToExclusive(); + ~UpgradeToExclusive(); + + bool gotUpgrade() const { return _gotUpgrade; } + private: + bool _gotUpgrade; + }; + + private: + bool _locked_w; + bool _locked_W; + WrapperForRWLock *_weLocked; + const string _what; + bool _nested; + }; + + // lock this database for reading. do not shared_lock globally first, that is handledin herein. + class DBRead : public ScopedLock { + void lockTop(LockState&); + void lockNestable(Nestable db); + void lockOther(const string& db); + void lockDB(const string& ns); + void unlockDB(); + + protected: + void _tempRelease(); + void _relock(); + + public: + DBRead(const StringData& dbOrNs); + virtual ~DBRead(); + + private: + bool _locked_r; + WrapperForRWLock *_weLocked; + string _what; + bool _nested; + + }; + + }; + + class readlocktry : boost::noncopyable { + bool _got; + scoped_ptr<Lock::GlobalRead> _dbrlock; + public: + readlocktry( int tryms ); + ~readlocktry(); + bool got() const { return _got; } + }; + + class writelocktry : boost::noncopyable { + bool _got; + scoped_ptr<Lock::GlobalWrite> _dbwlock; + public: + writelocktry( int tryms ); + ~writelocktry(); + bool got() const { return _got; } + }; + + /** a mutex, but reported in curop() - thus a "high level" (HL) one + some overhead so we don't use this for everything. the externalobjsort mutex + uses this, as it can be held for eons. implementation still needed. */ + class HLMutex : public SimpleMutex { + LockStat ls; + public: + HLMutex(const char *name); + }; + + +} |
