Skip to content

Commit a21bcfb

Browse files
committed
CDRIVER-1056 use setversion to detect stale primary
1 parent 998dd42 commit a21bcfb

9 files changed

+193
-19
lines changed

src/mongoc/mongoc-server-description-private.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#define MONGOC_DEFAULT_BSON_OBJ_SIZE 16 * 1024 * 1024
2626
#define MONGOC_DEFAULT_MAX_MSG_SIZE 48000000
2727

28+
/* represent a server or topology with no replica set config version */
29+
#define MONGOC_NO_SET_VERSION -1
2830

2931
typedef enum
3032
{
@@ -68,6 +70,7 @@ struct _mongoc_server_description_t
6870

6971
bson_t tags;
7072
const char *current_primary;
73+
int64_t set_version;
7174
bson_oid_t election_id;
7275
};
7376

@@ -79,6 +82,10 @@ bool
7982
mongoc_server_description_has_rs_member (mongoc_server_description_t *description,
8083
const char *address);
8184

85+
86+
bool
87+
mongoc_server_description_has_set_version (mongoc_server_description_t *description);
88+
8289
bool
8390
mongoc_server_description_has_election_id (mongoc_server_description_t *description);
8491

@@ -92,6 +99,9 @@ void
9299
mongoc_server_description_set_state (mongoc_server_description_t *description,
93100
mongoc_server_description_type_t type);
94101
void
102+
mongoc_server_description_set_set_version (mongoc_server_description_t *description,
103+
int64_t set_version);
104+
void
95105
mongoc_server_description_set_election_id (mongoc_server_description_t *description,
96106
const bson_oid_t *election_id);
97107
void

