diff options
| author | Laszlo Boszormenyi (GCS) <gcs@debian.org> | 2014-04-27 22:12:11 +0200 |
|---|---|---|
| committer | Laszlo Boszormenyi (GCS) <gcs@debian.org> | 2014-04-27 22:12:11 +0200 |
| commit | f0716c5e9c213302422db87c1c36c1d177853e8e (patch) | |
| tree | 44f26826e6dde7c32ad2f57f206d7da74e994625 | |
| parent | 547377230880c8e9def9ee9458ae69d298918467 (diff) | |
Imported Upstream version 2.4.10upstream/2.4.10
41 files changed, 540 insertions, 187 deletions
diff --git a/doxygenConfig b/doxygenConfig index 90b26608766..c301d1acf09 100644 --- a/doxygenConfig +++ b/doxygenConfig @@ -3,7 +3,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = MongoDB -PROJECT_NUMBER = 2.4.9 +PROJECT_NUMBER = 2.4.10 OUTPUT_DIRECTORY = docs/doxygen CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff --git a/jstests/bench_test3.js b/jstests/bench_test3.js index 4bc21ed2505..34e033fe52a 100644 --- a/jstests/bench_test3.js +++ b/jstests/bench_test3.js @@ -8,7 +8,7 @@ benchArgs = { ops : [ { ns : t.getFullName() , query : { _id : { "#RAND_INT" : [ 0 , 5 , 4 ] } } , update : { $inc : { x : 1 } } } ] , parallel : 2 , - seconds : 1 , + seconds : 5 , totals : true , host : db.getMongo().host } @@ -24,4 +24,5 @@ printjson( res ); var keys = [] var totals = {} db.bench_test3.find().sort( { _id : 1 } ).forEach( function(z){ keys.push( z._id ); totals[z._id] = z.x } ); +printjson(totals); assert.eq( [ 0 , 4 , 8 , 12 , 16 ] , keys ) diff --git a/jstests/geo_s2indexversion1.js b/jstests/geo_s2indexversion1.js new file mode 100644 index 00000000000..799ba775f02 --- /dev/null +++ b/jstests/geo_s2indexversion1.js @@ -0,0 +1,113 @@ +// Tests 2dsphere index option "2dsphereIndexVersion". Verifies that only index version 1 is +// permitted. + +var coll = db.getCollection("geo_s2indexversion1"); +coll.drop(); + +// +// Index build should fail for invalid values of "2dsphereIndexVersion". +// + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": -1}); +assert.gleError(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": 0}); +assert.gleError(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": 2}); +assert.gleError(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": 3}); +assert.gleError(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": Infinity}); +assert.gleError(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": "foo"}); +assert.gleError(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": {a: 1}}); +assert.gleError(db); +coll.drop(); + +// +// Index build should succeed for valid values of "2dsphereIndexVersion". +// + +coll.ensureIndex({geo: "2dsphere"}); +assert.gleSuccess(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": 1}); +assert.gleSuccess(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": NumberInt(1)}); +assert.gleSuccess(db); +coll.drop(); + +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": NumberLong(1)}); +assert.gleSuccess(db); +coll.drop(); + +// +// Test compatibility of various GeoJSON objects with 2dsphere. +// + +var pointDoc = {geo: {type: "Point", coordinates: [40, 5]}}; +var lineStringDoc = {geo: {type: "LineString", coordinates: [[40, 5], [41, 6]]}}; +var polygonDoc = {geo: {type: "Polygon", coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]}}; +var multiPointDoc = {geo: {type: "MultiPoint", + coordinates: [[-73.9580, 40.8003], [-73.9498, 40.7968], + [-73.9737, 40.7648], [-73.9814, 40.7681]]}}; +var multiLineStringDoc = {geo: {type: "MultiLineString", + coordinates: [[[-73.96943, 40.78519], [-73.96082, 40.78095]], + [[-73.96415, 40.79229], [-73.95544, 40.78854]], + [[-73.97162, 40.78205], [-73.96374, 40.77715]], + [[-73.97880, 40.77247], [-73.97036, 40.76811]]]}}; +var multiPolygonDoc = {geo: {type: "MultiPolygon", + coordinates: [[[[-73.958, 40.8003], [-73.9498, 40.7968], + [-73.9737, 40.7648], [-73.9814, 40.7681], + [-73.958, 40.8003]]], + [[[-73.958, 40.8003], [-73.9498, 40.7968], + [-73.9737, 40.7648], [-73.958, 40.8003]]]]}}; +var geometryCollectionDoc = {geo: {type: "GeometryCollection", + geometries: [{type: "MultiPoint", + coordinates: [[-73.9580, 40.8003], + [-73.9498, 40.7968], + [-73.9737, 40.7648], + [-73.9814, 40.7681]]}, + {type: "MultiLineString", + coordinates: [[[-73.96943, 40.78519], + [-73.96082, 40.78095]], + [[-73.96415, 40.79229], + [-73.95544, 40.78854]], + [[-73.97162, 40.78205], + [-73.96374, 40.77715]], + [[-73.97880, 40.77247], + [-73.97036, 40.76811]]]}]}}; + +// {2dsphereIndexVersion: 1} indexes allow only Point, LineString, and Polygon. +coll.ensureIndex({geo: "2dsphere"}, {"2dsphereIndexVersion": 1}); +assert.gleSuccess(db); +coll.insert(pointDoc); +assert.gleSuccess(db); +coll.insert(lineStringDoc); +assert.gleSuccess(db); +coll.insert(polygonDoc); +assert.gleSuccess(db); +coll.insert(multiPointDoc); +assert.gleError(db); +coll.insert(multiLineStringDoc); +assert.gleError(db); +coll.insert(multiPolygonDoc); +assert.gleError(db); +coll.insert(geometryCollectionDoc); +assert.gleError(db); +coll.drop(); diff --git a/jstests/indexes_on_indexes.js b/jstests/indexes_on_indexes.js new file mode 100644 index 00000000000..807c1e25bfd --- /dev/null +++ b/jstests/indexes_on_indexes.js @@ -0,0 +1,19 @@ +// ensure an index cannot be created on system.indexes +t = db.getSiblingDB("indexes_on_indexes"); +printjson(t.system.indexes.getIndexes()); +assert.eq(t.system.indexes.getIndexes().length, 0); +print("trying via ensureIndex"); +assert.throws(t.system.indexes.ensureIndex({_id:1})); +printjson(t.system.indexes.getIndexes()); +assert.eq(t.system.indexes.getIndexes().length, 0); +print("trying via createIndex"); +assert.throws(t.system.indexes.createIndex({_id:1})); +printjson(t.system.indexes.getIndexes()); +assert.eq(t.system.indexes.getIndexes().length, 0); +print("trying via direct insertion"); +assert.throws(t.system.indexes.insert({ v:1, + key:{_id:1}, + ns: "indexes_on_indexes.system.indexes", + name:"wontwork"})); +printjson(t.system.indexes.getIndexes()); +assert.eq(t.system.indexes.getIndexes().length, 0); diff --git a/jstests/replsets/compact.js b/jstests/replsets/compact.js new file mode 100644 index 00000000000..d2a83a8c423 --- /dev/null +++ b/jstests/replsets/compact.js @@ -0,0 +1,59 @@ +if (0) { // this test also commented out in master (renamed to auth_compact.js) b/c of SERVER-12697 + +// test that nodes still respond to heartbeats during compact() SERVER-12264 +var replTest = new ReplSetTest({ name: 'compact', nodes: 3 }); + +replTest.startSet(); +replTest.initiate(); + +var master = replTest.getMaster(); +var compactingSlave = replTest.liveNodes.slaves[0]; + +// populate data +for (i=0; i<1000; i++) { + var bulkInsertArr = []; + for (j=0; j<1000; j++) { + bulkInsertArr.push({x:i, y:j}); + } + master.getDB("compact").foo.insert(bulkInsertArr); +} + +// takes a while to replicate all this data... +replTest.awaitReplication(1000*60*5); + +// run compact in parallel with this rest of the script +var cmd = "tojson(db.getSiblingDB('compact').runCommand({'compact': 'foo', 'paddingFactor': 2}));"; +var compactor = startParallelShell(cmd, compactingSlave.port);; + +// wait for compact to show up in currentOp +assert.soon(function() { + var curop = compactingSlave.getDB('compact').currentOp(); + for (index in curop.inprog) { + entry = curop.inprog[index]; + if (entry.query.hasOwnProperty("compact") && entry.query.compact === "foo" + && entry.hasOwnProperty("locks") && entry.locks.hasOwnProperty("^compact") + && entry.locks["^compact"] === "W") { + return true; + } + } + return false; +}, "compact didn't start in 30 seconds", 30*1000, 100); + +// then check that it is still responding to heartbeats +for (i=0; i<5; i++) { + var start = new Date(); + var result = compactingSlave.getDB("admin").runCommand({"replSetHeartbeat": "compact", + "v": NumberInt(1), + "pv": NumberInt(1), + "checkEmpty": false, + "fromId": NumberInt(0) + }); + var end = new Date(); + assert.eq(result.ok, 1, "heartbeat didn't return properly"); + // wait for 10 seconds because that's how long it takes for a node to be considered down + assert.lt(end - start, 10 * 1000, "heartbeat didn't return quickly enough"); +} + +replTest.stopSet(); + +} diff --git a/jstests/replsets/initSyncV1Index.js b/jstests/replsets/initSyncV1Index.js index deec0177382..184eb76615f 100644 --- a/jstests/replsets/initSyncV1Index.js +++ b/jstests/replsets/initSyncV1Index.js @@ -12,8 +12,8 @@ for (var i = 0; i < 10000; i++) db1.foo.insert( {_id:i, x:i%1000, t:t} ); db1.foo.createIndex( {x:1}, {v: 0} ); var r2 = rs.add(); -rs.reInitiate(); -rs.awaitSecondaryNodes(); +rs.reInitiate(60000); + var db2 = r2.getDB('test'); r2.setSlaveOk(); diff --git a/jstests/replsets/replset_remove_node.js b/jstests/replsets/replset_remove_node.js index bf99b1236fc..3294b226e27 100644 --- a/jstests/replsets/replset_remove_node.js +++ b/jstests/replsets/replset_remove_node.js @@ -1,9 +1,8 @@ -doTest = function( signal ) { +(function() { - // Make sure that we can manually shutdown a remove a - // slave from the configuration. + // Make sure that we can manually shutdown and remove a + // secondary from the configuration. - // Create a new replica set test. Specify set name and the number of nodes you want. var replTest = new ReplSetTest( {name: 'testSet', nodes: 3} ); // call startSet() to start each mongod in the replica set @@ -30,6 +29,10 @@ doTest = function( signal ) { // Shut down the unwanted node replTest.stop( slaveId ); + // Note: this will cause the PRIMARY to step down, which causes it to close all + // connections, including the one we're using from the shell to drive this test. + // The shell will attempt to reconnect once. + // Remove that node from the configuration replTest.remove( slaveId ); @@ -39,40 +42,44 @@ doTest = function( signal ) { var config = replTest.getReplSetConfig(); config.version = c.version + 1; config.members = [ { "_id" : 0, "host" : replTest.host + ":31000" }, - { "_id" : 2, "host" : replTest.host + ":31002" } ] + { "_id" : 2, "host" : replTest.host + ":31002" } ]; try { + // Note that this will cause the shell's connection to the primary to be disconnected again replTest.initiate( config , 'replSetReconfig' ); } catch(e) { print(e); } - // Make sure that a new master comes up master = replTest.getMaster(); slaves = replTest.liveNodes.slaves; + // Trigger a reconnect from the shell again, to be sure we're reconnected. + try { + master.getDB("local").system.replset.findOne(); + } + catch (e) { + print (e); + } + // Do a status check on each node // Master should be set to 1 (primary) assert.soon(function() { - stat = master.getDB("admin").runCommand({replSetGetStatus: 1}); + var stat = master.getDB("admin").runCommand({replSetGetStatus: 1}); printjson( stat ); return stat.myState == 1; }, "Master failed to come up as master.", 60000); // Slaves to be set to 2 (secondary) assert.soon(function() { - stat = slaves[0].getDB("admin").runCommand({replSetGetStatus: 1}); + var stat = slaves[0].getDB("admin").runCommand({replSetGetStatus: 1}); return stat.myState == 2; }, "Slave failed to come up as slave.", 60000); assert.soon(function() { - stat = slaves[0].getDB("admin").runCommand({replSetGetStatus: 1}); + var stat = slaves[0].getDB("admin").runCommand({replSetGetStatus: 1}); return stat.members.length == 2; }, "Wrong number of members", 60000); -}
-
-print("replset_remove_node.js");
-doTest(15);
-print("replset_remove_node SUCCESS");
+}()); diff --git a/jstests/replsets/slavedelay1.js b/jstests/replsets/slavedelay1.js index 13c6adfcdf3..623fa8a5ab4 100644 --- a/jstests/replsets/slavedelay1.js +++ b/jstests/replsets/slavedelay1.js @@ -12,17 +12,16 @@ doTest = function( signal ) { /* set slaveDelay to 30 seconds */ var config = replTest.getReplSetConfig(); config.members[2].priority = 0; - config.members[2].slaveDelay = 10; + config.members[2].slaveDelay = 30; replTest.initiate(config); var master = replTest.getMaster().getDB(name); var slaveConns = replTest.liveNodes.slaves; - var slave = []; + var slaves = []; for (var i in slaveConns) { var d = slaveConns[i].getDB(name); - d.getMongo().setSlaveOk(); - slave.push(d); + slaves.push(d); } waitForAllMembers(master); @@ -35,68 +34,44 @@ doTest = function( signal ) { assert.eq(doc.x, 1); // make sure slave has it - var doc = slave[0].foo.findOne(); + var doc = slaves[0].foo.findOne(); assert.eq(doc.x, 1); // make sure delayed slave doesn't have it - assert.eq(slave[1].foo.findOne(), null); - for (var i=0; i<8; i++) { - assert.eq(slave[1].foo.findOne(), null); + assert.eq(slaves[1].foo.findOne(), null); sleep(1000); } - // now delayed slave should have it + // within 30 seconds delayed slave should have it assert.soon(function() { - var z = slave[1].foo.findOne(); + var z = slaves[1].foo.findOne(); return z && z.x == 1; }); /************* Part 2 *******************/ - // how about non-initial sync? - - for (var i=0; i<100; i++) { - master.foo.insert({_id : i, "foo" : "bar"}); - } - master.runCommand({getlasterror:1,w:2}); - - assert.eq(master.foo.findOne({_id : 99}).foo, "bar"); - assert.eq(slave[0].foo.findOne({_id : 99}).foo, "bar"); - assert.eq(slave[1].foo.findOne({_id : 99}), null); - - for (var i=0; i<8; i++) { - assert.eq(slave[1].foo.findOne({_id:99}), null); - sleep(1000); - } - - assert.soon(function() { - var z = slave[1].foo.findOne({_id : 99}); - return z && z.foo == "bar"; - }); - - /************* Part 3 *******************/ - // how about if we add a new server? will it sync correctly? - conn = replTest.add(); config = master.getSisterDB("local").system.replset.findOne(); printjson(config); config.version++; - config.members.push({_id : 3, host : host+":"+replTest.ports[replTest.ports.length-1],priority:0, slaveDelay:10}); + config.members.push({_id: 3, + host: host+":"+replTest.ports[replTest.ports.length-1], + priority:0, + slaveDelay:30}); master = reconfig(replTest, config); master = master.getSisterDB(name); - // it should be all caught up now + // wait for the node to catch up + replTest.awaitReplication(); master.foo.insert({_id : 123, "x" : "foo"}); master.runCommand({getlasterror:1,w:2}); - conn.setSlaveOk(); - for (var i=0; i<8; i++) { assert.eq(conn.getDB(name).foo.findOne({_id:123}), null); sleep(1000); @@ -107,7 +82,7 @@ doTest = function( signal ) { return z != null && z.x == "foo" }); - /************* Part 4 ******************/ + /************* Part 3 ******************/ print("reconfigure slavedelay"); @@ -120,6 +95,7 @@ doTest = function( signal ) { return conn.getDB("local").system.replset.findOne().version == config.version; }); + // wait for node to become secondary assert.soon(function() { var result = conn.getDB("admin").isMaster(); printjson(result); @@ -130,12 +106,15 @@ doTest = function( signal ) { master.foo.insert({_id : 124, "x" : "foo"}); assert(master.foo.findOne({_id:124}) != null); - for (var i=0; i<13; i++) { + for (var i=0; i<10; i++) { assert.eq(conn.getDB(name).foo.findOne({_id:124}), null); sleep(1000); } - replTest.awaitReplication(); + // the node should have the document in 15 seconds (20 for some safety against races) + assert.soon(function() { + return conn.getDB(name).foo.findOne({_id:124}) != null; + }, 10*1000); replTest.stopSet(); } diff --git a/jstests/replsets/sync2.js b/jstests/replsets/sync2.js index 258cfd3ee12..57577c6c46b 100644 --- a/jstests/replsets/sync2.js +++ b/jstests/replsets/sync2.js @@ -21,22 +21,6 @@ replTest.awaitSecondaryNodes(); master.getDB("foo").bar.insert({x:1}); replTest.awaitReplication(); -jsTestLog("Checking that currentOp for secondaries uses OpTime, not Date"); -assert.soon( - function() { - var count = 0; - var currentOp = master.getDB("admin").currentOp({ns: 'local.oplog.rs'}); - printjson(currentOp); - currentOp.inprog.forEach( - function(op) { - assert.eq(op.query.ts.$gte.constructor, Timestamp); - count++; - } - ); - return count >= 4; - } -); - jsTestLog("Bridging replica set"); master = replTest.bridge(); diff --git a/jstests/replsets/two_initsync.js b/jstests/replsets/two_initsync.js index 7d1442d344f..08e440406cb 100755 --- a/jstests/replsets/two_initsync.js +++ b/jstests/replsets/two_initsync.js @@ -63,7 +63,7 @@ doTest = function (signal) { // Add the second node. // This runs the equivalent of rs.add(newNode); - replTest.reInitiate(); + replTest.reInitiate(60000); var b = second.getDB("admin"); diff --git a/jstests/sharding/prefix_shard_key.js b/jstests/sharding/prefix_shard_key.js index 58091490b1c..0e55aae2d44 100644 --- a/jstests/sharding/prefix_shard_key.js +++ b/jstests/sharding/prefix_shard_key.js @@ -119,7 +119,7 @@ for( i=0; i < 3; i++ ){ var coll2 = db.foo2; coll2.drop(); var moveRes = admin.runCommand( { movePrimary : coll2.getDB() + "", to : shards[0]._id } ); - assert.eq( moveRes.ok , 1 , "primary not moved correctly" ); + assert.eq( moveRes.ok, 1, "primary not moved correctly: " + tojson( moveRes )); // declare a longer index if ( i == 0 ) { diff --git a/jstests/sharding/sync7.js b/jstests/sharding/sync7.js index 87eeaa0b36b..8c1430ea3c0 100644 --- a/jstests/sharding/sync7.js +++ b/jstests/sharding/sync7.js @@ -3,11 +3,11 @@ s = new ShardingTest( "moveDistLock", 3, 0, undefined, { sync : true } ); s._connections[0].getDB( "admin" ).runCommand( { _skewClockCommand : 1, skew : 15000 } ) -s._connections[1].getDB( "admin" ).runCommand( { _skewClockCommand : 1, skew : -16000 } ) +s._connections[1].getDB( "admin" ).runCommand( { _skewClockCommand : 1, skew : -32000 } ) // We need to start another mongos after skewing the clock, since the first mongos will have already // tested the config servers (via the balancer) before we manually skewed them -otherMongos = startMongos( { port : 30020, v : 0, configdb : s._configDB } ); +otherMongos = startMongos( { port : 30020, v : 2, configdb : s._configDB } ); // Initialize DB data initDB = function(name) { diff --git a/src/mongo/client/distlock.cpp b/src/mongo/client/distlock.cpp index 0e38a64f953..a2f56e564bf 100644 --- a/src/mongo/client/distlock.cpp +++ b/src/mongo/client/distlock.cpp @@ -131,19 +131,32 @@ namespace mongo { continue; } - // remove really old entries from the lockpings collection if they're not holding a lock - // (this may happen if an instance of a process was taken down and no new instance came up to - // replace it for a quite a while) - // if the lock is taken, the take-over mechanism should handle the situation - auto_ptr<DBClientCursor> c = conn->query( LocksType::ConfigNS , BSONObj() ); - // TODO: Would be good to make clear whether query throws or returns empty on errors - uassert( 16060, str::stream() << "cannot query locks collection on config server " << conn.getHost(), c.get() ); + // Remove really old entries from the lockpings collection if they're not + // holding a lock. This may happen if an instance of a process was taken down + // and no new instance came up to replace it for a quite a while. + // NOTE this is NOT the same as the standard take-over mechanism, which forces + // the lock entry. + BSONObj fieldsToReturn = BSON( LocksType::state() << 1 << + LocksType::process() << 1 ); + auto_ptr<DBClientCursor> activeLocks = + conn->query( LocksType::ConfigNS, + BSON( LocksType::state() << GT << 0 ) ); + + uassert( 16060, + str::stream() << "cannot query locks collection on config server " + << conn.getHost(), + activeLocks.get() ); set<string> pids; - while ( c->more() ) { - BSONObj lock = c->next(); - if ( ! lock[LocksType::process()].eoo() ) { - pids.insert( lock[LocksType::process()].valuestrsafe() ); + while ( activeLocks->more() ) { + BSONObj lock = activeLocks->nextSafe(); + + if ( !lock[LocksType::process()].eoo() ) { + pids.insert( lock[LocksType::process()].str() ); + } + else { + warning() << "found incorrect lock document during lock ping cleanup: " + << lock.toString() << endl; } } diff --git a/src/mongo/client/distlock.h b/src/mongo/client/distlock.h index 183826afcce..774d94a0df8 100644 --- a/src/mongo/client/distlock.h +++ b/src/mongo/client/distlock.h @@ -57,12 +57,19 @@ namespace mongo { }; /** - * The distributed lock is a configdb backed way of synchronizing system-wide tasks. A task must be identified by a - * unique name across the system (e.g., "balancer"). A lock is taken by writing a document in the configdb's locks - * collection with that name. + * The distributed lock is a configdb backed way of synchronizing system-wide tasks. A task + * must be identified by a unique name across the system (e.g., "balancer"). A lock is taken + * by writing a document in the configdb's locks collection with that name. * - * To be maintained, each taken lock needs to be revalidated ("pinged") within a pre-established amount of time. This - * class does this maintenance automatically once a DistributedLock object was constructed. + * To be maintained, each taken lock needs to be revalidated ("pinged") within a + * pre-established amount of time. This class does this maintenance automatically once a + * DistributedLock object was constructed. The ping procedure records the local time to + * the ping document, but that time is untrusted and is only used as a point of reference + * of whether the ping was refreshed or not. Ultimately, the clock a configdb is the source + * of truth when determining whether a ping is still fresh or not. This is achieved by + * (1) remembering the ping document time along with config server time when unable to + * take a lock, and (2) ensuring all config servers report similar times and have similar + * time rates (the difference in times must start and stay small). */ class DistributedLock { public: @@ -147,9 +154,13 @@ namespace mongo { const ConnectionString& getRemoteConnection(); /** - * Check the skew between a cluster of servers + * Checks the skew among a cluster of servers and returns true if the min and max clock + * times among the servers are within maxClockSkew. */ - static bool checkSkew( const ConnectionString& cluster, unsigned skewChecks = NUM_LOCK_SKEW_CHECKS, unsigned long long maxClockSkew = MAX_LOCK_CLOCK_SKEW, unsigned long long maxNetSkew = MAX_LOCK_NET_SKEW ); + static bool checkSkew( const ConnectionString& cluster, + unsigned skewChecks = NUM_LOCK_SKEW_CHECKS, + unsigned long long maxClockSkew = MAX_LOCK_CLOCK_SKEW, + unsigned long long maxNetSkew = MAX_LOCK_NET_SKEW ); /** * Get the remote time from a server or cluster diff --git a/src/mongo/client/gridfs.cpp b/src/mongo/client/gridfs.cpp index e2d1038d6ee..6d58ec690c2 100644 --- a/src/mongo/client/gridfs.cpp +++ b/src/mongo/client/gridfs.cpp @@ -37,7 +37,7 @@ namespace mongo { - const unsigned DEFAULT_CHUNK_SIZE = 256 * 1024; + const unsigned DEFAULT_CHUNK_SIZE = 255 * 1024; GridFSChunk::GridFSChunk( BSONObj o ) { _data = o; diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index ec337c89885..046101a29bf 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -77,6 +77,7 @@ namespace mongo { extern int diagLogging; extern unsigned lenForNewNsFiles; extern int lockFile; + extern bool checkNsFilesOnLoad; extern string repairpath; static void setupSignalHandlers(); @@ -321,6 +322,8 @@ namespace mongo { Client::GodScope gs; LOG(1) << "enter repairDatabases (to check pdfile version #)" << endl; + checkNsFilesOnLoad = false; // we are mainly just checking the header - don't scan the whole .ns file for every db here. + Lock::GlobalWrite lk; vector< string > dbNames; getDatabaseNames( dbNames ); @@ -361,12 +364,12 @@ namespace mongo { } } else { - if (h->versionMinor == PDFILE_VERSION_MINOR_22_AND_OLDER) { - const string systemIndexes = cc().database()->name + ".system.indexes"; - shared_ptr<Cursor> cursor(theDataFileMgr.findAll(systemIndexes)); - for ( ; cursor && cursor->ok(); cursor->advance()) { - const BSONObj index = cursor->current(); - const BSONObj key = index.getObjectField("key"); + const string systemIndexes = cc().database()->name + ".system.indexes"; + shared_ptr<Cursor> cursor(theDataFileMgr.findAll(systemIndexes)); + for ( ; cursor && cursor->ok(); cursor->advance()) { + const BSONObj index = cursor->current(); + const BSONObj key = index.getObjectField("key"); + if (h->versionMinor == PDFILE_VERSION_MINOR_22_AND_OLDER) { const string plugin = IndexPlugin::findPluginName(key); if (IndexPlugin::existedBefore24(plugin)) continue; @@ -377,6 +380,21 @@ namespace mongo { << "http://dochub.mongodb.org/core/upgrade-2.4" << startupWarningsLog; } + else { + verify(h->versionMinor == PDFILE_VERSION_MINOR_24_AND_NEWER); + try { + IndexSpec(key, index, IndexSpec::RulesFor24); + } + catch (const DBException& e) { + error() << "Encountered an unrecognized index spec: " << index << endl; + error() << "Reason this index spec could not be loaded: \"" << e.what() + << "\"" << endl; + error() << "The index cannot be used with this version of MongoDB; " + << "exiting..." << endl; + cc().shutdown(); + dbexit(EXIT_UNCAUGHT); + } + } } Database::closeDatabase( dbName.c_str(), dbpath ); } @@ -389,6 +407,8 @@ namespace mongo { cc().shutdown(); dbexit( EXIT_CLEAN ); } + + checkNsFilesOnLoad = true; } void clearTmpFiles() { @@ -528,39 +548,47 @@ namespace mongo { /// warn if readahead > 256KB (gridfs chunk size) static void checkReadAhead(const string& dir) { #ifdef __linux__ - const dev_t dev = getPartition(dir); - - // This path handles the case where the filesystem uses the whole device (including LVM) - string path = str::stream() << - "/sys/dev/block/" << major(dev) << ':' << minor(dev) << "/queue/read_ahead_kb"; - - if (!boost::filesystem::exists(path)){ - // This path handles the case where the filesystem is on a partition. - path = str::stream() - << "/sys/dev/block/" << major(dev) << ':' << minor(dev) // this is a symlink - << "/.." // parent directory of a partition is for the whole device - << "/queue/read_ahead_kb"; - } + try { + const dev_t dev = getPartition(dir); + + // This path handles the case where the filesystem uses the whole device (including LVM) + string path = str::stream() << + "/sys/dev/block/" << major(dev) << ':' << minor(dev) << "/queue/read_ahead_kb"; + + if (!boost::filesystem::exists(path)){ + // This path handles the case where the filesystem is on a partition. + path = str::stream() + << "/sys/dev/block/" << major(dev) << ':' << minor(dev) // this is a symlink + << "/.." // parent directory of a partition is for the whole device + << "/queue/read_ahead_kb"; + } - if (boost::filesystem::exists(path)) { - ifstream file (path.c_str()); - if (file.is_open()) { - int kb; - file >> kb; - if (kb > 256) { - log() << startupWarningsLog; + if (boost::filesystem::exists(path)) { + ifstream file (path.c_str()); + if (file.is_open()) { + int kb; + file >> kb; + if (kb > 256) { + log() << startupWarningsLog; - log() << "** WARNING: Readahead for " << dir << " is set to " << kb << "KB" + log() << "** WARNING: Readahead for " << dir << " is set to " << kb << "KB" << startupWarningsLog; - log() << "** We suggest setting it to 256KB (512 sectors) or less" + log() << "** We suggest setting it to 256KB (512 sectors) or less" << startupWarningsLog; - log() << "** http://dochub.mongodb.org/core/readahead" + log() << "** http://dochub.mongodb.org/core/readahead" << startupWarningsLog; + } } } } + catch (const std::exception& e) { + log() << "unable to validate readahead settings due to error: " << e.what() + << startupWarningsLog; + log() << "for more information, see http://dochub.mongodb.org/core/readahead" + << startupWarningsLog; + } #endif // __linux__ } @@ -1415,6 +1443,7 @@ namespace mongo { sigaddset( &asyncSignals, SIGINT ); sigaddset( &asyncSignals, SIGTERM ); sigaddset( &asyncSignals, SIGUSR1 ); + sigaddset( &asyncSignals, SIGXCPU ); set_terminate( myterminate ); set_new_handler( my_new_handler ); diff --git a/src/mongo/db/geo/s2index.cpp b/src/mongo/db/geo/s2index.cpp index d52f0ad2991..412d425f2f8 100644 --- a/src/mongo/db/geo/s2index.cpp +++ b/src/mongo/db/geo/s2index.cpp @@ -365,6 +365,11 @@ namespace mongo { uassert(16688, "finestIndexedLevel must be <= 30", params.finestIndexedLevel <= 30); uassert(16689, "finestIndexedLevel must be >= coarsestIndexedLevel", params.finestIndexedLevel >= params.coarsestIndexedLevel); + massert(17289, + str::stream() << "unsupported geo index version { " + << spec->info["2dsphereIndexVersion"] + << " }, only support versions: [1]", + configValueWithDefault(spec, "2dsphereIndexVersion", 1) == 1); // Categorize the fields we're indexing and make sure we have a geo field. int geoFields = 0; @@ -388,6 +393,15 @@ namespace mongo { return new S2IndexType(SPHERE_2D_NAME, this, spec, params); } + virtual BSONObj adjustIndexSpec( const BSONObj& spec ) const { + BSONElement indexVersionElt = spec["2dsphereIndexVersion"]; + uassert(17290, + str::stream() << "unsupported geo index version { " << indexVersionElt + << " }, only support versions: [1]", + indexVersionElt.eoo() || indexVersionElt.numberInt() == 1); + return spec; + } + int configValueWithDefault(const IndexSpec* spec, const string& name, int def) const { BSONElement e = spec->info[name]; if (e.isNumber()) { return e.numberInt(); } diff --git a/src/mongo/db/index.cpp b/src/mongo/db/index.cpp index f7346978313..e4366977081 100644 --- a/src/mongo/db/index.cpp +++ b/src/mongo/db/index.cpp @@ -324,6 +324,8 @@ namespace mongo { getDur().writingInt(dfh->versionMinor) = PDFILE_VERSION_MINOR_24_AND_NEWER; } + extern BSONObj id_obj; // { _id : 1 } + bool prepareToBuildIndex(const BSONObj& io, bool mayInterrupt, bool god, @@ -334,9 +336,11 @@ namespace mongo { // the collection for which we are building an index sourceNS = io.getStringField("ns"); + NamespaceString nss(sourceNS); uassert(10096, "invalid ns to index", sourceNS.find( '.' ) != string::npos); - massert(10097, str::stream() << "bad table to index name on add index attempt current db: " << cc().database()->name << " source: " << sourceNS , - cc().database()->name == nsToDatabase(sourceNS)); + uassert(17072, "cannot create indexes on the system.indexes collection", + !nss.isSystemDotIndexes()); + massert(10097, str::stream() << "bad table to index name on add index attempt current db: " << cc().database()->name << " source: " << sourceNS , cc().database()->name == nsToDatabase(sourceNS)); // logical name of the index. todo: get rid of the name, we don't need it! const char *name = io.getStringField("name"); @@ -393,10 +397,10 @@ namespace mongo { all be treated as the same pattern. */ if ( IndexDetails::isIdIndexPattern(key) ) { - if( !god ) { - ensureHaveIdIndex( sourceNS.c_str(), mayInterrupt ); - return false; - } + //if( !god ) { + //ensureHaveIdIndex( sourceNS.c_str(), mayInterrupt ); + //return false; + //} } else { /* is buildIndexes:false set for this replica set member? @@ -435,7 +439,14 @@ namespace mongo { } // idea is to put things we use a lot earlier b.append("v", v); - b.append(o["key"]); + if ( IndexDetails::isIdIndexPattern(o["key"].Obj()) ) { + b.append("name", "_id_"); + b.append("key", id_obj); + } + else { + b.append( o["name"] ); + b.append(o["key"]); + } if( o["unique"].trueValue() ) b.appendBool("unique", true); // normalize to bool true in case was int 1 or something... b.append(o["ns"]); @@ -446,7 +457,7 @@ namespace mongo { while ( i.more() ) { BSONElement e = i.next(); string s = e.fieldName(); - if( s != "_id" && s != "v" && s != "ns" && s != "unique" && s != "key" ) + if( s != "_id" && s != "v" && s != "ns" && s != "unique" && s != "key" && s != "name" ) b.append(e); } } diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 926cdeecdb6..b95bcb1bfea 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -792,16 +792,19 @@ namespace mongo { } } - theDataFileMgr.insertWithObjMod(ns, - // May be modified in the call to add an _id field. - js, - // Only permit interrupting an (index build) insert if the - // insert comes from a socket client request rather than a - // parent operation using the client interface. The parent - // operation might not support interrupts. - cc().curop()->parent() == NULL, - false); - logOp("i", ns, js); + DiskLoc dl = theDataFileMgr. + insertWithObjMod(ns, + // May be modified in the call to add an _id field. + js, + // Only permit interrupting an (index build) insert if the + // insert comes from a socket client request rather than a + // parent operation using the client interface. The parent + // operation might not support interrupts. + cc().curop()->parent() == NULL, + false); + if (!dl.isNull()) { + logOp("i", ns, js); + } } NOINLINE_DECL void insertMulti(bool keepGoing, const char *ns, vector<BSONObj>& objs, CurOp& op) { diff --git a/src/mongo/db/namespace_details.cpp b/src/mongo/db/namespace_details.cpp index 0fc7bdf5eb5..382522bb50a 100644 --- a/src/mongo/db/namespace_details.cpp +++ b/src/mongo/db/namespace_details.cpp @@ -122,6 +122,29 @@ namespace mongo { } #endif + void NamespaceDetails::onLoad(const Namespace& k) { + + if( k.isExtra() ) { + /* overflow storage for indexes - so don't treat as a NamespaceDetails object. */ + return; + } + + if( indexBuildsInProgress ) { + verify( Lock::isW() ); // TODO(erh) should this be per db? + if( indexBuildsInProgress ) { + log() << "indexBuildsInProgress was " << indexBuildsInProgress << " for " << k + << ", indicating an abnormal db shutdown" << endl; + getDur().writingInt( indexBuildsInProgress ) = 0; + } + } + } + + static void namespaceOnLoadCallback(const Namespace& k, NamespaceDetails& v) { + v.onLoad(k); + } + + bool checkNsFilesOnLoad = true; + NOINLINE_DECL void NamespaceIndex::_init() { verify( !ht ); @@ -174,6 +197,9 @@ namespace mongo { verify( len <= 0x7fffffff ); ht = new HashTable<Namespace,NamespaceDetails>(p, (int) len, "namespace index"); + if( checkNsFilesOnLoad ) + ht->iterAll(namespaceOnLoadCallback); + } static void namespaceGetNamespacesCallback( const Namespace& k , NamespaceDetails& v , void * extra ) { diff --git a/src/mongo/db/namespace_details.h b/src/mongo/db/namespace_details.h index 0e7e324da67..3f381605250 100644 --- a/src/mongo/db/namespace_details.h +++ b/src/mongo/db/namespace_details.h @@ -405,6 +405,7 @@ namespace mongo { /** Make all linked Extra objects writeable as well */ NamespaceDetails *writingWithExtra(); + void onLoad( const Namespace& k ); private: DiskLoc _alloc(const char *ns, int len); void maybeComplain( const char *ns, int len ) const; diff --git a/src/mongo/db/namespacestring.h b/src/mongo/db/namespacestring.h index d108bbaac72..96d78230b39 100644 --- a/src/mongo/db/namespacestring.h +++ b/src/mongo/db/namespacestring.h @@ -46,6 +46,7 @@ namespace mongo { bool isSystem() const { return strncmp(coll.c_str(), "system.", 7) == 0; } bool isCommand() const { return coll == "$cmd"; } + bool isSystemDotIndexes() const { return strncmp(coll.c_str(), "system.indexes", 14) == 0; } /** * @return true if the namespace is valid. Special namespaces for internal use are considered as valid. diff --git a/src/mongo/db/oplog.cpp b/src/mongo/db/oplog.cpp index b88ad66ac03..33990367d92 100644 --- a/src/mongo/db/oplog.cpp +++ b/src/mongo/db/oplog.cpp @@ -95,7 +95,15 @@ namespace mongo { */ if( theReplSet ) { if( !(theReplSet->lastOpTimeWritten<ts) ) { - log() << "replSet error possible failover clock skew issue? " << theReplSet->lastOpTimeWritten.toString() << ' ' << endl; + log() << "replication oplog stream went back in time. previous timestamp: " + << theReplSet->lastOpTimeWritten << " newest timestamp: " << ts + << ". attempting to sync directly from primary." << endl; + std::string errmsg; + BSONObjBuilder result; + if (!theReplSet->forceSyncFrom(theReplSet->box.getPrimary()->fullName(), + errmsg, result)) { + log() << "Can't sync from primary: " << errmsg << endl; + } } theReplSet->lastOpTimeWritten = ts; theReplSet->lastH = h; @@ -222,8 +230,15 @@ namespace mongo { */ if( theReplSet ) { if( !(theReplSet->lastOpTimeWritten<ts) ) { - log() << "replSet ERROR possible failover clock skew issue? " << theReplSet->lastOpTimeWritten << ' ' << ts << rsLog; - log() << "replSet " << theReplSet->isPrimary() << rsLog; + log() << "replication oplog stream went back in time. previous timestamp: " + << theReplSet->lastOpTimeWritten << " newest timestamp: " << ts + << ". attempting to sync directly from primary." << endl; + std::string errmsg; + BSONObjBuilder result; + if (!theReplSet->forceSyncFrom(theReplSet->box.getPrimary()->fullName(), + errmsg, result)) { + log() << "Can't sync from primary: " << errmsg << endl; + } } theReplSet->lastOpTimeWritten = ts; theReplSet->lastH = hashNew; diff --git a/src/mongo/db/pdfile.cpp b/src/mongo/db/pdfile.cpp index 4085dfd2b3f..aa49b156a28 100644 --- a/src/mongo/db/pdfile.cpp +++ b/src/mongo/db/pdfile.cpp @@ -1316,8 +1316,10 @@ namespace mongo { void DataFileMgr::insertAndLog( const char *ns, const BSONObj &o, bool god, bool fromMigrate ) { BSONObj tmp = o; - insertWithObjMod( ns, tmp, false, god ); - logOp( "i", ns, tmp, 0, 0, fromMigrate ); + DiskLoc loc = insertWithObjMod( ns, tmp, false, god ); + if (!loc.isNull()) { + logOp( "i", ns, tmp, 0, 0, fromMigrate ); + } } /** @param o the object to insert. can be modified to add _id and thus be an in/out param @@ -1475,16 +1477,20 @@ namespace mongo { } try { - IndexDetails& idx = tableToIndex->getNextIndexDetails(tabletoidxns.c_str()); - // It's important that this is outside the inner try/catch so that we never try to call - // kill_idx on a half-formed disk loc (if this asserts). - getDur().writingDiskLoc(idx.info) = loc; + { + IndexDetails& idx = tableToIndex->getNextIndexDetails(tabletoidxns.c_str()); + // It's important that this is outside the inner try/catch so that we never try to call + // kill_idx on a half-formed disk loc (if this asserts). + getDur().writingDiskLoc(idx.info) = loc; + } try { + IndexDetails& idx = tableToIndex->getNextIndexDetails(tabletoidxns.c_str()); getDur().writingInt(tableToIndex->indexBuildsInProgress) += 1; buildAnIndex(tabletoidxns, tableToIndex, idx, background, mayInterrupt); } catch (DBException& e) { + log() << "error building index: " << e << endl; // save our error msg string as an exception or dropIndexes will overwrite our message LastError *le = lastError.get(); int savecode = 0; @@ -1499,7 +1505,10 @@ namespace mongo { } // Recalculate the index # so we can remove it from the list in the next catch + idxNo = IndexBuildsInProgress::get(tabletoidxns.c_str(), idxName); + IndexDetails& idx = tableToIndex->idx(idxNo); + // roll back this index idx.kill_idx(); @@ -1519,6 +1528,7 @@ namespace mongo { << tableToIndex->nIndexes << endl; // We cannot use idx here, as it may point to a different index entry if it was // flipped during building + IndexDetails temp = tableToIndex->idx(idxNo); *getDur().writing(&tableToIndex->idx(idxNo)) = tableToIndex->idx(tableToIndex->nIndexes); @@ -1531,6 +1541,7 @@ namespace mongo { tableToIndex->setIndexIsMultikey(tabletoidxns.c_str(), tableToIndex->nIndexes, tempMultikey); + idxNo = tableToIndex->nIndexes; } @@ -1542,10 +1553,10 @@ namespace mongo { tableToIndex->addIndex(tabletoidxns.c_str()); getDur().writingInt(tableToIndex->indexBuildsInProgress) -= 1; - IndexType* indexType = idx.getSpec().getType(); + IndexType* indexType = tableToIndex->idx(idxNo).getSpec().getType(); const IndexPlugin *plugin = indexType ? indexType->getPlugin() : NULL; if (plugin) { - plugin->postBuildHook( idx.getSpec() ); + plugin->postBuildHook( tableToIndex->idx(idxNo).getSpec() ); } } @@ -1589,7 +1600,8 @@ namespace mongo { Lock::assertWriteLocked(ns); NamespaceDetails* nsd = nsdetails(ns); - for (int i=offset; i<nsd->getTotalIndexCount(); i++) { + // offset is 0-based, so we subtract one from the index count + for (int i = offset; i < (nsd->getTotalIndexCount() - 1); i++) { if (i < NamespaceDetails::NIndexesMax-1) { *getDur().writing(&nsd->idx(i)) = nsd->idx(i+1); nsd->setIndexIsMultikey(ns, i, nsd->isMultikey(i+1)); diff --git a/src/mongo/db/pipeline/value.cpp b/src/mongo/db/pipeline/value.cpp index 207dc4e37b8..6045207c764 100644 --- a/src/mongo/db/pipeline/value.cpp +++ b/src/mongo/db/pipeline/value.cpp @@ -513,19 +513,15 @@ namespace mongo { } string Value::coerceToString() const { - stringstream ss; switch(getType()) { case NumberDouble: - ss << _storage.doubleValue; - return ss.str(); + return str::stream() << _storage.doubleValue; case NumberInt: - ss << _storage.intValue; - return ss.str(); + return str::stream() << _storage.intValue; case NumberLong: - ss << _storage.longValue; - return ss.str(); + return str::stream() << _storage.longValue; case Code: case Symbol: @@ -533,8 +529,7 @@ namespace mongo { return getStringData().toString(); case Timestamp: - ss << getTimestamp().toStringPretty(); - return ss.str(); + return getTimestamp().toStringPretty(); case Date: return tmToISODateString(coerceToTm()); diff --git a/src/mongo/db/repl/consensus.cpp b/src/mongo/db/repl/consensus.cpp index dcb31408c11..a2459477432 100644 --- a/src/mongo/db/repl/consensus.cpp +++ b/src/mongo/db/repl/consensus.cpp @@ -253,7 +253,6 @@ namespace mongo { try { vote = yea(whoid); dassert( hopeful->id() == whoid ); - rs.relinquish(); log() << "replSet info voting yea for " << hopeful->fullName() << " (" << whoid << ')' << rsLog; } catch(VoteException&) { diff --git a/src/mongo/db/repl/manager.cpp b/src/mongo/db/repl/manager.cpp index cbc3a3e7baa..4e9708a1d19 100644 --- a/src/mongo/db/repl/manager.cpp +++ b/src/mongo/db/repl/manager.cpp @@ -80,11 +80,7 @@ namespace mongo { } if (rs->box.getState().primary()) { - // make sure exactly one primary steps down - if (rs->selfId() < m->id()) { - return; - } - + log() << "stepping down; another primary seen in replicaset"; rs->relinquish(); } diff --git a/src/mongo/db/repl/rs_sync.cpp b/src/mongo/db/repl/rs_sync.cpp index e6e31943a9f..f904d86c5ad 100644 --- a/src/mongo/db/repl/rs_sync.cpp +++ b/src/mongo/db/repl/rs_sync.cpp @@ -585,13 +585,6 @@ namespace replset { bool golive = false; lock rsLock( this ); - Lock::GlobalWrite writeLock; - - // make sure we're not primary, secondary, rollback, or fatal already - if (box.getState().primary() || box.getState().secondary() || - box.getState().fatal()) { - return false; - } if (_maintenanceMode > 0) { // we're not actually going live @@ -603,6 +596,14 @@ namespace replset { return false; } + Lock::GlobalWrite writeLock; + + // make sure we're not primary, secondary, rollback, or fatal already + if (box.getState().primary() || box.getState().secondary() || + box.getState().fatal()) { + return false; + } + minvalid = getMinValid(); if( minvalid <= lastOpTimeWritten ) { golive=true; diff --git a/src/mongo/dbtests/d_chunk_manager_tests.cpp b/src/mongo/dbtests/d_chunk_manager_tests.cpp index e50961d3ee7..be7639f5794 100644 --- a/src/mongo/dbtests/d_chunk_manager_tests.cpp +++ b/src/mongo/dbtests/d_chunk_manager_tests.cpp @@ -362,6 +362,20 @@ namespace { ASSERT( cloned->belongsToMe( split1 ) ); ASSERT( cloned->belongsToMe( split2 ) ); ASSERT( ! cloned->belongsToMe( max ) ); + + ASSERT_FALSE( cloned->getNextChunk( BSON( "a" << MinKey << "b" << 0 ), &min, &max )); + ASSERT_EQUALS( BSON( "a" << 10 << "b" << 0 ), min ); + ASSERT_EQUALS( BSON( "a" << 15 << "b" << 0 ), max ); + + ASSERT_FALSE( cloned->getNextChunk( BSON( "a" << 10 << "b" << 0 ), &min, &max )); + ASSERT_EQUALS( BSON( "a" << 15 << "b" << 0 ), min ); + ASSERT_EQUALS( BSON( "a" << 18 << "b" << 0 ), max ); + + ASSERT_FALSE( cloned->getNextChunk( BSON( "a" << 15 << "b" << 0 ), &min, &max )); + ASSERT_EQUALS( BSON( "a" << 18 << "b" << 0 ), min ); + ASSERT_EQUALS( BSON( "a" << 20 << "b" << 0 ), max ); + + ASSERT( cloned->getNextChunk( BSON( "a" << 18 << "b" << 0 ), &min, &max )); } }; diff --git a/src/mongo/s/balance.cpp b/src/mongo/s/balance.cpp index 2cf9d06d131..7e12e1c47b8 100644 --- a/src/mongo/s/balance.cpp +++ b/src/mongo/s/balance.cpp @@ -467,6 +467,7 @@ namespace mongo { conn.done(); warning() << "Skipping balancing round because data inconsistency" << " was detected amongst the config servers." << endl; + sleepsecs( sleepTime ); continue; } diff --git a/src/mongo/s/commands_admin.cpp b/src/mongo/s/commands_admin.cpp index 91577d33b97..d7061f6fa86 100644 --- a/src/mongo/s/commands_admin.cpp +++ b/src/mongo/s/commands_admin.cpp @@ -663,7 +663,7 @@ namespace mongo { result << "collectionsharded" << ns; // only initially move chunks when using a hashed shard key - if (isHashedShardKey) { + if (isHashedShardKey && isEmpty) { // Reload the new config info. If we created more than one initial chunk, then // we need to move them around to balance. diff --git a/src/mongo/s/config.cpp b/src/mongo/s/config.cpp index b8698a10687..9e042938607 100644 --- a/src/mongo/s/config.cpp +++ b/src/mongo/s/config.cpp @@ -34,6 +34,8 @@ #include "mongo/s/type_chunk.h" #include "mongo/s/type_collection.h" #include "mongo/s/type_database.h" +#include "mongo/s/type_locks.h" +#include "mongo/s/type_lockpings.h" #include "mongo/s/type_settings.h" #include "mongo/s/type_shard.h" #include "mongo/util/net/message.h" @@ -985,6 +987,16 @@ namespace mongo { conn->get()->ensureIndex(ShardType::ConfigNS, BSON(ShardType::host() << 1), true); + conn->get()->ensureIndex(LocksType::ConfigNS, + BSON( LocksType::lockID() << 1 ), true); + + conn->get()->ensureIndex(LockpingsType::ConfigNS, + BSON( LockpingsType::ping() << 1 ), false); + + conn->get()->ensureIndex(LocksType::ConfigNS, + BSON( LocksType::state() << 1 << + LocksType::process() << 1 ), false); + conn->done(); } catch ( DBException& e ) { diff --git a/src/mongo/s/d_chunk_manager.cpp b/src/mongo/s/d_chunk_manager.cpp index 4eb360702bc..98a6d90d341 100644 --- a/src/mongo/s/d_chunk_manager.cpp +++ b/src/mongo/s/d_chunk_manager.cpp @@ -426,7 +426,7 @@ namespace mongo { BSONObj startKey = min; for ( vector<BSONObj>::const_iterator it = splitKeys.begin() ; it != splitKeys.end() ; ++it ) { BSONObj split = *it; - p->_chunksMap[min] = split.getOwned(); + p->_chunksMap[startKey] = split.getOwned(); p->_chunksMap.insert( make_pair( split.getOwned() , max.getOwned() ) ); p->_version.incMinor(); startKey = split; diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp index e6aa728d7a3..5bcfe291519 100644 --- a/src/mongo/s/server.cpp +++ b/src/mongo/s/server.cpp @@ -197,6 +197,9 @@ namespace mongo { signal(SIGTERM, sighandler); signal(SIGINT, sighandler); +#if defined(SIGXCPU) + signal(SIGXCPU, sighandler); +#endif #if defined(SIGQUIT) signal( SIGQUIT , printStackAndExit ); diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js index a9c8c36b050..6b84da39a06 100644 --- a/src/mongo/shell/replsettest.js +++ b/src/mongo/shell/replsettest.js @@ -489,12 +489,13 @@ ReplSetTest.prototype.initiate = function( cfg , initCmd , timeout ) { } } -ReplSetTest.prototype.reInitiate = function() { +ReplSetTest.prototype.reInitiate = function(timeout) { var master = this.nodes[0]; var c = master.getDB("local")['system.replset'].findOne(); var config = this.getReplSetConfig(); + var timeout = timeout || 60000; config.version = c.version + 1; - this.initiate( config , 'replSetReconfig' ); + this.initiate( config , 'replSetReconfig', timeout ); } ReplSetTest.prototype.getLastOpTimeWritten = function() { diff --git a/src/mongo/shell/shell_utils_extended.cpp b/src/mongo/shell/shell_utils_extended.cpp index 1e68882a3bc..2808bab7688 100644 --- a/src/mongo/shell/shell_utils_extended.cpp +++ b/src/mongo/shell/shell_utils_extended.cpp @@ -26,6 +26,7 @@ #include "mongo/util/file.h" #include "mongo/util/md5.hpp" #include "mongo/util/net/sock.h" +#include "mongo/util/scopeguard.h" #include "mongo/util/text.h" namespace mongo { @@ -144,6 +145,7 @@ namespace mongo { stringstream ss; FILE* f = fopen(e.valuestrsafe(), "rb"); uassert(CANT_OPEN_FILE, "couldn't open file", f ); + ON_BLOCK_EXIT(fclose, f); md5digest d; md5_state_t st; diff --git a/src/mongo/util/file_allocator.cpp b/src/mongo/util/file_allocator.cpp index e59bce6934b..7876744f7d5 100644 --- a/src/mongo/util/file_allocator.cpp +++ b/src/mongo/util/file_allocator.cpp @@ -39,6 +39,7 @@ #include "mongo/platform/posix_fadvise.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/paths.h" +#include "mongo/util/processinfo.h" #include "mongo/util/time_support.h" #include "mongo/util/timer.h" @@ -186,6 +187,15 @@ namespace mongo { size - 1 == lseek(fd, size - 1, SEEK_SET) ); uassert( 10442 , str::stream() << "Unable to allocate new file of size " << size << ' ' << errnoWithDescription(), 1 == write(fd, "", 1) ); + + // File expansion is completed here. Do not do the zeroing out on OS-es where there + // is no risk of triggering allocation-related bugs such as + // http://support.microsoft.com/kb/2731284. + // + if (!ProcessInfo::isDataFileZeroingNeeded()) { + return; + } + lseek(fd, 0, SEEK_SET); const long z = 256 * 1024; diff --git a/src/mongo/util/processinfo.h b/src/mongo/util/processinfo.h index 8e9044d39e4..03fcdd85993 100644 --- a/src/mongo/util/processinfo.h +++ b/src/mongo/util/processinfo.h @@ -92,6 +92,11 @@ namespace mongo { bool hasNumaEnabled() const { return sysInfo().hasNuma; } /** + * Determine if file zeroing is necessary for newly allocated data files. + */ + static bool isDataFileZeroingNeeded() { return systemInfo->fileZeroNeeded; } + + /** * Get extra system stats */ void appendSystemDetails( BSONObjBuilder& details ) const { @@ -145,12 +150,19 @@ namespace mongo { string cpuArch; bool hasNuma; BSONObj _extraStats; + + // This is an OS specific value, which determines whether files should be zero-filled + // at allocation time in order to avoid Microsoft KB 2731284. + // + bool fileZeroNeeded; + SystemInfo() : addrSize( 0 ), memSize( 0 ), numCores( 0 ), pageSize( 0 ), - hasNuma( false ) { + hasNuma( false ), + fileZeroNeeded (false) { // populate SystemInfo during construction collectSystemInfo(); } diff --git a/src/mongo/util/processinfo_win32.cpp b/src/mongo/util/processinfo_win32.cpp index 3f42eb12698..d6f88e88a59 100644 --- a/src/mongo/util/processinfo_win32.cpp +++ b/src/mongo/util/processinfo_win32.cpp @@ -100,7 +100,7 @@ namespace mongo { void ProcessInfo::SystemInfo::collectSystemInfo() { BSONObjBuilder bExtra; stringstream verstr; - OSVERSIONINFOEX osvi; // os version + OSVERSIONINFOEX osvi; // os version MEMORYSTATUSEX mse; // memory stats SYSTEM_INFO ntsysinfo; //system stats @@ -142,6 +142,15 @@ namespace mongo { osName += "Windows 7"; else osName += "Windows Server 2008 R2"; + + // Windows 6.1 is either Windows 7 or Windows 2008 R2. There is no SP2 for + // either of these two operating systems, but the check will hold if one + // were released. This code assumes that SP2 will include fix for + // http://support.microsoft.com/kb/2731284. + // + if ((osvi.wServicePackMajor >= 0) && (osvi.wServicePackMajor < 2)) { + fileZeroNeeded = true; + } break; case 0: if ( osvi.wProductType == VER_NT_WORKSTATION ) diff --git a/src/mongo/util/version.cpp b/src/mongo/util/version.cpp index a5622e4dbbb..e27c3843a4a 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.9"; + const char versionString[] = "2.4.10"; // See unit test for example outputs BSONArray toVersionArray(const char* version){ diff --git a/src/third_party/v8/src/spaces-inl.h b/src/third_party/v8/src/spaces-inl.h index ed78fc7a15f..d84019084cc 100644 --- a/src/third_party/v8/src/spaces-inl.h +++ b/src/third_party/v8/src/spaces-inl.h @@ -164,7 +164,7 @@ Page* Page::Initialize(Heap* heap, Executability executable, PagedSpace* owner) { Page* page = reinterpret_cast<Page*>(chunk); - ASSERT(chunk->size() <= static_cast<size_t>(kPageSize)); + ASSERT(page->area_size() <= kNonCodeObjectAreaSize); ASSERT(chunk->owner() == owner); owner->IncreaseCapacity(page->area_size()); owner->Free(page->area_start(), page->area_size()); |
