diff options
Diffstat (limited to 'util/concurrency')
-rw-r--r-- | util/concurrency/rwlock.h | 2 | ||||
-rw-r--r-- | util/concurrency/spin_lock.cpp | 31 | ||||
-rw-r--r-- | util/concurrency/value.h | 69 | ||||
-rw-r--r-- | util/concurrency/vars.cpp | 2 |
4 files changed, 94 insertions, 10 deletions
diff --git a/util/concurrency/rwlock.h b/util/concurrency/rwlock.h index d8a11ea..ed5bda0 100644 --- a/util/concurrency/rwlock.h +++ b/util/concurrency/rwlock.h @@ -203,7 +203,7 @@ namespace mongo { DEV mutexDebugger.entering(_name); } void unlock() { - mutexDebugger.leaving(_name); + DEV mutexDebugger.leaving(_name); check( pthread_rwlock_unlock( &_lock ) ); } diff --git a/util/concurrency/spin_lock.cpp b/util/concurrency/spin_lock.cpp index 1811f15..52bd218 100644 --- a/util/concurrency/spin_lock.cpp +++ b/util/concurrency/spin_lock.cpp @@ -45,7 +45,36 @@ namespace mongo { #if defined(_WIN32) EnterCriticalSection(&_cs); #elif defined(__USE_XOPEN2K) - pthread_spin_lock( &_lock ); + + /** + * this is designed to perform close to the default spin lock + * the reason for the mild insanity is to prevent horrible performance + * when contention spikes + * it allows spinlocks to be used in many more places + * which is good because even with this change they are about 8x faster on linux + */ + + if ( pthread_spin_trylock( &_lock ) == 0 ) + return; + + for ( int i=0; i<1000; i++ ) + if ( pthread_spin_trylock( &_lock ) == 0 ) + return; + + for ( int i=0; i<1000; i++ ) { + if ( pthread_spin_trylock( &_lock ) == 0 ) + return; + pthread_yield(); + } + + struct timespec t; + t.tv_sec = 0; + t.tv_nsec = 5000000; + + while ( pthread_spin_trylock( &_lock ) != 0 ) { + nanosleep(&t, NULL); + } + #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) // fast path if (!_locked && !__sync_lock_test_and_set(&_locked, true)) { diff --git a/util/concurrency/value.h b/util/concurrency/value.h index c66977b..897fa95 100644 --- a/util/concurrency/value.h +++ b/util/concurrency/value.h @@ -21,6 +21,7 @@ #pragma once #include "mutex.h" +#include "spin_lock.h" namespace mongo { @@ -36,7 +37,7 @@ namespace mongo { builds at runtime. */ template <typename T, mutex& BY> - class Guarded { + class Guarded : boost::noncopyable { T _val; public: T& ref(const scoped_lock& lk) { @@ -47,29 +48,85 @@ namespace mongo { class DiagStr { string _s; - static mutex m; + mutable SpinLock m; public: DiagStr(const DiagStr& r) : _s(r.get()) { } DiagStr() { } bool empty() const { - mutex::scoped_lock lk(m); + scoped_spinlock lk(m); return _s.empty(); } string get() const { - mutex::scoped_lock lk(m); + scoped_spinlock lk(m); return _s; } void set(const char *s) { - mutex::scoped_lock lk(m); + scoped_spinlock lk(m); _s = s; } void set(const string& s) { - mutex::scoped_lock lk(m); + scoped_spinlock lk(m); _s = s; } operator string() const { return get(); } void operator=(const string& s) { set(s); } + void operator=(const DiagStr& rhs) { + scoped_spinlock lk(m); + _s = rhs.get(); + } }; +#if 0 // not including in 2.0 + + /** Thread safe map. + Be careful not to use this too much or it could make things slow; + if not a hot code path no problem. + + Examples: + + mapsf<int,int> mp; + + int x = mp.get(); + + map<int,int> two; + mp.swap(two); + + { + mapsf<int,int>::ref r(mp); + r[9] = 1; + map<int,int>::iterator i = r.r.begin(); + } + + */ + template< class K, class V > + struct mapsf : boost::noncopyable { + SimpleMutex m; + map<K,V> val; + friend struct ref; + public: + mapsf() : m("mapsf") { } + void swap(map<K,V>& rhs) { + SimpleMutex::scoped_lock lk(m); + val.swap(rhs); + } + // safe as we pass by value: + V get(K k) { + SimpleMutex::scoped_lock lk(m); + map<K,V>::iterator i = val.find(k); + if( i == val.end() ) + return K(); + return i->second; + } + // think about deadlocks when using ref. the other methods + // above will always be safe as they are "leaf" operations. + struct ref { + SimpleMutex::scoped_lock lk; + public: + map<K,V> const &r; + ref(mapsf<K,V> &m) : lk(m.m), r(m.val) { } + V& operator[](const K& k) { return r[k]; } + }; + }; +#endif } diff --git a/util/concurrency/vars.cpp b/util/concurrency/vars.cpp index 213e576..b561ccc 100644 --- a/util/concurrency/vars.cpp +++ b/util/concurrency/vars.cpp @@ -22,8 +22,6 @@ namespace mongo { - mutex DiagStr::m("diags"); - // intentional leak. otherwise destructor orders can be problematic at termination. MutexDebugger &mutexDebugger = *(new MutexDebugger()); |