src/mongoc/mongoc-server-description.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ mongoc_server_description_init (mongoc_server_description_t *sd,
9696
sd->round_trip_time = -1;
9797

9898
sd->set_name = NULL;
99+
sd->set_version = MONGOC_NO_SET_VERSION;
99100
sd->current_primary = NULL;
100101

101102
if (!_mongoc_host_list_from_string(&sd->host, address)) {
@@ -193,6 +194,25 @@ mongoc_server_description_has_rs_member(mongoc_server_description_t *server,
193194
return false;
194195
}
195196

197+
/*
198+
*--------------------------------------------------------------------------
199+
*
200+
* mongoc_server_description_has_set_version --
201+
*
202+
* Did this server's ismaster response have a "setVersion" field?
203+
*
204+
* Returns:
205+
* True if the server description's setVersion is set.
206+
*
207+
*--------------------------------------------------------------------------
208+
*/
209+
210+
bool
211+
mongoc_server_description_has_set_version (mongoc_server_description_t *description)
212+
{
213+
return description->set_version != MONGOC_NO_SET_VERSION;
214+
}
215+
196216
/*
197217
*--------------------------------------------------------------------------
198218
*
@@ -267,6 +287,25 @@ mongoc_server_description_set_state (mongoc_server_description_t *description,
267287
}
268288

269289

290+
/*
291+
*--------------------------------------------------------------------------
292+
*
293+
* mongoc_server_description_set_set_version --
294+
*
295+
* Set the replica set version of this server.
296+
*
297+
* Side effects:
298+
* None.
299+
*
300+
*--------------------------------------------------------------------------
301+
*/
302+
void
303+
mongoc_server_description_set_set_version (mongoc_server_description_t *description,
304+
int64_t set_version)
305+
{
306+
description->set_version = set_version;
307+
}
308+
270309
/*
271310
*--------------------------------------------------------------------------
272311
*
@@ -388,6 +427,9 @@ mongoc_server_description_handle_ismaster (
388427
} else if (strcmp ("setName", bson_iter_key (&iter)) == 0) {
389428
if (! BSON_ITER_HOLDS_UTF8 (&iter)) goto failure;
390429
sd->set_name = bson_iter_utf8 (&iter, NULL);
430+
} else if (strcmp ("setVersion", bson_iter_key (&iter)) == 0) {
431+
mongoc_server_description_set_set_version (sd,
432+
bson_iter_as_int64 (&iter));
391433
} else if (strcmp ("electionId", bson_iter_key (&iter)) == 0) {
392434
if (! BSON_ITER_HOLDS_OID (&iter)) goto failure;
393435
mongoc_server_description_set_election_id (sd, bson_iter_oid (&iter));
@@ -485,6 +527,7 @@ mongoc_server_description_new_copy (const mongoc_server_description_t *descripti
485527

486528
/* wait for handle_ismaster to fill these in properly */
487529
copy->has_is_master = false;
530+
copy->set_version = MONGOC_NO_SET_VERSION;
488531
bson_init_static (&copy->hosts, kMongocEmptyBson, sizeof (kMongocEmptyBson));
489532
bson_init_static (&copy->passives, kMongocEmptyBson, sizeof (kMongocEmptyBson));
490533
bson_init_static (&copy->arbiters, kMongocEmptyBson, sizeof (kMongocEmptyBson));

src/mongoc/mongoc-topology-description-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ typedef struct _mongoc_topology_description_t
3838
mongoc_topology_description_type_t type;
3939
mongoc_set_t *servers;
4040
char *set_name;
41+
int64_t max_set_version;
4142
bson_oid_t max_election_id;
4243
bool compatible;
4344
char *compatibility_error;

src/mongoc/mongoc-topology-description.c

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ mongoc_topology_description_init (mongoc_topology_description_t *description
6060
description->type = type;
6161
description->servers = mongoc_set_new(8, _mongoc_topology_server_dtor, NULL);
6262
description->set_name = NULL;
63+
description->max_set_version = MONGOC_NO_SET_VERSION;
6364
description->compatible = true;
6465
description->compatibility_error = NULL;
6566
description->stale = true;
@@ -152,8 +153,8 @@ _mongoc_topology_description_has_primary (mongoc_topology_description_t *descrip
152153
* than this server has.
153154
*
154155
* Returns:
155-
* True if the topology description's max election id is greater
156-
* than the server description's election_id.
156+
* True if the topology description's max replica set version plus
157+
* election id is later than the server description's.
157158
*
158159
* Side effects:
159160
* None
@@ -164,7 +165,28 @@ static bool
164165
_mongoc_topology_description_later_election (mongoc_topology_description_t *td,
165166
mongoc_server_description_t *sd)
166167
{
167-
return bson_oid_compare (&td->max_election_id, &sd->election_id) > 0;
168+
/* initially max_set_version is -1 and max_election_id is zeroed */
169+
return td->max_set_version > sd->set_version ||
170+
(td->max_set_version == sd->set_version &&
171+
bson_oid_compare (&td->max_election_id, &sd->election_id) > 0);
172+
}
173+
174+
/*
175+
*--------------------------------------------------------------------------
176+
*
177+
* _mongoc_topology_description_set_max_set_version --
178+
*
179+
* Remember that we've seen a new replica set version. Unconditionally
180+
* sets td->set_version to sd->set_version.
181+
*
182+
*--------------------------------------------------------------------------
183+
*/
184+
static void
185+
_mongoc_topology_description_set_max_set_version (
186+
mongoc_topology_description_t *td,
187+
mongoc_server_description_t *sd)
188+
{
189+
td->max_set_version = sd->set_version;
168190
}
169191

170192
/*
@@ -590,6 +612,27 @@ _mongoc_topology_description_has_server_cb (void *item,
590612
return true;
591613
}
592614

615+
/*
616+
*--------------------------------------------------------------------------
617+
*
618+
* _mongoc_topology_description_has_set_version --
619+
*
620+
* Whether @topology's max replica set version has been set.
621+
*
622+
* Returns:
623+
* True if the max setVersion was ever set.
624+
*
625+
* Side effects:
626+
* None.
627+
*
628+
*--------------------------------------------------------------------------
629+
*/
630+
static bool
631+
_mongoc_topology_description_has_set_version (mongoc_topology_description_t *td)
632+
{
633+
return td->max_set_version != MONGOC_NO_SET_VERSION;
634+
}
635+
593636
/*
594637
*--------------------------------------------------------------------------
595638
*
@@ -855,6 +898,7 @@ _mongoc_topology_description_invalidate_primaries_cb (void *item,
855898
if (server->id != data->primary->id &&
856899
server->type == MONGOC_SERVER_RS_PRIMARY) {
857900
mongoc_server_description_set_state (server, MONGOC_SERVER_UNKNOWN);
901+
mongoc_server_description_set_set_version (server, MONGOC_NO_SET_VERSION);
858902
mongoc_server_description_set_election_id (server, NULL);
859903
}
860904
return true;
@@ -988,7 +1032,8 @@ _mongoc_topology_description_update_rs_from_primary (mongoc_topology_description
9881032
}
9891033
}
9901034

991-
if (mongoc_server_description_has_election_id (server)) {
1035+
if (mongoc_server_description_has_set_version (server) &&
1036+
mongoc_server_description_has_election_id (server)) {
9921037
/* Server Discovery And Monitoring Spec: "The client remembers the
9931038
* greatest electionId reported by a primary, and distrusts primaries
9941039
* with lesser electionIds. This prevents the client from oscillating
@@ -1005,6 +1050,12 @@ _mongoc_topology_description_update_rs_from_primary (mongoc_topology_description
10051050
_mongoc_topology_description_set_max_election_id (topology, server);
10061051
}
10071052

1053+
if (mongoc_server_description_has_set_version (server) &&
1054+
(! _mongoc_topology_description_has_set_version (topology) ||
1055+
server->set_version > topology->max_set_version)) {
1056+
_mongoc_topology_description_set_max_set_version (topology, server);
1057+
}
1058+
10081059
/* 'Server' is the primary! Invalidate other primaries if found */
10091060
data.primary = server;
10101061
data.topology = topology;

tests/json/server_discovery_and_monitoring/rs/equal_electionids.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
"a:27017": {
88
"electionId": null,
99
"setName": null,
10+
"setVersion": null,
1011
"type": "Unknown"
1112
},
1213
"b:27017": {
1314
"electionId": {
1415
"$oid": "000000000000000000000001"
1516
},
1617
"setName": "rs",
18+
"setVersion": 1,
1719
"type": "RSPrimary"
1820
}
1921
},
@@ -33,7 +35,8 @@
3335
],
3436
"ismaster": true,
3537
"ok": 1,
36-
"setName": "rs"
38+
"setName": "rs",
39+
"setVersion": 1
3740
}
3841
],
3942
[
@@ -48,7 +51,8 @@
4851
],
4952
"ismaster": true,
5053
"ok": 1,
51-
"setName": "rs"
54+
"setName": "rs",
55+
"setVersion": 1
5256
}
5357
]
5458
]

