summaryrefslogtreecommitdiff
path: root/src/mongo/s/strategy_single.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/s/strategy_single.cpp')
-rw-r--r--src/mongo/s/strategy_single.cpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/mongo/s/strategy_single.cpp b/src/mongo/s/strategy_single.cpp
new file mode 100644
index 00000000000..442e1d23691
--- /dev/null
+++ b/src/mongo/s/strategy_single.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2010 10gen Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// strategy_simple.cpp
+
+#include "pch.h"
+#include "request.h"
+#include "cursors.h"
+#include "../client/connpool.h"
+#include "../db/commands.h"
+
+namespace mongo {
+
+ class SingleStrategy : public Strategy {
+
+ public:
+ SingleStrategy() {}
+
+ private:
+ virtual void queryOp( Request& r ) {
+ QueryMessage q( r.d() );
+
+ LOG(3) << "single query: " << q.ns << " " << q.query << " ntoreturn: " << q.ntoreturn << " options : " << q.queryOptions << endl;
+
+ if ( r.isCommand() ) {
+
+ if ( handleSpecialNamespaces( r , q ) )
+ return;
+
+ int loops = 5;
+ while ( true ) {
+ BSONObjBuilder builder;
+ try {
+ BSONObj cmdObj = q.query;
+ {
+ BSONElement e = cmdObj.firstElement();
+ if ( e.type() == Object && (e.fieldName()[0] == '$'
+ ? str::equals("query", e.fieldName()+1)
+ : str::equals("query", e.fieldName())))
+ cmdObj = e.embeddedObject();
+ }
+ bool ok = Command::runAgainstRegistered(q.ns, cmdObj, builder, q.queryOptions);
+ if ( ok ) {
+ BSONObj x = builder.done();
+ replyToQuery(0, r.p(), r.m(), x);
+ return;
+ }
+ break;
+ }
+ catch ( StaleConfigException& e ) {
+ if ( loops <= 0 )
+ throw e;
+
+ loops--;
+ log() << "retrying command: " << q.query << endl;
+
+ // For legacy reasons, ns may not actually be set in the exception :-(
+ string staleNS = e.getns();
+ if( staleNS.size() == 0 ) staleNS = q.ns;
+
+ ShardConnection::checkMyConnectionVersions( staleNS );
+ if( loops < 4 ) versionManager.forceRemoteCheckShardVersionCB( staleNS );
+ }
+ catch ( AssertionException& e ) {
+ e.getInfo().append( builder , "assertion" , "assertionCode" );
+ builder.append( "errmsg" , "db assertion failure" );
+ builder.append( "ok" , 0 );
+ BSONObj x = builder.done();
+ replyToQuery(0, r.p(), r.m(), x);
+ return;
+ }
+ }
+
+ string commandName = q.query.firstElementFieldName();
+
+ uasserted(13390, "unrecognized command: " + commandName);
+ }
+
+ doQuery( r , r.primaryShard() );
+ }
+
+ // Deprecated
+ virtual void getMore( Request& r ) {
+ // Don't use anymore, moved logic to strategy_shard, will remove in larger refactor
+ verify( 0 );
+ }
+
+ // Deprecated
+ virtual void writeOp( int op , Request& r ) {
+ // Don't use anymore, requires single-step detection of chunk manager or primary
+ verify( 0 );
+ }
+
+ bool handleSpecialNamespaces( Request& r , QueryMessage& q ) {
+ const char * ns = r.getns();
+ ns = strstr( r.getns() , ".$cmd.sys." );
+ if ( ! ns )
+ return false;
+ ns += 10;
+
+ r.checkAuth( Auth::WRITE );
+
+ BSONObjBuilder b;
+ vector<Shard> shards;
+
+ if ( strcmp( ns , "inprog" ) == 0 ) {
+ Shard::getAllShards( shards );
+
+ BSONArrayBuilder arr( b.subarrayStart( "inprog" ) );
+
+ for ( unsigned i=0; i<shards.size(); i++ ) {
+ Shard shard = shards[i];
+ scoped_ptr<ScopedDbConnection> conn(
+ ScopedDbConnection::getScopedDbConnection( shard.getConnString() ) );
+ BSONObj temp = conn->get()->findOne( r.getns() , q.query );
+ if ( temp["inprog"].isABSONObj() ) {
+ BSONObjIterator i( temp["inprog"].Obj() );
+ while ( i.more() ) {
+ BSONObjBuilder x;
+
+ BSONObjIterator j( i.next().Obj() );
+ while( j.more() ) {
+ BSONElement e = j.next();
+ if ( str::equals( e.fieldName() , "opid" ) ) {
+ stringstream ss;
+ ss << shard.getName() << ':' << e.numberInt();
+ x.append( "opid" , ss.str() );
+ }
+ else if ( str::equals( e.fieldName() , "client" ) ) {
+ x.appendAs( e , "client_s" );
+ }
+ else {
+ x.append( e );
+ }
+ }
+ arr.append( x.obj() );
+ }
+ }
+ conn->done();
+ }
+
+ arr.done();
+ }
+ else if ( strcmp( ns , "killop" ) == 0 ) {
+ r.checkAuth( Auth::WRITE , "admin" );
+
+ BSONElement e = q.query["op"];
+ if ( e.type() != String ) {
+ b.append( "err" , "bad op" );
+ b.append( e );
+ }
+ else {
+ b.append( e );
+ string s = e.String();
+ string::size_type i = s.find( ':' );
+ if ( i == string::npos ) {
+ b.append( "err" , "bad opid" );
+ }
+ else {
+ string shard = s.substr( 0 , i );
+ int opid = atoi( s.substr( i + 1 ).c_str() );
+ b.append( "shard" , shard );
+ b.append( "shardid" , opid );
+
+ log() << "want to kill op: " << e << endl;
+ Shard s(shard);
+
+ scoped_ptr<ScopedDbConnection> conn(
+ ScopedDbConnection::getScopedDbConnection( s.getConnString() ) );
+ conn->get()->findOne( r.getns() , BSON( "op" << opid ) );
+ conn->done();
+ }
+ }
+ }
+ else if ( strcmp( ns , "unlock" ) == 0 ) {
+ b.append( "err" , "can't do unlock through mongos" );
+ }
+ else {
+ log( LL_WARNING ) << "unknown sys command [" << ns << "]" << endl;
+ return false;
+ }
+
+ BSONObj x = b.done();
+ replyToQuery(0, r.p(), r.m(), x);
+ return true;
+ }
+ };
+
+ Strategy * SINGLE = new SingleStrategy();
+}