summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonin Kral <a.kral@bobek.cz>2012-06-05 19:50:34 +0200
committerAntonin Kral <a.kral@bobek.cz>2012-06-05 19:50:34 +0200
commit3703a282eca7e79e91f4bd651b1b861b76dc6c68 (patch)
treeb69552c69c48ebc6899f7bbbe42843793a423237
parent61619b3142c1de8f60f91964ff2656054d4f11a6 (diff)
downloadmongodb-3703a282eca7e79e91f4bd651b1b861b76dc6c68.tar.gz
Imported Upstream version 2.0.6
-rw-r--r--SConstruct10
-rw-r--r--bson/util/builder.h49
-rw-r--r--client/dbclient_rs.cpp27
-rw-r--r--client/dbclient_rs.h5
-rw-r--r--db/cloner.cpp6
-rw-r--r--db/compact.cpp5
-rw-r--r--db/dbwebserver.cpp11
-rw-r--r--db/queryoptimizer.cpp51
-rw-r--r--db/queryoptimizer.h1
-rw-r--r--db/repl.cpp2
-rw-r--r--db/repl/rs_initialsync.cpp45
-rw-r--r--db/security_common.h4
-rw-r--r--doxygenConfig2
-rw-r--r--jstests/queryoptimizer7.js24
-rw-r--r--jstests/queryoptimizera.js87
-rw-r--r--jstests/replsets/replset7.js46
-rw-r--r--jstests/replsets/slavedelay3.js38
-rw-r--r--jstests/slowNightly/sharding_passthrough.js2
-rw-r--r--rpm/mongo.spec2
-rw-r--r--s/d_migrate.cpp57
-rw-r--r--s/d_state.cpp9
-rw-r--r--shell/utils.js3
-rw-r--r--third_party/js-1.7/jsprf.c2
-rw-r--r--util/net/sock.cpp26
-rw-r--r--util/version.cpp2
25 files changed, 408 insertions, 108 deletions
diff --git a/SConstruct b/SConstruct
index 3d40050..88ea3f8 100644
--- a/SConstruct
+++ b/SConstruct
@@ -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){