diff options
| author | Antonin Kral <a.kral@bobek.cz> | 2013-04-17 21:51:49 +0200 |
|---|---|---|
| committer | Antonin Kral <a.kral@bobek.cz> | 2013-04-17 21:51:49 +0200 |
| commit | 3c0811b838ca6b5e26855e6850b2f1d7fd8ea20a (patch) | |
| tree | b0c6fec4fa8578d9215c7fdcadd89b705aad2c64 | |
| parent | f0db7048a1748ec5ee8a55eaf964b2b1ca886cef (diff) | |
Imported Upstream version 2.4.2upstream/2.4.2
62 files changed, 4047 insertions, 793 deletions
diff --git a/buildscripts/packager.py b/buildscripts/packager.py index 3fc17954d96..dcddf0ab91b 100644 --- a/buildscripts/packager.py +++ b/buildscripts/packager.py @@ -924,9 +924,9 @@ fi %{_mandir}/man1/mongostat.1* # FIXME: uncomment when mongosniff is back in the package #%{_mandir}/man1/mongosniff.1* -#@@VERSION>2.4.0@@%{_mandir}/man1/mongotop.1* -#@@VERSION>2.4.0@@%{_mandir}/man1/mongoperf.1* -#@@VERSION>2.4.0@@%{_mandir}/man1/mongooplog.1* +#@@VERSION>=2.4.0@@%{_mandir}/man1/mongotop.1* +#@@VERSION>=2.4.0@@%{_mandir}/man1/mongoperf.1* +#@@VERSION>=2.4.0@@%{_mandir}/man1/mongooplog.1* %files server %defattr(-,root,root,-) diff --git a/doxygenConfig b/doxygenConfig index 555ca59a38f..06f0529edba 100644 --- a/doxygenConfig +++ b/doxygenConfig @@ -3,7 +3,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = MongoDB -PROJECT_NUMBER = 2.4.1 +PROJECT_NUMBER = 2.4.2 OUTPUT_DIRECTORY = docs/doxygen CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff --git a/jstests/fts_partition1.js b/jstests/fts_partition1.js index 7fa4aa40335..f1b4c437c3c 100644 --- a/jstests/fts_partition1.js +++ b/jstests/fts_partition1.js @@ -18,3 +18,6 @@ assert.eq( [ 1 ], queryIDS( t, "foo" , { x : 1 } ) ); res = t.runCommand( "text", { search : "foo" , filter : { x : 1 } } ); assert( res.results[0].score > 0, tojson( res ) ) +// repeat search with "language" specified, SERVER-8999 +res = t.runCommand( "text", { search : "foo" , filter : { x : 1 } , language : "english" } ); +assert( res.results[0].score > 0, tojson( res ) ) diff --git a/jstests/geo_s2edgecases.js b/jstests/geo_s2edgecases.js index 02bd17d8b9f..bf46baba744 100755 --- a/jstests/geo_s2edgecases.js +++ b/jstests/geo_s2edgecases.js @@ -5,20 +5,20 @@ roundworldpoint = { "type" : "Point", "coordinates": [ 180, 0 ] } // Opposite the equator roundworld = { "type" : "Polygon", - "coordinates" : [ [ [179,1], [181,1], [181,-1], [179,-1], [179,1]]]} + "coordinates" : [ [ [179,1], [-179,1], [-179,-1], [179,-1], [179,1]]]} t.insert({geo : roundworld}) roundworld2 = { "type" : "Polygon", - "coordinates" : [ [ [179,1], [179,-1], [181,-1], [181,1], [179,1]]]} + "coordinates" : [ [ [179,1], [179,-1], [-179,-1], [-179,1], [179,1]]]} t.insert({geo : roundworld2}) // North pole santapoint = { "type" : "Point", "coordinates": [ 180, 90 ] } santa = { "type" : "Polygon", - "coordinates" : [ [ [179,89], [179,90], [181,90], [181,89], [179,89]]]} + "coordinates" : [ [ [179,89], [179,90], [-179,90], [-179,89], [179,89]]]} t.insert({geo : santa}) santa2 = { "type" : "Polygon", - "coordinates" : [ [ [179,89], [181,89], [181,90], [179,90], [179,89]]]} + "coordinates" : [ [ [179,89], [-179,89], [-179,90], [179,90], [179,89]]]} t.insert({geo : santa2}) // South pole diff --git a/jstests/geo_s2nearComplex.js b/jstests/geo_s2nearComplex.js index 78a055d719b..87dd034ca24 100644 --- a/jstests/geo_s2nearComplex.js +++ b/jstests/geo_s2nearComplex.js @@ -59,15 +59,25 @@ function uniformPoints(origin, count, minDist, maxDist){ var pointLat = asin((sin(lat) * cos(distance)) + (cos(lat) * sin(distance) * cos(angle))); var pointDLng = atan2(sin(angle) * sin(distance) * cos(lat), cos(distance) - sin(lat) * sin(pointLat)); var pointLng = ((lng - pointDLng + PI) % 2*PI) - PI; + + // Latitude must be [-90, 90] + var newLat = lat + pointLat; + if (newLat > 90) newLat -= 180; + if (newLat < -90) newLat += 180; + + // Longitude must be [-180, 180] + var newLng = lng + pointLng; + if (newLng > 180) newLng -= 360; + if (newLng < -180) newLng += 360; + var newPoint = { geo: { type: "Point", - coordinates: [lng + pointLng, lat + pointLat] + //coordinates: [lng + pointLng, lat + pointLat] + coordinates: [newLng, newLat] } }; - if(lat + pointLat > 90.0){ - continue; - } + points.push(newPoint); } for(i=0; i < points.length; i++){ diff --git a/jstests/nestedobj1.js b/jstests/nestedobj1.js index f1e733e8401..02dc5f085c4 100644 --- a/jstests/nestedobj1.js +++ b/jstests/nestedobj1.js @@ -14,7 +14,7 @@ t = db.objNestTest; t.drop(); t.ensureIndex({a:1}); -nestedObj = makeNestObj(500); +nestedObj = makeNestObj(300); t.insert( { tst : "test1", a : nestedObj }, true ); t.insert( { tst : "test2", a : nestedObj }, true ); diff --git a/jstests/sharding/cursor_cleanup.js b/jstests/sharding/cursor_cleanup.js new file mode 100644 index 00000000000..a28b5416e38 --- /dev/null +++ b/jstests/sharding/cursor_cleanup.js @@ -0,0 +1,62 @@ +// +// Tests cleanup of sharded and unsharded cursors +// + +var st = new ShardingTest({ shards : 2, mongos : 1, other : { separateConfig : true } }); +st.stopBalancer(); + +var mongos = st.s0; +var admin = mongos.getDB( "admin" ); +var config = mongos.getDB( "config" ); +var shards = config.shards.find().toArray(); +var coll = mongos.getCollection( "foo.bar" ); +var collUnsharded = mongos.getCollection( "foo.baz" ); + +// Shard collection +printjson(admin.runCommand({ enableSharding : coll.getDB() + "" })); +printjson(admin.runCommand({ movePrimary : coll.getDB() + "", to : shards[0]._id })); +printjson(admin.runCommand({ shardCollection : coll + "", key : { _id : 1 } })); +printjson(admin.runCommand({ split : coll + "", middle : { _id : 0 } })); +printjson(admin.runCommand({ moveChunk : coll + "", find : { _id : 0 }, to : shards[1]._id })); + +jsTest.log("Collection set up..."); +st.printShardingStatus(true); + +jsTest.log("Insert enough data to overwhelm a query batch."); + +for (var i = -150; i < 150; i++) { + coll.insert({ _id : i }); + collUnsharded.insert({ _id : i }); +} +assert.eq(null, coll.getDB().getLastError()); + +jsTest.log("Open a cursor to a sharded and unsharded collection."); + +var shardedCursor = coll.find(); +assert.neq(null, shardedCursor.next()); + +var unshardedCursor = collUnsharded.find(); +assert.neq(null, unshardedCursor.next()); + +jsTest.log("Check whether the cursor is registered in the cursor info."); + +var cursorInfo = admin.runCommand({ cursorInfo : true }); +printjson(cursorInfo); + +assert.eq(cursorInfo.sharded, 1); +assert.eq(cursorInfo.refs, 1); + +jsTest.log("End the cursors."); + +shardedCursor.itcount(); +unshardedCursor.itcount(); + +var cursorInfo = admin.runCommand({ cursorInfo : true }); +printjson(cursorInfo); + +assert.eq(cursorInfo.sharded, 0); +assert.eq(cursorInfo.refs, 0); + +jsTest.log("DONE!"); + +st.stop(); diff --git a/jstests/sharding/gle_with_conf_servers.js b/jstests/sharding/gle_with_conf_servers.js index 1fa7bde17bc..f4335a05d73 100644 --- a/jstests/sharding/gle_with_conf_servers.js +++ b/jstests/sharding/gle_with_conf_servers.js @@ -10,6 +10,14 @@ function writeToConfigTest(){ var gleObj = confDB.runCommand({ getLastError: 1, w: 'majority' }); assert( gleObj.ok ); + assert.eq("norepl", gleObj.err); + + // w:1 should still work + confDB.settings.update({ _id: 'balancer' }, { $set: { stopped: true }}); + var gleObj = confDB.runCommand({ getLastError: 1, w: 1 }); + + assert(gleObj.ok); + assert.eq(null, gleObj.err); st.stop(); } diff --git a/jstests/sharding/migrateBig.js b/jstests/sharding/migrateBig.js index d98459edd24..853a671915a 100644 --- a/jstests/sharding/migrateBig.js +++ b/jstests/sharding/migrateBig.js @@ -1,6 +1,6 @@ s = new ShardingTest( "migrateBig" , 2 , 0 , 1 , { chunksize : 1 } ); -s.config.settings.update( { _id: "balancer" }, { $set : { stopped: true } } , true ); +s.config.settings.update( { _id: "balancer" }, { $set : { stopped : true, _waitForDelete : true } } , true ); s.adminCommand( { enablesharding : "test" } ); s.adminCommand( { shardcollection : "test.foo" , key : { x : 1 } } ); diff --git a/jstests/sharding/read_pref_rs_client.js b/jstests/sharding/read_pref_rs_client.js deleted file mode 100644 index 8a458101aa2..00000000000 --- a/jstests/sharding/read_pref_rs_client.js +++ /dev/null @@ -1,220 +0,0 @@ -/** - * Testing read preference on DBClientReplicaSets, specifically on the auto-retry - * and automatic failover selection - */ -// NOTE: this test is skipped when running smoke.py with --auth because of SERVER-6972 - -function basicTest() { - var replTest = new ReplSetTest({ name: 'basic', nodes: 2, useHostName: true }); - replTest.startSet({ oplogSize: 1 }); - replTest.initiate(); - replTest.awaitSecondaryNodes(); - - var PRI_HOST = replTest.getPrimary().host; - var SEC_HOST = replTest.getSecondary().host; - - var replConn = new Mongo(replTest.getURL()); - var coll = replConn.getDB('test').user; - var dest = coll.find().readPref('primary').explain().server; - assert.eq(PRI_HOST, dest); - - // Create brand new connection to make sure that the last cached is not used - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('secondary').explain().server; - assert.eq(SEC_HOST, dest); - - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('primaryPreferred').explain().server; - assert.eq(PRI_HOST, dest); - - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('secondaryPreferred').explain().server; - assert.eq(SEC_HOST, dest); - - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - // just make sure that it doesn't throw - coll.find().readPref('nearest').explain(); - - replTest.stopSet(); -} - -function noPriNoSecTest() { - var replTest = new ReplSetTest({ name: 'noPriNoSec', useHostName: true, - nodes: [{}, { arbiter: true }, { arbiter: true }]}); - replTest.startSet({ oplogSize: 1 }); - replTest.initiate(); - replTest.awaitSecondaryNodes(); - - var replConn = new Mongo(replTest.getURL()); - var coll = replConn.getDB('test').user; - - replTest.stop(0); - - assert.throws(function() { - coll.find().readPref('primary').explain(); - }); - - // Make sure that it still fails even when trying to refresh - assert.throws(function() { - coll.find().readPref('primary').explain(); - }); - - // Don't need to create new connection because failed connections - // would never be reused, and also becasue the js Mongo contructor - // will throw when it can't connect to a primary - assert.throws(function() { - coll.find().readPref('secondary').explain(); - }); - - assert.throws(function() { - coll.find().readPref('secondary').explain(); - }); - - assert.throws(function() { - coll.find().readPref('primaryPreferred').explain(); - }); - - assert.throws(function() { - coll.find().readPref('primaryPreferred').explain(); - }); - - assert.throws(function() { - coll.find().readPref('secondaryPreferred').explain(); - }); - - assert.throws(function() { - coll.find().readPref('secondaryPreferred').explain(); - }); - - assert.throws(function() { - coll.find().readPref('neareset').explain(); - }); - - assert.throws(function() { - coll.find().readPref('nearest').explain(); - }); - - replTest.stopSet(); -} - -function priOkNoSecTest() { - var replTest = new ReplSetTest({ name: 'priOkNoSec', useHostName: true, - nodes: [{}, { arbiter: true }, {}]}); - replTest.startSet({ oplogSize: 1 }); - replTest.initiate(); - replTest.awaitSecondaryNodes(); - - var replConn = new Mongo(replTest.getURL()); - var coll = replConn.getDB('test').user; - - replTest.stop(2); - - var PRI_HOST = replTest.getPrimary().host; - - var dest = coll.find().readPref('primary').explain().server; - assert.eq(PRI_HOST, dest); - - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('primaryPreferred').explain().server; - assert.eq(PRI_HOST, dest); - - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - assert.throws(function() { - coll.find().readPref('secondary').explain(); - }); - - assert.throws(function() { - coll.find().readPref('secondary').explain(); - }); - - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('secondaryPreferred').explain().server; - assert.eq(PRI_HOST, dest); - - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('nearest').explain().server; - assert.eq(PRI_HOST, dest); - - replTest.stopSet(); -} - -function noPriSecOkTest() { - var replTest = new ReplSetTest({ name: 'noPriSecOk', useHostName: true, - nodes: [{ }, { arbiter: true }, { }]}); - replTest.startSet({ oplogSize: 1 }); - replTest.initiate(); - replTest.awaitSecondaryNodes(); - - var priConn = replTest.getPrimary(); - var conf = priConn.getDB('local').system.replset.findOne(); - conf.version++; - conf.members[0].priority = 99; - conf.members[2].priority = 0; - - var SEC_HOST = replTest.nodes[2].host; - - try { - priConn.getDB('admin').runCommand({ replSetReconfig: conf }); - } catch (x) { - print('Exception from reconfig: ' + x); - } - - var replConn = new Mongo(replTest.getURL()); - var coll = replConn.getDB('test').user; - - replTest.stop(0); - - assert.throws(function() { - coll.find().readPref('primary').explain(); - }); - - // Make sure that it still fails even when trying to refresh - assert.throws(function() { - coll.find().readPref('primary').explain(); - }); - - replConn = new Mongo(replTest.getURL()); - coll = replConn.getDB('test').user; - var dest = coll.find().readPref('primaryPreferred').explain().server; - assert.eq(SEC_HOST, dest); - - replTest.start(0, {}, true); - replTest.awaitSecondaryNodes(); - replConn = new Mongo(replTest.getURL()); - replTest.stop(0); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('secondary').explain().server; - assert.eq(SEC_HOST, dest); - - replTest.start(0, {}, true); - replTest.awaitSecondaryNodes(); - replConn = new Mongo(replTest.getURL()); - replTest.stop(0); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('secondaryPreferred').explain().server; - assert.eq(SEC_HOST, dest); - - replTest.start(0, {}, true); - replTest.awaitSecondaryNodes(); - replConn = new Mongo(replTest.getURL()); - replTest.stop(0); - coll = replConn.getDB('test').user; - dest = coll.find().readPref('nearest').explain().server; - assert.eq(SEC_HOST, dest); - - replTest.stopSet(); -} - -basicTest(); -noPriNoSecTest(); -priOkNoSecTest(); -noPriSecOkTest(); - diff --git a/jstests/slowNightly/sharding_migrateBigObject.js b/jstests/slowNightly/sharding_migrateBigObject.js index 4e4f7dd9a04..9d45e35c253 100644 --- a/jstests/slowNightly/sharding_migrateBigObject.js +++ b/jstests/slowNightly/sharding_migrateBigObject.js @@ -65,7 +65,7 @@ assert.soon( return res.length > 1 && Math.abs( res[0].nChunks - res[1].nChunks ) <= 3; } , - "never migrated" , 180000 , 1000 ); + "never migrated" , 10 * 60 * 1000 , 1000 ); stopMongod( 30000 ); stopMongod( 29999 ); diff --git a/jstests/slowNightly/ttl_repl_secondary_disabled.js b/jstests/slowNightly/ttl_repl_secondary_disabled.js new file mode 100644 index 00000000000..47a447e048d --- /dev/null +++ b/jstests/slowNightly/ttl_repl_secondary_disabled.js @@ -0,0 +1,52 @@ +/** Test TTL docs are not deleted from secondaries directly + */ + +var rt = new ReplSetTest( { name : "ttl_repl" , nodes: 2 } ); + +// setup set +var nodes = rt.startSet(); +rt.initiate(); +var master = rt.getMaster(); +rt.awaitSecondaryNodes(); +var slave1 = rt.getSecondary(); + +// shortcuts +var masterdb = master.getDB( 'd' ); +var slave1db = slave1.getDB( 'd' ); +var mastercol = masterdb[ 'c' ]; +var slave1col = slave1db[ 'c' ]; + +// create TTL index, wait for TTL monitor to kick in, then check things +mastercol.ensureIndex( { x : 1 } , { expireAfterSeconds : 10 } ); + +rt.awaitReplication(); + +//increase logging +slave1col.getDB().adminCommand({setParameter:1, logLevel:1}); + +//insert old doc (10 minutes old) directly on secondary using godinsert +slave1col.runCommand("godinsert", + {obj: {_id: new Date(), x: new Date( (new Date()).getTime() - 600000 ) } }) +assert.eq(1, slave1col.count(), "missing inserted doc" ); + +sleep(70*1000) //wait for 70seconds +assert.eq(1, slave1col.count(), "ttl deleted my doc!" ); + +// looking for this error : "Assertion: 13312:replSet error : logOp() but not primary" +// indicating that the secondary tried to delete the doc, but shouldn't be writing +var errorString = "13312"; +var foundError = false; +var globalLogLines = slave1col.getDB().adminCommand({getLog:"global"}).log +for (i in globalLogLines) { + var line = globalLogLines[i]; + if (line.match( errorString )) { + foundError = true; + errorString = line; // replace error string with what we found. + break; + } +} + +assert.eq(false, foundError, "found error in this line: " + errorString); + +// finish up +rt.stopSet();
\ No newline at end of file diff --git a/rpm/mongo.spec b/rpm/mongo.spec index 2946228d6d6..7610f421e96 100755 --- a/rpm/mongo.spec +++ b/rpm/mongo.spec @@ -1,7 +1,7 @@ Name: mongo-10gen Conflicts: mongo, mongo-10gen-unstable Obsoletes: mongo-stable -Version: 2.4.1 +Version: 2.4.0 Release: mongodb_1%{?dist} Summary: mongo client shell and tools License: AGPL 3.0 diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp index 64161cb0708..88abdb77a83 100644 --- a/src/mongo/client/dbclient.cpp +++ b/src/mongo/client/dbclient.cpp @@ -500,11 +500,19 @@ namespace mongo { return getLastErrorString( info ); } - string DBClientWithCommands::getLastErrorString( const BSONObj& info ) { - BSONElement e = info["err"]; - if( e.eoo() ) return ""; - if( e.type() == Object ) return e.toString(); - return e.str(); + string DBClientWithCommands::getLastErrorString(const BSONObj& info) { + if (info["ok"].trueValue()) { + BSONElement e = info["err"]; + if (e.eoo()) return ""; + if (e.type() == Object) return e.toString(); + return e.str(); + } else { + // command failure + BSONElement e = info["errmsg"]; + if (e.eoo()) return ""; + if (e.type() == Object) return "getLastError command failed: " + e.toString(); + return "getLastError command failed: " + e.str(); + } } const BSONObj getpreverrorcmdobj = fromjson("{getpreverror:1}"); diff --git a/src/mongo/client/dbclient_rs.cpp b/src/mongo/client/dbclient_rs.cpp index 90cbd5fcd58..2bd395d0232 100644 --- a/src/mongo/client/dbclient_rs.cpp +++ b/src/mongo/client/dbclient_rs.cpp @@ -244,19 +244,18 @@ namespace mongo { uassert(16385, "tags for read preference should be an array", tagsElem.type() == mongo::Array); - std::auto_ptr<TagSet> tags(new TagSet(BSONArray(tagsElem.Obj()))); - if (pref == mongo::ReadPreference_PrimaryOnly && !tags->isExhausted()) { + TagSet tags(BSONArray(tagsElem.Obj().getOwned())); + if (pref == mongo::ReadPreference_PrimaryOnly && !tags.isExhausted()) { uassert(16384, "Only empty tags are allowed with primary read preference", - tags->getCurrentTag().isEmpty()); + tags.getCurrentTag().isEmpty()); } - return new ReadPreferenceSetting(pref, tags.release()); + return new ReadPreferenceSetting(pref, tags); } } - BSONArrayBuilder arrayBuilder; - arrayBuilder.append(BSONObj()); - return new ReadPreferenceSetting(pref, new TagSet(arrayBuilder.arr())); + TagSet tags(BSON_ARRAY(BSONObj())); + return new ReadPreferenceSetting(pref, tags); } /** @@ -1538,8 +1537,8 @@ namespace mongo { DBClientConnection& DBClientReplicaSet::slaveConn() { BSONArray emptyArray(BSON_ARRAY(BSONObj())); TagSet tags(emptyArray); - shared_ptr<ReadPreferenceSetting> readPref(new ReadPreferenceSetting( - ReadPreference_SecondaryPreferred, new TagSet(emptyArray))); + shared_ptr<ReadPreferenceSetting> readPref( + new ReadPreferenceSetting(ReadPreference_SecondaryPreferred, tags)); DBClientConnection* conn = selectNodeUsingTags(readPref); uassert( 16369, str::stream() << "No good nodes available for set: " @@ -1743,7 +1742,7 @@ namespace mongo { ReplicaSetMonitorPtr monitor = _getMonitor(); bool isPrimarySelected = false; - _lastSlaveOkHost = monitor->selectAndCheckNode(readPref->pref, readPref->tags, + _lastSlaveOkHost = monitor->selectAndCheckNode(readPref->pref, &readPref->tags, &isPrimarySelected); if ( _lastSlaveOkHost.empty() ){ @@ -2011,6 +2010,13 @@ namespace mongo { TagSet::TagSet() : _isExhausted(true), _tagIterator(_tags) { } + TagSet::TagSet(const TagSet& other) : + _isExhausted(false), + _tags(other._tags.getOwned()), + _tagIterator(_tags) { + next(); + } + TagSet::TagSet(const BSONArray& tags) : _isExhausted(false), _tags(tags.getOwned()), @@ -2042,10 +2048,6 @@ namespace mongo { return new BSONObjIterator(_tags); } - TagSet* TagSet::clone() const { - return new TagSet(BSONArray(_tags.copy())); - } - bool TagSet::equals(const TagSet& other) const { return _tags.equal(other._tags); } diff --git a/src/mongo/client/dbclient_rs.h b/src/mongo/client/dbclient_rs.h index 45eabead460..ffdf0e0ecee 100644 --- a/src/mongo/client/dbclient_rs.h +++ b/src/mongo/client/dbclient_rs.h @@ -617,7 +617,7 @@ namespace mongo { * A simple object for representing the list of tags. The initial state will * have a valid current tag as long as the list is not empty. */ - class TagSet : public boost::noncopyable { // because of BSONArrayIteratorSorted + class TagSet { public: /** * Creates an empty tag list that is initially exhausted. @@ -625,6 +625,12 @@ namespace mongo { TagSet(); /** + * Creates a copy of the given TagSet. The new copy will have the + * iterator pointing at the initial position. + */ + explicit TagSet(const TagSet& other); + + /** * Creates a tag set object that lazily iterates over the tag list. * * @param tags the list of tags associated with this option. This object @@ -661,18 +667,18 @@ namespace mongo { BSONObjIterator* getIterator() const; /** - * Create a new copy of this tag set and wuth the iterator pointing at the - * head. - */ - TagSet* clone() const; - - /** * @returns true if the other TagSet has the same tag set specification with * this tag set, disregarding where the current iterator is pointing to. */ bool equals(const TagSet& other) const; private: + /** + * This is purposely undefined as the semantics for assignment can be + * confusing. This is because BSONArrayIteratorSorted shouldn't be + * copied (because of how it manages internal buffer). + */ + TagSet& operator=(const TagSet& other); BSONObj _currentTag; bool _isExhausted; @@ -683,25 +689,21 @@ namespace mongo { struct ReadPreferenceSetting { /** - * @param tag cannot be NULL. + * @parm pref the read preference mode. + * @param tag the tag set. Note that this object will have the + * tag set will have this in a reset state (meaning, this + * object's copy of tag will have the iterator in the initial + * position). */ - ReadPreferenceSetting(ReadPreference pref, TagSet* tag): - pref(pref), tags(tag->clone()) { - } - - ~ReadPreferenceSetting() { - delete tags; + ReadPreferenceSetting(ReadPreference pref, const TagSet& tag): + pref(pref), tags(tag) { } inline bool equals(const ReadPreferenceSetting& other) const { - return pref == other.pref && tags->equals(*other.tags); + return pref == other.pref && tags.equals(other.tags); } const ReadPreference pref; - - /** - * Note: This object owns this memory. - */ - TagSet* tags; + TagSet tags; }; } diff --git a/src/mongo/client/dbclient_rs_test.cpp b/src/mongo/client/dbclient_rs_test.cpp index 19e94a0fc9f..ccb7b71063e 100644 --- a/src/mongo/client/dbclient_rs_test.cpp +++ b/src/mongo/client/dbclient_rs_test.cpp @@ -15,7 +15,8 @@ */ /** - * This file contains tests for DBClientReplicaSet. + * This file contains tests for DBClientReplicaSet. The tests mocks the servers + * the DBClientReplicaSet talks to, so the tests only covers the client side logic. */ #include "mongo/bson/bson_field.h" @@ -25,35 +26,13 @@ #include "mongo/dbtests/mock/mock_conn_registry.h" #include "mongo/dbtests/mock/mock_replica_set.h" #include "mongo/unittest/unittest.h" +#include "mongo/util/assert_util.h" #include <map> #include <memory> #include <string> #include <vector> -using std::auto_ptr; -using std::map; -using std::make_pair; -using std::pair; -using std::string; -using std::vector; -using boost::scoped_ptr; - -using mongo::BSONField; -using mongo::BSONObj; -using mongo::BSONArray; -using mongo::BSONElement; -using mongo::ConnectionString; -using mongo::DBClientCursor; -using mongo::DBClientReplicaSet; -using mongo::HostAndPort; -using mongo::MockReplicaSet; -using mongo::Query; -using mongo::ReadPreference; -using mongo::ReplicaSetMonitor; -using mongo::ScopedDbConnection; -using mongo::TagSet; - namespace mongo { // Symbols defined to build the binary correctly. CmdLine cmdLine; @@ -73,16 +52,373 @@ namespace mongo { } } -namespace mongo_test { +namespace { + using boost::scoped_ptr; + using std::auto_ptr; + using std::map; + using std::make_pair; + using std::pair; + using std::string; + using std::vector; + + using mongo::AssertionException; + using mongo::BSONArray; + using mongo::BSONElement; + using mongo::BSONField; + using mongo::BSONObj; + using mongo::ConnectionString; + using mongo::DBClientCursor; + using mongo::DBClientReplicaSet; + using mongo::HostAndPort; + using mongo::HostField; + using mongo::IdentityNS; + using mongo::MockReplicaSet; + using mongo::Query; + using mongo::ReadPreference; + using mongo::ReplicaSetMonitor; + using mongo::ScopedDbConnection; + using mongo::TagSet; + + /** + * Basic fixture with one primary and one secondary. + */ + class BasicRS: public mongo::unittest::Test { + protected: + void setUp() { + _replSet.reset(new MockReplicaSet("test", 2)); + ConnectionString::setConnectionHook( + mongo::MockConnRegistry::get()->getConnStrHook()); + } + + void tearDown() { + ReplicaSetMonitor::remove(_replSet->getSetName(), true); + _replSet.reset(); + + // TODO: remove this after we remove replSetGetStatus from ReplicaSetMonitor. + mongo::ScopedDbConnection::clearPool(); + } + + MockReplicaSet* getReplSet() { + return _replSet.get(); + } + + private: + boost::scoped_ptr<MockReplicaSet> _replSet; + }; + + TEST_F(BasicRS, ReadFromPrimary) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); + } + + TEST_F(BasicRS, SecondaryOnly) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); + } + + TEST_F(BasicRS, PrimaryPreferred) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); + } + + TEST_F(BasicRS, SecondaryPreferred) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); + } + + /** + * Setup for 2 member replica set will all of the nodes down. + */ + class AllNodesDown: public mongo::unittest::Test { + protected: + void setUp() { + _replSet.reset(new MockReplicaSet("test", 2)); + ConnectionString::setConnectionHook( + mongo::MockConnRegistry::get()->getConnStrHook()); + + vector<HostAndPort> hostList(_replSet->getHosts()); + for (vector<HostAndPort>::const_iterator iter = hostList.begin(); + iter != hostList.end(); ++iter) { + _replSet->kill(iter->toString(true)); + } + } + + void tearDown() { + ReplicaSetMonitor::remove(_replSet->getSetName(), true); + _replSet.reset(); + + // TODO: remove this after we remove replSetGetStatus from ReplicaSetMonitor. + mongo::ScopedDbConnection::clearPool(); + } + + MockReplicaSet* getReplSet() { + return _replSet.get(); + } + + private: + boost::scoped_ptr<MockReplicaSet> _replSet; + }; + + TEST_F(AllNodesDown, ReadFromPrimary) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); + ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); + } + + TEST_F(AllNodesDown, SecondaryOnly) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); + ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); + } + + TEST_F(AllNodesDown, PrimaryPreferred) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); + ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); + } + + TEST_F(AllNodesDown, SecondaryPreferred) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); + ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); + } + + TEST_F(AllNodesDown, Nearest) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_Nearest, BSONArray()); + ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); + } + + /** + * Setup for 2 member replica set with the primary down. + */ + class PrimaryDown: public mongo::unittest::Test { + protected: + void setUp() { + _replSet.reset(new MockReplicaSet("test", 2)); + ConnectionString::setConnectionHook( + mongo::MockConnRegistry::get()->getConnStrHook()); + _replSet->kill(_replSet->getPrimary()); + } + + void tearDown() { + ReplicaSetMonitor::remove(_replSet->getSetName(), true); + _replSet.reset(); + + // TODO: remove this after we remove replSetGetStatus from ReplicaSetMonitor. + mongo::ScopedDbConnection::clearPool(); + } + + MockReplicaSet* getReplSet() { + return _replSet.get(); + } + + private: + boost::scoped_ptr<MockReplicaSet> _replSet; + }; + + TEST_F(PrimaryDown, ReadFromPrimary) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); + ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); + } + + TEST_F(PrimaryDown, SecondaryOnly) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); + } + + TEST_F(PrimaryDown, PrimaryPreferred) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); + } + + TEST_F(PrimaryDown, SecondaryPreferred) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); + } + + TEST_F(PrimaryDown, Nearest) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_Nearest, BSONArray()); + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getSecondaries().front(), doc[HostField.name()].str()); + } + + /** + * Setup for 2 member replica set with the secondary down. + */ + class SecondaryDown: public mongo::unittest::Test { + protected: + void setUp() { + _replSet.reset(new MockReplicaSet("test", 2)); + ConnectionString::setConnectionHook( + mongo::MockConnRegistry::get()->getConnStrHook()); + + _replSet->kill(_replSet->getSecondaries().front()); + } + + void tearDown() { + ReplicaSetMonitor::remove(_replSet->getSetName(), true); + _replSet.reset(); + + // TODO: remove this after we remove replSetGetStatus from ReplicaSetMonitor. + mongo::ScopedDbConnection::clearPool(); + } + + MockReplicaSet* getReplSet() { + return _replSet.get(); + } + + private: + boost::scoped_ptr<MockReplicaSet> _replSet; + }; + + TEST_F(SecondaryDown, ReadFromPrimary) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_PrimaryOnly, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); + } + + TEST_F(SecondaryDown, SecondaryOnly) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_SecondaryOnly, BSONArray()); + ASSERT_THROWS(replConn.query(IdentityNS, query), AssertionException); + } + + TEST_F(SecondaryDown, PrimaryPreferred) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); + } + + TEST_F(SecondaryDown, SecondaryPreferred) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); + } + + TEST_F(SecondaryDown, Nearest) { + MockReplicaSet* replSet = getReplSet(); + DBClientReplicaSet replConn(replSet->getSetName(), replSet->getHosts()); + + Query query; + query.readPref(mongo::ReadPreference_Nearest, BSONArray()); + + // Note: IdentityNS contains the name of the server. + auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); + BSONObj doc = cursor->next(); + ASSERT_EQUALS(replSet->getPrimary(), doc[HostField.name()].str()); + } + /** * Warning: Tests running this fixture cannot be run in parallel with other tests * that uses ConnectionString::setConnectionHook */ class TaggedFiveMemberRS: public mongo::unittest::Test { protected: - static const string IdentityNS; - static const BSONField<string> HostField; - void setUp() { _replSet.reset(new MockReplicaSet("test", 5)); _originalConnectionHook = ConnectionString::getConnectionHook(); @@ -153,6 +489,8 @@ namespace mongo_test { ConnectionString::setConnectionHook(_originalConnectionHook); ReplicaSetMonitor::remove(_replSet->getSetName(), true); _replSet.reset(); + + // TODO: remove this after we remove replSetGetStatus from ReplicaSetMonitor. mongo::ScopedDbConnection::clearPool(); } @@ -165,9 +503,6 @@ namespace mongo_test { boost::scoped_ptr<MockReplicaSet> _replSet; }; - const string TaggedFiveMemberRS::IdentityNS("local.me"); - const BSONField<string> TaggedFiveMemberRS::HostField("host", "bad"); - TEST_F(TaggedFiveMemberRS, ConnShouldPinIfSameSettings) { MockReplicaSet* replSet = getReplSet(); vector<HostAndPort> seedList; @@ -179,6 +514,8 @@ namespace mongo_test { { Query query; query.readPref(mongo::ReadPreference_PrimaryPreferred, BSONArray()); + + // Note: IdentityNS contains the name of the server. auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); @@ -205,6 +542,8 @@ namespace mongo_test { { Query query; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSONArray()); + + // Note: IdentityNS contains the name of the server. auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); @@ -233,6 +572,8 @@ namespace mongo_test { Query query; query.readPref(mongo::ReadPreference_SecondaryPreferred, BSON_ARRAY(BSON("dc" << "sf"))); + + // Note: IdentityNS contains the name of the server. auto_ptr<DBClientCursor> cursor = replConn.query(IdentityNS, query); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); @@ -261,6 +602,8 @@ namespace mongo_test { string dest; mongo::DBClientConnection& secConn = replConn.slaveConn(); + + // Note: IdentityNS contains the name of the server. auto_ptr<DBClientCursor> cursor = secConn.query(IdentityNS, Query()); BSONObj doc = cursor->next(); dest = doc[HostField.name()].str(); diff --git a/src/mongo/client/distlock.cpp b/src/mongo/client/distlock.cpp index d1fff0c1124..8b932e73b3a 100644 --- a/src/mongo/client/distlock.cpp +++ b/src/mongo/client/distlock.cpp @@ -492,12 +492,58 @@ namespace mongo { return true; } + + bool DistributedLock::isLockHeld( double timeout, string* errMsg ) { + scoped_ptr<ScopedDbConnection> connPtr( + ScopedDbConnection::getInternalScopedDbConnection( _conn.toString(), timeout ) ); + ScopedDbConnection& conn = *connPtr; + + BSONObj lockObj; + try { + lockObj = conn->findOne( LocksType::ConfigNS, + BSON( LocksType::name(_name) ) ).getOwned(); + } + catch ( DBException& e ) { + *errMsg = str::stream() << "error checking whether lock " << _name << " is held " + << causedBy( e ); + return false; + } + conn.done(); + + if ( lockObj.isEmpty() ) { + *errMsg = str::stream() << "no lock for " << _name << " exists in the locks collection"; + return false; + } + + if ( lockObj[LocksType::state()].numberInt() < 2 ) { + *errMsg = str::stream() << "lock " << _name << " current state is not held (" + << lockObj[LocksType::state()].numberInt() << ")"; + return false; + } + + if ( lockObj[LocksType::process()].String() != _processId ) { + *errMsg = str::stream() << "lock " << _name << " is currently being held by " + << "another process (" + << lockObj[LocksType::process()].String() << ")"; + return false; + } + + if ( distLockPinger.willUnlockOID( lockObj[LocksType::lockID()].OID() ) ) { + *errMsg = str::stream() << "lock " << _name << " is not held and is currently being " + << "scheduled for lazy unlock by " + << lockObj[LocksType::lockID()].OID(); + return false; + } + + return true; + } + // Semantics of this method are basically that if the lock cannot be acquired, returns false, can be retried. // If the lock should not be tried again (some unexpected error) a LockException is thrown. // If we are only trying to re-enter a currently held lock, reenter should be true. // Note: reenter doesn't actually make this lock re-entrant in the normal sense, since it can still only // be unlocked once, instead it is used to verify that the lock is already held. - bool DistributedLock::lock_try( const string& why , bool reenter, BSONObj * other ) { + bool DistributedLock::lock_try( const string& why , bool reenter, BSONObj * other, double timeout ) { // TODO: Start pinging only when we actually get the lock? // If we don't have a thread pinger, make sure we shouldn't have one @@ -520,7 +566,7 @@ namespace mongo { other = &dummyOther; scoped_ptr<ScopedDbConnection> connPtr( - ScopedDbConnection::getInternalScopedDbConnection( _conn.toString() ) ); + ScopedDbConnection::getInternalScopedDbConnection( _conn.toString(), timeout ) ); ScopedDbConnection& conn = *connPtr; BSONObjBuilder queryBuilder; diff --git a/src/mongo/client/distlock.h b/src/mongo/client/distlock.h index c51f766f1ba..183826afcce 100644 --- a/src/mongo/client/distlock.h +++ b/src/mongo/client/distlock.h @@ -123,7 +123,15 @@ namespace mongo { * details if not * @return true if it managed to grab the lock */ - bool lock_try( const string& why , bool reenter = false, BSONObj * other = 0 ); + bool lock_try( const string& why , bool reenter = false, BSONObj * other = 0, double timeout = 0.0 ); + + /** + * Returns true if we currently believe we hold this lock and it was possible to + * confirm that, within 'timeout' seconds, if provided, with the config servers. If the + * lock is not held or if we failed to contact the config servers within the timeout, + * returns false. + */ + bool isLockHeld( double timeout, string* errMsg ); /** * Releases a previously taken lock. @@ -223,9 +231,9 @@ namespace mongo { return *this; } - dist_lock_try( DistributedLock * lock , const std::string& why ) + dist_lock_try( DistributedLock * lock , const std::string& why, double timeout = 0.0 ) : _lock(lock), _why(why) { - _got = _lock->lock_try( why , false , &_other ); + _got = _lock->lock_try( why , false , &_other, timeout ); } ~dist_lock_try() { @@ -235,16 +243,23 @@ namespace mongo { } } - bool reestablish(){ - return retry(); - } + /** + * Returns false if the lock is known _not_ to be held, otherwise asks the underlying + * lock to issue a 'isLockHeld' call and returns whatever that calls does. + */ + bool isLockHeld( double timeout, string* errMsg) { + if ( !_lock ) { + *errMsg = "Lock is not currently set up"; + return false; + } - bool retry() { - verify( _lock ); - verify( _got ); - verify( ! _other.isEmpty() ); + if ( !_got ) { + *errMsg = str::stream() << "Lock " << _lock->_name << " is currently held by " + << _other; + return false; + } - return _got = _lock->lock_try( _why , true, &_other ); + return _lock->isLockHeld( timeout, errMsg ); } bool got() const { return _got; } diff --git a/src/mongo/client/syncclusterconnection.cpp b/src/mongo/client/syncclusterconnection.cpp index 3183f337203..7bb538079eb 100644 --- a/src/mongo/client/syncclusterconnection.cpp +++ b/src/mongo/client/syncclusterconnection.cpp @@ -181,7 +181,7 @@ namespace mongo { if ( lockType > 0 ) { // write $cmd string errmsg; if ( ! prepare( errmsg ) ) - throw UserException( 13104 , (string)"SyncClusterConnection::findOne prepare failed: " + errmsg ); + throw UserException( PrepareConfigsFailedCode , (string)"SyncClusterConnection::findOne prepare failed: " + errmsg ); vector<BSONObj> all; for ( size_t i=0; i<_conns.size(); i++ ) { @@ -336,7 +336,31 @@ namespace mongo { return; } - uassert( 10023 , "SyncClusterConnection bulk insert not implemented" , 0); + for (vector<BSONObj>::const_iterator it = v.begin(); it != v.end(); ++it ) { + BSONObj obj = *it; + if ( obj["_id"].type() == EOO ) { + string assertMsg = "SyncClusterConnection::insert (batched) obj misses an _id: "; + uasserted( 16743, assertMsg + obj.jsonString() ); + } + } + + // fsync all connections before starting the batch. + string errmsg; + if ( ! prepare( errmsg ) ) { + string assertMsg = "SyncClusterConnection::insert (batched) prepare failed: "; + throw UserException( 16744, assertMsg + errmsg ); + } + + // We still want one getlasterror per document, even if they're batched. + for ( size_t i=0; i<_conns.size(); i++ ) { + for ( vector<BSONObj>::const_iterator it = v.begin(); it != v.end(); ++it ) { + _conns[i]->insert( ns, *it, flags ); + _conns[i]->getLastErrorDetailed(); + } + } + + // We issue a final getlasterror, but this time with an fsync. + _checkLast(); } void SyncClusterConnection::remove( const string &ns , Query query, int flags ) { diff --git a/src/mongo/db/auth/auth_external_state.cpp b/src/mongo/db/auth/auth_external_state.cpp index f6e3eb9e387..946b75b322a 100644 --- a/src/mongo/db/auth/auth_external_state.cpp +++ b/src/mongo/db/auth/auth_external_state.cpp @@ -30,9 +30,12 @@ namespace mongo { const PrincipalName& principalName, BSONObj* result) { - if (dbname == StringData("$external", StringData::LiteralTag())) { + if (dbname == StringData("$external", StringData::LiteralTag()) || + dbname == AuthorizationManager::SERVER_RESOURCE_NAME || + dbname == AuthorizationManager::CLUSTER_RESOURCE_NAME) { return Status(ErrorCodes::UserNotFound, - "No privilege documents stored in the $external user source."); + mongoutils::str::stream() << "No privilege documents stored in the " << + dbname << " user source."); } if (!NamespaceString::validDBName(dbname)) { diff --git a/src/mongo/db/auth/auth_index_d.cpp b/src/mongo/db/auth/auth_index_d.cpp index 2f809219341..3ce6c0de43f 100644 --- a/src/mongo/db/auth/auth_index_d.cpp +++ b/src/mongo/db/auth/auth_index_d.cpp @@ -23,6 +23,7 @@ #include "mongo/db/index_update.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_details.h" +#include "mongo/util/assert_util.h" #include "mongo/util/log.h" namespace mongo { @@ -90,10 +91,21 @@ namespace { void createSystemIndexes(const NamespaceString& ns) { if (ns.coll == "system.users") { - Helpers::ensureIndex(ns.ns().c_str(), - extendedSystemUsersKeyPattern, - true, // unique - extendedSystemUsersIndexName.c_str()); + try { + Helpers::ensureIndex(ns.ns().c_str(), + extendedSystemUsersKeyPattern, + true, // unique + extendedSystemUsersIndexName.c_str()); + } catch (const DBException& e) { + if (e.getCode() == ASSERT_ID_DUPKEY) { + log() << "Duplicate key exception while trying to build unique index on " << + ns << ". You most likely have user documents with duplicate \"user\" " + "fields. To resolve this, start up with a version of MongoDB prior to " + "2.4, drop the duplicate user documents, then start up again with the " + "current version." << endl; + } + throw; + } } } diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp index da97299d719..bcc5a2f16a0 100644 --- a/src/mongo/db/commands/authentication_commands.cpp +++ b/src/mongo/db/commands/authentication_commands.cpp @@ -16,10 +16,12 @@ #include "mongo/db/commands/authentication_commands.h" +#include <boost/scoped_ptr.hpp> #include <string> #include <vector> #include "mongo/base/status.h" +#include "mongo/client/sasl_client_authenticate.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" @@ -29,6 +31,7 @@ #include "mongo/db/commands.h" #include "mongo/db/jsobj.h" #include "mongo/platform/random.h" +#include "mongo/util/concurrency/mutex.h" #include "mongo/util/md5.hpp" namespace mongo { @@ -53,8 +56,10 @@ namespace mongo { class CmdGetNonce : public Command { public: - CmdGetNonce() : Command("getnonce") { - _random = SecureRandom::create(); + CmdGetNonce() : + Command("getnonce"), + _randMutex("getnonce"), + _random(SecureRandom::create()) { } virtual bool requiresAuth() { return false; } @@ -68,7 +73,7 @@ namespace mongo { const BSONObj& cmdObj, std::vector<Privilege>* out) {} // No auth required bool run(const string&, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { - nonce64 n = _random->nextInt64(); + nonce64 n = getNextNonce(); stringstream ss; ss << hex << n; result.append("nonce", ss.str() ); @@ -77,7 +82,14 @@ namespace mongo { return true; } - SecureRandom* _random; + private: + nonce64 getNextNonce() { + SimpleMutex::scoped_lock lk(_randMutex); + return _random->nextInt64(); + } + + SimpleMutex _randMutex; // Synchronizes accesses to _random. + boost::scoped_ptr<SecureRandom> _random; } cmdGetNonce; bool CmdAuthenticate::run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { @@ -92,6 +104,7 @@ namespace mongo { if (dbname != StringData("local", StringData::LiteralTag()) || user != internalSecurity.user) { errmsg = _nonceAuthenticateCommandsDisabledMessage; + result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } } @@ -105,6 +118,7 @@ namespace mongo { << endl; errmsg = "auth fails"; sleepmillis(10); + result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } @@ -132,6 +146,7 @@ namespace mongo { log() << "auth: bad nonce received or getnonce not called. could be a driver bug or a security attack. db:" << dbname << endl; errmsg = "auth fails"; sleepmillis(30); + result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } } @@ -143,6 +158,7 @@ namespace mongo { if (!status.isOK()) { log() << status.reason() << std::endl; errmsg = "auth fails"; + result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } pwd = userObj["pwd"].String(); @@ -163,6 +179,7 @@ namespace mongo { if ( key != computed ) { log() << "auth: key mismatch " << user << ", ns:" << dbname << endl; errmsg = "auth fails"; + result.append(saslCommandCodeFieldName, ErrorCodes::AuthenticationFailed); return false; } diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index b06ff459847..2b345c70200 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -187,7 +187,9 @@ namespace mongo { BSONElement e = cmdObj["w"]; if ( e.ok() ) { - if ( cmdLine.configsvr ) { + if ( cmdLine.configsvr && (!e.isNumber() || e.numberInt() > 1) ) { + // w:1 on config servers should still work, but anything greater than that + // should not. result.append( "wnote", "can't use w on config servers" ); result.append( "err", "norepl" ); return true; diff --git a/src/mongo/db/fts/fts_command_mongod.cpp b/src/mongo/db/fts/fts_command_mongod.cpp index 979222cc72b..6fe534ad681 100644 --- a/src/mongo/db/fts/fts_command_mongod.cpp +++ b/src/mongo/db/fts/fts_command_mongod.cpp @@ -89,14 +89,14 @@ namespace mongo { const IndexDetails& id = d->idx( idxMatches[0] ); BSONObj indexPrefix; + FTSIndex* ftsIndex = static_cast<FTSIndex*>(id.getSpec().getType()); if ( language == "" ) { - FTSIndex* ftsIndex = static_cast<FTSIndex*>(id.getSpec().getType()); language = ftsIndex->getFtsSpec().defaultLanguage(); - Status s = ftsIndex->getFtsSpec().getIndexPrefix( filter, &indexPrefix ); - if ( !s.isOK() ) { - errmsg = s.toString(); - return false; - } + } + Status s = ftsIndex->getFtsSpec().getIndexPrefix( filter, &indexPrefix ); + if ( !s.isOK() ) { + errmsg = s.toString(); + return false; } diff --git a/src/mongo/db/geo/geoparser.cpp b/src/mongo/db/geo/geoparser.cpp index 3b53b30cdd2..f74022dde76 100644 --- a/src/mongo/db/geo/geoparser.cpp +++ b/src/mongo/db/geo/geoparser.cpp @@ -68,7 +68,9 @@ namespace mongo { } // ...where the latitude is valid double lat = thisCoord[1].Number(); + double lng = thisCoord[0].Number(); if (lat < -90 || lat > 90) { return false; } + if (lng < -180 || lng > 180) { return false; } } return true; } @@ -101,7 +103,8 @@ namespace mongo { if (coordinates.size() != 2) { return false; } if (!coordinates[0].isNumber() || !coordinates[1].isNumber()) { return false; } double lat = coordinates[1].Number(); - return lat >= -90 && lat <= 90; + double lng = coordinates[0].Number(); + return lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180; } void GeoParser::parseGeoJSONPoint(const BSONObj& obj, S2Cell* out) { diff --git a/src/mongo/db/geo/geoparser_test.cpp b/src/mongo/db/geo/geoparser_test.cpp index 2e7fffb515f..cb3af1a119e 100644 --- a/src/mongo/db/geo/geoparser_test.cpp +++ b/src/mongo/db/geo/geoparser_test.cpp @@ -54,6 +54,10 @@ namespace { // Make sure lat is in range ASSERT_TRUE(GeoParser::isPoint(fromjson("{'type':'Point', 'coordinates': [0, 90.0]}"))); ASSERT_TRUE(GeoParser::isPoint(fromjson("{'type':'Point', 'coordinates': [0, -90.0]}"))); + ASSERT_TRUE(GeoParser::isPoint(fromjson("{'type':'Point', 'coordinates': [180, 90.0]}"))); + ASSERT_TRUE(GeoParser::isPoint(fromjson("{'type':'Point', 'coordinates': [-180, -90.0]}"))); + ASSERT_FALSE(GeoParser::isPoint(fromjson("{'type':'Point', 'coordinates': [180.01, 90.0]}"))); + ASSERT_FALSE(GeoParser::isPoint(fromjson("{'type':'Point', 'coordinates': [-180.01, -90.0]}"))); ASSERT_FALSE(GeoParser::isPoint(fromjson("{'type':'Point', 'coordinates': [0, 90.1]}"))); ASSERT_FALSE(GeoParser::isPoint(fromjson("{'type':'Point', 'coordinates': [0, -90.1]}"))); } @@ -63,6 +67,10 @@ namespace { fromjson("{'type':'LineString', 'coordinates':[[1,2], [3,4]]}"))); ASSERT_TRUE(GeoParser::isLineString( fromjson("{'type':'LineString', 'coordinates':[[0,-90], [0,90]]}"))); + ASSERT_TRUE(GeoParser::isLineString( + fromjson("{'type':'LineString', 'coordinates':[[180,-90], [-180,90]]}"))); + ASSERT_FALSE(GeoParser::isLineString( + fromjson("{'type':'LineString', 'coordinates':[[180.1,-90], [-180.1,90]]}"))); ASSERT_FALSE(GeoParser::isLineString( fromjson("{'type':'LineString', 'coordinates':[[0,-91], [0,90]]}"))); ASSERT_FALSE(GeoParser::isLineString( @@ -82,6 +90,13 @@ namespace { TEST(GeoParser, isValidPolygon) { ASSERT_TRUE(GeoParser::isPolygon( fromjson("{'type':'Polygon', 'coordinates':[ [[0,0],[5,0],[5,5],[0,5],[0,0]] ]}"))); + // No out of bounds points + ASSERT_FALSE(GeoParser::isPolygon( + fromjson("{'type':'Polygon', 'coordinates':[ [[0,0],[5,0],[5,91],[0,5],[0,0]] ]}"))); + ASSERT_TRUE(GeoParser::isPolygon( + fromjson("{'type':'Polygon', 'coordinates':[ [[0,0],[180,0],[5,5],[0,5],[0,0]] ]}"))); + ASSERT_FALSE(GeoParser::isPolygon( + fromjson("{'type':'Polygon', 'coordinates':[ [[0,0],[181,0],[5,5],[0,5],[0,0]] ]}"))); // And one with a hole. ASSERT_TRUE(GeoParser::isPolygon( fromjson("{'type':'Polygon', 'coordinates':[ [[0,0],[5,0],[5,5],[0,5],[0,0]]," diff --git a/src/mongo/db/geo/s2cursor.cpp b/src/mongo/db/geo/s2cursor.cpp index f94971d8e08..56bb9230ce2 100644 --- a/src/mongo/db/geo/s2cursor.cpp +++ b/src/mongo/db/geo/s2cursor.cpp @@ -97,6 +97,12 @@ namespace mongo { BSONObj S2Cursor::currKey() const { return _btreeCursor->currKey(); } DiskLoc S2Cursor::refLoc() { return DiskLoc(); } long long S2Cursor::nscanned() { return _nscanned; } + bool S2Cursor::getsetdup(DiskLoc loc) { return _btreeCursor->getsetdup(loc); } + void S2Cursor::aboutToDeleteBucket(const DiskLoc& b) { + if (NULL != _btreeCursor) { + _btreeCursor->aboutToDeleteBucket(b); + } + } // This is the actual search. bool S2Cursor::advance() { diff --git a/src/mongo/db/geo/s2cursor.h b/src/mongo/db/geo/s2cursor.h index ec4881d40db..d3cfa9e21b1 100644 --- a/src/mongo/db/geo/s2cursor.h +++ b/src/mongo/db/geo/s2cursor.h @@ -39,7 +39,8 @@ namespace mongo { virtual bool isMultiKey() const { return true; } virtual bool autoDedup() const { return false; } virtual bool modifiedKeys() const { return true; } - virtual bool getsetdup(DiskLoc loc) { return false; } + virtual bool getsetdup(DiskLoc loc); + virtual void aboutToDeleteBucket(const DiskLoc& b); virtual string toString() { return "S2Cursor"; } BSONObj indexKeyPattern() { return _keyPattern; } virtual bool ok(); diff --git a/src/mongo/db/json.cpp b/src/mongo/db/json.cpp index 74fac9f1b3c..afe08f3b0f5 100644 --- a/src/mongo/db/json.cpp +++ b/src/mongo/db/json.cpp @@ -465,6 +465,9 @@ namespace mongo { } Status JParse::dbRefObject(const StringData& fieldName, BSONObjBuilder& builder) { + + BSONObjBuilder subBuilder(builder.subobjStart(fieldName)); + if (!accept(COLON)) { return parseError("Expecting ':'"); } @@ -474,6 +477,8 @@ namespace mongo { if (ret != Status::OK()) { return ret; } + subBuilder.append("$ref", ns); + if (!accept(COMMA)) { return parseError("Expecting ','"); } @@ -484,42 +489,12 @@ namespace mongo { if (!accept(COLON)) { return parseError("Expecting ':'"); } - if (accept("ObjectId")) { - BSONObjBuilder subBuilder(builder.subobjStart(fieldName)); - subBuilder.append("$ref", ns); - objectId("$id", subBuilder); - subBuilder.done(); - } - else if (accept(LBRACE)) { - BSONObjBuilder subBuilder(builder.subobjStart(fieldName)); - subBuilder.append("$ref", ns); - if (!acceptField("$oid")) { - return parseError("Expected field name: \"$oid\""); - } - objectIdObject("$id", subBuilder); - subBuilder.done(); - if (!accept(RBRACE)) { - return parseError("Expecting '}'"); - } - } - else { - std::string id; - id.reserve(ID_RESERVE_SIZE); - Status ret = quotedString(&id); - if (ret != Status::OK()) { - return ret; - } - if (id.size() != 24) { - return parseError("Expecting 24 hex digits: " + id); - } - if (!isHexString(id)) { - return parseError("Expecting hex digits: " + id); - } - BSONObjBuilder subBuilder(builder.subobjStart(fieldName)); - subBuilder.append("$ref", ns); - subBuilder.append("$id", OID(id)); - subBuilder.done(); + Status valueRet = value("$id", subBuilder); + if (valueRet != Status::OK()) { + return valueRet; } + + subBuilder.done(); return Status::OK(); } @@ -661,6 +636,8 @@ namespace mongo { } Status JParse::dbRef(const StringData& fieldName, BSONObjBuilder& builder) { + BSONObjBuilder subBuilder(builder.subobjStart(fieldName)); + if (!accept(LPAREN)) { return parseError("Expecting '('"); } @@ -670,27 +647,21 @@ namespace mongo { if (refRet != Status::OK()) { return refRet; } + subBuilder.append("$ref", ns); + if (!accept(COMMA)) { return parseError("Expecting ','"); } - std::string id; - id.reserve(ID_RESERVE_SIZE); - Status idRet = quotedString(&id); - if (idRet != Status::OK()) { - return idRet; - } - if (id.size() != 24) { - return parseError("Expecting 24 hex digits: " + id); - } - if (!isHexString(id)) { - return parseError("Expecting hex digits: " + id); + + Status valueRet = value("$id", subBuilder); + if (valueRet != Status::OK()) { + return valueRet; } + if (!accept(RPAREN)) { return parseError("Expecting ')'"); } - BSONObjBuilder subBuilder(builder.subobjStart(fieldName)); - subBuilder.append("$ref", ns); - subBuilder.append("$id", OID(id)); + subBuilder.done(); return Status::OK(); } diff --git a/src/mongo/db/repl/health.cpp b/src/mongo/db/repl/health.cpp index 7c2f85f6c87..a45809df732 100644 --- a/src/mongo/db/repl/health.cpp +++ b/src/mongo/db/repl/health.cpp @@ -446,6 +446,11 @@ namespace mongo { bb.append("authenticated", false); } + string syncingTo = m->hbinfo().syncingTo; + if (!syncingTo.empty()) { + bb.append("syncingTo", syncingTo); + } + v.push_back(bb.obj()); m = m->next(); } diff --git a/src/mongo/db/repl/heartbeat.cpp b/src/mongo/db/repl/heartbeat.cpp index fbac43b1d99..5ba3d5f3427 100644 --- a/src/mongo/db/repl/heartbeat.cpp +++ b/src/mongo/db/repl/heartbeat.cpp @@ -122,6 +122,11 @@ namespace mongo { result.append("hbmsg", theReplSet->hbmsg()); result.append("time", (long long) time(0)); result.appendDate("opTime", theReplSet->lastOpTimeWritten.asDate()); + const Member *syncTarget = replset::BackgroundSync::get()->getSyncTarget(); + if (syncTarget) { + result.append("syncingTo", syncTarget->fullName()); + } + int v = theReplSet->config().version; result.append("v", v); if( v > cmdObj["v"].Int() ) @@ -396,6 +401,10 @@ namespace mongo { } mem.health = 1.0; mem.lastHeartbeatMsg = info["hbmsg"].String(); + if (info.hasElement("syncingTo")) { + mem.syncingTo = info["syncingTo"].String(); + } + if( info.hasElement("opTime") ) mem.opTime = info["opTime"].Date(); diff --git a/src/mongo/db/repl/rs_member.h b/src/mongo/db/repl/rs_member.h index 967052c4da8..100a2013314 100644 --- a/src/mongo/db/repl/rs_member.h +++ b/src/mongo/db/repl/rs_member.h @@ -84,6 +84,7 @@ namespace mongo { // This is the last time we got a heartbeat request from a given member. time_t lastHeartbeatRecv; DiagStr lastHeartbeatMsg; + DiagStr syncingTo; OpTime opTime; int skew; bool authIssue; diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp index d94552cb5fc..584bc20a3bc 100644 --- a/src/mongo/db/ttl.cpp +++ b/src/mongo/db/ttl.cpp @@ -50,6 +50,9 @@ namespace mongo { void doTTLForDB( const string& dbName ) { + //check isMaster before becoming god + bool isMaster = isMasterNs( dbName.c_str() ); + Client::GodScope god; vector<BSONObj> indexes; @@ -100,7 +103,7 @@ namespace mongo { nsd->syncUserFlags( ns ); } // only do deletes if on master - if ( ! isMasterNs( dbName.c_str() ) ) { + if ( ! isMaster ) { continue; } diff --git a/src/mongo/dbtests/gle_test.cpp b/src/mongo/dbtests/gle_test.cpp new file mode 100644 index 00000000000..1a5f89ad1b2 --- /dev/null +++ b/src/mongo/dbtests/gle_test.cpp @@ -0,0 +1,85 @@ +/** + * Copyright (C) 2013 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/>. + */ + +#include "mongo/dbtests/dbtests.h" +#include "mongo/util/assert_util.h" + +using mongo::MsgAssertionException; + +/** + * Test getLastError client handling + */ +namespace { + DBDirectClient _client; + static const char* const _ns = "unittests.gle"; + + /** + * Verify that when the command fails we get back an error message. + */ + class GetLastErrorCommandFailure { + public: + void run() { + _client.insert(_ns, BSON( "test" << "test")); + // Cannot mix fsync + j, will make command fail + string gleString = _client.getLastError(true, true, 10, 10); + ASSERT_NOT_EQUALS(gleString, ""); + } + }; + + /** + * Verify that the write succeeds + */ + class GetLastErrorClean { + public: + void run() { + _client.insert(_ns, BSON( "test" << "test")); + // Make sure there was no error + string gleString = _client.getLastError(); + ASSERT_EQUALS(gleString, ""); + } + }; + + /** + * Verify that the write succeed first, then error on dup + */ + class GetLastErrorFromDup { + public: + void run() { + _client.insert(_ns, BSON( "_id" << 1)); + // Make sure there was no error + string gleString = _client.getLastError(); + ASSERT_EQUALS(gleString, ""); + + //insert dup + _client.insert(_ns, BSON( "_id" << 1)); + // Make sure there was an error + gleString = _client.getLastError(); + ASSERT_NOT_EQUALS(gleString, ""); + } + }; + + class All : public Suite { + public: + All() : Suite( "gle" ) { + } + + void setupTests() { + add< GetLastErrorClean >(); + add< GetLastErrorCommandFailure >(); + add< GetLastErrorFromDup >(); + } + } myall; +} diff --git a/src/mongo/dbtests/jsontests.cpp b/src/mongo/dbtests/jsontests.cpp index 0afee14a37b..98a5624dbd4 100644 --- a/src/mongo/dbtests/jsontests.cpp +++ b/src/mongo/dbtests/jsontests.cpp @@ -860,11 +860,9 @@ namespace JsonTests { class DBRefConstructor : public Base { virtual BSONObj bson() const { BSONObjBuilder b; - OID o; - memset( &o, 0, 12 ); BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); - subBuilder.append("$id", o); + subBuilder.append("$id", "000000000000000000000000"); subBuilder.done(); return b.obj(); } @@ -877,11 +875,9 @@ namespace JsonTests { class DBRefConstructorCapitals : public Base { virtual BSONObj bson() const { BSONObjBuilder b; - OID o; - memset( &o, 0, 12 ); BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); - subBuilder.append("$id", o); + subBuilder.append("$id", "000000000000000000000000"); subBuilder.done(); return b.obj(); } @@ -890,14 +886,40 @@ namespace JsonTests { } }; - class DBRefObjectIDString : public Base { + class DBRefConstructorNumber : public Base { virtual BSONObj bson() const { BSONObjBuilder b; - OID o; - memset( &o, 0, 12 ); BSONObjBuilder subBuilder(b.subobjStart("a")); subBuilder.append("$ref", "ns"); - subBuilder.append("$id", o); + subBuilder.append("$id", 1); + subBuilder.done(); + return b.obj(); + } + virtual string json() const { + return "{ \"a\" : Dbref( \"ns\", 1 ) }"; + } + }; + + class DBRefNumberId : public Base { + virtual BSONObj bson() const { + BSONObjBuilder b; + BSONObjBuilder subBuilder(b.subobjStart("a")); + subBuilder.append("$ref", "ns"); + subBuilder.append("$id", 1); + subBuilder.done(); + return b.obj(); + } + virtual string json() const { + return "{ \"a\" : { \"$ref\" : \"ns\", \"$id\" : 1 } }"; + } + }; + + class DBRefStringId : public Base { + virtual BSONObj bson() const { + BSONObjBuilder b; + BSONObjBuilder subBuilder(b.subobjStart("a")); + subBuilder.append("$ref", "ns"); + subBuilder.append("$id", "000000000000000000000000"); subBuilder.done(); return b.obj(); } @@ -1605,7 +1627,8 @@ namespace JsonTests { add< FromJsonTests::Utf8TooShort >(); add< FromJsonTests::DBRefConstructor >(); add< FromJsonTests::DBRefConstructorCapitals >(); - add< FromJsonTests::DBRefObjectIDString >(); + add< FromJsonTests::DBRefNumberId >(); + add< FromJsonTests::DBRefStringId >(); add< FromJsonTests::DBRefObjectIDObject >(); add< FromJsonTests::DBRefObjectIDConstructor >(); add< FromJsonTests::Oid >(); diff --git a/src/mongo/dbtests/jstests.cpp b/src/mongo/dbtests/jstests.cpp index 5e5bd597ee2..67262de778b 100644 --- a/src/mongo/dbtests/jstests.cpp +++ b/src/mongo/dbtests/jstests.cpp @@ -18,14 +18,12 @@ */ #include "pch.h" -#include "../db/instance.h" -#include "mongo/db/json.h" - -#include "../pch.h" -#include "../scripting/engine.h" -#include "../util/timer.h" -#include "dbtests.h" +#include "mongo/db/instance.h" +#include "mongo/scripting/engine.h" +#include "mongo/util/timer.h" +#include "mongo/dbtests/dbtests.h" +#include "mongo/db/json.h" namespace mongo { bool dbEval(const string& dbName , BSONObj& cmd, BSONObjBuilder& result, string& errmsg); @@ -33,14 +31,10 @@ namespace mongo { namespace JSTests { - class Fundamental { + class BuiltinTests { public: void run() { - // By calling JavaJSImpl() inside run(), we ensure the unit test framework's - // signal handlers are pre-installed from JNI's perspective. This allows - // JNI to catch signals generated within the JVM and forward other signals - // as appropriate. - ScriptEngine::setup(); + // Run any tests included with the scripting engine globalScriptEngine->runTest(); } }; @@ -48,7 +42,7 @@ namespace JSTests { class BasicScope { public: void run() { - auto_ptr<Scope> s; + scoped_ptr<Scope> s; s.reset( globalScriptEngine->newScope() ); s->setNumber( "x" , 5 ); @@ -63,18 +57,15 @@ namespace JSTests { s->setBoolean( "b" , true ); ASSERT( s->getBoolean( "b" ) ); - if ( 0 ) { - s->setBoolean( "b" , false ); - ASSERT( ! s->getBoolean( "b" ) ); - } + s->setBoolean( "b" , false ); + ASSERT( ! s->getBoolean( "b" ) ); } }; class ResetScope { public: void run() { - // Not worrying about this for now SERVER-446. - /* + /* Currently reset does not clear data in v8 or spidermonkey scopes. See SECURITY-10 auto_ptr<Scope> s; s.reset( globalScriptEngine->newScope() ); @@ -90,15 +81,23 @@ namespace JSTests { class FalseTests { public: void run() { - Scope * s = globalScriptEngine->newScope(); + // Test falsy javascript values + scoped_ptr<Scope> s; + s.reset( globalScriptEngine->newScope() ); - ASSERT( ! s->getBoolean( "x" ) ); + ASSERT( ! s->getBoolean( "notSet" ) ); - s->setString( "z" , "" ); - ASSERT( ! s->getBoolean( "z" ) ); + s->setString( "emptyString" , "" ); + ASSERT( ! s->getBoolean( "emptyString" ) ); + s->setNumber( "notANumberVal" , std::numeric_limits<double>::quiet_NaN()); + ASSERT( ! s->getBoolean( "notANumberVal" ) ); - delete s ; + s->setElement( "nullVal" , BSONObjBuilder().appendNull("null").obj().getField("null") ); + ASSERT( ! s->getBoolean( "nullVal" ) ); + + s->setNumber( "zeroVal" , 0 ); + ASSERT( ! s->getBoolean( "zeroVal" ) ); } }; @@ -453,6 +452,22 @@ namespace JSTests { ASSERT_EQUALS( Array, out.firstElement().type() ); } + // symbol + { + // test mutable object with symbol type + BSONObjBuilder builder; + builder.appendSymbol("sym", "value"); + BSONObj in = builder.done(); + s->setObject( "x", in, false ); + BSONObj out = s->getObject( "x" ); + ASSERT_EQUALS( Symbol, out.firstElement().type() ); + + // readonly + s->setObject( "x", in, true ); + out = s->getObject( "x" ); + ASSERT_EQUALS( Symbol, out.firstElement().type() ); + } + delete s; } }; @@ -940,70 +955,194 @@ namespace JSTests { } }; - class DBRefTest { - public: - DBRefTest() { - _a = "unittest.dbref.a"; - _b = "unittest.dbref.b"; - reset(); - } - ~DBRefTest() { - //reset(); - } + namespace RoundTripTests { - void run() { + // Inherit from this class to test round tripping of JSON objects + class TestRoundTrip { + public: + virtual ~TestRoundTrip() {} + void run() { - client.insert( _a , BSON( "a" << "17" ) ); + // Insert in Javascript -> Find using DBDirectClient - { - BSONObj fromA = client.findOne( _a , BSONObj() ); - verify( fromA.valid() ); - //cout << "Froma : " << fromA << endl; + // Drop the collection + client.dropCollection( "unittest.testroundtrip" ); + + // Insert in Javascript + stringstream jsInsert; + jsInsert << "db.testroundtrip.insert(" << jsonIn() << ")"; + ASSERT_TRUE( client.eval( "unittest" , jsInsert.str() ) ); + + // Find using DBDirectClient + BSONObj excludeIdProjection = BSON( "_id" << 0 ); + BSONObj directFind = client.findOne( "unittest.testroundtrip", + "", + &excludeIdProjection); + bsonEquals( bson(), directFind ); + + + // Insert using DBDirectClient -> Find in Javascript + + // Drop the collection + client.dropCollection( "unittest.testroundtrip" ); + + // Insert using DBDirectClient + client.insert( "unittest.testroundtrip" , bson() ); + + // Find in Javascript + stringstream jsFind; + jsFind << "dbref = db.testroundtrip.findOne( { } , { _id : 0 } )\n" + << "assert.eq(dbref, " << jsonOut() << ")"; + ASSERT_TRUE( client.eval( "unittest" , jsFind.str() ) ); + } + protected: + + // Methods that must be defined by child classes + virtual BSONObj bson() const = 0; + virtual string json() const = 0; + + // This can be overriden if a different meaning of equality besides woCompare is needed + virtual void bsonEquals( const BSONObj &expected, const BSONObj &actual ) { + if ( expected.woCompare( actual ) ) { + out() << "want:" << expected.jsonString() << " size: " << expected.objsize() << endl; + out() << "got :" << actual.jsonString() << " size: " << actual.objsize() << endl; + out() << expected.hexDump() << endl; + out() << actual.hexDump() << endl; + } + ASSERT( !expected.woCompare( actual ) ); + } + + // This can be overriden if the JSON representation is altered on the round trip + virtual string jsonIn() const { + return json(); + } + virtual string jsonOut() const { + return json(); + } + }; + + class DBRefTest : public TestRoundTrip { + virtual BSONObj bson() const { BSONObjBuilder b; - b.append( "b" , 18 ); - b.appendDBRef( "c" , "dbref.a" , fromA["_id"].__oid() ); - client.insert( _b , b.obj() ); + OID o; + memset( &o, 0, 12 ); + BSONObjBuilder subBuilder(b.subobjStart("a")); + subBuilder.append("$ref", "ns"); + subBuilder.append("$id", o); + subBuilder.done(); + return b.obj(); + } + virtual string json() const { + return "{ \"a\" : DBRef( \"ns\", ObjectId( \"000000000000000000000000\" ) ) }"; } - ASSERT( client.eval( "unittest" , "x = db.dbref.b.findOne(); assert.eq( 17 , x.c.fetch().a , 'ref working' );" ) ); + // A "fetch" function is added to the DBRef object when it is inserted using the + // constructor, so we need to compare the fields individually + virtual void bsonEquals( const BSONObj &expected, const BSONObj &actual ) { + ASSERT_EQUALS( expected["a"].type() , actual["a"].type() ); + ASSERT_EQUALS( expected["a"]["$id"].OID() , actual["a"]["$id"].OID() ); + ASSERT_EQUALS( expected["a"]["$ref"].String() , actual["a"]["$ref"].String() ); + } + }; - // BSON DBRef <=> JS DBPointer - ASSERT( client.eval( "unittest", "x = db.dbref.b.findOne(); db.dbref.b.drop(); x.c = new DBPointer( x.c.ns, x.c.id ); db.dbref.b.insert( x );" ) ); - ASSERT_EQUALS( DBRef, client.findOne( "unittest.dbref.b", "" )[ "c" ].type() ); + class DBPointerTest : public TestRoundTrip { + virtual BSONObj bson() const { + BSONObjBuilder b; + OID o; + memset( &o, 0, 12 ); + b.appendDBRef( "a" , "ns" , o ); + return b.obj(); + } + virtual string json() const { + return "{ \"a\" : DBPointer( \"ns\", ObjectId( \"000000000000000000000000\" ) ) }"; + } + }; - // BSON Object <=> JS DBRef - ASSERT( client.eval( "unittest", "x = db.dbref.b.findOne(); db.dbref.b.drop(); x.c = new DBRef( x.c.ns, x.c.id ); db.dbref.b.insert( x );" ) ); - ASSERT_EQUALS( Object, client.findOne( "unittest.dbref.b", "" )[ "c" ].type() ); - ASSERT_EQUALS( string( "dbref.a" ), client.findOne( "unittest.dbref.b", "" )[ "c" ].embeddedObject().getStringField( "$ref" ) ); - } + class InformalDBRefTest : public TestRoundTrip { + virtual BSONObj bson() const { + BSONObjBuilder b; + BSONObjBuilder subBuilder(b.subobjStart("a")); + subBuilder.append("$ref", "ns"); + subBuilder.append("$id", "000000000000000000000000"); + subBuilder.done(); + return b.obj(); + } - void reset() { - client.dropCollection( _a ); - client.dropCollection( _b ); - } + // Don't need to return anything because we are overriding both jsonOut and jsonIn + virtual string json() const { return ""; } - const char * _a; - const char * _b; - }; + // Need to override these because the JSON doesn't actually round trip. + // An object with "$ref" and "$id" fields is handled specially and different on the way out. + virtual string jsonOut() const { + return "{ \"a\" : DBRef( \"ns\", \"000000000000000000000000\" ) }"; + } + virtual string jsonIn() const { + stringstream ss; + ss << "{ \"a\" : { \"$ref\" : \"ns\" , " << + "\"$id\" : \"000000000000000000000000\" } }"; + return ss.str(); + } + }; - class InformalDBRef { - public: - void run() { - client.insert( ns(), BSON( "i" << 1 ) ); - BSONObj obj = client.findOne( ns(), BSONObj() ); - client.remove( ns(), BSONObj() ); - client.insert( ns(), BSON( "r" << BSON( "$ref" << "jstests.informaldbref" << "$id" << obj["_id"].__oid() << "foo" << "bar" ) ) ); - obj = client.findOne( ns(), BSONObj() ); - ASSERT_EQUALS( "bar", obj[ "r" ].embeddedObject()[ "foo" ].str() ); - - ASSERT( client.eval( "unittest", "x = db.jstests.informaldbref.findOne(); y = { r:x.r }; db.jstests.informaldbref.drop(); y.r[ \"a\" ] = \"b\"; db.jstests.informaldbref.save( y );" ) ); - obj = client.findOne( ns(), BSONObj() ); - ASSERT_EQUALS( "bar", obj[ "r" ].embeddedObject()[ "foo" ].str() ); - ASSERT_EQUALS( "b", obj[ "r" ].embeddedObject()[ "a" ].str() ); - } - private: - static const char *ns() { return "unittest.jstests.informaldbref"; } - }; + class InformalDBRefOIDTest : public TestRoundTrip { + virtual BSONObj bson() const { + BSONObjBuilder b; + OID o; + memset( &o, 0, 12 ); + BSONObjBuilder subBuilder(b.subobjStart("a")); + subBuilder.append("$ref", "ns"); + subBuilder.append("$id", o); + subBuilder.done(); + return b.obj(); + } + + // Don't need to return anything because we are overriding both jsonOut and jsonIn + virtual string json() const { return ""; } + + // Need to override these because the JSON doesn't actually round trip. + // An object with "$ref" and "$id" fields is handled specially and different on the way out. + virtual string jsonOut() const { + return "{ \"a\" : DBRef( \"ns\", ObjectId( \"000000000000000000000000\" ) ) }"; + } + virtual string jsonIn() const { + stringstream ss; + ss << "{ \"a\" : { \"$ref\" : \"ns\" , " << + "\"$id\" : ObjectId( \"000000000000000000000000\" ) } }"; + return ss.str(); + } + }; + + class InformalDBRefExtraFieldTest : public TestRoundTrip { + virtual BSONObj bson() const { + BSONObjBuilder b; + OID o; + memset( &o, 0, 12 ); + BSONObjBuilder subBuilder(b.subobjStart("a")); + subBuilder.append("$ref", "ns"); + subBuilder.append("$id", o); + subBuilder.append("otherfield", "value"); + subBuilder.done(); + return b.obj(); + } + + // Don't need to return anything because we are overriding both jsonOut and jsonIn + virtual string json() const { return ""; } + + // Need to override these because the JSON doesn't actually round trip. + // An object with "$ref" and "$id" fields is handled specially and different on the way out. + virtual string jsonOut() const { + return "{ \"a\" : DBRef( \"ns\", ObjectId( \"000000000000000000000000\" ) ) }"; + } + virtual string jsonIn() const { + stringstream ss; + ss << "{ \"a\" : { \"$ref\" : \"ns\" , " << + "\"$id\" : ObjectId( \"000000000000000000000000\" ) , " << + "\"otherfield\" : \"value\" } }"; + return ss.str(); + } + }; + + } // namespace RoundTripTests class BinDataType { public: @@ -1094,7 +1233,7 @@ namespace JSTests { Timer t; double n = 0; - for ( ; n < 100000; n++ ) { + for ( ; n < 10000 ; n++ ) { s->invoke( f , &empty, &start ); ASSERT_EQUALS( 11 , s->getNumber( "__returnValue" ) ); } @@ -1173,10 +1312,12 @@ namespace JSTests { class All : public Suite { public: All() : Suite( "js" ) { + // Initialize the Javascript interpreter + ScriptEngine::setup(); } void setupTests() { - add< Fundamental >(); + add< BuiltinTests >(); add< BasicScope >(); add< ResetScope >(); add< FalseTests >(); @@ -1202,8 +1343,6 @@ namespace JSTests { add< WeirdObjects >(); add< CodeTests >(); - add< DBRefTest >(); - add< InformalDBRef >(); add< BinDataType >(); add< VarTests >(); @@ -1216,6 +1355,12 @@ namespace JSTests { add< ScopeOut >(); add< InvalidStoredJS >(); + + add< RoundTripTests::DBRefTest >(); + add< RoundTripTests::DBPointerTest >(); + add< RoundTripTests::InformalDBRefTest >(); + add< RoundTripTests::InformalDBRefOIDTest >(); + add< RoundTripTests::InformalDBRefExtraFieldTest >(); } } myall; diff --git a/src/mongo/dbtests/mock/mock_remote_db_server.cpp b/src/mongo/dbtests/mock/mock_remote_db_server.cpp index e78d245c70c..9d8506b37ba 100644 --- a/src/mongo/dbtests/mock/mock_remote_db_server.cpp +++ b/src/mongo/dbtests/mock/mock_remote_db_server.cpp @@ -24,6 +24,7 @@ using std::string; using std::vector; namespace mongo { + MockRemoteDBServer::CircularBSONIterator::CircularBSONIterator( const vector<BSONObj>& replyVector) { for (std::vector<mongo::BSONObj>::const_iterator iter = replyVector.begin(); @@ -54,6 +55,7 @@ namespace mongo { _cmdCount(0), _queryCount(0), _instanceID(0) { + insert(IdentityNS, BSON(HostField(hostAndPort)), 0); } MockRemoteDBServer::~MockRemoteDBServer() { diff --git a/src/mongo/dbtests/mock/mock_remote_db_server.h b/src/mongo/dbtests/mock/mock_remote_db_server.h index 6aaba91113c..0455e755d07 100644 --- a/src/mongo/dbtests/mock/mock_remote_db_server.h +++ b/src/mongo/dbtests/mock/mock_remote_db_server.h @@ -19,12 +19,17 @@ #include <string> #include <vector> +#include "mongo/bson/bson_field.h" #include "mongo/bson/bsonobjbuilder.h" #include "mongo/client/dbclientinterface.h" #include "mongo/platform/unordered_map.h" #include "mongo/util/concurrency/spin_lock.h" namespace mongo { + + const std::string IdentityNS("local.me"); + const BSONField<string> HostField("host"); + /** * A very simple mock that acts like a database server. Every object keeps track of its own * InstanceID, which initially starts at zero and increments every time it is restarted. @@ -51,6 +56,9 @@ namespace mongo { * 1. hostAndPort of this server should start with $. * 2. No other instance has the same hostAndPort as this. * + * This server will also contain the hostAndPort inside the IdentityNS + * collection. This is convenient for testing query routing. + * * @param hostAndPort the host name with port for this server. * * @see MockConnRegistry @@ -70,7 +78,7 @@ namespace mongo { /** * Shuts down this server. Any operations on this server with an InstanceID * less than or equal to the current one will throw a mongo::SocketException. - * To bring the server up again, use the #reboot method. + * To bring the server up again, use the reboot method. */ void shutdown(); diff --git a/src/mongo/dbtests/replica_set_monitor_test.cpp b/src/mongo/dbtests/replica_set_monitor_test.cpp index 57ef4756d49..b016b1affc0 100644 --- a/src/mongo/dbtests/replica_set_monitor_test.cpp +++ b/src/mongo/dbtests/replica_set_monitor_test.cpp @@ -1414,6 +1414,33 @@ namespace mongo_test { ASSERT_EQUALS("b", lastHost.host()); } + TEST(TagSet, CopyConstructor) { + TagSet* copy; + + { + BSONArrayBuilder builder; + builder.append(BSON("dc" << "nyc")); + builder.append(BSON("priority" << "1")); + TagSet original(builder.arr()); + + original.next(); + + copy = new TagSet(original); + } + + ASSERT_FALSE(copy->isExhausted()); + ASSERT(copy->getCurrentTag().equal(BSON("dc" << "nyc"))); + copy->next(); + + ASSERT_FALSE(copy->isExhausted()); + ASSERT(copy->getCurrentTag().equal(BSON("priority" << "1"))); + copy->next(); + + ASSERT(copy->isExhausted()); + + delete copy; + } + TEST(TagSet, NearestMultiTagsNoMatch) { vector<ReplicaSetMonitor::Node> nodes = NodeSetFixtures::getThreeMemberWithTags(); diff --git a/src/mongo/s/config_upgrade_helpers.cpp b/src/mongo/s/config_upgrade_helpers.cpp index a589e02b460..6495b5d9c80 100644 --- a/src/mongo/s/config_upgrade_helpers.cpp +++ b/src/mongo/s/config_upgrade_helpers.cpp @@ -19,6 +19,7 @@ #include "mongo/client/connpool.h" #include "mongo/db/namespacestring.h" #include "mongo/s/cluster_client_internal.h" +#include "mongo/util/timer.h" namespace mongo { @@ -249,18 +250,62 @@ namespace mongo { return e.toStatus("could not create indexes in new collection"); } - // Copy data over + // + // Copy data over in batches. A batch size here is way smaller than the maximum size of + // a bsonobj. We want to copy efficiently but we don't need to maximize the object size + // here. + // + + Timer t; + int64_t docCount = 0; + const int32_t maxBatchSize = BSONObjMaxUserSize / 16; try { - ScopedDbConnection& conn = *connPtr; - scoped_ptr<DBClientCursor> cursor(_safeCursor(conn->query(fromNS, BSONObj()))); + log() << "About to copy " << fromNS << " to " << toNS << endl; + // Lower the query's batchSize so that we incur in getMore()'s more frequently. + // The rationale here is that, if for some reason the config server is extremely + // slow, we wouldn't time this cursor out. + ScopedDbConnection& conn = *connPtr; + scoped_ptr<DBClientCursor> cursor(_safeCursor(conn->query(fromNS, + BSONObj(), + 0 /* nToReturn */, + 0 /* nToSkip */, + NULL /* fieldsToReturn */, + 0 /* queryOptions */, + 1024 /* batchSize */))); + + vector<BSONObj> insertBatch; + int32_t insertSize = 0; while (cursor->more()) { - BSONObj next = cursor->nextSafe(); + BSONObj next = cursor->nextSafe().getOwned(); + ++docCount; + + insertBatch.push_back(next); + insertSize += next.objsize(); - conn->insert(toNS, next); + if (insertSize > maxBatchSize ) { + conn->insert(toNS, insertBatch); + _checkGLE(conn); + insertBatch.clear(); + insertSize = 0; + } + + if (t.seconds() >= 10) { + t.reset(); + log() << "Copied " << docCount << " documents so far from " + << fromNS << " to " << toNS << endl; + } + } + + if (!insertBatch.empty()) { + conn->insert(toNS, insertBatch); _checkGLE(conn); } + + log() << "Finished copying " << docCount << " documents from " + << fromNS << " to " << toNS << endl; + } catch (const DBException& e) { return e.toStatus("could not copy data into new collection"); diff --git a/src/mongo/s/cursors.cpp b/src/mongo/s/cursors.cpp index affb7f744fd..4e904e39c4c 100644 --- a/src/mongo/s/cursors.cpp +++ b/src/mongo/s/cursors.cpp @@ -203,6 +203,13 @@ namespace mongo { _cursors.erase( id ); } + void CursorCache::removeRef( long long id ) { + verify( id ); + scoped_lock lk( _mutex ); + _refs.erase( id ); + _refsNS.erase( id ); + } + void CursorCache::storeRef(const std::string& server, long long id, const std::string& ns) { LOG(_myLogLevel) << "CursorCache::storeRef server: " << server << " id: " << id << endl; verify( id ); diff --git a/src/mongo/s/cursors.h b/src/mongo/s/cursors.h index b42ea7538d7..c250d70ded2 100644 --- a/src/mongo/s/cursors.h +++ b/src/mongo/s/cursors.h @@ -105,6 +105,7 @@ namespace mongo { void remove( long long id ); void storeRef(const std::string& server, long long id, const std::string& ns); + void removeRef( long long id ); /** @return the server for id or "" */ string getRef( long long id ) const ; diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp index 914b43b8b21..a9507e0b96c 100644 --- a/src/mongo/s/d_migrate.cpp +++ b/src/mongo/s/d_migrate.cpp @@ -58,6 +58,7 @@ #include "mongo/s/d_logic.h" #include "mongo/s/shard.h" #include "mongo/s/type_chunk.h" +#include "mongo/util/assert_util.h" #include "mongo/util/elapsed_tracker.h" #include "mongo/util/processinfo.h" #include "mongo/util/queue.h" @@ -999,7 +1000,7 @@ namespace mongo { dist_lock_try dlk; try{ - dlk = dist_lock_try( &lockSetup , (string)"migrate-" + min.toString() ); + dlk = dist_lock_try( &lockSetup , (string)"migrate-" + min.toString(), 30.0 /*timeout*/ ); } catch( LockException& e ){ errmsg = str::stream() << "error locking distributed lock for migration " << "migrate-" << min.toString() << causedBy( e ); @@ -1214,6 +1215,22 @@ namespace mongo { timing.done(4); // 5. + + // Before we get into the critical section of the migration, let's double check + // that the config servers are reachable and the lock is in place. + log() << "About to check if it is safe to enter critical section"; + + string lockHeldMsg; + bool lockHeld = dlk.isLockHeld( 30.0 /* timeout */, &lockHeldMsg ); + if ( !lockHeld ) { + errmsg = str::stream() << "not entering migrate critical section because " + << lockHeldMsg; + warning() << errmsg << endl; + return false; + } + + log() << "About to enter migrate critical section"; + { // 5.a // we're under the collection lock here, so no other migrate can change maxVersion or ShardChunkManager state @@ -1386,6 +1403,7 @@ namespace mongo { BSONObj cmd = cmdBuilder.obj(); LOG(7) << "moveChunk update: " << cmd << migrateLog; + int exceptionCode = OkCode; bool ok = false; BSONObj cmdResult; try { @@ -1399,12 +1417,39 @@ namespace mongo { catch ( DBException& e ) { warning() << e << migrateLog; ok = false; + exceptionCode = e.getCode(); BSONObjBuilder b; e.getInfo().append( b ); cmdResult = b.obj(); + errmsg = cmdResult.toString(); } - if ( ! ok ) { + if ( exceptionCode == PrepareConfigsFailedCode ) { + + // In the process of issuing the migrate commit, the SyncClusterConnection + // checks that the config servers are reachable. If they are not, we are + // sure that the applyOps command was not sent to any of the configs, so we + // can safely back out of the migration here, by resetting the shard + // version that we bumped up to in the donateChunk() call above. + + log() << "About to acquire moveChunk global lock to reset shard version from " + << "failed migration" << endl; + + { + Lock::GlobalWrite lk; + + // Revert the chunk manager back to the state before "forgetting" + // about the chunk. + shardingState.undoDonateChunk( ns , min , max , startingVersion ); + } + + log() << "Shard version successfully reset to clean up failed migration" << endl; + + errmsg = "Failed to send migrate commit to configs because " + errmsg; + return false; + + } + else if ( ! ok || exceptionCode != OkCode ) { // this could be a blip in the connectivity // wait out a few seconds and check if the commit request made it @@ -1433,6 +1478,7 @@ namespace mongo { if ( checkVersion.isEquivalentTo( nextVersion ) ) { log() << "moveChunk commit confirmed" << migrateLog; + errmsg.clear(); } else { diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp index 57a65015e33..f7e647662f9 100644 --- a/src/mongo/s/server.cpp +++ b/src/mongo/s/server.cpp @@ -107,6 +107,12 @@ namespace mongo { try { r.init(); r.process(); + + // Release connections after non-write op + if ( ShardConnection::releaseConnectionsAfterResponse && r.expectResponse() ) { + LOG(2) << "release thread local connections back to pool" << endl; + ShardConnection::releaseMyConnections(); + } } catch ( AssertionException & e ) { LOG( e.isUserAssertion() ? 1 : 0 ) << "AssertionException while processing op type : " << m.operation() << " to : " << r.getns() << causedBy(e) << endl; diff --git a/src/mongo/s/shard.h b/src/mongo/s/shard.h index 44b20792cae..e917baa0986 100644 --- a/src/mongo/s/shard.h +++ b/src/mongo/s/shard.h @@ -290,10 +290,18 @@ namespace mongo { */ bool runCommand( const string& db , const BSONObj& cmd , BSONObj& res ); + static bool releaseConnectionsAfterResponse; + /** checks all of my thread local connections for the version of this ns */ static void checkMyConnectionVersions( const string & ns ); /** + * Returns all the current sharded connections to the pool. + * Note: This is *dangerous* if we have GLE state. + */ + static void releaseMyConnections(); + + /** * Clears all connections in the sharded pool, including connections in the * thread local storage pool of the current thread. */ diff --git a/src/mongo/s/shardconnection.cpp b/src/mongo/s/shardconnection.cpp index 3a56a38a044..61b47904147 100644 --- a/src/mongo/s/shardconnection.cpp +++ b/src/mongo/s/shardconnection.cpp @@ -21,6 +21,8 @@ #include <set> #include "mongo/db/client.h" +#include "mongo/db/commands.h" +#include "mongo/db/server_parameters.h" #include "mongo/s/config.h" #include "mongo/s/request.h" #include "mongo/s/shard.h" @@ -33,6 +35,70 @@ namespace mongo { DBConnectionPool shardConnectionPool; + class ClientConnections; + + /** + * Class which tracks ClientConnections (the client connection pool) for each incoming + * connection, allowing stats access. + */ + + class ActiveClientConnections { + public: + + ActiveClientConnections() : _mutex( "ActiveClientConnections" ) { + } + + void add( const ClientConnections* cc ) { + scoped_lock lock( _mutex ); + _clientConnections.insert( cc ); + } + + void remove( const ClientConnections* cc ) { + scoped_lock lock( _mutex ); + _clientConnections.erase( cc ); + } + + // Implemented after ClientConnections + void appendInfo( BSONObjBuilder& b ); + + private: + mongo::mutex _mutex; + set<const ClientConnections*> _clientConnections; + + } activeClientConnections; + + /** + * Command to allow access to the sharded conn pool information in mongos. + * TODO: Refactor with other connection pooling changes + */ + class ShardedPoolStats : public Command { + public: + + ShardedPoolStats() : Command( "shardConnPoolStats" ) {} + virtual void help( stringstream &help ) const { help << "stats about the shard connection pool"; } + virtual LockType locktype() const { return NONE; } + virtual bool slaveOk() const { return true; } + + // Same privs as connPoolStats + virtual void addRequiredPrivileges( const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out ) + { + ActionSet actions; + actions.addAction( ActionType::connPoolStats ); + out->push_back( Privilege( AuthorizationManager::SERVER_RESOURCE_NAME, actions ) ); + } + + virtual bool run ( const string&, mongo::BSONObj&, int, std::string&, mongo::BSONObjBuilder& result, bool ) { + // Base pool info + shardConnectionPool.appendInfo( result ); + // Thread connection info + activeClientConnections.appendInfo( result ); + return true; + } + + } shardedPoolStatsCmd; + /** * holds all the actual db connections for a client to various servers * 1 per thread, so doesn't have to be thread safe @@ -42,14 +108,39 @@ namespace mongo { struct Status : boost::noncopyable { Status() : created(0), avail(0) {} + // May be read concurrently, but only written from + // this thread. long long created; DBClientBase* avail; }; + // Gets or creates the status object for the host + Status* _getStatus( const string& addr ) { + scoped_spinlock lock( _lock ); + Status* &temp = _hosts[addr]; + if ( ! temp ) + temp = new Status(); + return temp; + } - ClientConnections() {} + ClientConnections() { + // Start tracking client connections + activeClientConnections.add( this ); + } ~ClientConnections() { + // Stop tracking these client connections + activeClientConnections.remove( this ); + + releaseAll( true ); + } + + void releaseAll( bool fromDestructor = false ) { + + // Don't need spinlock protection because if not in the destructor, we don't + // modify _hosts, and if in the destructor we are not accessible to external + // threads. + for ( HostMap::iterator i=_hosts.begin(); i!=_hosts.end(); ++i ) { string addr = i->first; Status* ss = i->second; @@ -65,17 +156,15 @@ namespace mongo { release( addr , ss->avail ); ss->avail = 0; } - delete ss; + if ( fromDestructor ) delete ss; } - _hosts.clear(); + if ( fromDestructor ) _hosts.clear(); } DBClientBase * get( const string& addr , const string& ns ) { _check( ns ); - Status* &s = _hosts[addr]; - if ( ! s ) - s = new Status(); + Status* s = _getStatus( addr ); auto_ptr<DBClientBase> c; // Handles cleanup if there's an exception thrown if ( s->avail ) { @@ -83,8 +172,8 @@ namespace mongo { s->avail = 0; shardConnectionPool.onHandedOut( c.get() ); // May throw an exception } else { - s->created++; c.reset( shardConnectionPool.get( addr ) ); + s->created++; // After, so failed creation doesn't get counted } return c.release(); } @@ -152,18 +241,19 @@ namespace mongo { Shard& shard = all[i]; try { string sconnString = shard.getConnString(); - Status* &s = _hosts[sconnString]; - - if ( ! s ){ - s = new Status(); - } + Status* s = _getStatus( sconnString ); - if( ! s->avail ) + if( ! s->avail ) { s->avail = shardConnectionPool.get( sconnString ); + s->created++; // After, so failed creation doesn't get counted + } versionManager.checkShardVersionCB( s->avail, ns, false, 1 ); - } catch(...) { - LOGATMOST(2) << "exception in checkAllVersions shard:" << shard.getName() << endl; + } + catch ( const std::exception& e ) { + + warning() << "problem while initially checking shard versions on" + << " " << shard.getName() << causedBy(e) << endl; throw; } } @@ -174,12 +264,47 @@ namespace mongo { } void _check( const string& ns ) { - if ( ns.size() == 0 || _seenNS.count( ns ) ) - return; - _seenNS.insert( ns ); + + { + // We want to report ns stats too + scoped_spinlock lock( _lock ); + if ( ns.size() == 0 || _seenNS.count( ns ) ) + return; + _seenNS.insert( ns ); + } + checkVersions( ns ); } + /** + * Appends info about the client connection pool to a BOBuilder + * Safe to call with activeClientConnections lock + */ + void appendInfo( BSONObjBuilder& b ) const { + + scoped_spinlock lock( _lock ); + + BSONArrayBuilder hostsArrB( b.subarrayStart( "hosts" ) ); + for ( HostMap::const_iterator i = _hosts.begin(); i != _hosts.end(); ++i ) { + BSONObjBuilder bb( hostsArrB.subobjStart() ); + bb.append( "host", i->first ); + bb.append( "created", i->second->created ); + bb.appendBool( "avail", static_cast<bool>( i->second->avail ) ); + bb.done(); + } + hostsArrB.done(); + + BSONArrayBuilder nsArrB( b.subarrayStart( "seenNS" ) ); + for ( set<string>::const_iterator i = _seenNS.begin(); i != _seenNS.end(); ++i ) { + nsArrB.append(*i); + } + nsArrB.done(); + } + + // Protects only the creation of new entries in the _hosts and _seenNS map + // from external threads. Reading _hosts / _seenNS in this thread doesn't + // need protection. + mutable SpinLock _lock; typedef map<string,Status*,DBConnectionPool::serverNameCompare> HostMap; HostMap _hosts; set<string> _seenNS; @@ -213,6 +338,27 @@ namespace mongo { thread_specific_ptr<ClientConnections> ClientConnections::_perThread; + /** + * Appends info about all active client shard connections to a BOBuilder + */ + void ActiveClientConnections::appendInfo( BSONObjBuilder& b ) { + + BSONArrayBuilder arr( 64 * 1024 ); // There may be quite a few threads + + { + scoped_lock lock( _mutex ); + for ( set<const ClientConnections*>::const_iterator i = _clientConnections.begin(); + i != _clientConnections.end(); ++i ) + { + BSONObjBuilder bb( arr.subobjStart() ); + (*i)->appendInfo( bb ); + bb.done(); + } + } + + b.appendArray( "threads", arr.obj() ); + } + ShardConnection::ShardConnection( const Shard * s , const string& ns, ChunkManagerPtr manager ) : _addr( s->getConnString() ) , _ns( ns ), _manager( manager ) { _init(); @@ -323,6 +469,20 @@ namespace mongo { } } + bool ShardConnection::releaseConnectionsAfterResponse( false ); + + ExportedServerParameter<bool> ReleaseConnectionsAfterResponse( + ServerParameterSet::getGlobal(), + "releaseConnectionsAfterResponse", + &ShardConnection::releaseConnectionsAfterResponse, + true, + true + ); + + void ShardConnection::releaseMyConnections() { + ClientConnections::threadInstance()->releaseAll(); + } + void ShardConnection::clearPool() { shardConnectionPool.clear(); ClientConnections::threadInstance()->clearPool(); diff --git a/src/mongo/s/shardkey.cpp b/src/mongo/s/shardkey.cpp index a2ad2ce02f2..b7f37e779e7 100644 --- a/src/mongo/s/shardkey.cpp +++ b/src/mongo/s/shardkey.cpp @@ -49,8 +49,10 @@ namespace mongo { for(set<string>::const_iterator it = patternfields.begin(); it != patternfields.end(); ++it) { BSONElement e = obj.getFieldDotted(it->c_str()); - if(e.eoo() || e.type() == Array || (e.type() == Object && e.embeddedObject().firstElementFieldName()[0] == '$')) { - // cant use getGtLtOp here as it returns Equality for unknown $ops and we want to reject them + if( e.eoo() || + e.type() == Array || + (e.type() == Object && !e.embeddedObject().okForStorage())) { + // Don't allow anything for a shard key we can't store -- like $gt/$lt ops return false; } } @@ -143,16 +145,26 @@ namespace mongo { public: void hasshardkeytest() { - BSONObj x = fromjson("{ zid : \"abcdefg\", num: 1.0, name: \"eliot\" }"); ShardKeyPattern k( BSON( "num" << 1 ) ); + + BSONObj x = fromjson("{ zid : \"abcdefg\", num: 1.0, name: \"eliot\" }"); verify( k.hasShardKey(x) ); verify( !k.hasShardKey( fromjson("{foo:'a'}") ) ); verify( !k.hasShardKey( fromjson("{x: {$gt: 1}}") ) ); + verify( !k.hasShardKey( fromjson("{num: {$gt: 1}}") ) ); + BSONObj obj = BSON( "num" << BSON( "$ref" << "coll" << "$id" << 1)); + verify( k.hasShardKey(obj)); // try compound key { ShardKeyPattern k( fromjson("{a:1,b:-1,c:1}") ); verify( k.hasShardKey( fromjson("{foo:'a',a:'b',c:'z',b:9,k:99}") ) ); + BSONObj obj = BSON( "foo" << "a" << + "a" << BSON("$ref" << "coll" << "$id" << 1) << + "c" << 1 << "b" << 9 << "k" << 99 ); + verify( k.hasShardKey( obj ) ); + verify( !k.hasShardKey( fromjson("{foo:'a',a:[1,2],c:'z',b:9,k:99}") ) ); + verify( !k.hasShardKey( fromjson("{foo:'a',a:{$gt:1},c:'z',b:9,k:99}") ) ); verify( !k.hasShardKey( fromjson("{foo:'a',a:'b',c:'z',bb:9,k:99}") ) ); verify( !k.hasShardKey( fromjson("{k:99}") ) ); } @@ -162,7 +174,16 @@ namespace mongo { ShardKeyPattern k( fromjson("{'a.b':1}") ); verify( k.hasShardKey( fromjson("{a:{b:1,c:1},d:1}") ) ); verify( k.hasShardKey( fromjson("{'a.b':1}") ) ); + BSONObj obj = BSON( "c" << "a" << + "a" << BSON("$ref" << "coll" << "$id" << 1) ); + verify( !k.hasShardKey( obj ) ); + obj = BSON( "c" << "a" << + "a" << BSON( "b" << BSON("$ref" << "coll" << "$id" << 1) << + "c" << 1)); + verify( k.hasShardKey( obj ) ); verify( !k.hasShardKey( fromjson("{'a.c':1}") ) ); + verify( !k.hasShardKey( fromjson("{'a':[{b:1}, {c:1}]}") ) ); + verify( !k.hasShardKey( fromjson("{a:{b:[1,2]},d:1}") ) ); verify( !k.hasShardKey( fromjson("{a:{c:1},d:1}") ) ); verify( !k.hasShardKey( fromjson("{a:1}") ) ); verify( !k.hasShardKey( fromjson("{b:1}") ) ); diff --git a/src/mongo/s/strategy_shard.cpp b/src/mongo/s/strategy_shard.cpp index 2f8667de6d8..0d4adcef155 100644 --- a/src/mongo/s/strategy_shard.cpp +++ b/src/mongo/s/strategy_shard.cpp @@ -212,8 +212,14 @@ namespace mongo { Message response; bool ok = conn->get()->callRead( r.m() , response); uassert( 10204 , "dbgrid: getmore: error calling db", ok); - r.reply( response , "" /*conn->getServerAddress() */ ); + bool hasMore = (response.singleData()->getCursor() != 0); + + if ( !hasMore ) { + cursorCache.removeRef( id ); + } + + r.reply( response , "" /*conn->getServerAddress() */ ); conn->done(); return; } diff --git a/src/mongo/scripting/engine_spidermonkey.cpp b/src/mongo/scripting/engine_spidermonkey.cpp index 1a0cd117155..e39734305a2 100644 --- a/src/mongo/scripting/engine_spidermonkey.cpp +++ b/src/mongo/scripting/engine_spidermonkey.cpp @@ -1071,11 +1071,25 @@ namespace spidermonkey { JSBool native_helper( JSContext *cx , JSObject *obj , uintN argc, jsval *argv , jsval *rval ) { try { Convertor c(cx); - NativeFunction func = reinterpret_cast<NativeFunction>( - static_cast<long long>( c.getNumber( obj , "x" ) ) ); - void* data = reinterpret_cast<void*>( - static_cast<long long>( c.getNumber( obj , "y" ) ) ); - verify( func ); + + // get function pointer from JS caller's argument property 'x' + massert(16740, "nativeHelper argument requires object with 'x' property", + c.hasProperty(obj, "x")); + FunctionMap::iterator funcIter = currentScope->_functionMap.find(c.getNumber(obj, "x")); + massert(16742, "JavaScript function not in map", + funcIter != currentScope->_functionMap.end()); + NativeFunction func = funcIter->second; + verify(func); + + // get data pointer from JS caller's argument property 'y' + void* data = NULL; + if (c.hasProperty(obj, "y")) { + ArgumentMap::iterator argIter = + currentScope->_argumentMap.find(c.getNumber(obj, "y")); + massert(16741, "nativeHelper 'y' parameter must be in the argumentMap", + argIter != currentScope->_argumentMap.end()); + data = argIter->second; + } BSONObj a; if ( argc > 0 ) { @@ -1725,12 +1739,16 @@ namespace spidermonkey { smlock; string name = field; jsval v; - v = _convertor->toval( static_cast<double>( reinterpret_cast<long long>(func) ) ); + uint32_t funcId = _functionMap.size(); + _functionMap.insert(make_pair(funcId, func)); + v = _convertor->toval(static_cast<double>(funcId)); _convertor->setProperty( _global, (name + "_").c_str(), v ); stringstream code; if (data) { - v = _convertor->toval( static_cast<double>( reinterpret_cast<long long>(data) ) ); + uint32_t argsId = _argumentMap.size(); + _argumentMap.insert(make_pair(argsId, data)); + v = _convertor->toval(static_cast<double>(argsId)); _convertor->setProperty( _global, (name + "_data_").c_str(), v ); code << field << "_" << " = { x : " << field << "_ , y: " << field << "_data_ }; "; } else { diff --git a/src/mongo/scripting/engine_spidermonkey_internal.h b/src/mongo/scripting/engine_spidermonkey_internal.h index 26d772c84f7..5b31db677a6 100644 --- a/src/mongo/scripting/engine_spidermonkey_internal.h +++ b/src/mongo/scripting/engine_spidermonkey_internal.h @@ -47,6 +47,9 @@ namespace spidermonkey { using std::string; + typedef std::map<uint32_t, NativeFunction> FunctionMap; + typedef std::map<uint32_t, void*> ArgumentMap; + string trim( string s ); class BSONFieldIterator; @@ -295,6 +298,11 @@ namespace spidermonkey { JSContext *SavedContext() const { return _context; } + // map from internal function id to function pointer + FunctionMap _functionMap; + // map from internal function argument id to function pointer + ArgumentMap _argumentMap; + private: void _postCreateHacks(); diff --git a/src/mongo/scripting/engine_v8.cpp b/src/mongo/scripting/engine_v8.cpp index f5adc04fd67..484b748b975 100644 --- a/src/mongo/scripting/engine_v8.cpp +++ b/src/mongo/scripting/engine_v8.cpp @@ -17,6 +17,7 @@ #include "mongo/scripting/engine_v8.h" +#include "mongo/platform/unordered_set.h" #include "mongo/scripting/v8_db.h" #include "mongo/scripting/v8_utils.h" #include "mongo/util/base64.h" @@ -52,10 +53,15 @@ namespace mongo { return (BSONHolder*)ptr; } + static v8::Handle<v8::Object> unwrapObject(const v8::Handle<v8::Object>& obj) { + return obj->GetInternalField(1).As<v8::Object>(); + } + v8::Persistent<v8::Object> V8Scope::wrapBSONObject(v8::Local<v8::Object> obj, BSONHolder* data) { data->_scope = this; - obj->SetInternalField(0, v8::External::New(data)); + obj->SetInternalField(0, v8::External::New(data)); // Holder + obj->SetInternalField(1, v8::Object::New()); // Object v8::Persistent<v8::Object> p = v8::Persistent<v8::Object>::New(obj); bsonHolderTracker.track(p, data); return p; @@ -66,9 +72,10 @@ namespace mongo { v8::HandleScope handle_scope; v8::Handle<v8::Value> val; try { - if (info.This()->HasRealNamedProperty(name)) { - // value already cached - return handle_scope.Close(info.This()->GetRealNamedProperty(name)); + v8::Handle<v8::Object> realObject = unwrapObject(info.Holder()); + if (realObject->HasOwnProperty(name)) { + // value already cached or added + return handle_scope.Close(realObject->Get(name)); } string key = toSTLString(name); @@ -83,8 +90,12 @@ namespace mongo { v8::Local<v8::External> scp = v8::External::Cast(*info.Data()); V8Scope* scope = (V8Scope*)(scp->Value()); - val = scope->mongoToV8Element(elmt, false); - info.This()->ForceSet(name, val, v8::DontEnum); + val = scope->mongoToV8Element(elmt, holder->_readOnly); + + if (obj.objsize() > 128 || val->IsObject()) { + // Only cache if expected to help (large BSON) or is required due to js semantics + realObject->Set(name, val); + } if (elmt.type() == mongo::Object || elmt.type() == mongo::Array) { // if accessing a subobject, it may get modified and base obj would not know @@ -103,6 +114,9 @@ namespace mongo { static v8::Handle<v8::Value> namedGetRO(v8::Local<v8::String> name, const v8::AccessorInfo &info) { + return namedGet(name, info); + // Rest of function is unused but left in to ease backporting of SERVER-9267 + v8::HandleScope handle_scope; v8::Handle<v8::Value> val; string key = toSTLString(name); @@ -130,25 +144,25 @@ namespace mongo { string key = toSTLString(name); BSONHolder* holder = unwrapHolder(info.Holder()); holder->_removed.erase(key); - holder->_extra.push_back(key); holder->_modified = true; - // set into JS object - return v8::Handle<v8::Value>(); + v8::Handle<v8::Object> realObject = unwrapObject(info.Holder()); + realObject->Set(name, value_obj); + return value_obj; } static v8::Handle<v8::Array> namedEnumerator(const v8::AccessorInfo &info) { v8::HandleScope handle_scope; BSONHolder* holder = unwrapHolder(info.Holder()); BSONObj obj = holder->_obj; - v8::Handle<v8::Array> arr = v8::Handle<v8::Array>(v8::Array::New(obj.nFields())); - int i = 0; + v8::Handle<v8::Array> out = v8::Array::New(); + int outIndex = 0; v8::Local<v8::External> scp = v8::External::Cast(*info.Data()); V8Scope* scope = (V8Scope*)(scp->Value()); - set<string> added; + unordered_set<string> added; // note here that if keys are parseable number, v8 will access them using index - for (BSONObjIterator it(obj); it.more(); ++i) { + for (BSONObjIterator it(obj); it.more();) { const BSONElement& f = it.next(); string sname = f.fieldName(); if (holder->_removed.count(sname)) @@ -156,17 +170,21 @@ namespace mongo { v8::Handle<v8::String> name = scope->v8StringData(sname); added.insert(sname); - arr->Set(i, name); + out->Set(outIndex++, name); } - for (list<string>::iterator it = holder->_extra.begin(); - it != holder->_extra.end(); it++) { - string sname = *it; + + v8::Handle<v8::Object> realObject = unwrapObject(info.Holder()); + v8::Handle<v8::Array> fields = realObject->GetOwnPropertyNames(); + const int len = fields->Length(); + for (int field=0; field < len; field++) { + v8::Handle<v8::String> name = fields->Get(field).As<v8::String>(); + string sname = toSTLString(name); if (added.count(sname)) continue; - arr->Set(i++, scope->v8StringData(sname)); + out->Set(outIndex++, name); } - return handle_scope.Close(arr); + return handle_scope.Close(out); } v8::Handle<v8::Boolean> namedDelete(v8::Local<v8::String> name, const v8::AccessorInfo& info) { @@ -174,26 +192,25 @@ namespace mongo { string key = toSTLString(name); BSONHolder* holder = unwrapHolder(info.Holder()); holder->_removed.insert(key); - holder->_extra.remove(key); holder->_modified = true; - // also delete in JS obj - return handle_scope.Close(v8::Handle<v8::Boolean>()); + v8::Handle<v8::Object> realObject = unwrapObject(info.Holder()); + realObject->Delete(name); + return v8::True(); } static v8::Handle<v8::Value> indexedGet(uint32_t index, const v8::AccessorInfo &info) { v8::HandleScope handle_scope; v8::Handle<v8::Value> val; try { + v8::Handle<v8::Object> realObject = unwrapObject(info.Holder()); + if (realObject->Has(index)) { + // value already cached or added + return handle_scope.Close(realObject->Get(index)); + } string key = str::stream() << index; v8::Local<v8::External> scp = v8::External::Cast(*info.Data()); V8Scope* scope = (V8Scope*)(scp->Value()); - v8::Handle<v8::String> name = scope->v8StringData(key); - - if (info.This()->HasRealIndexedProperty(index)) { - // value already cached - return handle_scope.Close(info.This()->GetRealNamedProperty(name)); - } BSONHolder* holder = unwrapHolder(info.Holder()); if (holder->_removed.count(key)) @@ -203,8 +220,8 @@ namespace mongo { BSONElement elmt = obj.getField(key); if (elmt.eoo()) return handle_scope.Close(v8::Handle<v8::Value>()); - val = scope->mongoToV8Element(elmt, false); - info.This()->ForceSet(name, val, v8::DontEnum); + val = scope->mongoToV8Element(elmt, holder->_readOnly); + realObject->Set(index, val); if (elmt.type() == mongo::Object || elmt.type() == mongo::Array) { // if accessing a subobject, it may get modified and base obj would not know @@ -226,14 +243,18 @@ namespace mongo { string key = str::stream() << index; BSONHolder* holder = unwrapHolder(info.Holder()); holder->_removed.insert(key); - holder->_extra.remove(key); holder->_modified = true; // also delete in JS obj - return v8::Handle<v8::Boolean>(); + v8::Handle<v8::Object> realObject = unwrapObject(info.Holder()); + realObject->Delete(index); + return v8::True(); } static v8::Handle<v8::Value> indexedGetRO(uint32_t index, const v8::AccessorInfo &info) { + return indexedGet(index, info); + // Rest of function is unused but left in-place to ease backporting of SERVER-9267 + v8::HandleScope handle_scope; v8::Handle<v8::Value> val; try { @@ -265,11 +286,11 @@ namespace mongo { string key = str::stream() << index; BSONHolder* holder = unwrapHolder(info.Holder()); holder->_removed.erase(key); - holder->_extra.push_back(key); holder->_modified = true; - // set into JS object - return v8::Handle<v8::Value>(); + v8::Handle<v8::Object> realObject = unwrapObject(info.Holder()); + realObject->Set(index, value_obj); + return value_obj; } v8::Handle<v8::Value> NamedReadOnlySet(v8::Local<v8::String> property, @@ -298,6 +319,15 @@ namespace mongo { return v8::Boolean::New(false); } + /** + * GC Prologue and Epilogue constants (used to display description constants) + */ + struct GCPrologueState { static const char* name; }; + const char* GCPrologueState::name = "prologue"; + struct GCEpilogueState { static const char* name; }; + const char* GCEpilogueState::name = "epilogue"; + + template <typename _GCState> void gcCallback(v8::GCType type, v8::GCCallbackFlags flags) { const int verbosity = 1; // log level for stat collection if (logLevel < verbosity) @@ -306,12 +336,13 @@ namespace mongo { v8::HeapStatistics stats; v8::V8::GetHeapStatistics(&stats); - LOG(verbosity) << "V8 GC heap stats - " - << " total: " << stats.total_heap_size() - << " exec: " << stats.total_heap_size_executable() - << " used: " << stats.used_heap_size()<< " limit: " - << stats.heap_size_limit() - << endl; + log() << "V8 GC " << _GCState::name + << " heap stats - " + << " total: " << stats.total_heap_size() + << " exec: " << stats.total_heap_size_executable() + << " used: " << stats.used_heap_size()<< " limit: " + << stats.heap_size_limit() + << endl; } V8ScriptEngine::V8ScriptEngine() : @@ -455,12 +486,6 @@ namespace mongo { _isolate = v8::Isolate::New(); v8::Isolate::Scope iscope(_isolate); - // resource constraints must be set on isolate, before any call or lock - v8::ResourceConstraints rc; - rc.set_max_young_space_size(4 * 1024 * 1024); - rc.set_max_old_space_size(64 * 1024 * 1024); - v8::SetResourceConstraints(&rc); - // lock the isolate and enter the context v8::Locker l(_isolate); v8::HandleScope handleScope; @@ -468,7 +493,8 @@ namespace mongo { v8::Context::Scope context_scope(_context); // display heap statistics on MarkAndSweep GC run - v8::V8::AddGCPrologueCallback(gcCallback, v8::kGCTypeMarkSweepCompact); + v8::V8::AddGCPrologueCallback(gcCallback<GCPrologueState>, v8::kGCTypeMarkSweepCompact); + v8::V8::AddGCEpilogueCallback(gcCallback<GCEpilogueState>, v8::kGCTypeMarkSweepCompact); // if the isolate runs out of heap space, raise a flag on the StackGuard instead of // calling abort() @@ -479,7 +505,7 @@ namespace mongo { // initialize lazy object template lzObjectTemplate = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New()); - lzObjectTemplate->SetInternalFieldCount(1); + lzObjectTemplate->SetInternalFieldCount(2); lzObjectTemplate->SetNamedPropertyHandler(namedGet, namedSet, 0, namedDelete, namedEnumerator, v8::External::New(this)); lzObjectTemplate->SetIndexedPropertyHandler(indexedGet, indexedSet, 0, indexedDelete, @@ -490,7 +516,7 @@ namespace mongo { v8::DontEnum); roObjectTemplate = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New()); - roObjectTemplate->SetInternalFieldCount(1); + roObjectTemplate->SetInternalFieldCount(2); roObjectTemplate->SetNamedPropertyHandler(namedGetRO, NamedReadOnlySet, 0, NamedReadOnlyDelete, namedEnumerator, v8::External::New(this)); @@ -1250,188 +1276,13 @@ namespace mongo { return handle_scope.Close(idCons->NewInstance(1, argv)); } - v8::Local<v8::Object> V8Scope::mongoToV8(const BSONObj& m, bool array, bool readOnly) { - v8::HandleScope handle_scope; - v8::Handle<v8::Value> argv[3]; // arguments for v8 instance constructors - v8::Local<v8::ObjectTemplate> readOnlyObjects; - v8::Local<v8::Object> o; - - // handle DBRef. needs to come first. isn't it? (metagoto) - static string ref = "$ref"; - if (ref == m.firstElement().fieldName()) { - const BSONElement& id = m["$id"]; - if (!id.eoo()) { // there's no check on $id exitence in sm implementation. risky ? - v8::Function* dbRef = getNamedCons("DBRef"); - o = dbRef->NewInstance(); - } - } - - if (!o.IsEmpty()) { - readOnly = false; - } - else if (array) { - // NOTE Looks like it's impossible to add interceptors to v8 arrays. - // so array itself will never be read only, but its values can be - o = v8::Array::New(); - } - else if (!readOnly) { - o = v8::Object::New(); - } - else { - // NOTE Our readOnly implemention relies on undocumented ObjectTemplate - // functionality that may be fragile, but it still seems like the best option - // for now -- fwiw, the v8 docs are pretty sparse. I've determined experimentally - // that when property handlers are set for an object template, they will attach - // to objects previously created by that template. To get this to work, though, - // it is necessary to initialize the template's property handlers before - // creating objects from the template (as I have in the following few lines - // of code). - // NOTE In my first attempt, I configured the permanent property handlers before - // constructiong the object and replaced the Set() calls below with ForceSet(). - // However, it turns out that ForceSet() only bypasses handlers for named - // properties and not for indexed properties. - readOnlyObjects = v8::ObjectTemplate::New(); - // NOTE This internal field will store type info for special db types. For - // regular objects the field is unnecessary - for simplicity I'm creating just - // one readOnlyObjects template for objects where the field is & isn't necessary, - // assuming that the overhead of an internal field is slight. - readOnlyObjects->SetInternalFieldCount(1); - readOnlyObjects->SetNamedPropertyHandler(0); - readOnlyObjects->SetIndexedPropertyHandler(0); - o = readOnlyObjects->NewInstance(); - } - - mongo::BSONObj sub; - - for (BSONObjIterator i(m); i.more();) { - const BSONElement& f = i.next(); - - v8::Local<v8::Value> v; - v8::Handle<v8::String> name = v8StringData(f.fieldName()); - - switch (f.type()) { - case mongo::Code: - o->ForceSet(name, newFunction(f.valuestr())); - break; - case CodeWScope: - if (!f.codeWScopeObject().isEmpty()) - log() << "warning: CodeWScope doesn't transfer to db.eval" << endl; - o->ForceSet(name, newFunction(f.codeWScopeCode())); - break; - case mongo::String: - o->ForceSet(name, v8::String::New(f.valuestr())); - break; - case mongo::jstOID: { - v8::Function * idCons = getObjectIdCons(); - argv[0] = v8::String::New(f.__oid().str().c_str()); - o->ForceSet(name, idCons->NewInstance(1, argv)); - break; - } - case mongo::NumberDouble: - case mongo::NumberInt: - o->ForceSet(name, v8::Number::New(f.number())); - break; - case mongo::Array: - sub = f.embeddedObject(); - o->ForceSet(name, mongoToV8(sub, true, readOnly)); - break; - case mongo::Object: - sub = f.embeddedObject(); - o->ForceSet(name, mongoToLZV8(sub, readOnly)); - break; - case mongo::Date: - o->ForceSet(name, v8::Date::New((double) ((long long)f.date().millis))); - break; - case mongo::Bool: - o->ForceSet(name, v8::Boolean::New(f.boolean())); - break; - case mongo::jstNULL: - case mongo::Undefined: // duplicate sm behavior - o->ForceSet(name, v8::Null()); - break; - case mongo::RegEx: { - v8::Function * regex = getNamedCons("RegExp"); - argv[0] = v8::String::New(f.regex()); - argv[1] = v8::String::New(f.regexFlags()); - o->ForceSet(name, regex->NewInstance(2, argv)); - break; - } - case mongo::BinData: { - int len; - const char *data = f.binData(len); - stringstream ss; - base64::encode(ss, data, len); - argv[0] = v8::Number::New(f.binDataType()); - argv[1] = v8::String::New(ss.str().c_str()); - o->ForceSet(name, getNamedCons("BinData")->NewInstance(2, argv)); - break; - } - case mongo::Timestamp: { - v8::Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : - internalFieldObjects->NewInstance(); - sub->ForceSet(v8::String::New("t"), v8::Number::New(f.timestampTime() / 1000)); - sub->ForceSet(v8::String::New("i"), v8::Number::New(f.timestampInc())); - sub->SetInternalField(0, v8::Uint32::New(f.type())); - o->ForceSet(name, sub); - break; - } - case mongo::NumberLong: { - unsigned long long val = f.numberLong(); - v8::Function* numberLong = getNamedCons("NumberLong"); - double floatApprox = (double)(long long)val; - // values above 2^53 are not accurately represented in JS - if ((long long)val == (long long)floatApprox && val < 9007199254740992ULL) { - argv[0] = v8::Number::New(floatApprox); - o->ForceSet(name, numberLong->NewInstance(1, argv)); - } - else { - argv[0] = v8::Number::New(floatApprox); - argv[1] = v8::Integer::New(val >> 32); - argv[2] = v8::Integer::New((unsigned long)(val & 0x00000000ffffffff)); - o->ForceSet(name, numberLong->NewInstance(3, argv)); - } - break; - } - case mongo::MinKey: { - o->ForceSet(name, newMinKeyInstance()); - break; - } - case mongo::MaxKey: { - o->ForceSet(name, newMaxKeyInstance()); - break; - } - case mongo::DBRef: { - v8::Function* dbPointer = getNamedCons("DBPointer"); - argv[0] = v8StringData(f.dbrefNS()); - argv[1] = newId(f.dbrefOID()); - o->ForceSet(name, dbPointer->NewInstance(2, argv)); - break; - } - default: - cout << "can't handle type: "; - cout << f.type() << " "; - cout << f.toString(); - cout << endl; - break; - } - } - - if (!array && readOnly) { - readOnlyObjects->SetNamedPropertyHandler(0, NamedReadOnlySet, - 0, NamedReadOnlyDelete); - readOnlyObjects->SetIndexedPropertyHandler(0, IndexedReadOnlySet, - 0, IndexedReadOnlyDelete); - } - - return handle_scope.Close(o); - } - /** * converts a BSONObj to a Lazy V8 object */ v8::Persistent<v8::Object> V8Scope::mongoToLZV8(const BSONObj& m, bool readOnly) { v8::Local<v8::Object> o; BSONHolder* own = new BSONHolder(m); + own->_readOnly = readOnly; if (readOnly) { o = roObjectTemplate->NewInstance(); @@ -1519,6 +1370,7 @@ namespace mongo { if (!elem.codeWScopeObject().isEmpty()) log() << "warning: CodeWScope doesn't transfer to db.eval" << endl; return newFunction(elem.codeWScopeCode()); + case mongo::Symbol: case mongo::String: return v8::String::New(elem.valuestr()); case mongo::jstOID: @@ -1526,14 +1378,22 @@ namespace mongo { case mongo::NumberDouble: case mongo::NumberInt: return v8::Number::New(elem.number()); - case mongo::Array: + case mongo::Array: { // NB: This comment may no longer be accurate. // for arrays it's better to use non lazy object because: // - the lazy array is not a true v8 array and requires some v8 src change // for all methods to work // - it made several tests about 1.5x slower // - most times when an array is accessed, all its values will be used - return mongoToV8(elem.embeddedObject(), true, readOnly); + + // It is faster to allow the v8::Array to grow than call nFields() on the array + v8::Handle<v8::Array> array = v8::Array::New(); + int i = 0; + BSONForEach(subElem, elem.embeddedObject()) { + array->Set(i++, mongoToV8Element(subElem, readOnly)); + } + return array; + } case mongo::Object: return mongoToLZV8(elem.embeddedObject(), readOnly); case mongo::Date: @@ -1745,8 +1605,14 @@ namespace mongo { return; } if (value->IsArray()) { - BSONObj sub = v8ToMongo(value->ToObject(), depth); - b.appendArray(sname, sub); + // Note: can't use BSONArrayBuilder because need to call recursively + BSONObjBuilder arrBuilder(b.subarrayStart(sname)); + v8::Handle<v8::Array> array = value.As<v8::Array>(); + const int len = array->Length(); + for (int i=0; i < len; i++) { + const string name = BSONObjBuilder::numStr(i); + v8ToMongoElement(arrBuilder, name, array->Get(i), depth+1, originalParent); + } return; } if (value->IsDate()) { diff --git a/src/mongo/scripting/engine_v8.h b/src/mongo/scripting/engine_v8.h index 1406da51cac..b86d063afae 100644 --- a/src/mongo/scripting/engine_v8.h +++ b/src/mongo/scripting/engine_v8.h @@ -63,17 +63,18 @@ namespace mongo { */ void track(v8::Persistent<v8::Value> instanceHandle, _ObjType* instance) { TrackedPtr* collectionHandle = new TrackedPtr(instance, this); + _container.insert(collectionHandle); instanceHandle.MakeWeak(collectionHandle, deleteOnCollect); } /** - * Free any remaining objects which are being tracked. Invoked when - * the V8Scope is destructed. + * Free any remaining objects and their TrackedPtrs. Invoked when the + * V8Scope is destructed. */ ~ObjTracker() { if (!_container.empty()) LOG(1) << "freeing " << _container.size() << " uncollected " << typeid(_ObjType).name() << " objects" << endl; - typename set<_ObjType*>::iterator it = _container.begin(); + typename set<TrackedPtr*>::iterator it = _container.begin(); while (it != _container.end()) { delete *it; _container.erase(it++); @@ -90,7 +91,7 @@ namespace mongo { TrackedPtr(_ObjType* instance, ObjTracker<_ObjType>* tracker) : _objPtr(instance), _tracker(tracker) { } - _ObjType* _objPtr; + scoped_ptr<_ObjType> _objPtr; ObjTracker<_ObjType>* _tracker; }; @@ -102,14 +103,13 @@ namespace mongo { */ static void deleteOnCollect(v8::Persistent<v8::Value> instanceHandle, void* rawData) { TrackedPtr* trackedPtr = static_cast<TrackedPtr*>(rawData); - trackedPtr->_tracker->_container.erase(trackedPtr->_objPtr); - delete trackedPtr->_objPtr; + trackedPtr->_tracker->_container.erase(trackedPtr); delete trackedPtr; instanceHandle.Dispose(); } - // container for all instances of the tracked _ObjType - set<_ObjType*> _container; + // container for all TrackedPtrs created by this ObjTracker instance + set<TrackedPtr*> _container; }; /** @@ -213,8 +213,6 @@ namespace mongo { /** * Convert BSON types to v8 Javascript types */ - v8::Local<v8::Object> mongoToV8(const mongo::BSONObj& m, bool array = 0, - bool readOnly = false); v8::Persistent<v8::Object> mongoToLZV8(const mongo::BSONObj& m, bool readOnly = false); v8::Handle<v8::Value> mongoToV8Element(const BSONElement& f, bool readOnly = false); @@ -447,7 +445,7 @@ namespace mongo { V8Scope* _scope; BSONObj _obj; bool _modified; - list<string> _extra; + bool _readOnly; set<string> _removed; }; diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js index edfdcbb7ee1..c343f9b6615 100644 --- a/src/mongo/shell/db.js +++ b/src/mongo/shell/db.js @@ -435,7 +435,7 @@ DB.prototype.repairDatabase = function() { DB.prototype.help = function() { print("DB methods:"); - print("\tdb.addUser(username, password[, readOnly=false])"); + print("\tdb.addUser(userDocument)"); print("\tdb.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [ just calls db.runCommand(...) ]"); print("\tdb.auth(username, password)"); print("\tdb.cloneDatabase(fromhost)"); @@ -761,7 +761,7 @@ DB.prototype.killOP = DB.prototype.killOp; DB.tsToSeconds = function(x){ if ( x.t && x.i ) - return x.t / 1000; + return x.t; return x / 4294967296; // low 32 bits are ordinal #s within a second } diff --git a/src/mongo/shell/types.js b/src/mongo/shell/types.js index 681c7deadb0..3c5cfa8622b 100644 --- a/src/mongo/shell/types.js +++ b/src/mongo/shell/types.js @@ -600,7 +600,11 @@ tojsonObject = function(x, indent, nolint){ var num = 1; for (var k in keys){ var val = x[k]; - if (val == DB.prototype || val == DBCollection.prototype) + + // skip internal DB types to avoid issues with interceptors + if (typeof DB != 'undefined' && val == DB.prototype) + continue; + if (typeof DBCollection != 'undefined' && val == DBCollection.prototype) continue; s += indent + "\"" + k + "\" : " + tojson(val, indent, nolint); diff --git a/src/mongo/tools/restore.cpp b/src/mongo/tools/restore.cpp index 35daa4c6f4d..e660bb541a4 100644 --- a/src/mongo/tools/restore.cpp +++ b/src/mongo/tools/restore.cpp @@ -459,7 +459,6 @@ private: int objSize; BSONObj obj; obj = fromjson (buf.get(), &objSize); - uassert(15934, "JSON object size didn't match file size", objSize == fileSize); return obj; } diff --git a/src/mongo/tools/stat.cpp b/src/mongo/tools/stat.cpp index 9dc436d087d..07194444671 100644 --- a/src/mongo/tools/stat.cpp +++ b/src/mongo/tools/stat.cpp @@ -360,7 +360,7 @@ namespace mongo { (int)ceil(_statUtil.getSeconds()) ) ) ); state->authParams = BSON( "user" << _username << "pwd" << _password << - "userSource" << _authenticationDatabase << + "userSource" << getAuthenticationDatabase() << "mechanism" << _authenticationMechanism ); return true; } diff --git a/src/mongo/tools/tool.cpp b/src/mongo/tools/tool.cpp index dfa20f2c8ea..c2728b88af0 100644 --- a/src/mongo/tools/tool.cpp +++ b/src/mongo/tools/tool.cpp @@ -270,7 +270,7 @@ namespace mongo { int ret = -1; try { - if (!useDirectClient) + if (!useDirectClient && !_noconnection) auth(); ret = run(); } @@ -406,6 +406,18 @@ namespace mongo { throw UserException( 9998 , "you need to specify fields" ); } + std::string Tool::getAuthenticationDatabase() { + if (!_authenticationDatabase.empty()) { + return _authenticationDatabase; + } + + if (!_db.empty()) { + return _db; + } + + return "admin"; + } + /** * Validate authentication on the server for the given dbname. */ @@ -422,17 +434,7 @@ namespace mongo { return; } - std::string userSource = _authenticationDatabase; - if ( userSource.empty() ) { - if ( !_db.empty() ) { - userSource = _db; - } - else { - userSource = "admin"; - } - } - - _conn->auth( BSON( saslCommandPrincipalSourceFieldName << userSource << + _conn->auth( BSON( saslCommandPrincipalSourceFieldName << getAuthenticationDatabase() << saslCommandPrincipalFieldName << _username << saslCommandPasswordFieldName << _password << saslCommandMechanismFieldName << _authenticationMechanism ) ); diff --git a/src/mongo/tools/tool.h b/src/mongo/tools/tool.h index 4820ef45c1e..2e7b0823d62 100644 --- a/src/mongo/tools/tool.h +++ b/src/mongo/tools/tool.h @@ -81,6 +81,8 @@ namespace mongo { return _db + "." + _coll; } + string getAuthenticationDatabase(); + void useStandardOutput( bool mode ) { _usesstdout = mode; } diff --git a/src/mongo/util/assert_util.h b/src/mongo/util/assert_util.h index 1c783cee05f..1a2f4fb1967 100644 --- a/src/mongo/util/assert_util.h +++ b/src/mongo/util/assert_util.h @@ -28,9 +28,11 @@ namespace mongo { enum CommonErrorCodes { - DatabaseDifferCaseCode = 13297 , - SendStaleConfigCode = 13388 , - RecvStaleConfigCode = 9996 + OkCode = 0, + DatabaseDifferCaseCode = 13297 , // uassert( 13297 ) + SendStaleConfigCode = 13388 , // uassert( 13388 ) + RecvStaleConfigCode = 9996, // uassert( 9996 ) + PrepareConfigsFailedCode = 13104 // uassert( 13104 ) }; class AssertionCount { diff --git a/src/mongo/util/version.cpp b/src/mongo/util/version.cpp index 2136a70c35e..609fa4afd35 100644 --- a/src/mongo/util/version.cpp +++ b/src/mongo/util/version.cpp @@ -47,7 +47,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.4.1"; + const char versionString[] = "2.4.2"; // See unit test for example outputs BSONArray toVersionArray(const char* version){ @@ -227,27 +227,24 @@ namespace mongo { std::ifstream f("/proc/self/numa_maps", std::ifstream::in); if (f.is_open()) { - char line[100]; //we only need the first line - f.getline(line, sizeof(line)); + std::string line; //we only need the first line + std::getline(f, line); if (f.fail()) { warning() << "failed to read from /proc/self/numa_maps: " << errnoWithDescription() << startupWarningsLog; warned = true; } else { - // just in case... - line[98] = ' '; - line[99] = '\0'; - // skip over pointer - const char* space = strchr(line, ' '); - - if ( ! space ) { + std::string::size_type where = line.find(' '); + if ( (where == std::string::npos) || (++where == line.size()) ) { log() << startupWarningsLog; - log() << "** WARNING: cannot parse numa_maps" << startupWarningsLog; + log() << "** WARNING: cannot parse numa_maps line: '" << line << "'" << startupWarningsLog; warned = true; } - else if ( ! startsWith(space+1, "interleave") ) { + // if the text following the space doesn't begin with 'interleave', then + // issue the warning. + else if ( line.find("interleave", where) != where ) { log() << startupWarningsLog; log() << "** WARNING: You are running on a NUMA machine." << startupWarningsLog; log() << "** We suggest launching mongod like this to avoid performance problems:" << startupWarningsLog; diff --git a/src/third_party/pcre-8.30/config.status b/src/third_party/pcre-8.30/config.status new file mode 100755 index 00000000000..b7e064fea3f --- /dev/null +++ b/src/third_party/pcre-8.30/config.status @@ -0,0 +1,2365 @@ +#! /bin/sh +# Generated by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by PCRE $as_me 8.30, which was +generated by GNU Autoconf 2.68. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +# Files that config.status was made for. +config_files=" Makefile libpcre.pc libpcre16.pc libpcreposix.pc libpcrecpp.pc pcre-config pcre.h pcre_stringpiece.h pcrecpparg.h" +config_headers=" config.h" +config_commands=" depfiles libtool script-chmod delete-old-chartables" + +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +ac_cs_config="" +ac_cs_version="\ +PCRE config.status 8.30 +configured by ./configure, generated by GNU Autoconf 2.68, + with options \"$ac_cs_config\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='/media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30' +srcdir='.' +INSTALL='/usr/bin/install -c' +MKDIR_P='/bin/mkdir -p' +AWK='gawk' +test -n "$AWK" || AWK=awk +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +if $ac_cs_recheck; then + set X '/bin/sh' './configure' $ac_configure_extra_args --no-create --no-recursion + shift + $as_echo "running CONFIG_SHELL=/bin/sh $*" >&6 + CONFIG_SHELL='/bin/sh' + export CONFIG_SHELL + exec "$@" +fi + +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +# +# INIT-COMMANDS +# +AMDEP_TRUE="" ac_aux_dir="." + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' +double_quote_subst='s/\(["`\\]\)/\\\1/g' +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' +AS='as' +DLLTOOL='dlltool' +OBJDUMP='objdump' +macro_version='2.4' +macro_revision='1.3293' +enable_shared='yes' +enable_static='yes' +pic_mode='default' +enable_fast_install='yes' +SHELL='/bin/sh' +ECHO='printf %s\n' +host_alias='' +host='x86_64-unknown-linux-gnu' +host_os='linux-gnu' +build_alias='' +build='x86_64-unknown-linux-gnu' +build_os='linux-gnu' +SED='/bin/sed' +Xsed='/bin/sed -e 1s/^X//' +GREP='/bin/grep' +EGREP='/bin/grep -E' +FGREP='/bin/grep -F' +LD='/usr/bin/ld -m elf_x86_64' +NM='/usr/bin/nm -B' +LN_S='ln -s' +max_cmd_len='1572864' +ac_objext='o' +exeext='' +lt_unset='unset' +lt_SP2NL='tr \040 \012' +lt_NL2SP='tr \015\012 \040\040' +lt_cv_to_host_file_cmd='func_convert_file_noop' +lt_cv_to_tool_file_cmd='func_convert_file_noop' +reload_flag=' -r' +reload_cmds='$LD$reload_flag -o $output$reload_objs' +deplibs_check_method='pass_all' +file_magic_cmd='$MAGIC_CMD' +file_magic_glob='' +want_nocaseglob='no' +sharedlib_from_linklib_cmd='printf %s\n' +AR='ar' +AR_FLAGS='cru' +archiver_list_spec='@' +STRIP='strip' +RANLIB='ranlib' +old_postinstall_cmds='chmod 644 $oldlib~$RANLIB $oldlib' +old_postuninstall_cmds='' +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs~$RANLIB $oldlib' +lock_old_archive_extraction='no' +CC='gcc' +CFLAGS='-O2' +compiler='g++' +GCC='yes' +lt_cv_sys_global_symbol_pipe='sed -n -e '\''s/^.*[ ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$/\1 \2 \2/p'\'' | sed '\''/ __gnu_lto/d'\''' +lt_cv_sys_global_symbol_to_cdecl='sed -n -e '\''s/^T .* \(.*\)$/extern int \1();/p'\'' -e '\''s/^[ABCDGIRSTW]* .* \(.*\)$/extern char \1;/p'\''' +lt_cv_sys_global_symbol_to_c_name_address='sed -n -e '\''s/^: \([^ ]*\)[ ]*$/ {\"\1\", (void *) 0},/p'\'' -e '\''s/^[ABCDGIRSTW]* \([^ ]*\) \([^ ]*\)$/ {"\2", (void *) \&\2},/p'\''' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='sed -n -e '\''s/^: \([^ ]*\)[ ]*$/ {\"\1\", (void *) 0},/p'\'' -e '\''s/^[ABCDGIRSTW]* \([^ ]*\) \(lib[^ ]*\)$/ {"\2", (void *) \&\2},/p'\'' -e '\''s/^[ABCDGIRSTW]* \([^ ]*\) \([^ ]*\)$/ {"lib\2", (void *) \&\2},/p'\''' +nm_file_list_spec='@' +lt_sysroot='' +objdir='.libs' +MAGIC_CMD='file' +lt_prog_compiler_no_builtin_flag=' -fno-builtin' +lt_prog_compiler_pic=' -fPIC -DPIC' +lt_prog_compiler_wl='-Wl,' +lt_prog_compiler_static='' +lt_cv_prog_compiler_c_o='yes' +need_locks='no' +MANIFEST_TOOL=':' +DSYMUTIL='' +NMEDIT='' +LIPO='' +OTOOL='' +OTOOL64='' +libext='a' +shrext_cmds='.so' +extract_expsyms_cmds='' +archive_cmds_need_lc='no' +enable_shared_with_static_runtimes='no' +export_dynamic_flag_spec='${wl}--export-dynamic' +whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' +compiler_needs_object='no' +old_archive_from_new_cmds='' +old_archive_from_expsyms_cmds='' +archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' +archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' +module_cmds='' +module_expsym_cmds='' +with_gnu_ld='yes' +allow_undefined_flag='' +no_undefined_flag='' +hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' +hardcode_libdir_flag_spec_ld='' +hardcode_libdir_separator='' +hardcode_direct='no' +hardcode_direct_absolute='no' +hardcode_minus_L='no' +hardcode_shlibpath_var='unsupported' +hardcode_automatic='no' +inherit_rpath='no' +link_all_deplibs='unknown' +always_export_symbols='no' +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' +exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' +include_expsyms='' +prelink_cmds='' +postlink_cmds='' +file_list_spec='' +variables_saved_for_relink='PATH LD_LIBRARY_PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH' +need_lib_prefix='no' +need_version='no' +version_type='linux' +runpath_var='LD_RUN_PATH' +shlibpath_var='LD_LIBRARY_PATH' +shlibpath_overrides_runpath='no' +libname_spec='lib$name' +library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' +soname_spec='${libname}${release}${shared_ext}$major' +install_override_mode='' +postinstall_cmds='' +postuninstall_cmds='' +finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' +finish_eval='' +hardcode_into_libs='yes' +sys_lib_search_path_spec='/usr/lib/gcc/x86_64-redhat-linux/4.6.2 /usr/lib64 /lib64 ' +sys_lib_dlsearch_path_spec='/lib /usr/lib /usr/lib64/atlas /usr/lib64/llvm /usr/lib64/tracker-0.12 /usr/lib64/xulrunner-2 ' +hardcode_action='immediate' +enable_dlopen='unknown' +enable_dlopen_self='unknown' +enable_dlopen_self_static='unknown' +old_striplib='strip --strip-debug' +striplib='strip --strip-unneeded' +compiler_lib_search_dirs='' +predep_objects='' +postdep_objects='' +predeps='' +postdeps='' +compiler_lib_search_path='' +LD_CXX='/usr/bin/ld -m elf_x86_64' +reload_flag_CXX=' -r' +reload_cmds_CXX='$LD$reload_flag -o $output$reload_objs' +old_archive_cmds_CXX='$AR $AR_FLAGS $oldlib$oldobjs~$RANLIB $oldlib' +compiler_CXX='g++' +GCC_CXX='yes' +lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' +lt_prog_compiler_pic_CXX=' -fPIC -DPIC' +lt_prog_compiler_wl_CXX='-Wl,' +lt_prog_compiler_static_CXX='' +lt_cv_prog_compiler_c_o_CXX='yes' +archive_cmds_need_lc_CXX='no' +enable_shared_with_static_runtimes_CXX='no' +export_dynamic_flag_spec_CXX='${wl}--export-dynamic' +whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' +compiler_needs_object_CXX='no' +old_archive_from_new_cmds_CXX='' +old_archive_from_expsyms_cmds_CXX='' +archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' +archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' +module_cmds_CXX='' +module_expsym_cmds_CXX='' +with_gnu_ld_CXX='yes' +allow_undefined_flag_CXX='' +no_undefined_flag_CXX='' +hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' +hardcode_libdir_flag_spec_ld_CXX='' +hardcode_libdir_separator_CXX='' +hardcode_direct_CXX='no' +hardcode_direct_absolute_CXX='no' +hardcode_minus_L_CXX='no' +hardcode_shlibpath_var_CXX='unsupported' +hardcode_automatic_CXX='no' +inherit_rpath_CXX='no' +link_all_deplibs_CXX='unknown' +always_export_symbols_CXX='no' +export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' +exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' +include_expsyms_CXX='' +prelink_cmds_CXX='' +postlink_cmds_CXX='' +file_list_spec_CXX='' +hardcode_action_CXX='immediate' +compiler_lib_search_dirs_CXX='/usr/lib/gcc/x86_64-redhat-linux/4.6.2 /usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../lib64 /lib/../lib64 /usr/lib/../lib64 /usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../..' +predep_objects_CXX='/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.6.2/crtbeginS.o' +postdep_objects_CXX='/usr/lib/gcc/x86_64-redhat-linux/4.6.2/crtendS.o /usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../lib64/crtn.o' +predeps_CXX='' +postdeps_CXX='-lstdc++ -lm -lgcc_s -lc -lgcc_s' +compiler_lib_search_path_CXX='-L/usr/lib/gcc/x86_64-redhat-linux/4.6.2 -L/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.6.2/../../..' + +LTCC='gcc' +LTCFLAGS='-O2' +compiler='gcc' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in AS DLLTOOL OBJDUMP SHELL ECHO SED GREP EGREP FGREP LD NM LN_S lt_SP2NL lt_NL2SP reload_flag deplibs_check_method file_magic_cmd file_magic_glob want_nocaseglob sharedlib_from_linklib_cmd AR AR_FLAGS archiver_list_spec STRIP RANLIB CC CFLAGS compiler lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl lt_cv_sys_global_symbol_to_c_name_address lt_cv_sys_global_symbol_to_c_name_address_lib_prefix nm_file_list_spec lt_prog_compiler_no_builtin_flag lt_prog_compiler_pic lt_prog_compiler_wl lt_prog_compiler_static lt_cv_prog_compiler_c_o need_locks MANIFEST_TOOL DSYMUTIL NMEDIT LIPO OTOOL OTOOL64 shrext_cmds export_dynamic_flag_spec whole_archive_flag_spec compiler_needs_object with_gnu_ld allow_undefined_flag no_undefined_flag hardcode_libdir_flag_spec hardcode_libdir_flag_spec_ld hardcode_libdir_separator exclude_expsyms include_expsyms file_list_spec variables_saved_for_relink libname_spec library_names_spec soname_spec install_override_mode finish_eval old_striplib striplib compiler_lib_search_dirs predep_objects postdep_objects predeps postdeps compiler_lib_search_path LD_CXX reload_flag_CXX compiler_CXX lt_prog_compiler_no_builtin_flag_CXX lt_prog_compiler_pic_CXX lt_prog_compiler_wl_CXX lt_prog_compiler_static_CXX lt_cv_prog_compiler_c_o_CXX export_dynamic_flag_spec_CXX whole_archive_flag_spec_CXX compiler_needs_object_CXX with_gnu_ld_CXX allow_undefined_flag_CXX no_undefined_flag_CXX hardcode_libdir_flag_spec_CXX hardcode_libdir_flag_spec_ld_CXX hardcode_libdir_separator_CXX exclude_expsyms_CXX include_expsyms_CXX file_list_spec_CXX compiler_lib_search_dirs_CXX predep_objects_CXX postdep_objects_CXX predeps_CXX postdeps_CXX compiler_lib_search_path_CXX; do + case `eval \\$ECHO \\""\\$$var"\\"` in + *[\\\`\"\$]*) + eval "lt_$var=\\\"\`\$ECHO \"\$$var\" | \$SED \"\$sed_quote_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\$$var\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds old_postinstall_cmds old_postuninstall_cmds old_archive_cmds extract_expsyms_cmds old_archive_from_new_cmds old_archive_from_expsyms_cmds archive_cmds archive_expsym_cmds module_cmds module_expsym_cmds export_symbols_cmds prelink_cmds postlink_cmds postinstall_cmds postuninstall_cmds finish_cmds sys_lib_search_path_spec sys_lib_dlsearch_path_spec reload_cmds_CXX old_archive_cmds_CXX old_archive_from_new_cmds_CXX old_archive_from_expsyms_cmds_CXX archive_cmds_CXX archive_expsym_cmds_CXX module_cmds_CXX module_expsym_cmds_CXX export_symbols_cmds_CXX prelink_cmds_CXX postlink_cmds_CXX; do + case `eval \\$ECHO \\""\\$$var"\\"` in + *[\\\`\"\$]*) + eval "lt_$var=\\\"\`\$ECHO \"\$$var\" | \$SED -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "lt_$var=\\\"\$$var\\\"" + ;; + esac +done + +ac_aux_dir='.' +xsi_shell='yes' +lt_shell_append='yes' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='pcre' + VERSION='8.30' + TIMESTAMP='' + RM='rm -f' + ofile='libtool' + + + + + + + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "libpcre.pc") CONFIG_FILES="$CONFIG_FILES libpcre.pc" ;; + "libpcre16.pc") CONFIG_FILES="$CONFIG_FILES libpcre16.pc" ;; + "libpcreposix.pc") CONFIG_FILES="$CONFIG_FILES libpcreposix.pc" ;; + "libpcrecpp.pc") CONFIG_FILES="$CONFIG_FILES libpcrecpp.pc" ;; + "pcre-config") CONFIG_FILES="$CONFIG_FILES pcre-config" ;; + "pcre.h") CONFIG_FILES="$CONFIG_FILES pcre.h" ;; + "pcre_stringpiece.h") CONFIG_FILES="$CONFIG_FILES pcre_stringpiece.h" ;; + "pcrecpparg.h") CONFIG_FILES="$CONFIG_FILES pcrecpparg.h" ;; + "script-chmod") CONFIG_COMMANDS="$CONFIG_COMMANDS script-chmod" ;; + "delete-old-chartables") CONFIG_COMMANDS="$CONFIG_COMMANDS delete-old-chartables" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +cat >>"$ac_tmp/subs1.awk" <<\_ACAWK && +S["am__EXEEXT_FALSE"]="" +S["am__EXEEXT_TRUE"]="#" +S["LTLIBOBJS"]="" +S["LIBOBJS"]="" +S["LIBBZ2"]="" +S["LIBZ"]="" +S["DISTCHECK_CONFIGURE_FLAGS"]="CFLAGS='' CXXFLAGS='' --enable-pcre16 --enable-jit --enable-cpp --enable-unicode-properties" +S["EXTRA_LIBPCRECPP_LDFLAGS"]=" -version-info 0:0:0 " +S["EXTRA_LIBPCREPOSIX_LDFLAGS"]=" -version-info 0:0:0" +S["EXTRA_LIBPCRE16_LDFLAGS"]=" -version-info 0:0:0" +S["EXTRA_LIBPCRE_LDFLAGS"]=" -version-info 1:0:0" +S["PCRE_STATIC_CFLAG"]="" +S["LIBREADLINE"]="-lreadline" +S["WITH_UTF_FALSE"]="" +S["WITH_UTF_TRUE"]="#" +S["WITH_JIT_FALSE"]="" +S["WITH_JIT_TRUE"]="#" +S["WITH_REBUILD_CHARTABLES_FALSE"]="" +S["WITH_REBUILD_CHARTABLES_TRUE"]="#" +S["WITH_PCRE_CPP_FALSE"]="#" +S["WITH_PCRE_CPP_TRUE"]="" +S["WITH_PCRE16_FALSE"]="" +S["WITH_PCRE16_TRUE"]="#" +S["WITH_PCRE8_FALSE"]="#" +S["WITH_PCRE8_TRUE"]="" +S["pcre_have_bits_type_traits"]="0" +S["pcre_have_type_traits"]="0" +S["pcre_have_ulong_long"]="1" +S["pcre_have_long_long"]="1" +S["enable_cpp"]="yes" +S["enable_pcre16"]="no" +S["enable_pcre8"]="yes" +S["PCRE_DATE"]="2012-02-04" +S["PCRE_PRERELEASE"]="" +S["PCRE_MINOR"]="30" +S["PCRE_MAJOR"]="8" +S["CXXCPP"]="g++ -E" +S["OTOOL64"]="" +S["OTOOL"]="" +S["LIPO"]="" +S["NMEDIT"]="" +S["DSYMUTIL"]="" +S["MANIFEST_TOOL"]=":" +S["RANLIB"]="ranlib" +S["ac_ct_AR"]="ar" +S["AR"]="ar" +S["LN_S"]="ln -s" +S["NM"]="/usr/bin/nm -B" +S["ac_ct_DUMPBIN"]="" +S["DUMPBIN"]="" +S["LD"]="/usr/bin/ld -m elf_x86_64" +S["FGREP"]="/bin/grep -F" +S["SED"]="/bin/sed" +S["LIBTOOL"]="$(SHELL) $(top_builddir)/libtool" +S["OBJDUMP"]="objdump" +S["DLLTOOL"]="dlltool" +S["AS"]="as" +S["host_os"]="linux-gnu" +S["host_vendor"]="unknown" +S["host_cpu"]="x86_64" +S["host"]="x86_64-unknown-linux-gnu" +S["build_os"]="linux-gnu" +S["build_vendor"]="unknown" +S["build_cpu"]="x86_64" +S["build"]="x86_64-unknown-linux-gnu" +S["EGREP"]="/bin/grep -E" +S["GREP"]="/bin/grep" +S["CPP"]="gcc -E" +S["am__fastdepCXX_FALSE"]="#" +S["am__fastdepCXX_TRUE"]="" +S["CXXDEPMODE"]="depmode=gcc3" +S["ac_ct_CXX"]="g++" +S["CXXFLAGS"]="-O2" +S["CXX"]="g++" +S["am__fastdepCC_FALSE"]="#" +S["am__fastdepCC_TRUE"]="" +S["CCDEPMODE"]="depmode=gcc3" +S["AMDEPBACKSLASH"]="\\" +S["AMDEP_FALSE"]="#" +S["AMDEP_TRUE"]="" +S["am__quote"]="" +S["am__include"]="include" +S["DEPDIR"]=".deps" +S["OBJEXT"]="o" +S["EXEEXT"]="" +S["ac_ct_CC"]="gcc" +S["CPPFLAGS"]="" +S["LDFLAGS"]="" +S["CFLAGS"]="-O2" +S["CC"]="gcc" +S["AM_BACKSLASH"]="\\" +S["AM_DEFAULT_VERBOSITY"]="0" +S["am__untar"]="${AMTAR} xf -" +S["am__tar"]="${AMTAR} chof - \"$$tardir\"" +S["AMTAR"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run tar" +S["am__leading_dot"]="." +S["SET_MAKE"]="" +S["AWK"]="gawk" +S["mkdir_p"]="/bin/mkdir -p" +S["MKDIR_P"]="/bin/mkdir -p" +S["INSTALL_STRIP_PROGRAM"]="$(install_sh) -c -s" +S["STRIP"]="strip" +S["install_sh"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/install-sh" +S["MAKEINFO"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run makeinfo" +S["AUTOHEADER"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run autoheader" +S["AUTOMAKE"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run automake-1.11" +S["AUTOCONF"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run autoconf" +S["ACLOCAL"]="${SHELL} /media/DATA0/data/m/3827/mongo/src/third_party/pcre-8.30/missing --run aclocal-1.11" +S["VERSION"]="8.30" +S["PACKAGE"]="pcre" +S["CYGPATH_W"]="echo" +S["am__isrc"]="" +S["INSTALL_DATA"]="${INSTALL} -m 644" +S["INSTALL_SCRIPT"]="${INSTALL}" +S["INSTALL_PROGRAM"]="${INSTALL}" +S["target_alias"]="" +S["host_alias"]="" +S["build_alias"]="" +S["LIBS"]="" +S["ECHO_T"]="" +S["ECHO_N"]="-n" +S["ECHO_C"]="" +S["DEFS"]="-DHAVE_CONFIG_H" +S["mandir"]="${datarootdir}/man" +S["localedir"]="${datarootdir}/locale" +S["libdir"]="${exec_prefix}/lib" +S["psdir"]="${docdir}" +S["pdfdir"]="${docdir}" +S["dvidir"]="${docdir}" +S["htmldir"]="${docdir}/html" +S["infodir"]="${datarootdir}/info" +S["docdir"]="${datarootdir}/doc/${PACKAGE_TARNAME}" +S["oldincludedir"]="/usr/include" +S["includedir"]="${prefix}/include" +S["localstatedir"]="${prefix}/var" +S["sharedstatedir"]="${prefix}/com" +S["sysconfdir"]="${prefix}/etc" +S["datadir"]="${datarootdir}" +S["datarootdir"]="${prefix}/share" +S["libexecdir"]="${exec_prefix}/libexec" +S["sbindir"]="${exec_prefix}/sbin" +S["bindir"]="${exec_prefix}/bin" +S["program_transform_name"]="s,x,x," +S["prefix"]="/usr/local" +S["exec_prefix"]="${prefix}" +S["PACKAGE_URL"]="" +S["PACKAGE_BUGREPORT"]="" +S["PACKAGE_STRING"]="PCRE 8.30" +S["PACKAGE_VERSION"]="8.30" +S["PACKAGE_TARNAME"]="pcre" +S["PACKAGE_NAME"]="PCRE" +S["PATH_SEPARATOR"]=":" +S["SHELL"]="/bin/sh" +_ACAWK +cat >>"$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +D["PACKAGE_NAME"]=" \"PCRE\"" +D["PACKAGE_TARNAME"]=" \"pcre\"" +D["PACKAGE_VERSION"]=" \"8.30\"" +D["PACKAGE_STRING"]=" \"PCRE 8.30\"" +D["PACKAGE_BUGREPORT"]=" \"\"" +D["PACKAGE_URL"]=" \"\"" +D["PACKAGE"]=" \"pcre\"" +D["VERSION"]=" \"8.30\"" +D["STDC_HEADERS"]=" 1" +D["HAVE_SYS_TYPES_H"]=" 1" +D["HAVE_SYS_STAT_H"]=" 1" +D["HAVE_STDLIB_H"]=" 1" +D["HAVE_STRING_H"]=" 1" +D["HAVE_MEMORY_H"]=" 1" +D["HAVE_STRINGS_H"]=" 1" +D["HAVE_INTTYPES_H"]=" 1" +D["HAVE_STDINT_H"]=" 1" +D["HAVE_UNISTD_H"]=" 1" +D["HAVE_DLFCN_H"]=" 1" +D["LT_OBJDIR"]=" \".libs/\"" +D["STDC_HEADERS"]=" 1" +D["HAVE_LIMITS_H"]=" 1" +D["HAVE_SYS_TYPES_H"]=" 1" +D["HAVE_SYS_STAT_H"]=" 1" +D["HAVE_DIRENT_H"]=" 1" +D["HAVE_STRING"]=" 1" +D["HAVE_STRTOQ"]=" 1" +D["HAVE_LONG_LONG"]=" 1" +D["HAVE_UNSIGNED_LONG_LONG"]=" 1" +D["HAVE_BCOPY"]=" 1" +D["HAVE_MEMMOVE"]=" 1" +D["HAVE_STRERROR"]=" 1" +D["HAVE_ZLIB_H"]=" 1" +D["HAVE_BZLIB_H"]=" 1" +D["HAVE_READLINE_READLINE_H"]=" 1" +D["HAVE_READLINE_HISTORY_H"]=" 1" +D["SUPPORT_PCRE8"]=" /**/" +D["PCREGREP_BUFSIZE"]=" 20480" +D["NEWLINE"]=" 10" +D["LINK_SIZE"]=" 2" +D["POSIX_MALLOC_THRESHOLD"]=" 10" +D["MATCH_LIMIT"]=" 10000000" +D["MATCH_LIMIT_RECURSION"]=" MATCH_LIMIT" +D["MAX_NAME_SIZE"]=" 32" +D["MAX_NAME_COUNT"]=" 10000" + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+[_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ][_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]*([\t (]|$)/ { + line = $ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + ac_datarootdir_hack=' + s&@datadir@&${datarootdir}&g + s&@docdir@&${datarootdir}/doc/${PACKAGE_TARNAME}&g + s&@infodir@&${datarootdir}/info&g + s&@localedir@&${datarootdir}/locale&g + s&@mandir@&${datarootdir}/man&g + s&\${datarootdir}&${prefix}/share&g' ;; +esac +ac_sed_extra="/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +} + +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010 Free Software Foundation, +# Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Assembler program. +AS=$lt_AS + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Object dumper program. +OBJDUMP=$lt_OBJDUMP + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + "script-chmod":C) chmod a+x pcre-config ;; + "delete-old-chartables":C) rm -f pcre_chartables.c ;; + + esac +done # for ac_tag + + +as_fn_exit 0 |
