SERVER-119413: Change configTerm from int to long long in idl and cod… (#48912)
GitOrigin-RevId: e23c0c72eef88abeebf1567048e8d01a3b39f8ec
This commit is contained in:
parent
2b1ff713b8
commit
ad71b7376c
@ -524,6 +524,8 @@ last-continuous:
|
||||
ticket: SERVER-117009
|
||||
- test_file: jstests/noPassthrough/replication/killOp_against_repl_threads.js
|
||||
ticket: SERVER-112273
|
||||
- test_file: jstests/replsets/election_term_over_int_max.js
|
||||
ticket: SERVER-119413
|
||||
suites: null
|
||||
last-lts:
|
||||
all:
|
||||
@ -1105,4 +1107,6 @@ last-lts:
|
||||
ticket: SERVER-117009
|
||||
- test_file: jstests/noPassthrough/replication/killOp_against_repl_threads.js
|
||||
ticket: SERVER-112273
|
||||
- test_file: jstests/replsets/election_term_over_int_max.js
|
||||
ticket: SERVER-119413
|
||||
suites: null
|
||||
|
||||
85
jstests/replsets/election_term_over_int_max.js
Normal file
85
jstests/replsets/election_term_over_int_max.js
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Basic smoke test that a replica set can be stopped, one member restarted as standalone,
|
||||
* then the full replica set brought back up. While standalone, we manually corrupt the
|
||||
* election term document.
|
||||
*
|
||||
* @tags: [requires_persistence, requires_replication]
|
||||
*/
|
||||
|
||||
import {ReplSetTest} from "jstests/libs/replsettest.js";
|
||||
|
||||
const rst = new ReplSetTest({name: jsTestName(), nodes: 3});
|
||||
rst.startSet();
|
||||
rst.initiate();
|
||||
|
||||
let primary = rst.getPrimary();
|
||||
const dbName = jsTestName();
|
||||
const collName = "coll";
|
||||
|
||||
// Do a majority write so we have something in the oplog.
|
||||
assert.commandWorked(
|
||||
primary.getDB(dbName)[collName].insert({x: 1}, {writeConcern: {w: "majority"}}));
|
||||
|
||||
jsTest.log.info("Stopping the replica set with forRestart=true");
|
||||
rst.stopSet(/* signal */ null, /* forRestart */ true);
|
||||
|
||||
jsTest.log.info("Starting node 0 as a standalone");
|
||||
const node0 = rst.nodes[0];
|
||||
let standalone = MongoRunner.runMongod({
|
||||
dbpath: node0.dbpath,
|
||||
noReplSet: true,
|
||||
noCleanData: true,
|
||||
});
|
||||
assert.neq(null, standalone, "failed to start standalone mongod");
|
||||
|
||||
// Sanity check: data is visible in standalone.
|
||||
let standaloneDB = standalone.getDB(dbName);
|
||||
assert.eq(1,
|
||||
standaloneDB[collName].find().itcount(),
|
||||
"expected to see document written before stopping replset");
|
||||
|
||||
// Set the election term to > int max
|
||||
jsTest.log.info("Updating local.replset.election.term while standalone");
|
||||
const electionColl = standalone.getDB("local").getCollection("replset.election");
|
||||
const res = electionColl.update(
|
||||
{},
|
||||
{$set: {term: NumberLong("18014398509482012")}},
|
||||
/* upsert */ false,
|
||||
/* multi */ true,
|
||||
);
|
||||
assert.commandWorked(res);
|
||||
|
||||
jsTest.log.info("Stopping standalone");
|
||||
MongoRunner.stopMongod(standalone);
|
||||
|
||||
jsTest.log.info("Restarting full replica set");
|
||||
rst.startSet({restart: true, noCleanData: true});
|
||||
|
||||
// Expecting node0 to become primary.
|
||||
primary = rst.getPrimary();
|
||||
|
||||
// The term we set to + 1 should be the new term when the replset restarts.
|
||||
assert.eq(NumberLong("18014398509482013"),
|
||||
primary.getDB("local").getCollection("replset.election").findOne({}).term);
|
||||
|
||||
const secondaries = rst.getSecondaries();
|
||||
|
||||
// Do a w:3 write so we know all nodes are on the new term.
|
||||
assert.commandWorked(primary.getDB(dbName)[collName].insert({y: 1}, {writeConcern: {w: 3}}));
|
||||
|
||||
// Force an election: step up one of the secondaries and verify it wins.
|
||||
jsTest.log.info("Forcing an election via replSetStepUp");
|
||||
const oldPrimary = primary;
|
||||
const candidate = secondaries[0];
|
||||
|
||||
assert.commandWorked(candidate.adminCommand({replSetStepUp: 1}));
|
||||
|
||||
// Wait for the cluster to agree on the new primary.
|
||||
rst.awaitNodesAgreeOnPrimary();
|
||||
const newPrimary = rst.getPrimary();
|
||||
|
||||
jsTest.log.info("New primary after forced election: " + tojson(newPrimary.host));
|
||||
assert.neq(newPrimary.host, oldPrimary.host, "expected a different primary after stepUp");
|
||||
assert.eq(candidate, newPrimary, "different primary than expected after forced stepup");
|
||||
|
||||
rst.stopSet();
|
||||
@ -170,7 +170,7 @@ structs:
|
||||
created this configuration. Configurations in a replica set are
|
||||
totally ordered by their term and configuration version."
|
||||
default: -1
|
||||
validator: {gte: -1, lt: 2147483648}
|
||||
validator: {gte: -1, lte: 9223372036854775807}
|
||||
members:
|
||||
type: array<memberConfig>
|
||||
description:
|
||||
|
||||
@ -339,14 +339,26 @@ TEST(ReplSetConfig, ParseFailsWithBadOrMissingTermField) {
|
||||
<< BSON_ARRAY(BSON("_id" << 0 << "host"
|
||||
<< "localhost:12345")))),
|
||||
DBException);
|
||||
ASSERT_THROWS(ReplSetConfig::parse(
|
||||
BSON("_id" << "rs0"
|
||||
<< "version" << 1 << "term"
|
||||
<< static_cast<long long>(std::numeric_limits<int>::max()) + 1
|
||||
<< "protocolVersion" << 1 << "members"
|
||||
<< BSON_ARRAY(BSON("_id" << 0 << "host"
|
||||
<< "localhost:12345")))),
|
||||
DBException);
|
||||
config = ReplSetConfig::parse(
|
||||
BSON("_id" << "rs0"
|
||||
<< "version" << 1 << "term"
|
||||
<< static_cast<long long>(std::numeric_limits<int>::max()) + 1
|
||||
<< "protocolVersion" << 1 << "members"
|
||||
<< BSON_ARRAY(BSON("_id" << 0 << "host"
|
||||
<< "localhost:12345"))));
|
||||
|
||||
ASSERT_OK(config.validate());
|
||||
|
||||
// Verify we can parse up to long long
|
||||
config = ReplSetConfig::parse(
|
||||
BSON("_id" << "rs0"
|
||||
<< "version" << 1 << "term"
|
||||
<< static_cast<long long>(std::numeric_limits<long long>::max())
|
||||
<< "protocolVersion" << 1 << "members"
|
||||
<< BSON_ARRAY(BSON("_id" << 0 << "host"
|
||||
<< "localhost:12345"))));
|
||||
|
||||
ASSERT_OK(config.validate());
|
||||
}
|
||||
|
||||
TEST(ReplSetConfig, ParseFailsWithBadMembers) {
|
||||
|
||||
@ -252,19 +252,22 @@ Status ReplSetHeartbeatResponse::initialize(const BSONObj& doc, long long term)
|
||||
str::stream() << "Response to replSetHeartbeat missing required \""
|
||||
<< kConfigVersionFieldName << "\" field");
|
||||
}
|
||||
if (configVersionElement.type() != BSONType::numberInt) {
|
||||
if (configVersionElement.type() != BSONType::numberInt &&
|
||||
configVersionElement.type() != BSONType::numberLong) {
|
||||
return Status(ErrorCodes::TypeMismatch,
|
||||
str::stream() << "Expected \"" << kConfigVersionFieldName
|
||||
<< "\" field in response to replSetHeartbeat to have "
|
||||
"type NumberInt, but found "
|
||||
"type NumberInt/NumberLong, but found "
|
||||
<< typeName(configVersionElement.type()));
|
||||
}
|
||||
_configVersion = configVersionElement.numberInt();
|
||||
_configVersion = configVersionElement.numberLong();
|
||||
|
||||
// Allow a missing term field for backward compatibility.
|
||||
const BSONElement configTermElement = doc[kConfigTermFieldName];
|
||||
if (!configTermElement.eoo() && configVersionElement.type() == BSONType::numberInt) {
|
||||
_configTerm = configTermElement.numberInt();
|
||||
if (!configTermElement.eoo() &&
|
||||
(configTermElement.type() == BSONType::numberInt ||
|
||||
configTermElement.type() == BSONType::numberLong)) {
|
||||
_configTerm = configTermElement.numberLong();
|
||||
}
|
||||
|
||||
const BSONElement syncingToElement = doc[kSyncSourceFieldName];
|
||||
|
||||
@ -94,7 +94,7 @@ public:
|
||||
int getConfigVersion() const {
|
||||
return _configVersion;
|
||||
}
|
||||
int getConfigTerm() const {
|
||||
long long getConfigTerm() const {
|
||||
return _configTerm;
|
||||
}
|
||||
ConfigVersionAndTerm getConfigVersionAndTerm() const {
|
||||
@ -171,7 +171,7 @@ public:
|
||||
/**
|
||||
* Sets _configTerm to "configTerm".
|
||||
*/
|
||||
void setConfigTerm(int configTerm) {
|
||||
void setConfigTerm(long long configTerm) {
|
||||
_configTerm = configTerm;
|
||||
}
|
||||
|
||||
@ -235,7 +235,7 @@ private:
|
||||
MemberState _state;
|
||||
|
||||
int _configVersion = -1;
|
||||
int _configTerm = OpTime::kUninitializedTerm;
|
||||
long long _configTerm = OpTime::kUninitializedTerm;
|
||||
std::string _setName;
|
||||
HostAndPort _syncingTo;
|
||||
|
||||
|
||||
@ -322,7 +322,7 @@ TEST(ReplSetHeartbeatResponse, InitializeVersionWrongType) {
|
||||
ASSERT_EQUALS(ErrorCodes::TypeMismatch, result);
|
||||
ASSERT_EQUALS(
|
||||
"Expected \"v\" field in response to replSetHeartbeat to "
|
||||
"have type NumberInt, but found string",
|
||||
"have type NumberInt/NumberLong, but found string",
|
||||
result.reason());
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user