File tree Expand file tree Collapse file tree 7 files changed +326
-7
lines changed Expand file tree Collapse file tree 7 files changed +326
-7
lines changed Original file line number Diff line number Diff line change @@ -60,11 +60,16 @@ def display_name
60
60
# @return [ ReplicaSet ] The topology.
61
61
def elect_primary ( description , servers )
62
62
if description . replica_set_name == replica_set_name
63
- log_debug ( [ "Server #{ description . address . to_s } elected as primary in #{ replica_set_name } ." ] )
64
- servers . each do |server |
65
- if server . primary? && server . address != description . address
66
- server . description . unknown!
63
+ if description . primary? && description . election_id && description . election_id < @max_election_id
64
+ description . unknown!
65
+ else
66
+ log_debug ( [ "Server #{ description . address . to_s } elected as primary in #{ replica_set_name } ." ] )
67
+ servers . each do |server |
68
+ if server . primary? && server . address != description . address
69
+ server . description . unknown!
70
+ end
67
71
end
72
+ @max_election_id = description . election_id
68
73
end
69
74
else
70
75
log_warn ( [
@@ -84,6 +89,7 @@ def elect_primary(description, servers)
84
89
# @since 2.0.0
85
90
def initialize ( options , seeds = [ ] )
86
91
@options = options
92
+ @max_election_id = 0
87
93
end
88
94
89
95
# A replica set topology is a replica set.
Original file line number Diff line number Diff line change @@ -124,10 +124,20 @@ class Description
124
124
# @since 2.0.0
125
125
TAGS = 'tags' . freeze
126
126
127
+ # Constant for reading electionID info from config.
128
+ #
129
+ # @since 2.1.0
130
+ ELECTION_ID = 'electionId' . freeze
131
+
132
+ # Constant for reading localTime info from config.
133
+ #
134
+ # @since 2.1.0
135
+ LOCAL_TIME = 'localTime' . freeze
136
+
127
137
# Fields to exclude when comparing two descriptions.
128
138
#
129
139
# @since 2.0.6
130
- EXCLUDE_FOR_COMPARISON = [ 'localTime' ]
140
+ EXCLUDE_FOR_COMPARISON = [ LOCAL_TIME , ELECTION_ID ]
131
141
132
142
# @return [ Address ] address The server's address.
133
143
attr_reader :address
@@ -304,6 +314,18 @@ def tags
304
314
config [ TAGS ] || { }
305
315
end
306
316
317
+ # Get the electionId from the config.
318
+ #
319
+ # @example Get the electionId.
320
+ # description.election_id
321
+ #
322
+ # @return [ BSON::ObjectId ] The election id.
323
+ #
324
+ # @since 2.1.0
325
+ def election_id
326
+ config [ ELECTION_ID ]
327
+ end
328
+
307
329
# Is the server a mongos?
308
330
#
309
331
# @example Is the server a mongos?
Original file line number Diff line number Diff line change
1
+ description : " New primary with equal electionId"
2
+
3
+ uri : " mongodb://a/?replicaSet=rs"
4
+
5
+ phases : [
6
+
7
+ # A and B claim to be primaries, with equal electionIds.
8
+ {
9
+ responses : [
10
+ ["a:27017", {
11
+ ok : 1,
12
+ ismaster : true,
13
+ hosts : ["a:27017", "b:27017"],
14
+ setName : " rs" ,
15
+ electionId : {"$oid": "000000000000000000000001"}
16
+ }],
17
+ ["b:27017", {
18
+ ok : 1,
19
+ ismaster : true,
20
+ hosts : ["a:27017", "b:27017"],
21
+ setName : " rs" ,
22
+ electionId : {"$oid": "000000000000000000000001"}
23
+ }]
24
+ ],
25
+
26
+ # No choice but to believe the latter response.
27
+ outcome : {
28
+ servers : {
29
+ " a:27017 " : {
30
+ type : " Unknown" ,
31
+ setName : ,
32
+ electionId : ,
33
+ },
34
+ " b:27017 " : {
35
+ type : " RSPrimary" ,
36
+ setName : " rs" ,
37
+ electionId : {"$oid": "000000000000000000000001"}
38
+ }
39
+ },
40
+ topologyType : " ReplicaSetWithPrimary" ,
41
+ setName : " rs" ,
42
+ maxElectionId : {"$oid": "000000000000000000000001"}
43
+ }
44
+ }
45
+ ]
Original file line number Diff line number Diff line change
1
+ description : " Ignore a secondary's electionId"
2
+
3
+ # Only primaries currently report electionId, make sure we're future-proof
4
+
5
+ uri : " mongodb://a/?replicaSet=rs"
6
+
7
+ phases : [
8
+
9
+ {
10
+ responses : [
11
+ ["a:27017", {
12
+ ok : 1,
13
+ ismaster : false,
14
+ secondary : true,
15
+ hosts : ["a:27017"],
16
+ setName : " rs" ,
17
+ electionId : {"$oid": "000000000000000000000001"}
18
+ }]
19
+ ],
20
+
21
+ outcome : {
22
+ servers : {
23
+ " a:27017 " : {
24
+ type : " RSSecondary" ,
25
+ setName : " rs" ,
26
+ electionId : {"$oid": "000000000000000000000001"}
27
+ }
28
+ },
29
+ topologyType : " ReplicaSetNoPrimary" ,
30
+ setName : " rs" ,
31
+ maxElectionId :
32
+ }
33
+ }
34
+ ]
Original file line number Diff line number Diff line change
1
+ description : " New primary with greater electionId"
2
+
3
+ uri : " mongodb://a/?replicaSet=rs"
4
+
5
+ phases : [
6
+
7
+ # Primary A is discovered and tells us about B.
8
+ {
9
+ responses : [
10
+ ["a:27017", {
11
+ ok : 1,
12
+ ismaster : true,
13
+ hosts : ["a:27017", "b:27017"],
14
+ setName : " rs" ,
15
+ electionId : {"$oid": "000000000000000000000001"}
16
+ }]
17
+ ],
18
+
19
+ outcome : {
20
+ servers : {
21
+ " a:27017 " : {
22
+ type : " RSPrimary" ,
23
+ setName : " rs" ,
24
+ electionId : {"$oid": "000000000000000000000001"}
25
+ },
26
+ " b:27017 " : {
27
+ type : " Unknown" ,
28
+ setName : ,
29
+ electionId :
30
+ }
31
+ },
32
+ topologyType : " ReplicaSetWithPrimary" ,
33
+ setName : " rs" ,
34
+ maxElectionId : {"$oid": "000000000000000000000001"}
35
+ }
36
+ },
37
+
38
+ # B is elected.
39
+ {
40
+ responses : [
41
+ ["b:27017", {
42
+ ok : 1,
43
+ ismaster : true,
44
+ hosts : ["a:27017", "b:27017"],
45
+ setName : " rs" ,
46
+ electionId : {"$oid": "000000000000000000000002"}
47
+ }]
48
+ ],
49
+
50
+ outcome : {
51
+ servers : {
52
+ " a:27017 " : {
53
+ type : " Unknown" ,
54
+ setName : ,
55
+ electionId :
56
+ },
57
+ " b:27017 " : {
58
+ type : " RSPrimary" ,
59
+ setName : " rs" ,
60
+ electionId : {"$oid": "000000000000000000000002"}
61
+ }
62
+ },
63
+ topologyType : " ReplicaSetWithPrimary" ,
64
+ setName : " rs" ,
65
+ maxElectionId : {"$oid": "000000000000000000000002"}
66
+ }
67
+ },
68
+
69
+ # A still claims to be primary but it's ignored.
70
+ {
71
+ responses : [
72
+ ["a:27017", {
73
+ ok : 1,
74
+ ismaster : true,
75
+ hosts : ["a:27017", "b:27017"],
76
+ setName : " rs" ,
77
+ electionId : {"$oid": "000000000000000000000001"}
78
+ }]
79
+ ],
80
+ outcome : {
81
+ servers : {
82
+ " a:27017 " : {
83
+ type : " Unknown" ,
84
+ setName : ,
85
+ electionId :
86
+ },
87
+ " b:27017 " : {
88
+ type : " RSPrimary" ,
89
+ setName : " rs" ,
90
+ electionId : {"$oid": "000000000000000000000002"}
91
+ }
92
+ },
93
+ topologyType : " ReplicaSetWithPrimary" ,
94
+ setName : " rs" ,
95
+ maxElectionId : {"$oid": "000000000000000000000002"}
96
+ }
97
+ }
98
+ ]
Original file line number Diff line number Diff line change
1
+ description : " Primary with no electionId, then a primary with electionId"
2
+
3
+ uri : " mongodb://a/?replicaSet=rs"
4
+
5
+ phases : [
6
+
7
+ # Primary A has no electionId.
8
+ {
9
+ responses : [
10
+ ["a:27017", {
11
+ ok : 1,
12
+ ismaster : true,
13
+ hosts : ["a:27017", "b:27017"],
14
+ setName : " rs"
15
+ }]
16
+ ],
17
+
18
+ outcome : {
19
+ servers : {
20
+ " a:27017 " : {
21
+ type : " RSPrimary" ,
22
+ setName : " rs" ,
23
+ electionId :
24
+ },
25
+ " b:27017 " : {
26
+ type : " Unknown" ,
27
+ setName : ,
28
+ electionId :
29
+ }
30
+ },
31
+ topologyType : " ReplicaSetWithPrimary" ,
32
+ setName : " rs" ,
33
+ maxElectionId :
34
+ }
35
+ },
36
+
37
+ # B is elected, it has an electionId.
38
+ {
39
+ responses : [
40
+ ["b:27017", {
41
+ ok : 1,
42
+ ismaster : true,
43
+ hosts : ["a:27017", "b:27017"],
44
+ setName : " rs" ,
45
+ electionId : {"$oid": "000000000000000000000001"}
46
+ }]
47
+ ],
48
+
49
+ outcome : {
50
+ servers : {
51
+ " a:27017 " : {
52
+ type : " Unknown" ,
53
+ setName : ,
54
+ electionId :
55
+ },
56
+ " b:27017 " : {
57
+ type : " RSPrimary" ,
58
+ setName : " rs" ,
59
+ electionId : {"$oid": "000000000000000000000001"}
60
+ }
61
+ },
62
+ topologyType : " ReplicaSetWithPrimary" ,
63
+ setName : " rs" ,
64
+ maxElectionId : {"$oid": "000000000000000000000001"}
65
+ }
66
+ },
67
+
68
+ # A still claims to be primary, no electionId, we have to trust it.
69
+ {
70
+ responses : [
71
+ ["a:27017", {
72
+ ok : 1,
73
+ ismaster : true,
74
+ hosts : ["a:27017", "b:27017"],
75
+ setName : " rs"
76
+ }]
77
+ ],
78
+ outcome : {
79
+ servers : {
80
+ " a:27017 " : {
81
+ type : " RSPrimary" ,
82
+ setName : " rs" ,
83
+ electionId :
84
+ },
85
+ " b:27017 " : {
86
+ type : " Unknown" ,
87
+ setName : ,
88
+ electionId :
89
+ }
90
+ },
91
+ topologyType : " ReplicaSetWithPrimary" ,
92
+ setName : " rs" ,
93
+ # But we remember old electionId.
94
+ maxElectionId : {"$oid": "000000000000000000000001"}
95
+ }
96
+ }
97
+ ]
Original file line number Diff line number Diff line change @@ -45,6 +45,15 @@ def find_server(client, uri)
45
45
client . cluster . instance_variable_get ( :@servers ) . detect { |s | s . address . to_s == uri }
46
46
end
47
47
48
+ # Helper to convert an extended JSON ObjectId to BSON::ObjectId.
49
+ #
50
+ # @since 2.1.0
51
+ def self . convert_oids ( docs )
52
+ docs . each do |doc |
53
+ doc [ 'electionId' ] = BSON ::ObjectId . from_string ( doc [ 'electionId' ] [ '$oid' ] ) if doc [ 'electionId' ]
54
+ end
55
+ end
56
+
48
57
# Represents a specification.
49
58
#
50
59
# @since 2.0.0
@@ -102,7 +111,7 @@ class Phase
102
111
# @since 2.0.0
103
112
def initialize ( phase , uri )
104
113
@phase = phase
105
- @responses = @phase [ 'responses' ] . map { |response | Response . new ( response , uri ) }
114
+ @responses = @phase [ 'responses' ] . map { |response | Response . new ( SDAM :: convert_oids ( response ) , uri ) }
106
115
@outcome = Outcome . new ( @phase [ 'outcome' ] )
107
116
end
108
117
end
@@ -158,10 +167,18 @@ class Outcome
158
167
#
159
168
# @since 2.0.0
160
169
def initialize ( outcome )
161
- @servers = outcome [ 'servers' ]
170
+ @servers = process_servers ( outcome [ 'servers' ] )
162
171
@set_name = outcome [ 'setName' ]
163
172
@topology_type = outcome [ 'topologyType' ]
164
173
end
174
+
175
+ private
176
+
177
+ def process_servers ( servers )
178
+ servers . each do |s |
179
+ SDAM ::convert_oids ( [ s [ 1 ] ] )
180
+ end
181
+ end
165
182
end
166
183
end
167
184
end
You can’t perform that action at this time.
0 commit comments