summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordwight <dwight@10gen.com>2011-12-12 14:46:22 -0500
committerdwight <dwight@10gen.com>2011-12-12 14:46:45 -0500
commitd5ca8e65e0d3b52ecd83bff13f417037b5d89518 (patch)
tree720b8570361de99dc0d6010f4edd28745b65a1f3
parent48f8aa29059e71cc152609a0b209390ffdff09f1 (diff)
downloadmongo-d5ca8e65e0d3b52ecd83bff13f417037b5d89518.tar.gz
clc
-rw-r--r--db/client.cpp2
-rw-r--r--db/client.h7
-rwxr-xr-x[-rw-r--r--]db/commands.cpp395
-rw-r--r--db/commands.h8
-rwxr-xr-x[-rw-r--r--]db/d_concurrency.cpp297
-rw-r--r--db/d_concurrency.h11
-rwxr-xr-xdb/db.vcxproj3
-rwxr-xr-xdb/db.vcxproj.filters1
-rw-r--r--db/dbcommands.cpp22
-rw-r--r--db/dur.cpp5
-rw-r--r--db/instance.cpp5
-rw-r--r--db/namespace.h2
-rw-r--r--db/namespacestring.h (renamed from db/namespace_common.h)8
-rw-r--r--db/ops/query.cpp2
-rw-r--r--dbtests/test.vcxproj2
-rw-r--r--s/d_split.cpp6
-rw-r--r--s/grid.cpp2
-rw-r--r--util/mongoutils/str.h4
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 << "&lt;";
- 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 << "&lt;";
+ 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; }