@@ -293,10 +293,11 @@ Fields:
293
293
294
294
* type: a `TopologyType `_ enum value. See `initial TopologyType `_.
295
295
* setName: the replica set name. Default null.
296
- * maxSetVersion: an integer or null. The largest setVersion ever reported by
297
- a primary. Default null.
298
296
* maxElectionId: an ObjectId or null. The largest electionId ever reported by
299
- a primary. Default null.
297
+ a primary. Default null. Part of the (``electionId ``, ``setVersion ``) tuple.
298
+ * maxSetVersion: an integer or null. The largest setVersion ever reported by
299
+ a primary. It may not monotonically increase, as electionId takes precedence in ordering
300
+ Default null. Part of the (``electionId ``, ``setVersion ``) tuple.
300
301
* servers: a set of ServerDescription instances.
301
302
Default contains one server: "localhost:27017", ServerType Unknown.
302
303
* stale: a boolean for single-threaded clients, whether the topology must
@@ -351,10 +352,10 @@ Fields:
351
352
The client `monitors all three types of servers `_ in a replica set.
352
353
* (=) tags: map from string to string. Default empty.
353
354
* (=) setName: string or null. Default null.
354
- * (=) setVersion: integer or null. Default null.
355
355
* (=) electionId: an ObjectId, if this is a MongoDB 2.6+ replica set member that
356
- believes it is primary. See `using setVersion and electionId to detect stale primaries `_.
356
+ believes it is primary. See `using electionId and setVersion to detect stale primaries `_.
357
357
Default null.
358
+ * (=) setVersion: integer or null. Default null.
358
359
* (=) primary: an address. This server's opinion of who the primary is.
359
360
Default null.
360
361
* lastUpdateTime: when this server was last checked. Default "infinity ago".
@@ -1094,57 +1095,49 @@ updateRSWithPrimaryFromMember
1094
1095
updateRSFromPrimary
1095
1096
This subroutine is executed with a ServerDescription of type RSPrimary::
1096
1097
1097
- if description .address not in topologyDescription.servers:
1098
+ if serverDescription .address not in topologyDescription.servers:
1098
1099
return
1099
1100
1100
1101
if topologyDescription.setName is null:
1101
- topologyDescription.setName = description .setName
1102
+ topologyDescription.setName = serverDescription .setName
1102
1103
1103
- else if topologyDescription.setName != description .setName:
1104
+ else if topologyDescription.setName != serverDescription .setName:
1104
1105
# We found a primary but it doesn't have the setName
1105
1106
# provided by the user or previously discovered.
1106
1107
remove this server from topologyDescription and stop monitoring it
1107
1108
checkIfHasPrimary()
1108
1109
return
1109
1110
1110
- if description.setVersion is not null and description.electionId is not null:
1111
- # Election ids are ObjectIds, see
1112
- # "using setVersion and electionId to detect stale primaries"
1113
- # for comparison rules.
1114
- if (topologyDescription.maxSetVersion is not null and
1115
- topologyDescription.maxElectionId is not null and (
1116
- topologyDescription.maxSetVersion > description.setVersion or (
1117
- topologyDescription.maxSetVersion == description.setVersion and
1118
- topologyDescription.maxElectionId > description.electionId
1119
- )
1120
- ):
1121
-
1122
- # Stale primary.
1123
- replace description with a default ServerDescription of type "Unknown"
1124
- checkIfHasPrimary()
1125
- return
1126
-
1127
- topologyDescription.maxElectionId = description.electionId
1128
-
1129
- if (description.setVersion is not null and
1130
- (topologyDescription.maxSetVersion is null or
1131
- description.setVersion > topologyDescription.maxSetVersion)):
1132
-
1133
- topologyDescription.maxSetVersion = description.setVersion
1111
+ # Election ids are ObjectIds, see
1112
+ # "using setVersion and electionId to detect stale primaries"
1113
+ # for comparison rules.
1114
+
1115
+ # Null values for both electionId and setVersion are always considered less than
1116
+ if serverDescription.electionId > serverDescription.maxElectionId or (
1117
+ serverDescription.electionId == topologyDescription.maxElectionId
1118
+ and serverDescription.setVersion >= topologyDescription.maxSetVersion
1119
+ ):
1120
+ topologyDescription.maxElectionId = serverDescription.electionId
1121
+ topologyDescription.maxSetVersion = serverDescription.setVersion
1122
+ else:
1123
+ # Stale primary.
1124
+ # replace serverDescription with a default ServerDescription of type "Unknown"
1125
+ checkIfHasPrimary()
1126
+ return
1134
1127
1135
1128
for each server in topologyDescription.servers:
1136
- if server.address != description .address:
1129
+ if server.address != serverDescription .address:
1137
1130
if server.type is RSPrimary:
1138
1131
# See note below about invalidating an old primary.
1139
1132
replace the server with a default ServerDescription of type "Unknown"
1140
1133
1141
- for each address in description 's "hosts", "passives", and "arbiters":
1134
+ for each address in serverDescription 's "hosts", "passives", and "arbiters":
1142
1135
if address is not in topologyDescription.servers:
1143
1136
add new default ServerDescription of type "Unknown"
1144
1137
begin monitoring the new server
1145
1138
1146
1139
for each server in topologyDescription.servers:
1147
- if server.address not in description 's "hosts", "passives", or "arbiters":
1140
+ if server.address not in serverDescription 's "hosts", "passives", or "arbiters":
1148
1141
remove the server and stop monitoring it
1149
1142
1150
1143
checkIfHasPrimary()
@@ -1165,10 +1158,10 @@ updateRSFromPrimary
1165
1158
1166
1159
See `replica set monitoring with and without a primary `_.
1167
1160
1168
- If the server is primary with an obsolete setVersion or electionId , it is
1161
+ If the server is primary with an obsolete electionId or setVersion , it is
1169
1162
likely a stale primary that is going to step down. Mark it Unknown and let periodic
1170
1163
monitoring detect when it becomes secondary. See
1171
- `using setVersion and electionId to detect stale primaries `_.
1164
+ `using electionId and setVersion to detect stale primaries `_.
1172
1165
1173
1166
A note on checking "me": Unlike `updateRSWithPrimaryFromMember `, there is no need to remove the server if the address is not equal to
1174
1167
"me": since the server address will not be a member of either "hosts", "passives", or "arbiters", the server will already have been
@@ -1966,7 +1959,7 @@ list are removed.
1966
1959
1967
1960
.. _stale primaries :
1968
1961
1969
- Using setVersion and electionId to detect stale primaries
1962
+ Using electionId and setVersion to detect stale primaries
1970
1963
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
1971
1964
1972
1965
Replica set members running MongoDB 2.6.10+ or 3.0+ include an integer called
@@ -1977,13 +1970,17 @@ protocol versions; electionIds from one protocol version must not be compared
1977
1970
to electionIds from a different protocol.
1978
1971
1979
1972
Because protocol version changes require replica set reconfiguration,
1980
- clients use the tuple (setVersion, electionId) to detect stale primaries.
1973
+ clients use the tuple (electionId, setVersion) to detect stale primaries.
1974
+ The tuple order comparison MUST be checked in the order of electionId followed
1975
+ by setVersion since that order of comparison is guaranteed monotonicity.
1981
1976
1982
- The client remembers the greatest setVersion and electionId reported by a primary,
1977
+ The client remembers the greatest electionId and setVersion reported by a primary,
1983
1978
and distrusts primaries from older setVersions or from the same setVersion
1984
1979
but with lesser electionIds.
1985
- It compares setVersions as integer values.
1986
- It compares electionIds as 12-byte big-endian integers.
1980
+
1981
+ - It compares electionIds as 12-byte sequence i.e. memory comparison.
1982
+ - It compares setVersions as integer values.
1983
+
1987
1984
This prevents the client from oscillating
1988
1985
between the old and new primary during a split-brain period,
1989
1986
and helps provide read-your-writes consistency with write concern "majority"
@@ -2024,15 +2021,18 @@ reads with WriteConcern Majority and ReadPreference Primary."
2024
2021
Detecting a stale primary
2025
2022
`````````````````````````
2026
2023
2027
- To prevent this scenario, the client uses setVersion and electionId to
2024
+ To prevent this scenario, the client uses electionId and setVersion to
2028
2025
determine which primary was elected last. In this case, it would not consider
2029
- A primary, nor read from it, after receiving B's hello or legacy hello response with the
2030
- same setVersion and a greater electionId .
2026
+ "A" a primary, nor read from it because server B will have a greater electionId
2027
+ but the same setVersion .
2031
2028
2032
2029
Monotonicity
2033
2030
````````````
2034
2031
2035
- The electionId is an ObjectId compared bytewise in big-endian order.
2032
+ The electionId is an ObjectId compared bytewise in order.
2033
+
2034
+ (ie. 000000000000000000000001 > 000000000000000000000000, FF0000000000000000000000 > FE0000000000000000000000 etc.)
2035
+
2036
2036
In some server versions, it is monotonic with respect
2037
2037
to a particular servers' system clock, but is not globally monotonic across
2038
2038
a deployment. However, if inter-server clock skews are small, it can be
@@ -2426,6 +2426,18 @@ Why is auto-discovery the preferred default?
2426
2426
2427
2427
Auto-discovery is most resilient and is therefore preferred.
2428
2428
2429
+ Why is it possible for maxSetVersion to go down?
2430
+ ''''''''''''''''''''''''''''''''''''''''''''''''
2431
+
2432
+ ``maxElectionId `` and ``maxSetVersion `` are actually considered a pair of values
2433
+ Drivers MAY consider implementing comparison in code as a tuple of the two to ensure their always updated together:
2434
+
2435
+ .. code :: typescript
2436
+
2437
+ // New tuple old tuple
2438
+ { electionId : 2 , setVersion : 1 } > { electionId: 1 , setVersion: 50 }
2439
+
2440
+ In this scenario, the maxSetVersion goes from 50 to 1, but the maxElectionId is raised to 2.
2429
2441
2430
2442
Acknowledgments
2431
2443
---------------
@@ -2440,6 +2452,8 @@ Bernie Hackett gently oversaw the specification process.
2440
2452
Changes
2441
2453
-------
2442
2454
2455
+ 2021-01-17: Require clients to compare (electionId, setVersion) tuples.
2456
+
2443
2457
2015-12-17: Require clients to compare (setVersion, electionId) tuples.
2444
2458
2445
2459
2015-10-09: Specify electionID comparison method.
0 commit comments