diff options
author | dwight <dwight@10gen.com> | 2011-12-12 14:46:22 -0500 |
---|---|---|
committer | dwight <dwight@10gen.com> | 2011-12-12 14:46:45 -0500 |
commit | d5ca8e65e0d3b52ecd83bff13f417037b5d89518 (patch) | |
tree | 720b8570361de99dc0d6010f4edd28745b65a1f3 | |
parent | 48f8aa29059e71cc152609a0b209390ffdff09f1 (diff) | |
download | mongo-d5ca8e65e0d3b52ecd83bff13f417037b5d89518.tar.gz |
clc
-rw-r--r-- | db/client.cpp | 2 | ||||
-rw-r--r-- | db/client.h | 7 | ||||
-rwxr-xr-x[-rw-r--r--] | db/commands.cpp | 395 | ||||
-rw-r--r-- | db/commands.h | 8 | ||||
-rwxr-xr-x[-rw-r--r--] | db/d_concurrency.cpp | 297 | ||||
-rw-r--r-- | db/d_concurrency.h | 11 | ||||
-rwxr-xr-x | db/db.vcxproj | 3 | ||||
-rwxr-xr-x | db/db.vcxproj.filters | 1 | ||||
-rw-r--r-- | db/dbcommands.cpp | 22 | ||||
-rw-r--r-- | db/dur.cpp | 5 | ||||
-rw-r--r-- | db/instance.cpp | 5 | ||||
-rw-r--r-- | db/namespace.h | 2 | ||||
-rw-r--r-- | db/namespacestring.h (renamed from db/namespace_common.h) | 8 | ||||
-rw-r--r-- | db/ops/query.cpp | 2 | ||||
-rw-r--r-- | dbtests/test.vcxproj | 2 | ||||
-rw-r--r-- | s/d_split.cpp | 6 | ||||
-rw-r--r-- | s/grid.cpp | 2 | ||||
-rw-r--r-- | util/mongoutils/str.h | 4 |
18 files changed, 430 insertions, 352 deletions
diff --git a/db/client.cpp b/db/client.cpp index 96987709705..0447cd06164 100644 --- a/db/client.cpp +++ b/db/client.cpp @@ -190,7 +190,7 @@ namespace mongo { _db(0) { _finishInit( doauth ); - _client->checkLocks(); + _client->checkLocks(); } /** "read lock, and set my context, all in one operation" diff --git a/db/client.h b/db/client.h index 8fb58773399..c817ff54656 100644 --- a/db/client.h +++ b/db/client.h @@ -229,9 +229,14 @@ namespace mongo { LockStatus(); string whichCollection; int coll; + bool isWriteLocked() const; } lockStatus; - void checkLocks() const {} +#if defined(CLC) + void checkLocks() const; +#else + void checkLocks() const { } +#endif }; // class Client diff --git a/db/commands.cpp b/db/commands.cpp index 59f6ba320f2..cc1c70793c4 100644..100755 --- a/db/commands.cpp +++ b/db/commands.cpp @@ -1,186 +1,209 @@ -/* commands.cpp - db "commands" (sent via db.$cmd.findOne(...)) - */ - -/* Copyright 2009 10gen Inc. - * - * 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. - */ - -#include "pch.h" -#include "jsobj.h" -#include "commands.h" -#include "client.h" -#include "replutil.h" - -namespace mongo { - - map<string,Command*> * Command::_commandsByBestName; - map<string,Command*> * Command::_webCommands; - map<string,Command*> * Command::_commands; - - void Command::htmlHelp(stringstream& ss) const { - string helpStr; - { - stringstream h; - help(h); - helpStr = h.str(); - } - ss << "\n<tr><td>"; - bool web = _webCommands->count(name) != 0; - if( web ) ss << "<a href=\"/" << name << "?text=1\">"; - ss << name; - if( web ) ss << "</a>"; - ss << "</td>\n"; - ss << "<td>"; - int l = locktype(); - //if( l == NONE ) ss << "N "; - if( l == READ ) ss << "R "; - else if( l == WRITE ) ss << "W "; - if( slaveOk() ) - ss << "S "; - if( adminOnly() ) - ss << "A"; - ss << "</td>"; - ss << "<td>"; - if( helpStr != "no help defined" ) { - const char *p = helpStr.c_str(); - while( *p ) { - if( *p == '<' ) { - ss << "<"; - p++; continue; - } - else if( *p == '{' ) - ss << "<code>"; - else if( *p == '}' ) { - ss << "}</code>"; - p++; - continue; - } - if( strncmp(p, "http:", 5) == 0 ) { - ss << "<a href=\""; - const char *q = p; - while( *q && *q != ' ' && *q != '\n' ) - ss << *q++; - ss << "\">"; - q = p; - if( startsWith(q, "http://www.mongodb.org/display/") ) - q += 31; - while( *q && *q != ' ' && *q != '\n' ) { - ss << (*q == '+' ? ' ' : *q); - q++; - if( *q == '#' ) - while( *q && *q != ' ' && *q != '\n' ) q++; - } - ss << "</a>"; - p = q; - continue; - } - if( *p == '\n' ) ss << "<br>"; - else ss << *p; - p++; - } - } - ss << "</td>"; - ss << "</tr>\n"; - } - - Command::Command(const char *_name, bool web, const char *oldName) : name(_name) { - // register ourself. - if ( _commands == 0 ) - _commands = new map<string,Command*>; - if( _commandsByBestName == 0 ) - _commandsByBestName = new map<string,Command*>; - Command*& c = (*_commands)[name]; - if ( c ) - log() << "warning: 2 commands with name: " << _name << endl; - c = this; - (*_commandsByBestName)[name] = this; - - if( web ) { - if( _webCommands == 0 ) - _webCommands = new map<string,Command*>; - (*_webCommands)[name] = this; - } - - if( oldName ) - (*_commands)[oldName] = this; - } - - void Command::help( stringstream& help ) const { - help << "no help defined"; - } - - Command* Command::findCommand( const string& name ) { - map<string,Command*>::iterator i = _commands->find( name ); - if ( i == _commands->end() ) - return 0; - return i->second; - } - - - Command::LockType Command::locktype( const string& name ) { - Command * c = findCommand( name ); - if ( ! c ) - return WRITE; - return c->locktype(); - } - - void Command::logIfSlow( const Timer& timer, const string& msg ) { - int ms = timer.millis(); - if ( ms > cmdLine.slowMS ) { - out() << msg << " took " << ms << " ms." << endl; - } - } - -} - -#include "../client/connpool.h" - -namespace mongo { - - extern DBConnectionPool pool; - - class PoolFlushCmd : public Command { - public: - PoolFlushCmd() : Command( "connPoolSync" , false , "connpoolsync" ) {} - virtual void help( stringstream &help ) const { help<<"internal"; } - virtual LockType locktype() const { return NONE; } - virtual bool run(const string&, mongo::BSONObj&, int, std::string&, mongo::BSONObjBuilder& result, bool) { - pool.flush(); - return true; - } - virtual bool slaveOk() const { - return true; - } - - } poolFlushCmd; - - class PoolStats : public Command { - public: - PoolStats() : Command( "connPoolStats" ) {} - virtual void help( stringstream &help ) const { help<<"stats about connection pool"; } - virtual LockType locktype() const { return NONE; } - virtual bool run(const string&, mongo::BSONObj&, int, std::string&, mongo::BSONObjBuilder& result, bool) { - pool.appendInfo( result ); - result.append( "numDBClientConnection" , DBClientConnection::getNumConnections() ); - result.append( "numAScopedConnection" , AScopedConnection::getNumConnections() ); - return true; - } - virtual bool slaveOk() const { - return true; - } - - } poolStatsCmd; - -} // namespace mongo +/* commands.cpp
+ db "commands" (sent via db.$cmd.findOne(...))
+ */
+
+/* Copyright 2009 10gen Inc.
+ *
+ * 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.
+ */
+
+#include "pch.h"
+#include "jsobj.h"
+#include "commands.h"
+#include "client.h"
+#include "replutil.h"
+
+namespace mongo {
+
+ map<string,Command*> * Command::_commandsByBestName;
+ map<string,Command*> * Command::_webCommands;
+ map<string,Command*> * Command::_commands;
+
+ string Command::parseNsFullyQualified(const string& dbname, const BSONObj& cmdObj) const {
+ string s = cmdObj.firstElement().valuestr();
+ NamespaceString nss(s);
+ // these are for security, do not remove:
+ verify(15940, dbname == nss.db || dbname == "admin" );
+ verify(15941, !nss.db.empty() );
+ return s;
+ }
+
+ /*virtual*/ string Command::parseNs(const string& dbname, const BSONObj& cmdObj) const {
+ string coll = cmdObj.firstElement().valuestr();
+#if defined(CLC)
+ DEV if( mongoutils::str::startsWith(coll, dbname+'.') ) {
+ log() << "DEBUG parseNs Command's collection name looks like it includes the db name\n"
+ << dbname << '\n'
+ << coll << '\n'
+ << cmdObj.toString() << endl;
+ dassert(false);
+ }
+#endif
+ return dbname + '.' + coll;
+ }
+
+ void Command::htmlHelp(stringstream& ss) const {
+ string helpStr;
+ {
+ stringstream h;
+ help(h);
+ helpStr = h.str();
+ }
+ ss << "\n<tr><td>";
+ bool web = _webCommands->count(name) != 0;
+ if( web ) ss << "<a href=\"/" << name << "?text=1\">";
+ ss << name;
+ if( web ) ss << "</a>";
+ ss << "</td>\n";
+ ss << "<td>";
+ int l = locktype();
+ //if( l == NONE ) ss << "N ";
+ if( l == READ ) ss << "R ";
+ else if( l == WRITE ) ss << "W ";
+ if( slaveOk() )
+ ss << "S ";
+ if( adminOnly() )
+ ss << "A";
+ ss << "</td>";
+ ss << "<td>";
+ if( helpStr != "no help defined" ) {
+ const char *p = helpStr.c_str();
+ while( *p ) {
+ if( *p == '<' ) {
+ ss << "<";
+ p++; continue;
+ }
+ else if( *p == '{' )
+ ss << "<code>";
+ else if( *p == '}' ) {
+ ss << "}</code>";
+ p++;
+ continue;
+ }
+ if( strncmp(p, "http:", 5) == 0 ) {
+ ss << "<a href=\"";
+ const char *q = p;
+ while( *q && *q != ' ' && *q != '\n' )
+ ss << *q++;
+ ss << "\">";
+ q = p;
+ if( startsWith(q, "http://www.mongodb.org/display/") )
+ q += 31;
+ while( *q && *q != ' ' && *q != '\n' ) {
+ ss << (*q == '+' ? ' ' : *q);
+ q++;
+ if( *q == '#' )
+ while( *q && *q != ' ' && *q != '\n' ) q++;
+ }
+ ss << "</a>";
+ p = q;
+ continue;
+ }
+ if( *p == '\n' ) ss << "<br>";
+ else ss << *p;
+ p++;
+ }
+ }
+ ss << "</td>";
+ ss << "</tr>\n";
+ }
+
+ Command::Command(const char *_name, bool web, const char *oldName) : name(_name) {
+ // register ourself.
+ if ( _commands == 0 )
+ _commands = new map<string,Command*>;
+ if( _commandsByBestName == 0 )
+ _commandsByBestName = new map<string,Command*>;
+ Command*& c = (*_commands)[name];
+ if ( c )
+ log() << "warning: 2 commands with name: " << _name << endl;
+ c = this;
+ (*_commandsByBestName)[name] = this;
+
+ if( web ) {
+ if( _webCommands == 0 )
+ _webCommands = new map<string,Command*>;
+ (*_webCommands)[name] = this;
+ }
+
+ if( oldName )
+ (*_commands)[oldName] = this;
+ }
+
+ void Command::help( stringstream& help ) const {
+ help << "no help defined";
+ }
+
+ Command* Command::findCommand( const string& name ) {
+ map<string,Command*>::iterator i = _commands->find( name );
+ if ( i == _commands->end() )
+ return 0;
+ return i->second;
+ }
+
+
+ Command::LockType Command::locktype( const string& name ) {
+ Command * c = findCommand( name );
+ if ( ! c )
+ return WRITE;
+ return c->locktype();
+ }
+
+ void Command::logIfSlow( const Timer& timer, const string& msg ) {
+ int ms = timer.millis();
+ if ( ms > cmdLine.slowMS ) {
+ out() << msg << " took " << ms << " ms." << endl;
+ }
+ }
+
+}
+
+#include "../client/connpool.h"
+
+namespace mongo {
+
+ extern DBConnectionPool pool;
+
+ class PoolFlushCmd : public Command {
+ public:
+ PoolFlushCmd() : Command( "connPoolSync" , false , "connpoolsync" ) {}
+ virtual void help( stringstream &help ) const { help<<"internal"; }
+ virtual LockType locktype() const { return NONE; }
+ virtual bool run(const string&, mongo::BSONObj&, int, std::string&, mongo::BSONObjBuilder& result, bool) {
+ pool.flush();
+ return true;
+ }
+ virtual bool slaveOk() const {
+ return true;
+ }
+
+ } poolFlushCmd;
+
+ class PoolStats : public Command {
+ public:
+ PoolStats() : Command( "connPoolStats" ) {}
+ virtual void help( stringstream &help ) const { help<<"stats about connection pool"; }
+ virtual LockType locktype() const { return NONE; }
+ virtual bool run(const string&, mongo::BSONObj&, int, std::string&, mongo::BSONObjBuilder& result, bool) {
+ pool.appendInfo( result );
+ result.append( "numDBClientConnection" , DBClientConnection::getNumConnections() );
+ result.append( "numAScopedConnection" , AScopedConnection::getNumConnections() );
+ return true;
+ }
+ virtual bool slaveOk() const {
+ return true;
+ }
+
+ } poolStatsCmd;
+
+} // namespace mongo
diff --git a/db/commands.h b/db/commands.h index 15f5ba2faab..26eeb352cdd 100644 --- a/db/commands.h +++ b/db/commands.h @@ -17,10 +17,8 @@ #pragma once -//#include "../pch.h" #include "jsobj.h" -//#include "../util/timer.h" -//#include "../client/dbclient.h" +#include "../util/mongoutils/str.h" namespace mongo { @@ -33,7 +31,11 @@ namespace mongo { subclass to make a command. define a singleton object for it. */ class Command { + protected: + string parseNsFullyQualified(const string& dbname, const BSONObj& cmdObj) const; public: + // only makes sense for commands where 1st parm is the collection. + virtual string parseNs(const string& dbname, const BSONObj& cmdObj) const; enum LockType { READ = -1 , NONE = 0 , WRITE = 1 }; diff --git a/db/d_concurrency.cpp b/db/d_concurrency.cpp index f4b47f04d22..59995b2c5d1 100644..100755 --- a/db/d_concurrency.cpp +++ b/db/d_concurrency.cpp @@ -1,126 +1,171 @@ -// @file d_concurrency.cpp - -#include "pch.h" -#include "d_concurrency.h" -#include "../util/concurrency/threadlocal.h" -#include "../util/concurrency/rwlock.h" -#include "../util/concurrency/value.h" -#include "../util/assert_util.h" -#include "client.h" - -// we will use the global write lock for writing to system.* collections for simplicity -// for now; this has some advantages in speed as we don't need to latch just for that then; -// also there are cases to be handled carefully otherwise such as namespacedetails methods -// reaching into system.indexes implicitly -// -// exception : system.profile - -// oplog locking -// ... - -namespace mongo { - - /** we want to be able to block any attempted write while allowing reads; additionally - force non-greedy acquisition so that reads can continue -- - that is, disallow greediness of write lock acquisitions. This is for that purpose. The - #1 need is by groupCommitWithLimitedLocks() but useful elsewhere such as for lock and fsync. - */ - SimpleRWLock writeExcluder; - - Client::LockStatus::LockStatus() { - coll = 0; - } - - bool subcollectionOf(const string& parent, const char *child) { - if( parent == child ) - return true; - if( !str::startsWith(child, parent) ) - return false; - const char *p = child + parent.size(); - return *p == '.' && p[1] == '$'; - } - - // we don't keep these locks in the namespacedetailstransient and Database - // objects -- that makes things safer as we need not prove to ourselves that they - // are always in scope when we need them. - // todo: we don't clean these locks up yet. - // todo: avoiding the mutex here might be nice. - class TheLocks { - //mapsf<string,RWLock*> dblocks; - mapsf<string,RWLock*> nslocks; - public: - /*RWLock& fordb(string db) { - mapsf<string,RWLock*>::ref r(dblocks); - RWLock*& rw = r[db]; - if( rw == 0 ) - rw = new RWLock(0); - return *rw; - }*/ - RWLock& forns(string ns) { - mapsf<string,RWLock*>::ref r(nslocks); - RWLock*& rw = r[ns]; - if( rw == 0 ) { - rw = new RWLock(0); - } - return *rw; - } - } theLocks; - - LockCollectionForWriting::Locks::Locks(string ns) : - excluder(writeExcluder), - gslk(), - clk(theLocks.forns(ns),true) - { } - LockCollectionForWriting::~LockCollectionForWriting() { - if( locks.get() ) { - Client::LockStatus& s = cc().lockStatus; - s.whichCollection.clear(); - s.coll--; - } - } - LockCollectionForWriting::LockCollectionForWriting(string coll) - { - Client::LockStatus& s = cc().lockStatus; - if( !s.whichCollection.empty() ) { - if( !subcollectionOf(s.whichCollection, coll.c_str()) ) { - massert(15937, str::stream() << "can't nest lock of " << coll << " beneath " << s.whichCollection, false); - } - massert(15938, "want collection write lock but it is already read locked", s.coll > 0); - return; - } - s.whichCollection = coll; - dassert( s.coll == 0 ); - s.coll++; - locks.reset( new Locks(coll) ); - } - - LockCollectionForReading::Locks::Locks(string ns) : - gslk(), - clk( theLocks.forns(ns) ) - { } - LockCollectionForReading::~LockCollectionForReading() { - Client::LockStatus& s = cc().lockStatus; - dassert( !s.whichCollection.empty() ); - if( locks.get() ) { - s.whichCollection.clear(); - s.coll++; - wassert( s.coll == 0 ); - } - } - LockCollectionForReading::LockCollectionForReading(string coll) - { - Client::LockStatus& s = cc().lockStatus; - if( !s.whichCollection.empty() ) { - if( !subcollectionOf(s.whichCollection, coll.c_str()) ) { - massert(15939, str::stream() << "can't nest lock of " << coll << " beneath " << s.whichCollection, false); - } - // already locked, so done; might have been a write lock. - return; - } - s.whichCollection = coll; - dassert( s.coll == 0 ); - s.coll--; - locks.reset( new Locks(coll) ); - } - -} +// @file d_concurrency.cpp
+
+#include "pch.h"
+#include "d_concurrency.h"
+#include "../util/concurrency/threadlocal.h"
+#include "../util/concurrency/rwlock.h"
+#include "../util/concurrency/value.h"
+#include "../util/assert_util.h"
+#include "client.h"
+#include "namespacestring.h"
+
+// oplog locking
+// no top level read locks
+// system.profile writing
+// oplog now
+// yielding
+
+namespace mongo {
+
+ bool subcollectionOf(const string& parent, const char *child) {
+ if( parent == child )
+ return true;
+ if( !str::startsWith(child, parent) )
+ return false;
+ const char *p = child + parent.size();
+ uassert(15942, str::stream() << "bad collection name: " << child, !str::endsWith(p, '.'));
+ return *p == '.' && p[1] == '$';
+ }
+
+ // we will use the global write lock for writing to system.* collections for simplicity
+ // for now; this has some advantages in speed as we don't need to latch just for that then;
+ // also there are cases to be handled carefully otherwise such as namespacedetails methods
+ // reaching into system.indexes implicitly
+ // exception : system.profile
+ static bool lkspecial(const string& ns) {
+ NamespaceString s(ns);
+ return s.isSystem() && s.coll != "system.profile";
+ }
+
+ /** we want to be able to block any attempted write while allowing reads; additionally
+ force non-greedy acquisition so that reads can continue --
+ that is, disallow greediness of write lock acquisitions. This is for that purpose. The
+ #1 need is by groupCommitWithLimitedLocks() but useful elsewhere such as for lock and fsync.
+ */
+ SimpleRWLock writeExcluder;
+ ExcludeAllWrites::ExcludeAllWrites() :
+ lk(writeExcluder)
+ {
+ LOG(3) << "ExcludeAllWrites" << endl;
+ wassert( !dbMutex.isWriteLocked() );
+ wassert( !cc().lockStatus.isWriteLocked() );
+ };
+
+ // CLC turns on the "collection level concurrency" code
+ // (which is under development and not finished)
+#if defined(CLC)
+ // called after a context is set. check that the correct collection is locked
+ void Client::checkLocks() const {
+ DEV {
+ if( !dbMutex.isWriteLocked() ) {
+ const char *n = ns();
+ if( lockStatus.whichCollection.empty() ) {
+ log() << "DEBUG checkLocks error expected to already be locked " << n << endl;
+ dassert(false);
+ }
+ dassert( subcollectionOf(lockStatus.whichCollection, n) || lkspecial(n) );
+ }
+ }
+ }
+#endif
+
+ Client::LockStatus::LockStatus() {
+ coll = 0;
+ }
+
+ bool Client::LockStatus::isWriteLocked() const {
+ return coll > 0;
+ }
+
+ // we don't keep these locks in the namespacedetailstransient and Database
+ // objects -- that makes things safer as we need not prove to ourselves that they
+ // are always in scope when we need them.
+ // todo: we don't clean these locks up yet.
+ // todo: avoiding the mutex here might be nice.
+ class LockObjectForEachCollection {
+ //mapsf<string,RWLock*> dblocks;
+ mapsf<string,RWLock*> nslocks;
+ public:
+ /*RWLock& fordb(string db) {
+ mapsf<string,RWLock*>::ref r(dblocks);
+ RWLock*& rw = r[db];
+ if( rw == 0 )
+ rw = new RWLock(0);
+ return *rw;
+ }*/
+ RWLock& forns(string ns) {
+ mapsf<string,RWLock*>::ref r(nslocks);
+#if defined(CLC)
+ massert(15943, str::stream() << "bad collection name to lock: " << ns, str::contains(ns, '.'));
+#endif
+ RWLock*& rw = r[ns];
+ if( rw == 0 ) {
+ rw = new RWLock(0);
+ }
+ return *rw;
+ }
+ } theLocks;
+
+ LockCollectionForWriting::Locks::Locks(string ns) :
+ excluder(writeExcluder),
+ gslk(),
+ clk(theLocks.forns(ns),true)
+ { }
+ LockCollectionForWriting::~LockCollectionForWriting() {
+ if( locks.get() ) {
+ Client::LockStatus& s = cc().lockStatus;
+ s.whichCollection.clear();
+ s.coll--;
+ }
+ }
+ LockCollectionForWriting::LockCollectionForWriting(string coll)
+ {
+ Client::LockStatus& s = cc().lockStatus;
+ if( !s.whichCollection.empty() ) {
+ if( !subcollectionOf(s.whichCollection, coll.c_str()) ) {
+ massert(15937, str::stream() << "can't nest lock of " << coll << " beneath " << s.whichCollection, false);
+ }
+ massert(15938, "want collection write lock but it is already read locked", s.coll > 0);
+ return;
+ }
+ verify(15944, !lkspecial(coll)); // you must global write lock for writes to special's
+ s.whichCollection = coll;
+ dassert( s.coll == 0 );
+ s.coll++;
+ locks.reset( new Locks(coll) );
+ }
+
+ LockCollectionForReading::Locks::Locks(string ns) :
+ gslk(),
+ clk( theLocks.forns(ns) )
+ { }
+ LockCollectionForReading::~LockCollectionForReading() {
+ Client::LockStatus& s = cc().lockStatus;
+ dassert( !s.whichCollection.empty() );
+ if( locks.get() ) {
+ s.whichCollection.clear();
+ s.coll++;
+ wassert( s.coll == 0 );
+ }
+ }
+ LockCollectionForReading::LockCollectionForReading(string coll)
+ {
+ Client::LockStatus& s = cc().lockStatus;
+ if( !s.whichCollection.empty() ) {
+ if( !subcollectionOf(s.whichCollection, coll.c_str()) ) {
+ if( lkspecial(coll) )
+ return;
+ massert(15939,
+ str::stream() << "can't nest lock of " << coll << " beneath " << s.whichCollection,
+ false);
+ }
+ // already locked, so done; might have been a write lock.
+ return;
+ }
+ s.whichCollection = coll;
+ dassert( s.coll == 0 );
+ s.coll--;
+ locks.reset( new Locks(coll) );
+ }
+
+}
diff --git a/db/d_concurrency.h b/db/d_concurrency.h index cb7e0161c92..833c71bb326 100644 --- a/db/d_concurrency.h +++ b/db/d_concurrency.h @@ -32,10 +32,11 @@ namespace mongo { ~LockCollectionForWriting(); }; - // CLC turns on the "collection level concurrency" code which is under development - // and not finished. -#if defined(CLC) - ... -#endif + class ExcludeAllWrites { + SimpleRWLock::Exclusive lk; + GlobalSharedLock gslk; + public: + ExcludeAllWrites(); + }; } diff --git a/db/db.vcxproj b/db/db.vcxproj index 962229c8816..62a59d21a5d 100755 --- a/db/db.vcxproj +++ b/db/db.vcxproj @@ -127,7 +127,7 @@ <ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\js\src;..\third_party\pcre-7.4;c:\boost;\boost</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>MONGO_EXPOSE_MACROS;OLDJS;STATIC_JS_API;XP_WIN;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>CLC;MONGO_EXPOSE_MACROS;OLDJS;STATIC_JS_API;XP_WIN;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
@@ -773,6 +773,7 @@ <ClInclude Include="mongommf.h" />
<ClInclude Include="mongomutex.h" />
<ClInclude Include="namespace-inl.h" />
+ <ClInclude Include="namespacestring.h" />
<ClInclude Include="oplogreader.h" />
<ClInclude Include="ops\delete.h" />
<ClInclude Include="ops\update.h" />
diff --git a/db/db.vcxproj.filters b/db/db.vcxproj.filters index c301651f392..3c2ffbdb5b5 100755 --- a/db/db.vcxproj.filters +++ b/db/db.vcxproj.filters @@ -381,6 +381,7 @@ <ClInclude Include="pipeline\value.h" />
<ClInclude Include="..\util\intrusive_counter.h" />
<ClInclude Include="..\util\systeminfo.h" />
+ <ClInclude Include="namespacestring.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="db.rc" />
diff --git a/db/dbcommands.cpp b/db/dbcommands.cpp index 9541b88fc9d..0e369b33279 100644 --- a/db/dbcommands.cpp +++ b/db/dbcommands.cpp @@ -804,22 +804,16 @@ namespace mongo { public: virtual LockType locktype() const { return READ; } CmdCount() : Command("count") { } - virtual bool logTheOp() { - return false; - } + virtual bool logTheOp() { return false; } virtual bool slaveOk() const { // ok on --slave setups return replSettings.slave == SimpleSlave; } - virtual bool slaveOverrideOk() { - return true; - } - virtual bool adminOnly() const { - return false; - } + virtual bool slaveOverrideOk() { return true; } + virtual bool adminOnly() const { return false; } virtual void help( stringstream& help ) const { help << "count objects in collection"; } virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - string ns = dbname + '.' + cmdObj.firstElement().valuestr(); + string ns = parseNs(dbname, cmdObj); string err; long long n = runCount(ns.c_str(), cmdObj, err); long long nn = n; @@ -1000,7 +994,7 @@ namespace mongo { totalSize += size; { - Client::ReadContext rc( *i ); + Client::ReadContext rc( *i + ".system.namespaces" ); b.appendBool( "empty", rc.ctx().db()->isEmpty() ); } @@ -1171,6 +1165,9 @@ namespace mongo { } class CmdDatasize : public Command { + virtual string parseNs(const string& dbname, const BSONObj& cmdObj) const { + return parseNsFullyQualified(dbname, cmdObj); + } public: CmdDatasize() : Command( "dataSize", false, "datasize" ) {} virtual bool slaveOk() const { return true; } @@ -1868,7 +1865,8 @@ namespace mongo { else if( c->locktype() != Command::WRITE ) { // read lock assert( ! c->logTheOp() ); - Client::ReadContext ctx( dbname , dbpath, c->requiresAuth() ); // read locks + string ns = c->parseNs(dbname, cmdObj); + Client::ReadContext ctx( ns , dbpath, c->requiresAuth() ); // read locks client.curop()->ensureStarted(); retval = _execCommand(c, dbname , cmdObj , queryOptions, result , fromRepl ); } diff --git a/db/dur.cpp b/db/dur.cpp index 7582bce4d5f..d15dba8a293 100644 --- a/db/dur.cpp +++ b/db/dur.cpp @@ -498,9 +498,7 @@ namespace mongo { int p = 0; LOG(3) << "groupcommitll " << p++ << endl; - scoped_ptr<readlocktry> lk1( new readlocktry("", 500) ); - if( !lk1->got() ) - return false; + scoped_ptr<ExcludeAllWrites> lk1( new ExcludeAllWrites() ); LOG(3) << "groupcommitll " << p++ << endl; @@ -539,6 +537,7 @@ namespace mongo { LOG(3) << "groupcommitll " << p++ << endl; // ****** now other threads can do writes ****** + WRITETOJOURNAL(h, commitJob._ab); assert( abLen == commitJob._ab.len() ); // a check that no one touched the builder while we were doing work. if so, our locking is wrong. diff --git a/db/instance.cpp b/db/instance.cpp index 495715728f8..f9fcf18b5e3 100644 --- a/db/instance.cpp +++ b/db/instance.cpp @@ -560,16 +560,13 @@ namespace mongo { OpTime last; while( 1 ) { try { - readlock lk; - + Client::ReadContext ctx(ns); if (str::startsWith(ns, "local.oplog.")){ if (pass == 0) last = OpTime::last_inlock(); else last.waitForDifferent(1000/*ms*/); } - - Client::Context ctx(ns); msgdata = processGetMore(ns, ntoreturn, cursorid, curop, pass, exhaust); } catch ( AssertionException& e ) { diff --git a/db/namespace.h b/db/namespace.h index 0e53153b4fd..00059935969 100644 --- a/db/namespace.h +++ b/db/namespace.h @@ -19,7 +19,7 @@ #pragma once #include "../pch.h" -#include "namespace_common.h" +#include "namespacestring.h" #include "jsobj.h" #include "querypattern.h" #include "diskloc.h" diff --git a/db/namespace_common.h b/db/namespacestring.h index b237a0b9280..92429894932 100644 --- a/db/namespace_common.h +++ b/db/namespacestring.h @@ -1,4 +1,4 @@ -// namespace_common.h +// @file namespacestring.h /** * Copyright (C) 2008 10gen Inc. @@ -20,10 +20,6 @@ #include <string> - -/** - * this file contains basics utilities for handling namespaces - */ namespace mongo { using std::string; @@ -43,7 +39,9 @@ namespace mongo { NamespaceString( const char * ns ) { init(ns); } NamespaceString( const string& ns ) { init(ns.c_str()); } + string ns() const { return db + '.' + coll; } + bool isSystem() const { return strncmp(coll.c_str(), "system.", 7) == 0; } /** diff --git a/db/ops/query.cpp b/db/ops/query.cpp index 7614853fb8b..5bd497ee783 100644 --- a/db/ops/query.cpp +++ b/db/ops/query.cpp @@ -224,7 +224,7 @@ namespace mongo { returns -1 on ns does not exist error. */ long long runCount( const char *ns, const BSONObj &cmd, string &err ) { - Client::Context cx(ns); + Client::ReadContext cx(ns); NamespaceDetails *d = nsdetails( ns ); if ( !d ) { err = "ns missing"; diff --git a/dbtests/test.vcxproj b/dbtests/test.vcxproj index 5c7a3e21fca..d5542c014bd 100644 --- a/dbtests/test.vcxproj +++ b/dbtests/test.vcxproj @@ -127,7 +127,7 @@ <ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\js\src;..\third_party\pcre-7.4;C:\boost;\boost;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>_DURABLE;_UNICODE;UNICODE;MONGO_EXPOSE_MACROS;OLDJS;STATIC_JS_API;XP_WIN;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>CLC;_DURABLE;_UNICODE;UNICODE;MONGO_EXPOSE_MACROS;OLDJS;STATIC_JS_API;XP_WIN;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
diff --git a/s/d_split.cpp b/s/d_split.cpp index d0ba7b44c10..b2480988c28 100644 --- a/s/d_split.cpp +++ b/s/d_split.cpp @@ -136,10 +136,14 @@ namespace mongo { virtual void help( stringstream &help ) const { help << "Internal command.\n"; } - + virtual string parseNs(const string& dbname, const BSONObj& cmdObj) const { + return parseNsFullyQualified(dbname, cmdObj); + } bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { const char* ns = jsobj.getStringField( "checkShardingIndex" ); + NamespaceString str(ns); + assert( str.db == dbname ); BSONObj keyPattern = jsobj.getObjectField( "keyPattern" ); if ( keyPattern.nFields() == 1 && str::equals( "_id" , keyPattern.firstElementFieldName() ) ) { diff --git a/s/grid.cpp b/s/grid.cpp index c14feb50a03..9d9c2e4555e 100644 --- a/s/grid.cpp +++ b/s/grid.cpp @@ -22,7 +22,7 @@ #include "../client/connpool.h" #include "../util/stringutils.h" #include "../util/unittest.h" -#include "../db/namespace_common.h" +#include "../db/namespacestring.h" #include "grid.h" #include "shard.h" diff --git a/util/mongoutils/str.h b/util/mongoutils/str.h index 4edf01dab4b..97b121b0068 100644 --- a/util/mongoutils/str.h +++ b/util/mongoutils/str.h @@ -79,6 +79,10 @@ namespace mongoutils { if( x < l ) return false; return strncmp(s.c_str()+x-l, p.c_str(), l) == 0; } + inline bool endsWith(const char *s, char p) { + size_t len = strlen(s); + return len && s[len-1] == p; + } inline bool equals( const char * a , const char * b ) { return strcmp( a , b ) == 0; } |