diff --git a/db/concurrency.h b/db/concurrency.h index bf6bc44d5f1..daf09b6cb18 100644 --- a/db/concurrency.h +++ b/db/concurrency.h @@ -59,6 +59,11 @@ namespace mongo { MutexInfo _minfo; boost::shared_mutex _m; ThreadLocalValue _state; + + /* we use a separate TLS value for releasedEarly - that is ok as + our normal/common code path, we never even touch it. + */ + ThreadLocalValue _releasedEarly; public: /** * @return @@ -67,9 +72,13 @@ namespace mongo { * < 0 read lock */ int getState(){ return _state.get(); } - void assertWriteLocked() { assert( _state.get() > 0 ); } + void assertWriteLocked() { + assert( getState() > 0 ); + DEV assert( !_releasedEarly.get() ); + } bool atLeastReadLocked() { return _state.get() != 0; } void assertAtLeastReadLocked() { assert(atLeastReadLocked()); } + void lock() { DEV cout << "LOCK" << endl; int s = _state.get(); @@ -89,11 +98,28 @@ namespace mongo { _state.set(s-1); return; } - assert( s == 1 ); + if( s != 1 ) { + if( _releasedEarly.get() ) { + _releasedEarly.set(false); + return; + } + assert(false); // attempt to unlock when wasn't in a write lock + } _state.set(0); _minfo.leaving(); _m.unlock(); } + + /* unlock (write lock), and when unlock() is called later, + be smart then and don't unlock it again. + */ + void releaseEarly() { + assert( getState() == 1 ); // must not be recursive + assert( !_releasedEarly.get() ); + _releasedEarly.set(true); + unlock(); + } + void lock_shared() { DEV cout << " LOCKSHARED" << endl; int s = _state.get(); @@ -135,6 +161,7 @@ namespace mongo { class MongoMutex { MutexInfo _minfo; boost::recursive_mutex m; + ThreadLocalValue _releasedEarly; public: MongoMutex() { } void lock() { @@ -146,7 +173,14 @@ namespace mongo { _minfo.entered(); } - void unlock() { + void releaseEarly() { + assertWriteLocked(); // aso must not be recursive, although we don't verify that in the old boost version + assert( !_releasedEarly.get() ); + _releasedEarly.set(true); + _unlock(); + } + + void _unlock() { _minfo.leaving(); #if BOOST_VERSION >= 103500 m.unlock(); @@ -154,6 +188,13 @@ namespace mongo { boost::detail::thread::lock_ops::unlock(m); #endif } + void unlock() { + if( _releasedEarly.get() ) { + _releasedEarly.set(false); + return; + } + _unlock(); + } void lock_shared() { lock(); } void unlock_shared() { unlock(); } diff --git a/db/dbcommands_admin.cpp b/db/dbcommands_admin.cpp index 15783b1187e..6c2b9a45776 100644 --- a/db/dbcommands_admin.cpp +++ b/db/dbcommands_admin.cpp @@ -30,6 +30,7 @@ #include "cmdline.h" #include "btree.h" #include "curop.h" +#include "../util/background.h" namespace mongo { @@ -249,30 +250,97 @@ namespace mongo { } } validateCmd; + static bool unlockRequested = false; + extern unsigned lockedForWriting; + static boost::mutex lockedForWritingMutex; + + class UnlockCommand : public Command { + public: + UnlockCommand() : Command( "unlock" ) { } + virtual bool readOnly() { return true; } + virtual bool slaveOk(){ return true; } + virtual bool adminOnly(){ return true; } + virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { + if( lockedForWriting ) { + errmsg = "unlock requested"; + unlockRequested = true; + } + else { + errmsg = "not locked, so cannot unlock"; + return 0; + } + return 1; + } + + } unlockCommand; + class FSyncCommand : public Command { + class LockDBJob : public BackgroundJob { + protected: + void run() { + { + boostlock lk(lockedForWritingMutex); + lockedForWriting++; + } + readlock lk(""); + MemoryMappedFile::flushAll(true); + log() << "db is now locked for snapshotting, no writes allowed. use command {unlock:1} to unlock" << endl; + _ready = true; + while( 1 ) { + if( unlockRequested ) { + unlockRequested = false; + break; + } + sleepmillis(20); + } + { + boostlock lk(lockedForWritingMutex); + lockedForWriting--; + } + } + public: + bool& _ready; + LockDBJob(bool& ready) : _ready(ready) { + deleteSelf = true; + _ready = false; + } + }; public: FSyncCommand() : Command( "fsync" ){} virtual bool slaveOk(){ return true; } virtual bool adminOnly(){ return true; } - virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { + /*virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { string x = cmdObj["exec"].valuestrsafe(); return !x.empty(); - } + }*/ virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { /* async means do an fsync, but return immediately */ bool sync = ! cmdObj["async"].trueValue(); - string exec = cmdObj["exec"].valuestrsafe(); - log() << "CMD fsync: sync:" << sync << endl; - result.append( "numFiles" , MemoryMappedFile::flushAll( sync ) ); - if( !exec.empty() ) { - uassert(12032, "fsync: sync option must be true when using exec", sync); - assert( localHostOnlyIfNoAuth(cmdObj) ); - log() << "execing: " << exec << " (db will be locked during operation)" << endl; - // ADD EXEC HERE - log() << "ERROR: exec call not yet implemented" << endl; - result.append("execOutput", "exec not yet implemented"); - log() << "exec complete" << endl; + bool lock = cmdObj["lock"].trueValue(); + log() << "CMD fsync: sync:" << sync << " lock:" << lock << endl; + + if( lock ) { + uassert(12034, "fsync: can't lock while an unlock is pending", !unlockRequested); + uassert(12032, "fsync: sync option must be true when using lock", sync); + /* With releaseEarly(), we must be extremely careful we don't do anything + where we would have assumed we were locked. profiling is one of those things. + Perhaps at profile time we could check if we released early -- however, + we need to be careful to keep that code very fast it's a very common code path when on. + */ + uassert(12033, "fsync: profiling must be off to enter locked mode", cc().database()->profile == 0); + bool ready = false; + LockDBJob *l = new LockDBJob(ready); + dbMutex.releaseEarly(); + l->go(); + // don't return until background thread has acquired the write lock + while( !ready ) { + sleepmillis(10); + } + result.append("info", "now locked against writes, use admin command {unlock:1} to unlock"); + } + else { + result.append( "numFiles" , MemoryMappedFile::flushAll( sync ) ); } return 1; } diff --git a/db/instance.cpp b/db/instance.cpp index f9b8619dba1..2ef344155bc 100644 --- a/db/instance.cpp +++ b/db/instance.cpp @@ -83,6 +83,7 @@ namespace mongo { KillCurrentOp killCurrentOp; int lockFile = 0; + unsigned lockedForWriting; // see FSyncCommand void inProgCmd( Message &m, DbResponse &dbresponse ) { BSONObjBuilder b; @@ -104,6 +105,11 @@ namespace mongo { } } b.append("inprog", vals); + unsigned x = lockedForWriting; + if( x ) { + b.append("fsyncLock", x); + b.append("info", "use command {unlock:0} to terminate the fsync write/snapshot lock"); + } } replyToQuery(0, m, dbresponse, b.obj()); diff --git a/s/dbgrid.vcxproj b/s/dbgrid.vcxproj index f6a30973ff8..e997055c9a8 100644 --- a/s/dbgrid.vcxproj +++ b/s/dbgrid.vcxproj @@ -1,201 +1,201 @@ - - - - - Debug Recstore - Win32 - - - Debug - Win32 - - - Release - Win32 - - - - mongos - {E03717ED-69B4-4D21-BC55-DF6690B585C6} - dbgrid - Win32Proj - - - - Application - Unicode - - - Application - Unicode - true - - - Application - Unicode - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.21006.1 - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - false - $(SolutionDir)$(Configuration)\ - $(Configuration)\ - true - - - - Disabled - ..\pcre-7.4;C:\Program Files\boost\boost_1_41_0;%(AdditionalIncludeDirectories) - USE_ASIO;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;PCRE_STATIC;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Use - stdafx.h - Level3 - EditAndContinue - 4355;4800;%(DisableSpecificWarnings) - - - ws2_32.lib;%(AdditionalDependencies) - c:\program files\boost\boost_1_41_0\lib;%(AdditionalLibraryDirectories) - true - Console - MachineX86 - - - - - MaxSpeed - true - USE_ASIO;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;PCRE_STATIC;%(PreprocessorDefinitions) - MultiThreadedDLL - true - Use - Level3 - ProgramDatabase - 4355;4800;%(DisableSpecificWarnings) - - - ws2_32.lib;%(AdditionalDependencies) - c:\Program Files\boost\boost_1_41_0\lib;%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX86 - - - - - Disabled - ..\pcre-7.4;C:\Program Files\boost\boost_1_41_0;%(AdditionalIncludeDirectories) - USE_ASIO;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;PCRE_STATIC;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - Use - stdafx.h - Level3 - EditAndContinue - 4355;4800;%(DisableSpecificWarnings) - - - ws2_32.lib;%(AdditionalDependencies) - c:\program files\boost\boost_1_41_0\lib;%(AdditionalLibraryDirectories) - true - Console - MachineX86 - - - - - - - - - - - - - - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - Use - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug Recstore + Win32 + + + Debug + Win32 + + + Release + Win32 + + + + mongos + {E03717ED-69B4-4D21-BC55-DF6690B585C6} + dbgrid + Win32Proj + + + + Application + Unicode + + + Application + Unicode + true + + + Application + Unicode + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.21006.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + + + + Disabled + ..\pcre-7.4;C:\Program Files\boost\boost_1_41_0;%(AdditionalIncludeDirectories) + USE_ASIO;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;PCRE_STATIC;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + stdafx.h + Level3 + EditAndContinue + 4355;4800;%(DisableSpecificWarnings) + + + ws2_32.lib;%(AdditionalDependencies) + c:\program files\boost\boost_1_41_0\lib;%(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + MaxSpeed + true + USE_ASIO;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;PCRE_STATIC;%(PreprocessorDefinitions) + MultiThreadedDLL + true + Use + Level3 + ProgramDatabase + 4355;4800;%(DisableSpecificWarnings) + + + ws2_32.lib;%(AdditionalDependencies) + c:\Program Files\boost\boost_1_41_0\lib;%(AdditionalLibraryDirectories) + true + Console + true + true + MachineX86 + + + + + Disabled + ..\pcre-7.4;C:\Program Files\boost\boost_1_41_0;%(AdditionalIncludeDirectories) + USE_ASIO;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;PCRE_STATIC;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + stdafx.h + Level3 + EditAndContinue + 4355;4800;%(DisableSpecificWarnings) + + + ws2_32.lib;%(AdditionalDependencies) + c:\program files\boost\boost_1_41_0\lib;%(AdditionalLibraryDirectories) + true + Console + MachineX86 + + + + + + + + + + + + + + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + Use + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/util/file_allocator.h b/util/file_allocator.h index 2643f270aad..a9e6b4dfa09 100644 --- a/util/file_allocator.h +++ b/util/file_allocator.h @@ -49,9 +49,9 @@ namespace mongo { // May be called if file exists. If file exists, or its allocation has // been requested, size is updated to match existing file size. void requestAllocation( const string &name, long &size ) { - /* Some of the system calls in the file allocator don't work in win, - so no win support - 32 or 64 bit. Plus we don't seem to need preallocation - on windows anyway as we don't have to pre-zero the file there. + /* Some of the system calls in the file allocator don't work in win, + so no win support - 32 or 64 bit. Plus we don't seem to need preallocation + on windows anyway as we don't have to pre-zero the file there. */ #if !defined(_WIN32) boostlock lk( pendingMutex_ );