diff options
author | Dwight Merriman <dwight@10gen.com> | 2010-04-29 10:52:49 -0400 |
---|---|---|
committer | Dwight Merriman <dwight@10gen.com> | 2010-04-29 10:52:49 -0400 |
commit | 492d1b8764d423593b77af98233dd0123ee258d2 (patch) | |
tree | eb2122263436f9b0a4756871aa7d3694a10a42f6 | |
parent | 577afd27569725ebe98ccb6aebfb50bd94a04d72 (diff) | |
parent | 5e8355818848719b263b24b9c8fc279f18819bbe (diff) | |
download | mongo-492d1b8764d423593b77af98233dd0123ee258d2.tar.gz |
Merge branch 'master' of github.com:mongodb/mongo
-rw-r--r-- | SConstruct | 2 | ||||
-rw-r--r-- | bson/bsoninlines.h | 4 | ||||
-rw-r--r-- | client/connpool.cpp | 41 | ||||
-rw-r--r-- | client/connpool.h | 20 | ||||
-rw-r--r-- | client/dbclient.cpp | 145 | ||||
-rw-r--r-- | client/dbclient.h | 146 | ||||
-rw-r--r-- | client/dbclientcursor.cpp | 190 | ||||
-rw-r--r-- | client/dbclientcursor.h | 172 | ||||
-rw-r--r-- | db/repl.cpp | 9 | ||||
-rw-r--r-- | jstests/sharding/shard6.js | 62 | ||||
-rw-r--r-- | s/shard.cpp | 4 | ||||
-rw-r--r-- | s/strategy.cpp | 3 | ||||
-rw-r--r-- | util/assert_util.h | 4 |
13 files changed, 487 insertions, 315 deletions
diff --git a/SConstruct b/SConstruct index 4628f11ca69..026e87cb85b 100644 --- a/SConstruct +++ b/SConstruct @@ -364,7 +364,7 @@ commonFiles += [ "util/background.cpp" , "util/mmap.cpp" , "util/ramstore.cpp", "util/assert_util.cpp" , "util/httpclient.cpp" , "util/md5main.cpp" , "util/base64.cpp", "util/debug_util.cpp", "util/thread_pool.cpp" ] commonFiles += Glob( "util/*.c" ) -commonFiles += Split( "client/connpool.cpp client/dbclient.cpp client/model.cpp client/syncclusterconnection.cpp" ) +commonFiles += Split( "client/connpool.cpp client/dbclient.cpp client/dbclientcursor.cpp client/model.cpp client/syncclusterconnection.cpp" ) commonFiles += [ "scripting/engine.cpp" , "scripting/utils.cpp" ] #mmap stuff diff --git a/bson/bsoninlines.h b/bson/bsoninlines.h index 9907772eef5..5ff47957724 100644 --- a/bson/bsoninlines.h +++ b/bson/bsoninlines.h @@ -330,10 +330,10 @@ namespace mongo { { const char *p = value(); size_t len1 = ( maxLen == -1 ) ? strlen( p ) : strnlen( p, remain ); - massert( 10318 , "Invalid regex string", len1 != -1 ); + //massert( 10318 , "Invalid regex string", len1 != -1 ); // ERH - 4/28/10 - don't think this does anything p = p + len1 + 1; size_t len2 = ( maxLen == -1 ) ? strlen( p ) : strnlen( p, remain - len1 - 1 ); - massert( 10319 , "Invalid regex options string", len2 != -1 ); + //massert( 10319 , "Invalid regex options string", len2 != -1 ); // ERH - 4/28/10 - don't think this does anything x = (int) (len1 + 1 + len2 + 1); } break; diff --git a/client/connpool.cpp b/client/connpool.cpp index 080fcfe1e5d..d81f26a8295 100644 --- a/client/connpool.cpp +++ b/client/connpool.cpp @@ -28,9 +28,9 @@ namespace mongo { DBConnectionPool pool; DBClientBase* DBConnectionPool::get(const string& host) { - scoped_lock L(poolMutex); + scoped_lock L(_mutex); - PoolForHost *&p = pools[host]; + PoolForHost *&p = _pools[host]; if ( p == 0 ) p = new PoolForHost(); if ( p->pool.empty() ) { @@ -65,6 +65,7 @@ namespace mongo { uassert( 13071 , (string)"invalid hostname [" + host + "]" , 0 ); c = 0; // prevents compiler warning } + p->created++; return c; } DBClientBase *c = p->pool.top(); @@ -74,8 +75,8 @@ namespace mongo { } void DBConnectionPool::flush(){ - scoped_lock L(poolMutex); - for ( map<string,PoolForHost*>::iterator i = pools.begin(); i != pools.end(); i++ ){ + scoped_lock L(_mutex); + for ( map<string,PoolForHost*>::iterator i = _pools.begin(); i != _pools.end(); i++ ){ PoolForHost* p = i->second; vector<DBClientBase*> all; @@ -115,6 +116,19 @@ namespace mongo { } } + void DBConnectionPool::appendInfo( BSONObjBuilder& b ){ + scoped_lock lk( _mutex ); + BSONObjBuilder bb( b.subobjStart( "hosts" ) ); + for ( map<string,PoolForHost*>::iterator i=_pools.begin(); i!=_pools.end(); ++i ){ + string s = i->first; + BSONObjBuilder temp( bb.subobjStart( s.c_str() ) ); + temp.append( "available" , (int)(i->second->pool.size()) ); + temp.appendNumber( "created" , i->second->created ); + temp.done(); + } + bb.done(); + } + ScopedDbConnection * ScopedDbConnection::steal(){ assert( _conn ); ScopedDbConnection * n = new ScopedDbConnection( _host , _conn ); @@ -133,12 +147,11 @@ namespace mongo { class PoolFlushCmd : public Command { public: - PoolFlushCmd() : Command( "connpoolsync" ){} + PoolFlushCmd() : Command( "connPoolSync" , false , "connpoolsync" ){} virtual void help( stringstream &help ) const { help<<"internal"; } virtual LockType locktype() const { return NONE; } virtual bool run(const char*, mongo::BSONObj&, std::string&, mongo::BSONObjBuilder& result, bool){ pool.flush(); - result << "ok" << 1; return true; } virtual bool slaveOk() const { @@ -147,4 +160,20 @@ namespace mongo { } 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 char*, mongo::BSONObj&, std::string&, mongo::BSONObjBuilder& result, bool){ + pool.appendInfo( result ); + return true; + } + virtual bool slaveOk() const { + return true; + } + + } poolStatsCmd; + + } // namespace mongo diff --git a/client/connpool.h b/client/connpool.h index 786ecc19f40..f39fc8da8ae 100644 --- a/client/connpool.h +++ b/client/connpool.h @@ -24,7 +24,10 @@ namespace mongo { struct PoolForHost { + PoolForHost() + : created(0){} std::stack<DBClientBase*> pool; + long long created; }; class DBConnectionHook { @@ -52,8 +55,8 @@ namespace mongo { } */ class DBConnectionPool { - mongo::mutex poolMutex; - map<string,PoolForHost*> pools; // servername -> pool + mongo::mutex _mutex; + map<string,PoolForHost*> _pools; // servername -> pool list<DBConnectionHook*> _hooks; void onCreate( DBClientBase * conn ); @@ -64,12 +67,13 @@ namespace mongo { void release(const string& host, DBClientBase *c) { if ( c->isFailed() ) return; - scoped_lock L(poolMutex); - pools[host]->pool.push(c); + scoped_lock L(_mutex); + _pools[host]->pool.push(c); } void addHook( DBConnectionHook * hook ); + void appendInfo( BSONObjBuilder& b ); }; - + extern DBConnectionPool pool; /** Use to get a connection from the pool. On exceptions things @@ -98,18 +102,20 @@ namespace mongo { } ScopedDbConnection() - : _host( "" ) , _conn(0 ){ + : _host( "" ) , _conn(0) { } /** throws UserException if can't connect */ ScopedDbConnection(const string& host) : _host(host), _conn( pool.get(host) ) { } - + ScopedDbConnection(const string& host, DBClientBase* conn ) : _host( host ) , _conn( conn ){ } + string getHost() const { return _host; } + /** Force closure of the connection. You should call this if you leave it in a bad state. Destructor will do this too, but it is verbose. */ diff --git a/client/dbclient.cpp b/client/dbclient.cpp index 310b7a11870..d7ff9cb1d82 100644 --- a/client/dbclient.cpp +++ b/client/dbclient.cpp @@ -764,151 +764,6 @@ namespace mongo { } } - int DBClientCursor::nextBatchSize(){ - if ( nToReturn == 0 ) - return batchSize; - if ( batchSize == 0 ) - return nToReturn; - - return batchSize < nToReturn ? batchSize : nToReturn; - } - - bool DBClientCursor::init() { - Message toSend; - if ( !cursorId ) { - assembleRequest( ns, query, nextBatchSize() , nToSkip, fieldsToReturn, opts, toSend ); - } else { - BufBuilder b; - b.append( opts ); - b.append( ns.c_str() ); - b.append( nToReturn ); - b.append( cursorId ); - toSend.setData( dbGetMore, b.buf(), b.len() ); - } - if ( !connector->call( toSend, *m, false ) ) - return false; - if ( ! m->data ) - return false; - dataReceived(); - return true; - } - - void DBClientCursor::requestMore() { - assert( cursorId && pos == nReturned ); - - if (haveLimit){ - nToReturn -= nReturned; - assert(nToReturn > 0); - } - BufBuilder b; - b.append(opts); - b.append(ns.c_str()); - b.append(nextBatchSize()); - b.append(cursorId); - - Message toSend; - toSend.setData(dbGetMore, b.buf(), b.len()); - auto_ptr<Message> response(new Message()); - connector->call( toSend, *response ); - - m = response; - dataReceived(); - } - - void DBClientCursor::dataReceived() { - QueryResult *qr = (QueryResult *) m->data; - resultFlags = qr->resultFlags(); - - if ( qr->resultFlags() & QueryResult::ResultFlag_CursorNotFound ) { - // cursor id no longer valid at the server. - assert( qr->cursorId == 0 ); - cursorId = 0; // 0 indicates no longer valid (dead) - if ( ! ( opts & QueryOption_CursorTailable ) ) - throw UserException( 13127 , "getMore: cursor didn't exist on server, possible restart or timeout?" ); - } - - if ( cursorId == 0 || ! ( opts & QueryOption_CursorTailable ) ) { - // only set initially: we don't want to kill it on end of data - // if it's a tailable cursor - cursorId = qr->cursorId; - } - - nReturned = qr->nReturned; - pos = 0; - data = qr->data(); - - connector->checkResponse( data, nReturned ); - /* this assert would fire the way we currently work: - assert( nReturned || cursorId == 0 ); - */ - } - - /** If true, safe to call next(). Requests more from server if necessary. */ - bool DBClientCursor::more() { - if ( !_putBack.empty() ) - return true; - - if (haveLimit && pos >= nToReturn) - return false; - - if ( pos < nReturned ) - return true; - - if ( cursorId == 0 ) - return false; - - requestMore(); - return pos < nReturned; - } - - BSONObj DBClientCursor::next() { - assert( more() ); - if ( !_putBack.empty() ) { - BSONObj ret = _putBack.top(); - _putBack.pop(); - return ret; - } - pos++; - BSONObj o(data); - data += o.objsize(); - return o; - } - - void DBClientCursor::attach( ScopedDbConnection * conn ){ - assert( ! _scopedConn ); - _scopedConn = conn->steal(); - } - - - - DBClientCursor::~DBClientCursor() { - DESTRUCTOR_GUARD ( - - if ( cursorId && _ownCursor ) { - BufBuilder b; - b.append( (int)0 ); // reserved - b.append( (int)1 ); // number - b.append( cursorId ); - - Message m; - m.setData( dbKillCursors , b.buf() , b.len() ); - - connector->sayPiggyBack( m ); - } - - if ( _scopedConn ){ - if ( moreInCurrentBatch() ){ - log() << "warning: cursor deleted, but moreInCurrentBatch and scoped conn." << endl; - } - else { - _scopedConn->done(); - } - delete _scopedConn; - } - - ); - } - /* --- class dbclientpaired --- */ string DBClientPaired::toString() { diff --git a/client/dbclient.h b/client/dbclient.h index 4e8e2aa5314..0c69a4f0cec 100644 --- a/client/dbclient.h +++ b/client/dbclient.h @@ -84,6 +84,7 @@ namespace mongo { class BSONObj; class ScopedDbConnection; + class DBClientCursor; /** Represents a Mongo query expression. Typically one uses the QUERY(...) macro to construct a Query object. Examples: @@ -209,149 +210,6 @@ namespace mongo { virtual void checkResponse( const string &data, int nReturned ) {} }; - /** Queries return a cursor object */ - class DBClientCursor : boost::noncopyable { - public: - /** If true, safe to call next(). Requests more from server if necessary. */ - bool more(); - - /** If true, there is more in our local buffers to be fetched via next(). Returns - false when a getMore request back to server would be required. You can use this - if you want to exhaust whatever data has been fetched to the client already but - then perhaps stop. - */ - bool moreInCurrentBatch() { return !_putBack.empty() || pos < nReturned; } - - /** next - @return next object in the result cursor. - on an error at the remote server, you will get back: - { $err: <string> } - if you do not want to handle that yourself, call nextSafe(). - */ - BSONObj next(); - - /** - restore an object previously returned by next() to the cursor - */ - void putBack( const BSONObj &o ) { _putBack.push( o.getOwned() ); } - - /** throws AssertionException if get back { $err : ... } */ - BSONObj nextSafe() { - BSONObj o = next(); - BSONElement e = o.firstElement(); - if( strcmp(e.fieldName(), "$err") == 0 ) { - if( logLevel >= 5 ) - log() << "nextSafe() error " << o.toString() << endl; - uassert(13106, "nextSafe() returns $err", false); - } - return o; - } - - /** - iterate the rest of the cursor and return the number if items - */ - int itcount(){ - int c = 0; - while ( more() ){ - next(); - c++; - } - return c; - } - - /** cursor no longer valid -- use with tailable cursors. - note you should only rely on this once more() returns false; - 'dead' may be preset yet some data still queued and locally - available from the dbclientcursor. - */ - bool isDead() const { - return cursorId == 0; - } - - bool tailable() const { - return (opts & QueryOption_CursorTailable) != 0; - } - - /** see QueryResult::ResultFlagType (db/dbmessage.h) for flag values - mostly these flags are for internal purposes - - ResultFlag_ErrSet is the possible exception to that - */ - bool hasResultFlag( int flag ){ - return (resultFlags & flag) != 0; - } - - DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj _query, int _nToReturn, - int _nToSkip, const BSONObj *_fieldsToReturn, int queryOptions , int bs ) : - connector(_connector), - ns(_ns), - query(_query), - nToReturn(_nToReturn), - haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_CursorTailable)), - nToSkip(_nToSkip), - fieldsToReturn(_fieldsToReturn), - opts(queryOptions), - batchSize(bs), - m(new Message()), - cursorId(), - nReturned(), - pos(), - data(), - _ownCursor( true ), - _scopedConn(0){ - } - - DBClientCursor( DBConnector *_connector, const string &_ns, long long _cursorId, int _nToReturn, int options ) : - connector(_connector), - ns(_ns), - nToReturn( _nToReturn ), - haveLimit( _nToReturn > 0 && !(options & QueryOption_CursorTailable)), - opts( options ), - m(new Message()), - cursorId( _cursorId ), - nReturned(), - pos(), - data(), - _ownCursor( true ), - _scopedConn(0){ - } - - virtual ~DBClientCursor(); - - long long getCursorId() const { return cursorId; } - - /** by default we "own" the cursor and will send the server a KillCursor - message when ~DBClientCursor() is called. This function overrides that. - */ - void decouple() { _ownCursor = false; } - - void attach( ScopedDbConnection * conn ); - - private: - friend class DBClientBase; - bool init(); - int nextBatchSize(); - DBConnector *connector; - string ns; - BSONObj query; - int nToReturn; - bool haveLimit; - int nToSkip; - const BSONObj *fieldsToReturn; - int opts; - int batchSize; - auto_ptr<Message> m; - stack< BSONObj > _putBack; - int resultFlags; - long long cursorId; - int nReturned; - int pos; - const char *data; - void dataReceived(); - void requestMore(); - bool _ownCursor; // see decouple() - ScopedDbConnection * _scopedConn; - }; - /** The interface that any db connection should implement */ @@ -967,4 +825,6 @@ namespace mongo { } // namespace mongo +#include "dbclientcursor.h" + #include "undef_macros.h" diff --git a/client/dbclientcursor.cpp b/client/dbclientcursor.cpp new file mode 100644 index 00000000000..2dbd55c9a30 --- /dev/null +++ b/client/dbclientcursor.cpp @@ -0,0 +1,190 @@ +// dbclient.cpp - connect to a Mongo database as a database, from C++ + +/* 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 "dbclient.h" +#include "../db/dbmessage.h" +#include "../db/cmdline.h" +#include "connpool.h" + +namespace mongo { + + void assembleRequest( const string &ns, BSONObj query, int nToReturn, int nToSkip, const BSONObj *fieldsToReturn, int queryOptions, Message &toSend ); + + int DBClientCursor::nextBatchSize(){ + if ( nToReturn == 0 ) + return batchSize; + if ( batchSize == 0 ) + return nToReturn; + + return batchSize < nToReturn ? batchSize : nToReturn; + } + + bool DBClientCursor::init() { + Message toSend; + if ( !cursorId ) { + assembleRequest( ns, query, nextBatchSize() , nToSkip, fieldsToReturn, opts, toSend ); + } else { + BufBuilder b; + b.append( opts ); + b.append( ns.c_str() ); + b.append( nToReturn ); + b.append( cursorId ); + toSend.setData( dbGetMore, b.buf(), b.len() ); + } + if ( !connector->call( toSend, *m, false ) ) + return false; + if ( ! m->data ) + return false; + dataReceived(); + return true; + } + + void DBClientCursor::requestMore() { + assert( cursorId && pos == nReturned ); + + if (haveLimit){ + nToReturn -= nReturned; + assert(nToReturn > 0); + } + BufBuilder b; + b.append(opts); + b.append(ns.c_str()); + b.append(nextBatchSize()); + b.append(cursorId); + + Message toSend; + toSend.setData(dbGetMore, b.buf(), b.len()); + auto_ptr<Message> response(new Message()); + + if ( connector ){ + connector->call( toSend, *response ); + m = response; + dataReceived(); + } + else { + assert( _scopedHost.size() ); + ScopedDbConnection conn( _scopedHost ); + conn->call( toSend , *response ); + connector = conn.get(); + m = response; + dataReceived(); + connector = 0; + conn.done(); + } + + + + } + + void DBClientCursor::dataReceived() { + QueryResult *qr = (QueryResult *) m->data; + resultFlags = qr->resultFlags(); + + if ( qr->resultFlags() & QueryResult::ResultFlag_CursorNotFound ) { + // cursor id no longer valid at the server. + assert( qr->cursorId == 0 ); + cursorId = 0; // 0 indicates no longer valid (dead) + if ( ! ( opts & QueryOption_CursorTailable ) ) + throw UserException( 13127 , "getMore: cursor didn't exist on server, possible restart or timeout?" ); + } + + if ( cursorId == 0 || ! ( opts & QueryOption_CursorTailable ) ) { + // only set initially: we don't want to kill it on end of data + // if it's a tailable cursor + cursorId = qr->cursorId; + } + + nReturned = qr->nReturned; + pos = 0; + data = qr->data(); + + connector->checkResponse( data, nReturned ); + /* this assert would fire the way we currently work: + assert( nReturned || cursorId == 0 ); + */ + } + + /** If true, safe to call next(). Requests more from server if necessary. */ + bool DBClientCursor::more() { + if ( !_putBack.empty() ) + return true; + + if (haveLimit && pos >= nToReturn) + return false; + + if ( pos < nReturned ) + return true; + + if ( cursorId == 0 ) + return false; + + requestMore(); + return pos < nReturned; + } + + BSONObj DBClientCursor::next() { + assert( more() ); + if ( !_putBack.empty() ) { + BSONObj ret = _putBack.top(); + _putBack.pop(); + return ret; + } + pos++; + BSONObj o(data); + data += o.objsize(); + return o; + } + + void DBClientCursor::attach( ScopedDbConnection * conn ){ + assert( _scopedHost.size() == 0 ); + assert( connector == conn->get() ); + _scopedHost = conn->getHost(); + conn->done(); + connector = 0; + } + + + + DBClientCursor::~DBClientCursor() { + DESTRUCTOR_GUARD ( + + if ( cursorId && _ownCursor ) { + BufBuilder b; + b.append( (int)0 ); // reserved + b.append( (int)1 ); // number + b.append( cursorId ); + + Message m; + m.setData( dbKillCursors , b.buf() , b.len() ); + + if ( connector ){ + connector->sayPiggyBack( m ); + } + else { + assert( _scopedHost.size() ); + ScopedDbConnection conn( _scopedHost ); + conn->sayPiggyBack( m ); + conn.done(); + } + } + + ); + } + + +} // namespace mongo diff --git a/client/dbclientcursor.h b/client/dbclientcursor.h new file mode 100644 index 00000000000..35829494e36 --- /dev/null +++ b/client/dbclientcursor.h @@ -0,0 +1,172 @@ +// file dbclientcursor.h + +/* 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. + */ + +#pragma once + +#include "../pch.h" +#include "../util/message.h" +#include "../db/jsobj.h" +#include "../db/json.h" +#include <stack> + +namespace mongo { + + /** Queries return a cursor object */ + class DBClientCursor : boost::noncopyable { + public: + /** If true, safe to call next(). Requests more from server if necessary. */ + bool more(); + + /** If true, there is more in our local buffers to be fetched via next(). Returns + false when a getMore request back to server would be required. You can use this + if you want to exhaust whatever data has been fetched to the client already but + then perhaps stop. + */ + bool moreInCurrentBatch() { return !_putBack.empty() || pos < nReturned; } + + /** next + @return next object in the result cursor. + on an error at the remote server, you will get back: + { $err: <string> } + if you do not want to handle that yourself, call nextSafe(). + */ + BSONObj next(); + + /** + restore an object previously returned by next() to the cursor + */ + void putBack( const BSONObj &o ) { _putBack.push( o.getOwned() ); } + + /** throws AssertionException if get back { $err : ... } */ + BSONObj nextSafe() { + BSONObj o = next(); + BSONElement e = o.firstElement(); + if( strcmp(e.fieldName(), "$err") == 0 ) { + if( logLevel >= 5 ) + log() << "nextSafe() error " << o.toString() << endl; + uassert(13106, "nextSafe() returns $err", false); + } + return o; + } + + /** + iterate the rest of the cursor and return the number if items + */ + int itcount(){ + int c = 0; + while ( more() ){ + next(); + c++; + } + return c; + } + + /** cursor no longer valid -- use with tailable cursors. + note you should only rely on this once more() returns false; + 'dead' may be preset yet some data still queued and locally + available from the dbclientcursor. + */ + bool isDead() const { + return cursorId == 0; + } + + bool tailable() const { + return (opts & QueryOption_CursorTailable) != 0; + } + + /** see QueryResult::ResultFlagType (db/dbmessage.h) for flag values + mostly these flags are for internal purposes - + ResultFlag_ErrSet is the possible exception to that + */ + bool hasResultFlag( int flag ){ + return (resultFlags & flag) != 0; + } + + DBClientCursor( DBConnector *_connector, const string &_ns, BSONObj _query, int _nToReturn, + int _nToSkip, const BSONObj *_fieldsToReturn, int queryOptions , int bs ) : + connector(_connector), + ns(_ns), + query(_query), + nToReturn(_nToReturn), + haveLimit( _nToReturn > 0 && !(queryOptions & QueryOption_CursorTailable)), + nToSkip(_nToSkip), + fieldsToReturn(_fieldsToReturn), + opts(queryOptions), + batchSize(bs), + m(new Message()), + cursorId(), + nReturned(), + pos(), + data(), + _ownCursor( true ){ + } + + DBClientCursor( DBConnector *_connector, const string &_ns, long long _cursorId, int _nToReturn, int options ) : + connector(_connector), + ns(_ns), + nToReturn( _nToReturn ), + haveLimit( _nToReturn > 0 && !(options & QueryOption_CursorTailable)), + opts( options ), + m(new Message()), + cursorId( _cursorId ), + nReturned(), + pos(), + data(), + _ownCursor( true ){ + } + + virtual ~DBClientCursor(); + + long long getCursorId() const { return cursorId; } + + /** by default we "own" the cursor and will send the server a KillCursor + message when ~DBClientCursor() is called. This function overrides that. + */ + void decouple() { _ownCursor = false; } + + void attach( ScopedDbConnection * conn ); + + private: + friend class DBClientBase; + bool init(); + int nextBatchSize(); + DBConnector *connector; + string ns; + BSONObj query; + int nToReturn; + bool haveLimit; + int nToSkip; + const BSONObj *fieldsToReturn; + int opts; + int batchSize; + auto_ptr<Message> m; + stack< BSONObj > _putBack; + int resultFlags; + long long cursorId; + int nReturned; + int pos; + const char *data; + void dataReceived(); + void requestMore(); + bool _ownCursor; // see decouple() + string _scopedHost; + }; + + +} // namespace mongo + +#include "undef_macros.h" diff --git a/db/repl.cpp b/db/repl.cpp index 8edd1b10399..72e21b9ea99 100644 --- a/db/repl.cpp +++ b/db/repl.cpp @@ -890,12 +890,17 @@ namespace mongo { else if ( *opType == 'n' ) { // no op } - else { + else if ( *opType == 'c' ){ BufBuilder bb; BSONObjBuilder ob; - assert( *opType == 'c' ); _runCommands(ns, o, bb, ob, true, 0); } + else { + stringstream ss; + ss << "unknown opType [" << opType << "]"; + throw MsgAssertionException( 13141 , ss.str() ); + } + } catch ( UserException& e ) { log() << "sync: caught user assertion " << e << " while applying op: " << op << endl;; diff --git a/jstests/sharding/shard6.js b/jstests/sharding/shard6.js index 5fd87c312f7..efcd7f85809 100644 --- a/jstests/sharding/shard6.js +++ b/jstests/sharding/shard6.js @@ -1,12 +1,30 @@ // shard6.js -s = new ShardingTest( "shard6" , 2 , 0 , 1 ); +summary = ""; + +s = new ShardingTest( "shard6" , 2 , 0 , 2 ); s.adminCommand( { enablesharding : "test" } ); s.adminCommand( { shardcollection : "test.data" , key : { num : 1 } } ); db = s.getDB( "test" ); +function poolStats( where ){ + var total = 0; + var msg = "poolStats " + where + " "; + var x = db.runCommand( "connPoolStats" ).hosts + for ( var h in x ){ + var z = x[h]; + msg += z.created + " "; + total += z.created + } + print( "****\n" + msg + "\n*****" ) + summary += msg + "\n"; + return total +} + +poolStats( "at start" ) + // we want a lot of data, so lets make a 50k string to cheat :) bigString = ""; while ( bigString.length < 50000 ) @@ -18,7 +36,9 @@ for ( ; num<100; num++ ){ db.data.save( { num : num , bigString : bigString } ); } -assert.eq( 100 , db.data.find().toArray().length ); +assert.eq( 100 , db.data.find().toArray().length , "basic find after setup" ); + +connBefore = poolStats( "setup done" ) // limit @@ -27,8 +47,11 @@ assert.eq( 1 , db.data.find().limit(1).itcount() , "limit test 2" ); for ( var i=1; i<10; i++ ){ assert.eq( i , db.data.find().limit(i).itcount() , "limit test 3a : " + i ); assert.eq( i , db.data.find().skip(i).limit(i).itcount() , "limit test 3b : " + i ); + poolStats( "after loop : " + i ); } +assert.eq( connBefore , poolStats( "limit test done" ) , "limit test conns" ); + function assertOrder( start , num ){ var a = db.data.find().skip(start).limit(num).sort( { num : 1 } ).map( function(z){ return z.num; } ); var c = [] @@ -40,12 +63,34 @@ function assertOrder( start , num ){ assertOrder( 0 , 10 ); assertOrder( 5 , 10 ); -assert.eq( 5 , db.data.find().skip( num - 5 ).itcount() , "skip 1 " ); -assert.eq( 5 , db.data.find().skip( num - 5 ).sort( { num : 1 } ).itcount() , "skip 2 " ); -assert.eq( 5 , db.data.find().skip( num - 5 ).sort( { _id : 1 } ).itcount() , "skip 3 " ); -assert.eq( 0 , db.data.find().skip( num + 5 ).sort( { num : 1 } ).itcount() , "skip 4 " ); -assert.eq( 0 , db.data.find().skip( num + 5 ).sort( { _id : 1 } ).itcount() , "skip 5 " ); +poolStats( "after checking order" ) +function doItCount( skip , sort , batchSize ){ + var c = db.data.find(); + if ( skip ) + c.skip( skip ) + if ( sort ) + c.sort( sort ); + if ( batchSize ) + c.batchSize( batchSize ) + return c.itcount(); + +} + +function checkItCount( batchSize ){ + assert.eq( 5 , doItCount( num - 5 , null , batchSize ) , "skip 1 " + batchSize ); + assert.eq( 5 , doItCount( num - 5 , { num : 1 } , batchSize ) , "skip 2 " + batchSize ); + assert.eq( 5 , doItCount( num - 5 , { _id : 1 } , batchSize ) , "skip 3 " + batchSize ); + assert.eq( 0 , doItCount( num + 5 , { num : 1 } , batchSize ) , "skip 4 " + batchSize ); + assert.eq( 0 , doItCount( num + 5 , { _id : 1 } , batchSize ) , "skip 5 " + batchSize ); +} + +poolStats( "before checking itcount" ) + +checkItCount( 0 ) +checkItCount( 2 ) + +poolStats( "after checking itcount" ) // --- test save support --- @@ -54,4 +99,7 @@ o.x = 16; db.data.save( o ); assert.eq( 16 , db.data.findOne( { _id : o._id } ).x , "x1 - did save fail?" ); +poolStats( "at end" ) + +print( summary ) s.stop(); diff --git a/s/shard.cpp b/s/shard.cpp index 666375af588..ed8524149f5 100644 --- a/s/shard.cpp +++ b/s/shard.cpp @@ -72,12 +72,14 @@ namespace mongo { if ( setAddr ) _lookup[addr] = s; } - + void getAllShards( list<Shard>& all ){ scoped_lock lk( _mutex ); std::set<string> seen; for ( map<string,Shard>::iterator i = _lookup.begin(); i!=_lookup.end(); ++i ){ Shard s = i->second; + if ( s.getName() == "config" ) + continue; if ( seen.count( s.getName() ) ) continue; seen.insert( s.getName() ); diff --git a/s/strategy.cpp b/s/strategy.cpp index 453b5e31f3c..9ea2b06799f 100644 --- a/s/strategy.cpp +++ b/s/strategy.cpp @@ -185,12 +185,13 @@ namespace mongo { << " my last seq: " << sequenceNumber << " current: " << officialSequenceNumber << " version: " << version << " manager: " << manager << endl; - + BSONObj result; if ( setShardVersion( conn , ns , version , authoritative , result ) ){ // success! log(1) << " setShardVersion success!" << endl; sequenceNumber = officialSequenceNumber; + dassert( sequenceNumber == checkShardVersionLastSequence[ make_pair(&conn,ns) ] ); return; } diff --git a/util/assert_util.h b/util/assert_util.h index 53800f685e5..d10c1dc8e6a 100644 --- a/util/assert_util.h +++ b/util/assert_util.h @@ -137,6 +137,10 @@ namespace mongo { code = c; msg = m; } + MsgAssertionException(int c, const string& m) { + code = c; + msg = m; + } virtual bool severe() { return false; } |