From 0cceba6f04b95f3652de84c2f1f4ab2a644dba6e Mon Sep 17 00:00:00 2001 From: Vesselina Ratcheva Date: Wed, 27 Oct 2021 21:34:16 +0000 Subject: SERVER-54909 Report last durable and last applied operation wall times for all members in replSetGetStatus --- etc/backports_required_for_multiversion_tests.yml | 4 ++ .../replsets/replSetGetStatus_member_wall_times.js | 84 ++++++++++++++++++++++ src/mongo/db/repl/topology_coordinator.cpp | 5 ++ 3 files changed, 93 insertions(+) create mode 100644 jstests/replsets/replSetGetStatus_member_wall_times.js diff --git a/etc/backports_required_for_multiversion_tests.yml b/etc/backports_required_for_multiversion_tests.yml index c4bea5b638b..3fdbbcf2692 100644 --- a/etc/backports_required_for_multiversion_tests.yml +++ b/etc/backports_required_for_multiversion_tests.yml @@ -106,6 +106,8 @@ last-continuous: test_file: jstests/core/sbe/sbe_cmd.js - ticket: SERVER-56127 test_file: jstests/sharding/retryable_writes_nested_shard_key.js + - ticket: SERVER-54909 + test_file: jstests/replsets/replSetGetStatus_member_wall_times.js # Tests that should only be excluded from particular suites should be listed under that suite. suites: @@ -372,6 +374,8 @@ last-lts: test_file: jstests/core/sbe/sbe_cmd.js - ticket: SERVER-56127 test_file: jstests/sharding/retryable_writes_nested_shard_key.js + - ticket: SERVER-54909 + test_file: jstests/replsets/replSetGetStatus_member_wall_times.js # Tests that should only be excluded from particular suites should be listed under that suite. suites: diff --git a/jstests/replsets/replSetGetStatus_member_wall_times.js b/jstests/replsets/replSetGetStatus_member_wall_times.js new file mode 100644 index 00000000000..4cd976a752b --- /dev/null +++ b/jstests/replsets/replSetGetStatus_member_wall_times.js @@ -0,0 +1,84 @@ +/** + * Tests that replSetGetStatus responses include the last applied and durable wall times for other + * members. + * + * @tags: [multiversion_incompatible] + */ + +(function() { +"use strict"; +load("jstests/libs/write_concern_util.js"); +load("jstests/replsets/rslib.js"); + +// We use GTE to account for the possibility of other writes in the system (e.g. HMAC). +// Comparison is GTE by default, GT if 'strict' is specified. +function checkWallTimes(primary, greaterMemberIndex, lesserMemberIndex, strict = false) { + let res = assert.commandWorked(primary.adminCommand({replSetGetStatus: 1})); + assert(res.members, () => tojson(res)); + + const greater = res.members[greaterMemberIndex]; + assert(greater, () => tojson(res)); + const greaterApplied = greater.lastAppliedWallTime; + const greaterDurable = greater.lastAppliedWallTime; + assert(greaterApplied, () => tojson(res)); + assert(greaterDurable, () => tojson(res)); + + const lesser = res.members[lesserMemberIndex]; + assert(lesser, () => tojson(res)); + const lesserApplied = lesser.lastAppliedWallTime; + const lesserDurable = lesser.lastDurableWallTime; + assert(lesser.lastAppliedWallTime, () => tojson(res)); + assert(lesser.lastDurableWallTime, () => tojson(res)); + + if (!strict) { + assert.gte(greaterApplied, lesserApplied, () => tojson(res)); + assert.gte(greaterDurable, lesserDurable, () => tojson(res)); + } else { + assert.gt(greaterApplied, lesserApplied, () => tojson(res)); + assert.gt(greaterDurable, lesserDurable, () => tojson(res)); + } +} + +const name = jsTestName(); +const rst = new ReplSetTest({name: name, nodes: 3, settings: {chainingAllowed: false}}); + +rst.startSet(); +rst.initiateWithHighElectionTimeout(); +rst.awaitReplication(); + +const primary = rst.getPrimary(); // node 0 +const [caughtUpSecondary, laggedSecondary] = rst.getSecondaries(); // nodes 1 and 2 + +const dbName = "testdb"; +const collName = "testcoll"; +const primaryDB = primary.getDB(dbName); +const primaryColl = primaryDB.getCollection(collName); + +jsTestLog("Creating test collection"); +assert.commandWorked(primaryColl.insert({"one": 1})); +rst.awaitReplication(); + +checkWallTimes(primary, 0 /* greater */, 1 /* lesser */); +checkWallTimes(primary, 0 /* greater */, 2 /* lesser */); + +jsTestLog("Stopping replication on secondary: " + laggedSecondary.host); +stopServerReplication(laggedSecondary); + +jsTestLog("Adding more documents to collection"); +assert.commandWorked(primaryColl.insert({"two": 2}, {writeConcern: {w: 1}})); +rst.awaitReplication( + undefined /* timeout */, undefined /* secondaryOpTimeType */, [caughtUpSecondary]); + +// Wall times of the lagged secondary should be strictly lesser. +checkWallTimes(primary, 0 /* greater */, 2 /* lesser */, true /* strict */); +checkWallTimes(primary, 1 /* greater */, 2 /* lesser */, true /* strict */); + +jsTestLog("Letting lagged secondary catch up"); +restartServerReplication(laggedSecondary); +rst.awaitReplication(); + +checkWallTimes(primary, 0 /* greater */, 1 /* lesser */); +checkWallTimes(primary, 0 /* greater */, 2 /* lesser */); + +rst.stopSet(); +})(); diff --git a/src/mongo/db/repl/topology_coordinator.cpp b/src/mongo/db/repl/topology_coordinator.cpp index a3df552f4df..68791c08a5d 100644 --- a/src/mongo/db/repl/topology_coordinator.cpp +++ b/src/mongo/db/repl/topology_coordinator.cpp @@ -1888,6 +1888,8 @@ void TopologyCoordinator::prepareStatusResponse(const ReplSetStatusArgs& rsStatu appendOpTime(&bb, "optime", lastOpApplied); bb.appendDate("optimeDate", Date_t::fromDurationSinceEpoch(Seconds(lastOpApplied.getSecs()))); + bb.appendDate("lastAppliedWallTime", it->getLastAppliedWallTime()); + bb.appendDate("lastDurableWallTime", it->getLastDurableWallTime()); } if (!_syncSource.empty() && !_iAmPrimary()) { @@ -1946,6 +1948,9 @@ void TopologyCoordinator::prepareStatusResponse(const ReplSetStatusArgs& rsStatu bb.appendDate("optimeDurableDate", Date_t::fromDurationSinceEpoch( Seconds(it->getHeartbeatDurableOpTime().getSecs()))); + + bb.appendDate("lastAppliedWallTime", it->getLastAppliedWallTime()); + bb.appendDate("lastDurableWallTime", it->getLastDurableWallTime()); } bb.appendDate("lastHeartbeat", it->getLastHeartbeat()); bb.appendDate("lastHeartbeatRecv", it->getLastHeartbeatRecv()); -- cgit v1.2.1