diff options
author | Antonin Kral <a.kral@bobek.cz> | 2012-06-05 19:50:34 +0200 |
---|---|---|
committer | Antonin Kral <a.kral@bobek.cz> | 2012-06-05 19:50:34 +0200 |
commit | 3703a282eca7e79e91f4bd651b1b861b76dc6c68 (patch) | |
tree | b69552c69c48ebc6899f7bbbe42843793a423237 | |
parent | 61619b3142c1de8f60f91964ff2656054d4f11a6 (diff) | |
download | mongodb-3703a282eca7e79e91f4bd651b1b861b76dc6c68.tar.gz |
Imported Upstream version 2.0.6
-rw-r--r-- | SConstruct | 10 | ||||
-rw-r--r-- | bson/util/builder.h | 49 | ||||
-rw-r--r-- | client/dbclient_rs.cpp | 27 | ||||
-rw-r--r-- | client/dbclient_rs.h | 5 | ||||
-rw-r--r-- | db/cloner.cpp | 6 | ||||
-rw-r--r-- | db/compact.cpp | 5 | ||||
-rw-r--r-- | db/dbwebserver.cpp | 11 | ||||
-rw-r--r-- | db/queryoptimizer.cpp | 51 | ||||
-rw-r--r-- | db/queryoptimizer.h | 1 | ||||
-rw-r--r-- | db/repl.cpp | 2 | ||||
-rw-r--r-- | db/repl/rs_initialsync.cpp | 45 | ||||
-rw-r--r-- | db/security_common.h | 4 | ||||
-rw-r--r-- | doxygenConfig | 2 | ||||
-rw-r--r-- | jstests/queryoptimizer7.js | 24 | ||||
-rw-r--r-- | jstests/queryoptimizera.js | 87 | ||||
-rw-r--r-- | jstests/replsets/replset7.js | 46 | ||||
-rw-r--r-- | jstests/replsets/slavedelay3.js | 38 | ||||
-rw-r--r-- | jstests/slowNightly/sharding_passthrough.js | 2 | ||||
-rw-r--r-- | rpm/mongo.spec | 2 | ||||
-rw-r--r-- | s/d_migrate.cpp | 57 | ||||
-rw-r--r-- | s/d_state.cpp | 9 | ||||
-rw-r--r-- | shell/utils.js | 3 | ||||
-rw-r--r-- | third_party/js-1.7/jsprf.c | 2 | ||||
-rw-r--r-- | util/net/sock.cpp | 26 | ||||
-rw-r--r-- | util/version.cpp | 2 |
25 files changed, 408 insertions, 108 deletions
@@ -713,11 +713,11 @@ if nix: env.Append( LIBS=[] ) #make scons colorgcc friendly - env['ENV']['HOME'] = os.environ['HOME'] - try: - env['ENV']['TERM'] = os.environ['TERM'] - except KeyError: - pass + for key in ('HOME', 'TERM'): + try: + env['ENV'][key] = os.environ[key] + except KeyError: + pass if linux and has_option( "sharedclient" ): env.Append( LINKFLAGS=" -Wl,--as-needed -Wl,-zdefs " ) diff --git a/bson/util/builder.h b/bson/util/builder.h index f189f58..a5c71a8 100644 --- a/bson/util/builder.h +++ b/bson/util/builder.h @@ -17,6 +17,7 @@ #pragma once +#include <cfloat> #include <string> #include <string.h> #include <stdio.h> @@ -36,7 +37,7 @@ namespace mongo { const int BSONObjMaxUserSize = 16 * 1024 * 1024; /* - Sometimeswe we need objects slightly larger - an object in the replication local.oplog + Sometimes we need objects slightly larger - an object in the replication local.oplog is slightly larger than a user object for example. */ const int BSONObjMaxInternalSize = BSONObjMaxUserSize + ( 16 * 1024 ); @@ -230,42 +231,51 @@ namespace mongo { void decouple(); // not allowed. not implemented. }; + namespace { #if defined(_WIN32) -#pragma warning( push ) -// warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. -#pragma warning( disable : 4996 ) + int (*mongo_snprintf)(char *str, size_t size, const char *format, ...) = &sprintf_s; +#else + int (*mongo_snprintf)(char *str, size_t size, const char *format, ...) = &snprintf; #endif + } /** stringstream deals with locale so this is a lot faster than std::stringstream for UTF8 */ class StringBuilder { public: + static const size_t MONGO_DBL_SIZE = 3 + DBL_MANT_DIG - DBL_MIN_EXP; + static const size_t MONGO_S32_SIZE = 12; + static const size_t MONGO_U32_SIZE = 11; + static const size_t MONGO_S64_SIZE = 23; + static const size_t MONGO_U64_SIZE = 22; + static const size_t MONGO_S16_SIZE = 7; + StringBuilder( int initsize=256 ) : _buf( initsize ) { } StringBuilder& operator<<( double x ) { - return SBNUM( x , 25 , "%g" ); + return SBNUM( x , MONGO_DBL_SIZE , "%g" ); } StringBuilder& operator<<( int x ) { - return SBNUM( x , 11 , "%d" ); + return SBNUM( x , MONGO_S32_SIZE , "%d" ); } StringBuilder& operator<<( unsigned x ) { - return SBNUM( x , 11 , "%u" ); + return SBNUM( x , MONGO_U32_SIZE , "%u" ); } StringBuilder& operator<<( long x ) { - return SBNUM( x , 22 , "%ld" ); + return SBNUM( x , MONGO_S64_SIZE , "%ld" ); } StringBuilder& operator<<( unsigned long x ) { - return SBNUM( x , 22 , "%lu" ); + return SBNUM( x , MONGO_U64_SIZE , "%lu" ); } StringBuilder& operator<<( long long x ) { - return SBNUM( x , 22 , "%lld" ); + return SBNUM( x , MONGO_S64_SIZE , "%lld" ); } StringBuilder& operator<<( unsigned long long x ) { - return SBNUM( x , 22 , "%llu" ); + return SBNUM( x , MONGO_U64_SIZE , "%llu" ); } StringBuilder& operator<<( short x ) { - return SBNUM( x , 8 , "%hd" ); + return SBNUM( x , MONGO_S16_SIZE , "%hd" ); } StringBuilder& operator<<( char c ) { _buf.grow( 1 )[0] = c; @@ -273,10 +283,12 @@ namespace mongo { } void appendDoubleNice( double x ) { - int prev = _buf.l; - char * start = _buf.grow( 32 ); - int z = sprintf( start , "%.16g" , x ); + const int prev = _buf.l; + const int maxSize = 32; + char * start = _buf.grow( maxSize ); + int z = mongo_snprintf( start , maxSize , "%.16g" , x ); assert( z >= 0 ); + assert( z < maxSize ); _buf.l = prev + z; if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ) { write( ".0" , 2 ); @@ -308,15 +320,12 @@ namespace mongo { template <typename T> StringBuilder& SBNUM(T val,int maxSize,const char *macro) { int prev = _buf.l; - int z = sprintf( _buf.grow(maxSize) , macro , (val) ); + int z = mongo_snprintf( _buf.grow(maxSize) , maxSize , macro , (val) ); assert( z >= 0 ); + assert( z < maxSize ); _buf.l = prev + z; return *this; } }; -#if defined(_WIN32) -#pragma warning( pop ) -#endif - } // namespace mongo diff --git a/client/dbclient_rs.cpp b/client/dbclient_rs.cpp index 4a8112b..c792656 100644 --- a/client/dbclient_rs.cpp +++ b/client/dbclient_rs.cpp @@ -303,12 +303,29 @@ namespace mongo { } } - void ReplicaSetMonitor::_checkStatus(DBClientConnection *conn) { + void ReplicaSetMonitor::_checkStatus( const string& hostAddr ) { BSONObj status; - if (!conn->runCommand("admin", BSON("replSetGetStatus" << 1), status) || - !status.hasField("members") || - status["members"].type() != Array) { + /* replSetGetStatus requires admin auth so use a connection from the pool, + * which are authenticated with the keyFile credentials. + */ + ScopedDbConnection authenticatedConn( hostAddr ); + + if ( !authenticatedConn->runCommand( "admin", BSON( "replSetGetStatus" << 1 ), status )) { + LOG(1) << "dbclient_rs replSetGetStatus failed" << endl; + authenticatedConn.done(); // connection worked properly, but we got an error from server + return; + } + + // Make sure we return when finished + authenticatedConn.done(); + + if( !status.hasField("members") ) { + log() << "dbclient_rs error expected members field in replSetGetStatus result" << endl; + return; + } + if( status["members"].type() != Array) { + log() << "dbclient_rs error expected members field in replSetGetStatus result to be an array" << endl; return; } @@ -523,7 +540,7 @@ namespace mongo { } _checkHosts( b.arr(), changed); - _checkStatus( conn ); + _checkStatus( conn->getServerAddress() ); } catch ( std::exception& e ) { diff --git a/client/dbclient_rs.h b/client/dbclient_rs.h index bf91f09..318b3cf 100644 --- a/client/dbclient_rs.h +++ b/client/dbclient_rs.h @@ -120,7 +120,7 @@ namespace mongo { * Use replSetGetStatus command to make sure hosts in host list are up * and readable. Sets Node::ok appropriately. */ - void _checkStatus(DBClientConnection *conn); + void _checkStatus( const string& hostAddr ); /** * Add array of hosts to host list. Doesn't do anything if hosts are @@ -181,9 +181,8 @@ namespace mongo { string _name; struct Node { Node( const HostAndPort& a , DBClientConnection* c ) - : addr( a ) , conn(c) , ok(true) , + : addr( a ) , conn(c) , ok( c != NULL ), ismaster(false), secondary( false ) , hidden( false ) , pingTimeMillis(0) { - ok = conn.get() == NULL; } bool okForSecondaryQueries() const { diff --git a/db/cloner.cpp b/db/cloner.cpp index 26c2f74..6d5b095 100644 --- a/db/cloner.cpp +++ b/db/cloner.cpp @@ -169,7 +169,8 @@ namespace mongo { getDur().commitIfNeeded(); } catch( UserException& e ) { - log() << "warning: exception cloning object in " << from_collection << ' ' << e.what() << " obj:" << js.toString() << '\n'; + error() << "error: exception cloning object in " << from_collection << ' ' << e.what() << " obj:" << js.toString() << '\n'; + throw; } RARELY if ( time( 0 ) - saveLast > 60 ) { @@ -238,7 +239,8 @@ namespace mongo { getDur().commitIfNeeded(); } catch( UserException& e ) { - log() << "warning: exception cloning object in " << from_collection << ' ' << e.what() << " obj:" << js.toString() << '\n'; + error() << "error: exception cloning object in " << from_collection << ' ' << e.what() << " obj:" << js.toString() << '\n'; + throw; } } } diff --git a/db/compact.cpp b/db/compact.cpp index c6e5f77..c100006 100644 --- a/db/compact.cpp +++ b/db/compact.cpp @@ -180,6 +180,11 @@ namespace mongo { d->deletedList[i].writing().Null(); } + + + // Start over from scratch with our extent sizing and growth + d->lastExtentSize=0; + // before dropping indexes, at least make sure we can allocate one extent! uassert(14025, "compact error no space available to allocate", !allocateSpaceForANewRecord(ns, d, Record::HeaderSize+1, false).isNull()); diff --git a/db/dbwebserver.cpp b/db/dbwebserver.cpp index 78c09c0..eb19ba3 100644 --- a/db/dbwebserver.cpp +++ b/db/dbwebserver.cpp @@ -79,11 +79,10 @@ namespace mongo { } bool allowed( const char * rq , vector<string>& headers, const SockAddr &from ) { - if ( from.isLocalHost() ) - return true; - - if ( ! _webUsers->haveAdminUsers() ) + if ( from.isLocalHost() || !_webUsers->haveAdminUsers() ) { + cmdAuthenticate.authenticate( "admin", "RestUser", false ); return true; + } string auth = getHeader( rq , "Authorization" ); @@ -118,8 +117,10 @@ namespace mongo { r << ha2; string r1 = md5simpledigest( r.str() ); - if ( r1 == parms["response"] ) + if ( r1 == parms["response"] ) { + cmdAuthenticate.authenticate( "admin", user["user"].str(), user[ "readOnly" ].isBoolean() && user[ "readOnly" ].boolean() ); return true; + } } } diff --git a/db/queryoptimizer.cpp b/db/queryoptimizer.cpp index 71ca657..8ec4cb4 100644 --- a/db/queryoptimizer.cpp +++ b/db/queryoptimizer.cpp @@ -214,22 +214,6 @@ doneCheckOrder: if ( willScanTable() ) { if ( _frs.nNontrivialRanges() ) { checkTableScanAllowed( _frs.ns() ); - - // if we are doing a table scan on _id - // and its a capped collection - // we disallow as its a common user error - // .system. and local collections are exempt - if ( _d && _d->capped && _frs.range( "_id" ).nontrivial() ) { - if ( cc().isSyncThread() || - str::contains( _frs.ns() , ".system." ) || - str::startsWith( _frs.ns() , "local." ) ) { - // ok - } - else { - warning() << "_id query on capped collection without an _id index, performance will be poor collection: " << _frs.ns() << endl; - //uassert( 14820, str::stream() << "doing _id query on a capped collection without an index is not allowed: " << _frs.ns() , - } - } } return findTableScan( _frs.ns(), _order, startLoc ); } @@ -486,12 +470,14 @@ doneCheckOrder: _usingPrerecordedPlan = true; _mayRecordPlan = false; _plans.push_back( p ); + warnOnCappedIdTableScan(); return; } } } addOtherPlans( false ); + warnOnCappedIdTableScan(); } void QueryPlanSet::addOtherPlans( bool checkFirst ) { @@ -633,6 +619,31 @@ doneCheckOrder: } return _plans[0]; } + + void QueryPlanSet::warnOnCappedIdTableScan() const { + // if we are doing a table scan on _id + // and it's a capped collection + // we warn as it's a common user error + // .system. and local collections are exempt + const char *ns = _frsp->ns(); + NamespaceDetails *d = nsdetails( ns ); + if ( d && + d->capped && + nPlans() == 1 && + firstPlan()->willScanTable() && + firstPlan()->multikeyFrs().range( "_id" ).nontrivial() ) { + if ( cc().isSyncThread() || + str::contains( ns , ".system." ) || + str::startsWith( ns , "local." ) ) { + // ok + } + else { + warning() + << "unindexed _id query on capped collection, " + << "performance will be poor collection: " << ns << endl; + } + } + } QueryPlanSet::Runner::Runner( QueryPlanSet &plans, QueryOp &op ) : _op( op ), @@ -1247,8 +1258,12 @@ doneCheckOrder: void QueryUtilIndexed::clearIndexesForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order ) { SimpleMutex::scoped_lock lk(NamespaceDetailsTransient::_qcMutex); NamespaceDetailsTransient& nsd = NamespaceDetailsTransient::get_inlock( frsp.ns() ); - nsd.registerIndexForPattern( frsp._singleKey.pattern( order ), BSONObj(), 0 ); - nsd.registerIndexForPattern( frsp._multiKey.pattern( order ), BSONObj(), 0 ); + if ( frsp._singleKey.matchPossible() ) { + nsd.registerIndexForPattern( frsp._singleKey.pattern( order ), BSONObj(), 0 ); + } + if ( frsp._multiKey.matchPossible() ) { + nsd.registerIndexForPattern( frsp._multiKey.pattern( order ), BSONObj(), 0 ); + } } pair< BSONObj, long long > QueryUtilIndexed::bestIndexForPatterns( const FieldRangeSetPair &frsp, const BSONObj &order ) { diff --git a/db/queryoptimizer.h b/db/queryoptimizer.h index fea6c0b..78d169d 100644 --- a/db/queryoptimizer.h +++ b/db/queryoptimizer.h @@ -314,6 +314,7 @@ namespace mongo { } void init(); void addHint( IndexDetails &id ); + void warnOnCappedIdTableScan() const; class Runner { public: Runner( QueryPlanSet &plans, QueryOp &op ); diff --git a/db/repl.cpp b/db/repl.cpp index 5edf0c2..8dcdd13 100644 --- a/db/repl.cpp +++ b/db/repl.cpp @@ -1115,7 +1115,7 @@ namespace mongo { bool OplogReader::commonConnect(const string& hostName) { if( conn() == 0 ) { - _conn = shared_ptr<DBClientConnection>(new DBClientConnection( false, 0, 0 /* tcp timeout */)); + _conn = shared_ptr<DBClientConnection>(new DBClientConnection( false, 0, 60*10 /* tcp timeout */)); string errmsg; ReplInfo r("trying to connect to sync source"); if ( !_conn->connect(hostName.c_str(), errmsg) || diff --git a/db/repl/rs_initialsync.cpp b/db/repl/rs_initialsync.cpp index 112d739..7065487 100644 --- a/db/repl/rs_initialsync.cpp +++ b/db/repl/rs_initialsync.cpp @@ -43,18 +43,24 @@ namespace mongo { } void ReplSetImpl::syncDoInitialSync() { + const static int maxFailedAttempts = 3; createOplog(); - - while( 1 ) { + int failedAttempts = 0; + while ( failedAttempts < maxFailedAttempts ) { try { _syncDoInitialSync(); break; } catch(DBException& e) { - sethbmsg("initial sync exception " + e.toString(), 0); + failedAttempts++; + str::stream msg; + msg << "initial sync exception: "; + msg << e.toString() << " " << (maxFailedAttempts - failedAttempts) << " attempts remaining" ; + sethbmsg(msg, 0); sleepsecs(30); } } + if ( failedAttempts >= maxFailedAttempts ) ::abort(); } /* todo : progress metering to sethbmsg. */ @@ -80,7 +86,7 @@ namespace mongo { } const Member* ReplSetImpl::getMemberToSyncTo() { - Member *closest = 0; + bool buildIndexes = true; // wait for 2N pings before choosing a sync target @@ -95,16 +101,31 @@ namespace mongo { buildIndexes = myConfig().buildIndexes; } + Member *closest = 0; + // find the member with the lowest ping time that has more data than me - for (Member *m = _members.head(); m; m = m->next()) { - if (m->hbinfo().up() && - // make sure members with buildIndexes sync from other members w/indexes - (!buildIndexes || (buildIndexes && m->config().buildIndexes)) && - (m->state() == MemberState::RS_PRIMARY || - (m->state() == MemberState::RS_SECONDARY && m->hbinfo().opTime > lastOpTimeWritten)) && - (!closest || m->hbinfo().ping < closest->hbinfo().ping)) { - closest = m; + + // Make two attempts. The first attempt, we ignore those nodes with + // slave delay higher than our own. The second attempt includes such + // nodes, in case those are the only ones we can reach. + for (int attempts = 0; attempts < 2; ++attempts) { + for (Member *m = _members.head(); m; m = m->next()) { + if (m->hbinfo().up() && + // make sure members with buildIndexes sync from other members w/indexes + (!buildIndexes || (buildIndexes && m->config().buildIndexes)) && + (m->state() == MemberState::RS_PRIMARY || + (m->state() == MemberState::RS_SECONDARY && + m->hbinfo().opTime > lastOpTimeWritten)) && + (!closest || m->hbinfo().ping < closest->hbinfo().ping)) { + + if ( attempts == 0 && + myConfig().slaveDelay < m->config().slaveDelay ) { + break; // skip this one in the first attempt + } + closest = m; + } } + if (closest) break; // no need for second attempt } { diff --git a/db/security_common.h b/db/security_common.h index c9a3e3a..80a7450 100644 --- a/db/security_common.h +++ b/db/security_common.h @@ -61,10 +61,12 @@ namespace mongo { virtual void help(stringstream& ss) const { ss << "internal"; } CmdAuthenticate() : Command("authenticate") {} bool run(const string& dbname , BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl); + void authenticate(const string& dbname, const string& user, const bool readOnly); private: bool getUserObj(const string& dbname, const string& user, BSONObj& userObj, string& pwd); - void authenticate(const string& dbname, const string& user, const bool readOnly); }; + + extern CmdAuthenticate cmdAuthenticate; class CmdLogout : public Command { public: diff --git a/doxygenConfig b/doxygenConfig index afe9177..0be602d 100644 --- a/doxygenConfig +++ b/doxygenConfig @@ -3,7 +3,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = MongoDB -PROJECT_NUMBER = 2.0.5 +PROJECT_NUMBER = 2.0.6 OUTPUT_DIRECTORY = docs/doxygen CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff --git a/jstests/queryoptimizer7.js b/jstests/queryoptimizer7.js new file mode 100644 index 0000000..c4ff75b --- /dev/null +++ b/jstests/queryoptimizer7.js @@ -0,0 +1,24 @@ +// Test query retry with a query that is non multikey unusable and unsatisfiable. SERVER-5581 + +t = db.jstests_queryoptimizer7; +t.drop(); + +t.ensureIndex( { a:1 } ); +t.ensureIndex( { b:1 } ); + +for( i = 0; i < 25; ++i ) { + t.save( { a:0, b:'' } ); // a:0 documents have small b strings. +} +big = new Array( 1000000 ).toString(); +for( i = 0; i < 50; ++i ) { + t.save( { a:[1,3], b:big } ); // a:[1,3] documents have very large b strings. +} + +// Record the a:1 index for the query pattern for { a: { $lt:1 } }, { b:1 }. +assert.eq( 'BtreeCursor a_1', t.find( { a:{ $lt:1 } } ).sort( { b:1 } ).explain().cursor ); + +// The multikey query pattern for this query will match that of the previous query. +// The a:1 index will be retried for this query but fail because an in memory sort must +// be performed on a larger data set. Because the query { a:{ $lt:2, $gt:2 } } is +// unsatisfiable, no attempt will be made to clear its query pattern. +assert.lt( -1, t.find( { a:{ $lt:2, $gt:2 } } ).sort( { b:1 } ).itcount() ); diff --git a/jstests/queryoptimizera.js b/jstests/queryoptimizera.js new file mode 100644 index 0000000..48d7ccf --- /dev/null +++ b/jstests/queryoptimizera.js @@ -0,0 +1,87 @@ +// Check that a warning message about doing a capped collection scan for a query with an _id +// constraint is printed at appropriate times. SERVER-5353 + +function numWarnings() { + logs = db.adminCommand( { getLog:"global" } ).log + ret = 0; + logs.forEach( function( x ) { + if ( x.match( warningMatchRegexp ) ) { + ++ret; + } + } ); + return ret; +} + +collectionNameIndex = 0; + +// Generate a collection name not already present in the log. +do { + testCollectionName = 'jstests_queryoptimizera__' + collectionNameIndex++; + warningMatchString = 'unindexed _id query on capped collection.*collection: test.' + + testCollectionName; + warningMatchRegexp = new RegExp( warningMatchString ); + +} while( numWarnings() > 0 ); + +t = db[ testCollectionName ]; +t.drop(); + +notCappedCollectionName = testCollectionName + '_notCapped'; + +notCapped = db[ notCappedCollectionName ]; +notCapped.drop(); + +db.createCollection( testCollectionName, { capped:true, size:1000 } ); +db.createCollection( notCappedCollectionName, { autoIndexId:false } ); + +t.insert( {} ); +notCapped.insert( {} ); + +oldNumWarnings = 0; + +function assertNoNewWarnings() { + assert.eq( oldNumWarnings, numWarnings() ); +} + +function assertNewWarning() { + ++oldNumWarnings; + assert.eq( oldNumWarnings, numWarnings() ); +} + +// Simple _id query without an _id index. +t.find( { _id:0 } ).itcount(); +assertNewWarning(); + +// Simple _id query without an _id index, on a non capped collection. +notCapped.find( { _id:0 } ).itcount(); +assertNoNewWarnings(); + +// A multi field query, including _id. +t.find( { _id:0, a:0 } ).itcount(); +assertNewWarning(); + +// An unsatisfiable query. +t.find( { _id:0, a:{$in:[]} } ).itcount(); +assertNoNewWarnings(); + +// An hinted query. +t.find( { _id:0 } ).hint( { $natural:1 } ).itcount(); +assertNoNewWarnings(); + +// Retry a multi field query. +t.find( { _id:0, a:0 } ).itcount(); +assertNewWarning(); + +// Warnings should not be printed when an index is added on _id. +t.ensureIndex( { _id:1 } ); + +t.find( { _id:0 } ).itcount(); +assertNoNewWarnings(); + +t.find( { _id:0, a:0 } ).itcount(); +assertNoNewWarnings(); + +t.find( { _id:0, a:0 } ).itcount(); +assertNoNewWarnings(); + +t.drop(); // cleanup diff --git a/jstests/replsets/replset7.js b/jstests/replsets/replset7.js new file mode 100644 index 0000000..f29c1fb --- /dev/null +++ b/jstests/replsets/replset7.js @@ -0,0 +1,46 @@ + +// test for SERVER-5040 - if documents move forward during an initial sync. + +var rt = new ReplSetTest( { name : "replset7tests" , nodes: 1 } ); + +var nodes = rt.startSet(); +rt.initiate(); +var master = rt.getMaster(); + +var md = master.getDB( 'd' ); +var mdc = md[ 'c' ]; + +// prep the data +var doccount = 100000; +for( i = 0; i < doccount; ++i ) { + mdc.insert( { _id:i, x:i } ); +} +md.getLastError(); + +mdc.ensureIndex( { x : 1 }, { unique: true } ); +md.getLastError(); + +// add a secondary +var slave = rt.add(); +rt.reInitiate(); +print ("initiation complete!"); +var sc = slave.getDB( 'd' )[ 'c' ]; +slave.setSlaveOk(); + +// Wait for slave to start cloning. +//assert.soon( function() { c = sc.find( { _id:1, x:1 } ); print( c ); return c > 0; } ); + + +// Move all documents to the end by growing it +for (i = 0; i < doccount; ++i) { + mdc.remove( { _id:i, x:i } ); + mdc.insert( { _id:doccount+i, x:i, bigstring: "ayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayayay" } ); + md.getLastError(); +} + +// Wait for replication to catch up. +rt.awaitSecondaryNodes(); + +// Do we have an index? +assert.eq (1, slave.getDB( 'd' )['system.indexes'] + .find({"v" : 1,"key" : {"x" : 1},"unique" : true,"ns" : "d.c","name" : "x_1"}).count()); diff --git a/jstests/replsets/slavedelay3.js b/jstests/replsets/slavedelay3.js new file mode 100644 index 0000000..e89fe96 --- /dev/null +++ b/jstests/replsets/slavedelay3.js @@ -0,0 +1,38 @@ +load("jstests/replsets/rslib.js"); + +var name = 'slavedelay3'; +var replTest = new ReplSetTest({ name: name, nodes: 3 }); +var nodes = replTest.startSet(); +var config = replTest.getReplSetConfig(); +// ensure member 0 is primary +config.members[0].priority = 2; +config.members[1].priority = 0; +config.members[1].slaveDelay = 5; + +replTest.initiate(config); +replTest.awaitReplication(); +replTest.bridge(); + + +var master = replTest.getMaster().getDB(name); + var slaveConns = replTest.liveNodes.slaves; + var slave = []; + for (var i in slaveConns) { + var d = slaveConns[i].getDB(name); + d.getMongo().setSlaveOk(); + slave.push(d); + } + +waitForAllMembers(master); + + + +replTest.partition(0,2); +replTest.awaitReplication(); + +master.foo.insert({x:1}); + +// make sure the record still appears in the remote slave +assert.soon( function() { return slave[1].foo.findOne() != null; } ); + +replTest.stopSet();
\ No newline at end of file diff --git a/jstests/slowNightly/sharding_passthrough.js b/jstests/slowNightly/sharding_passthrough.js index d81df68..fa1f7bc 100644 --- a/jstests/slowNightly/sharding_passthrough.js +++ b/jstests/slowNightly/sharding_passthrough.js @@ -72,7 +72,7 @@ files.forEach( return; } // These aren't supposed to get run under sharding: - if (/[\/\\](dbadmin|error1|fsync|fsync2|geo.*|indexh|remove5|update4|notablescan|compact.*|check_shard_index|bench_test.*|mr_replaceIntoDB)\.js$/.test(x.name)) { + if (/[\/\\](dbadmin|error1|fsync|fsync2|geo.*|indexh|remove5|update4|notablescan|compact.*|check_shard_index|bench_test.*|mr_replaceIntoDB|queryoptimizera)\.js$/.test(x.name)) { print(" >>>>>>>>>>>>>>> skipping test that would fail under sharding " + x.name) return; } diff --git a/rpm/mongo.spec b/rpm/mongo.spec index 260274c..5745ab5 100644 --- a/rpm/mongo.spec +++ b/rpm/mongo.spec @@ -1,5 +1,5 @@ Name: mongo -Version: 2.0.5 +Version: 2.0.6 Release: mongodb_1%{?dist} Summary: mongo client shell and tools License: AGPL 3.0 diff --git a/s/d_migrate.cpp b/s/d_migrate.cpp index 731761f..918dd86 100644 --- a/s/d_migrate.cpp +++ b/s/d_migrate.cpp @@ -482,32 +482,53 @@ namespace mongo { while ( 1 ) { bool filledBuffer = false; - - readlock l( _ns ); - Client::Context ctx( _ns ); - scoped_spinlock lk( _trackerLocks ); - set<DiskLoc>::iterator i = _cloneLocs.begin(); - for ( ; i!=_cloneLocs.end(); ++i ) { - if (tracker.ping()) // should I yield? - break; - DiskLoc dl = *i; - BSONObj o = dl.obj(); + auto_ptr<RWLockRecursive::Shared> fileLock; + Record* recordToTouch = NULL; - // use the builder size instead of accumulating 'o's size so that we take into consideration - // the overhead of BSONArray indices - if ( a.len() + o.objsize() + 1024 > BSONObjMaxUserSize ) { - filledBuffer = true; // break out of outer while loop - break; - } + { + readlock rlk(_ns); + Client::Context ctx( _ns ); // ReadContext? + scoped_spinlock lk( _trackerLocks ); + set<DiskLoc>::iterator i = _cloneLocs.begin(); + for ( ; i!=_cloneLocs.end(); ++i ) { + if (tracker.ping()) // should I yield? + break; - a.append( o ); - } + DiskLoc dl = *i; + Record* r = dl.rec(); + if ( ! r->likelyInPhysicalMemory() ) { + fileLock.reset( new RWLockRecursive::Shared( MongoFile::mmmutex) ); + recordToTouch = r; + break; + } + + BSONObj o = dl.obj(); + + // use the builder size instead of accumulating 'o's size so that we take into consideration + // the overhead of BSONArray indices + if ( a.len() + o.objsize() + 1024 > BSONObjMaxUserSize ) { + filledBuffer = true; // break out of outer while loop + break; + } + + a.append( o ); + } _cloneLocs.erase( _cloneLocs.begin() , i ); if ( _cloneLocs.empty() || filledBuffer ) break; + } + if ( recordToTouch ) { + // its safe to touch here because we have a LockMongoFilesShared + // we can't do where we get the lock because we would have to unlock the main readlock and tne _trackerLocks + // simpler to handle this out there + recordToTouch->touch(); + recordToTouch = NULL; + } + + } result.appendArray( "objects" , a.arr() ); diff --git a/s/d_state.cpp b/s/d_state.cpp index 638d8c1..ef933a0 100644 --- a/s/d_state.cpp +++ b/s/d_state.cpp @@ -614,6 +614,15 @@ namespace mongo { } if ( globalVersion == 0 && ! authoritative ) { + // Needed b/c when the last chunk is moved off a shard, the version gets reset to zero, which + // should require a reload. + // TODO: Maybe a more elegant way of doing this + while ( shardingState.inCriticalMigrateSection() ) { + dbtemprelease r; + sleepmillis(2); + OCCASIONALLY log() << "waiting till out of critical section for version reset" << endl; + } + // need authoritative for first look result.append( "ns" , ns ); result.appendBool( "need_authoritative" , true ); diff --git a/shell/utils.js b/shell/utils.js index 7d7a23b..4e20603 100644 --- a/shell/utils.js +++ b/shell/utils.js @@ -739,7 +739,8 @@ if ( typeof _threadInject != "undefined" ){ "jstests/notablescan.js", "jstests/drop2.js", "jstests/dropdb_race.js", - "jstests/bench_test1.js"] ); + "jstests/bench_test1.js", + "jstests/queryoptimizera.js"] ); // some tests can't be run in parallel with each other var serialTestsArr = [ "jstests/fsync.js", diff --git a/third_party/js-1.7/jsprf.c b/third_party/js-1.7/jsprf.c index 416c16c..6735520 100644 --- a/third_party/js-1.7/jsprf.c +++ b/third_party/js-1.7/jsprf.c @@ -58,6 +58,8 @@ */ #ifdef HAVE_VA_COPY #define VARARGS_ASSIGN(foo, bar) VA_COPY(foo,bar) +#elif defined(va_copy) +#define VARARGS_ASSIGN(foo, bar) va_copy(foo,bar) #elif defined(HAVE_VA_LIST_AS_ARRAY) #define VARARGS_ASSIGN(foo, bar) foo[0] = bar[0] #else diff --git a/util/net/sock.cpp b/util/net/sock.cpp index ac565c3..a032e50 100644 --- a/util/net/sock.cpp +++ b/util/net/sock.cpp @@ -52,10 +52,18 @@ namespace mongo { tv.tv_usec = (int)((long long)(secs*1000*1000) % (1000*1000)); bool report = logLevel > 3; // solaris doesn't provide these DEV report = true; - bool ok = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv) ) == 0; - if( report && !ok ) log() << "unabled to set SO_RCVTIMEO" << endl; - ok = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, sizeof(tv) ) == 0; - DEV if( report && !ok ) log() << "unabled to set SO_RCVTIMEO" << endl; +#if defined(_WIN32) + tv.tv_sec *= 1000; // Windows timeout is a DWORD, in milliseconds. + int status = setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv.tv_sec, sizeof(DWORD) ) == 0; + if( report && (status == SOCKET_ERROR) ) log() << "unable to set SO_RCVTIMEO" << endl; + status = setsockopt( sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv.tv_sec, sizeof(DWORD) ) == 0; + DEV if( report && (status == SOCKET_ERROR) ) log() << "unable to set SO_SNDTIMEO" << endl; +#else + bool ok = setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv) ) == 0; + if( report && !ok ) log() << "unable to set SO_RCVTIMEO" << endl; + ok = setsockopt( sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, sizeof(tv) ) == 0; + DEV if( report && !ok ) log() << "unable to set SO_SNDTIMEO" << endl; +#endif } #if defined(_WIN32) @@ -755,15 +763,7 @@ namespace mongo { } void Socket::setTimeout( double secs ) { - struct timeval tv; - tv.tv_sec = (int)secs; - tv.tv_usec = (int)((long long)(secs*1000*1000) % (1000*1000)); - bool report = logLevel > 3; // solaris doesn't provide these - DEV report = true; - bool ok = setsockopt(_fd, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv) ) == 0; - if( report && !ok ) log() << "unabled to set SO_RCVTIMEO" << endl; - ok = setsockopt(_fd, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, sizeof(tv) ) == 0; - DEV if( report && !ok ) log() << "unabled to set SO_RCVTIMEO" << endl; + setSockTimeouts( _fd, secs ); } #if defined(_WIN32) diff --git a/util/version.cpp b/util/version.cpp index 8b08ff4..03ff548 100644 --- a/util/version.cpp +++ b/util/version.cpp @@ -38,7 +38,7 @@ namespace mongo { * 1.2.3-rc4-pre- * If you really need to do something else you'll need to fix _versionArray() */ - const char versionString[] = "2.0.5"; + const char versionString[] = "2.0.6"; // See unit test for example outputs static BSONArray _versionArray(const char* version){ |