tests/json/server_discovery_and_monitoring/rs/new_primary_new_electionid.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"description": "New primary with greater electionId",
2+
"description": "New primary with greater setVersion and electionId",
33
"phases": [
44
{
55
"outcome": {
@@ -9,6 +9,7 @@
99
"$oid": "000000000000000000000001"
1010
},
1111
"setName": "rs",
12+
"setVersion": 1,
1213
"type": "RSPrimary"
1314
},
1415
"b:27017": {
@@ -33,7 +34,8 @@
3334
],
3435
"ismaster": true,
3536
"ok": 1,
36-
"setName": "rs"
37+
"setName": "rs",
38+
"setVersion": 1
3739
}
3840
]
3941
]
@@ -51,6 +53,7 @@
5153
"$oid": "000000000000000000000002"
5254
},
5355
"setName": "rs",
56+
"setVersion": 1,
5457
"type": "RSPrimary"
5558
}
5659
},
@@ -70,7 +73,8 @@
7073
],
7174
"ismaster": true,
7275
"ok": 1,
73-
"setName": "rs"
76+
"setName": "rs",
77+
"setVersion": 1
7478
}
7579
]
7680
]
@@ -88,6 +92,7 @@
8892
"$oid": "000000000000000000000002"
8993
},
9094
"setName": "rs",
95+
"setVersion": 1,
9196
"type": "RSPrimary"
9297
}
9398
},
@@ -107,7 +112,8 @@
107112
],
108113
"ismaster": true,
109114
"ok": 1,
110-
"setName": "rs"
115+
"setName": "rs",
116+
"setVersion": 1
111117
}
112118
]
113119
]

0 commit comments

Comments
 (0)