summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatt dannenberg <matt.dannenberg@10gen.com>2015-05-18 13:04:00 -0400
committermatt dannenberg <matt.dannenberg@10gen.com>2015-05-21 12:05:05 -0400
commit2d52cff7ee8fbff257698c334da85fa9115d35c0 (patch)
tree43b5fbdea3489eace0acc4e0a1794f05a51e05da
parent365f1d98a600472c1494e69ad0c2bf5f102df8da (diff)
downloadmongo-2d52cff7ee8fbff257698c334da85fa9115d35c0.tar.gz
SERVER-18511 report upstream progress when initial sync completes
-rw-r--r--jstests/replsets/initial_sync_report_progress.js42
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp5
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_heartbeat_test.cpp34
3 files changed, 73 insertions, 8 deletions
diff --git a/jstests/replsets/initial_sync_report_progress.js b/jstests/replsets/initial_sync_report_progress.js
new file mode 100644
index 00000000000..302f5ce4537
--- /dev/null
+++ b/jstests/replsets/initial_sync_report_progress.js
@@ -0,0 +1,42 @@
+// Ensure replication progress is sent upstream when initial sync completes
+load("jstests/replsets/rslib.js");
+(function() {
+ "use strict";
+ // start 2 node set
+ var name = "initialSyncReportProgress";
+ var ports = allocatePorts(3);
+ var hostname = getHostName();
+
+ var replSet = new ReplSetTest({name: name, nodes: 2});
+ replSet.startSet();
+
+ replSet.initiate({
+ _id: name,
+ members: [
+ {_id: 0, host: hostname + ":" + ports[0]},
+ {_id: 1, host: hostname + ":" + ports[1]},
+ ]});
+
+ var primary = replSet.getPrimary();
+ var secondary = replSet.getSecondary();
+
+ // do a single insert
+ assert.writeOK(primary.getDB(name).foo.insert({x: 13}));
+ var optime = primary.getDB(name).getLastErrorObj(1)["lastOp"];
+
+ // start a new node and add it to the replset
+ var secondary2 = startMongodTest(ports[2], name, false, {replSet: name, oplogSize: 25});
+ var config = replSet.getReplSetConfig();
+ config.version = 2;
+ config.members.push({_id: 2, host: hostname + ":" + ports[2]});
+ reconfig(replSet, config);
+ reconnect(secondary);
+ reconnect(secondary2);
+
+ // confirm that the primary becomes aware of the new node's progress
+ assert.commandWorked(primary.getDB(name).runCommand({getLastError: 1,
+ w: 3,
+ wOpTime: optime,
+ wTimeout: 30*1000}));
+ replSet.stopSet();
+})();
diff --git a/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp b/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
index f80d2a5c1a7..0aeba145a60 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_heartbeat.cpp
@@ -182,10 +182,7 @@ namespace {
invariant(targetIndex >= 0);
SlaveInfo& slaveInfo = _slaveInfo[targetIndex];
- if (optime > slaveInfo.opTime && slaveInfo.rid.isSet()) {
- // TODO(spencer): The second part of the above if-statement can be removed after 3.0
- // but for now, to maintain compatibility with 2.6, we can't record optimes for any
- // nodes we haven't heard from via replSetUpdatePosition yet to associate an RID.
+ if (optime > slaveInfo.opTime) {
_updateSlaveInfoOptime_inlock(&slaveInfo, optime);
}
}
diff --git a/src/mongo/db/repl/replication_coordinator_impl_heartbeat_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_heartbeat_test.cpp
index 9008dbb9854..76561b75005 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_heartbeat_test.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_heartbeat_test.cpp
@@ -85,8 +85,7 @@ namespace {
BSON("_id" << "mySet" <<
"version" << 3 <<
"members" << BSON_ARRAY(BSON("_id" << 1 << "host" << "h1:1") <<
- BSON("_id" << 2 << "host" << "h2:1") <<
- BSON("_id" << 3 << "host" << "h3:1"))));
+ BSON("_id" << 2 << "host" << "h2:1"))));
init("mySet");
addSelf(HostAndPort("h2", 1));
const Date_t startDate = getNet()->now();
@@ -132,8 +131,35 @@ namespace {
unittest::assertGet(getExternalState()->loadLocalConfigDocument(&txn))));
ASSERT_OK(storedConfig.validate());
ASSERT_EQUALS(3, storedConfig.getConfigVersion());
- ASSERT_EQUALS(3, storedConfig.getNumMembers());
- exitNetwork();
+ ASSERT_EQUALS(2, storedConfig.getNumMembers());
+
+ // confirm heartbeats update replication progress map
+ const ReplicationExecutor::RemoteCommandRequest& request2 = noi->getRequest();
+ ASSERT_EQUALS(HostAndPort("h1", 1), request2.target);
+ ReplSetHeartbeatArgs hbArgs2;
+ ASSERT_OK(hbArgs2.initialize(request2.cmdObj));
+
+ // process heartbeat response, updating optime
+ ReplSetHeartbeatResponse hbResp2;
+ hbResp2.setSetName("mySet");
+ hbResp2.setState(MemberState::RS_SECONDARY);
+ hbResp2.noteReplSet();
+ hbResp2.setVersion(rsConfig.getConfigVersion());
+ hbResp2.setOpTime(OpTime(100,0));
+ BSONObjBuilder responseBuilder2;
+ responseBuilder2 << "ok" << 1;
+ hbResp2.addToBSON(&responseBuilder2);
+ net->scheduleResponse(noi, startDate + 201, makeResponseStatus(responseBuilder2.obj()));
+ assertRunUntil(startDate + 201);
+
+ // confirm replication progress has been updated by preparing an update position command
+ BSONObjBuilder updatePositionBuilder;
+ getReplCoord()->prepareReplSetUpdatePositionCommand(&updatePositionBuilder);
+ BSONObj updatePositionCommand = updatePositionBuilder.obj();
+ log() << updatePositionCommand.toString();
+ ASSERT_EQ(OpTime(100,0),
+ updatePositionCommand["optimes"].Array()[0].Obj()["optime"]._opTime());
+ ASSERT_EQ(1, updatePositionCommand["optimes"].Array()[0].Obj()["memberId"].numberInt());
}
TEST_F(ReplCoordHBTest, DoNotJoinReplSetIfNotAMember) {