00001 // @file concurrency.h 00002 00003 /* 00004 * Copyright (C) 2010 10gen Inc. 00005 * 00006 * This program is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU Affero General Public License, version 3, 00008 * as published by the Free Software Foundation. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU Affero General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Affero General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 /*mongod concurrency rules & notes will be placed here. 00020 00021 Mutex heirarchy (1 = "leaf") 00022 name level 00023 Logstream::mutex 1 00024 ClientCursor::ccmutex 2 00025 dblock 3 00026 00027 End func name with _inlock to indicate "caller must lock before calling". 00028 */ 00029 00030 #pragma once 00031 00032 #include "../util/concurrency/rwlock.h" 00033 #include "../util/mmap.h" 00034 #include "../util/time_support.h" 00035 00036 namespace mongo { 00037 00038 string sayClientState(); 00039 bool haveClient(); 00040 00041 class Client; 00042 Client* curopWaitingForLock( int type ); 00043 void curopGotLock(Client*); 00044 00045 /* mutex time stats */ 00046 class MutexInfo { 00047 unsigned long long enter, timeLocked; // microseconds 00048 int locked; 00049 unsigned long long start; // last as we touch this least often 00050 00051 public: 00052 MutexInfo() : timeLocked(0) , locked(0) { 00053 start = curTimeMicros64(); 00054 } 00055 void entered() { 00056 if ( locked == 0 ) 00057 enter = curTimeMicros64(); 00058 locked++; 00059 assert( locked >= 1 ); 00060 } 00061 void leaving() { 00062 locked--; 00063 assert( locked >= 0 ); 00064 if ( locked == 0 ) 00065 timeLocked += curTimeMicros64() - enter; 00066 } 00067 int isLocked() const { return locked; } 00068 void getTimingInfo(unsigned long long &s, unsigned long long &tl) const { 00069 s = start; 00070 tl = timeLocked; 00071 } 00072 unsigned long long getTimeLocked() const { return timeLocked; } 00073 }; 00074 00075 } 00076 00077 #include "mongomutex.h" 00078 00079 namespace mongo { 00080 00081 inline void dbunlocking_write() { } 00082 inline void dbunlocking_read() { } 00083 00084 struct writelock { 00085 writelock() { dbMutex.lock(); } 00086 writelock(const string& ns) { dbMutex.lock(); } 00087 ~writelock() { 00088 DESTRUCTOR_GUARD( 00089 dbunlocking_write(); 00090 dbMutex.unlock(); 00091 ); 00092 } 00093 }; 00094 00095 struct readlock { 00096 readlock(const string& ns) { 00097 dbMutex.lock_shared(); 00098 } 00099 readlock() { dbMutex.lock_shared(); } 00100 ~readlock() { 00101 DESTRUCTOR_GUARD( 00102 dbunlocking_read(); 00103 dbMutex.unlock_shared(); 00104 ); 00105 } 00106 }; 00107 00108 struct readlocktry { 00109 readlocktry( const string&ns , int tryms ) { 00110 _got = dbMutex.lock_shared_try( tryms ); 00111 } 00112 ~readlocktry() { 00113 if ( _got ) { 00114 dbunlocking_read(); 00115 dbMutex.unlock_shared(); 00116 } 00117 } 00118 bool got() const { return _got; } 00119 private: 00120 bool _got; 00121 }; 00122 00123 struct writelocktry { 00124 writelocktry( const string&ns , int tryms ) { 00125 _got = dbMutex.lock_try( tryms ); 00126 } 00127 ~writelocktry() { 00128 if ( _got ) { 00129 dbunlocking_read(); 00130 dbMutex.unlock(); 00131 } 00132 } 00133 bool got() const { return _got; } 00134 private: 00135 bool _got; 00136 }; 00137 00138 struct readlocktryassert : public readlocktry { 00139 readlocktryassert(const string& ns, int tryms) : 00140 readlocktry(ns,tryms) { 00141 uassert(13142, "timeout getting readlock", got()); 00142 } 00143 }; 00144 00148 struct atleastreadlock { 00149 atleastreadlock( const string& ns ) { 00150 _prev = dbMutex.getState(); 00151 if ( _prev == 0 ) 00152 dbMutex.lock_shared(); 00153 } 00154 ~atleastreadlock() { 00155 if ( _prev == 0 ) 00156 dbMutex.unlock_shared(); 00157 } 00158 private: 00159 int _prev; 00160 }; 00161 00162 /* parameterized choice of read or write locking 00163 use readlock and writelock instead of this when statically known which you want 00164 */ 00165 class mongolock { 00166 bool _writelock; 00167 public: 00168 mongolock(bool write) : _writelock(write) { 00169 if( _writelock ) { 00170 dbMutex.lock(); 00171 } 00172 else 00173 dbMutex.lock_shared(); 00174 } 00175 ~mongolock() { 00176 DESTRUCTOR_GUARD( 00177 if( _writelock ) { 00178 dbunlocking_write(); 00179 dbMutex.unlock(); 00180 } 00181 else { 00182 dbunlocking_read(); 00183 dbMutex.unlock_shared(); 00184 } 00185 ); 00186 } 00187 /* this unlocks, does NOT upgrade. that works for our current usage */ 00188 void releaseAndWriteLock(); 00189 }; 00190 00191 /* deprecated - use writelock and readlock instead */ 00192 struct dblock : public writelock { 00193 dblock() : writelock("") { } 00194 }; 00195 00196 // eliminate this - we should just type "dbMutex.assertWriteLocked();" instead 00197 inline void assertInWriteLock() { dbMutex.assertWriteLocked(); } 00198 00199 }