Skip to content

Commit

Permalink
PYTHON-2970 Prioritize electionId over setVersion for stale primary c…
Browse files Browse the repository at this point in the history
…heck (mongodb#845)
  • Loading branch information
ShaneHarvey committed Mar 9, 2022
1 parent f081297 commit 225d131
Show file tree
Hide file tree
Showing 11 changed files with 481 additions and 50 deletions.
15 changes: 15 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ PyMongo 4.1 brings a number of improvements including:
- :meth:`gridfs.GridOut.seek` now returns the new position in the file, to
conform to the behavior of :meth:`io.IOBase.seek`.

Bug fixes
.........

- Fixed a bug where the client could be unable to discover the new primary
after a simultaneous replica set election and reconfig (`PYTHON-2970`_).

.. _PYTHON-2970: https://jira.mongodb.org/browse/PYTHON-2970

Issues Resolved
...............

See the `PyMongo 4.1 release notes in JIRA`_ for the list of resolved issues
in this release.

.. _PyMongo 4.1 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=30619

Changes in Version 4.0
----------------------
Expand Down
29 changes: 11 additions & 18 deletions pymongo/topology_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from random import sample
from typing import Any, Callable, Dict, List, NamedTuple, Optional, Tuple

from bson.min_key import MinKey
from bson.objectid import ObjectId
from pymongo import common
from pymongo.errors import ConfigurationError
Expand Down Expand Up @@ -531,24 +532,16 @@ def _update_rs_from_primary(
sds.pop(server_description.address)
return (_check_has_primary(sds), replica_set_name, max_set_version, max_election_id)

max_election_tuple = max_set_version, max_election_id
if None not in server_description.election_tuple:
if (
None not in max_election_tuple
and max_election_tuple > server_description.election_tuple
):

# Stale primary, set to type Unknown.
sds[server_description.address] = server_description.to_unknown()
return (_check_has_primary(sds), replica_set_name, max_set_version, max_election_id)

max_election_id = server_description.election_id

if server_description.set_version is not None and (
max_set_version is None or server_description.set_version > max_set_version
):

max_set_version = server_description.set_version
new_election_tuple = server_description.election_id, server_description.set_version
max_election_tuple = max_election_id, max_set_version
new_election_safe = tuple(MinKey() if i is None else i for i in new_election_tuple)
max_election_safe = tuple(MinKey() if i is None else i for i in max_election_tuple)
if new_election_safe >= max_election_safe:
max_election_id, max_set_version = new_election_tuple
else:
# Stale primary, set to type Unknown.
sds[server_description.address] = server_description.to_unknown()
return _check_has_primary(sds), replica_set_name, max_set_version, max_election_id

# We've heard from the primary. Is it the same primary as before?
for server in sds.values():
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"description": "ElectionId is considered higher precedence than setVersion",
"uri": "mongodb://a/?replicaSet=rs",
"phases": [
{
"responses": [
[
"a:27017",
{
"ok": 1,
"helloOk": true,
"isWritablePrimary": true,
"hosts": [
"a:27017",
"b:27017"
],
"setName": "rs",
"setVersion": 1,
"electionId": {
"$oid": "000000000000000000000001"
},
"minWireVersion": 0,
"maxWireVersion": 6
}
],
[
"b:27017",
{
"ok": 1,
"helloOk": true,
"isWritablePrimary": true,
"hosts": [
"a:27017",
"b:27017"
],
"setName": "rs",
"setVersion": 2,
"electionId": {
"$oid": "000000000000000000000001"
},
"minWireVersion": 0,
"maxWireVersion": 6
}
],
[
"a:27017",
{
"ok": 1,
"helloOk": true,
"isWritablePrimary": true,
"hosts": [
"a:27017",
"b:27017"
],
"setName": "rs",
"setVersion": 1,
"electionId": {
"$oid": "000000000000000000000002"
},
"minWireVersion": 0,
"maxWireVersion": 6
}
]
],
"outcome": {
"servers": {
"a:27017": {
"type": "RSPrimary",
"setName": "rs",
"setVersion": 1,
"electionId": {
"$oid": "000000000000000000000002"
}
},
"b:27017": {
"type": "Unknown",
"setName": null,
"setVersion": null,
"electionId": null
}
},
"topologyType": "ReplicaSetWithPrimary",
"logicalSessionTimeoutMinutes": null,
"setName": "rs",
"maxSetVersion": 1,
"maxElectionId": {
"$oid": "000000000000000000000002"
}
}
}
]
}
30 changes: 18 additions & 12 deletions test/discovery_and_monitoring/rs/null_election_id.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,16 +123,19 @@
"outcome": {
"servers": {
"a:27017": {
"type": "RSPrimary",
"setName": "rs",
"setVersion": 1,
"electionId": null
},
"b:27017": {
"type": "Unknown",
"setName": null,
"setVersion": null,
"electionId": null
},
"b:27017": {
"type": "RSPrimary",
"setName": "rs",
"setVersion": 1,
"electionId": {
"$oid": "000000000000000000000002"
}
},
"c:27017": {
"type": "Unknown",
"setName": null,
Expand Down Expand Up @@ -174,16 +177,19 @@
"outcome": {
"servers": {
"a:27017": {
"type": "RSPrimary",
"setName": "rs",
"setVersion": 1,
"electionId": null
},
"b:27017": {
"type": "Unknown",
"setName": null,
"setVersion": null,
"electionId": null
},
"b:27017": {
"type": "RSPrimary",
"setName": "rs",
"setVersion": 1,
"electionId": {
"$oid": "000000000000000000000002"
}
},
"c:27017": {
"type": "Unknown",
"setName": null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"description": "New primary",
"description": "Secondary ignored when ok is zero",
"uri": "mongodb://a,b/?replicaSet=rs",
"phases": [
{
Expand Down
149 changes: 149 additions & 0 deletions test/discovery_and_monitoring/rs/set_version_can_rollback.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
{
"description": "Set version rolls back after new primary with higher election Id",
"uri": "mongodb://a/?replicaSet=rs",
"phases": [
{
"responses": [
[
"a:27017",
{
"ok": 1,
"hello": true,
"isWritablePrimary": true,
"hosts": [
"a:27017",
"b:27017"
],
"setName": "rs",
"setVersion": 2,
"electionId": {
"$oid": "000000000000000000000001"
},
"minWireVersion": 0,
"maxWireVersion": 6
}
]
],
"outcome": {
"servers": {
"a:27017": {
"type": "RSPrimary",
"setName": "rs",
"setVersion": 2,
"electionId": {
"$oid": "000000000000000000000001"
}
},
"b:27017": {
"type": "Unknown",
"setName": null,
"electionId": null
}
},
"topologyType": "ReplicaSetWithPrimary",
"logicalSessionTimeoutMinutes": null,
"setName": "rs",
"maxSetVersion": 2,
"maxElectionId": {
"$oid": "000000000000000000000001"
}
}
},
{
"_comment": "Response from new primary with newer election Id",
"responses": [
[
"b:27017",
{
"ok": 1,
"hello": true,
"isWritablePrimary": true,
"hosts": [
"a:27017",
"b:27017"
],
"setName": "rs",
"setVersion": 1,
"electionId": {
"$oid": "000000000000000000000002"
},
"minWireVersion": 0,
"maxWireVersion": 6
}
]
],
"outcome": {
"servers": {
"a:27017": {
"type": "Unknown",
"setName": null,
"electionId": null
},
"b:27017": {
"type": "RSPrimary",
"setName": "rs",
"setVersion": 1,
"electionId": {
"$oid": "000000000000000000000002"
}
}
},
"topologyType": "ReplicaSetWithPrimary",
"logicalSessionTimeoutMinutes": null,
"setName": "rs",
"maxSetVersion": 1,
"maxElectionId": {
"$oid": "000000000000000000000002"
}
}
},
{
"_comment": "Response from stale primary",
"responses": [
[
"a:27017",
{
"ok": 1,
"hello": true,
"isWritablePrimary": true,
"hosts": [
"a:27017",
"b:27017"
],
"setName": "rs",
"setVersion": 2,
"electionId": {
"$oid": "000000000000000000000001"
},
"minWireVersion": 0,
"maxWireVersion": 6
}
]
],
"outcome": {
"servers": {
"a:27017": {
"type": "Unknown",
"setName": null,
"electionId": null
},
"b:27017": {
"type": "RSPrimary",
"setName": "rs",
"setVersion": 1,
"electionId": {
"$oid": "000000000000000000000002"
}
}
},
"topologyType": "ReplicaSetWithPrimary",
"logicalSessionTimeoutMinutes": null,
"setName": "rs",
"maxSetVersion": 1,
"maxElectionId": {
"$oid": "000000000000000000000002"
}
}
}
]
}
Loading

0 comments on commit 225d131

Please sign in to comment.