Skip to content

Commit b84fc35

Browse files
committed
CDRIVER-1906 implement idleWritePeriodMillis
1 parent e0e7bab commit b84fc35

16 files changed

+418
-21
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#define MONGOC_DEFAULT_WRITE_BATCH_SIZE 1000
2525
#define MONGOC_DEFAULT_BSON_OBJ_SIZE 16 * 1024 * 1024
2626
#define MONGOC_DEFAULT_MAX_MSG_SIZE 48000000
27+
#define MONGOC_DEFAULT_IDLE_WRITE_PERIOD_MS 10 * 1000
2728

2829
/* represent a server or topology with no replica set config version */
2930
#define MONGOC_NO_SET_VERSION -1
@@ -74,6 +75,7 @@ struct _mongoc_server_description_t
7475
int64_t set_version;
7576
bson_oid_t election_id;
7677
int64_t last_write_date_ms;
78+
int64_t idle_write_period_ms;
7779
};
7880

7981
void

src/mongoc/mongoc-server-description.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ mongoc_server_description_reset (mongoc_server_description_t *sd)
6363
sd->max_bson_obj_size = MONGOC_DEFAULT_BSON_OBJ_SIZE;
6464
sd->max_write_batch_size = MONGOC_DEFAULT_WRITE_BATCH_SIZE;
6565
sd->last_write_date_ms = -1;
66+
sd->idle_write_period_ms = -1;
6667

6768
/* always leave last ismaster in an init-ed state until we destroy sd */
6869
bson_destroy (&sd->last_is_master);
@@ -119,6 +120,8 @@ mongoc_server_description_init (mongoc_server_description_t *sd,
119120
sd->max_msg_size = MONGOC_DEFAULT_MAX_MSG_SIZE;
120121
sd->max_bson_obj_size = MONGOC_DEFAULT_BSON_OBJ_SIZE;
121122
sd->max_write_batch_size = MONGOC_DEFAULT_WRITE_BATCH_SIZE;
123+
sd->last_write_date_ms = -1;
124+
sd->idle_write_period_ms = -1;
122125

123126
bson_init_static (&sd->hosts, kMongocEmptyBson, sizeof (kMongocEmptyBson));
124127
bson_init_static (&sd->passives, kMongocEmptyBson, sizeof (kMongocEmptyBson));
@@ -586,6 +589,8 @@ mongoc_server_description_handle_ismaster (
586589
}
587590

588591
sd->last_write_date_ms = bson_iter_date_time (&child);
592+
} else if (strcmp ("idleWritePeriodMillis", bson_iter_key (&iter)) == 0) {
593+
sd->last_write_date_ms = bson_iter_as_int64 (&iter);
589594
}
590595
}
591596

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ bool
9999
mongoc_topology_description_all_sds_have_write_date (
100100
const mongoc_topology_description_t *td);
101101

102+
bool
103+
_mongoc_topology_description_validate_max_staleness (
104+
const mongoc_topology_description_t *td,
105+
double max_staleness_seconds,
106+
bson_error_t *error);
107+
102108
void
103109
mongoc_topology_description_suitable_servers (
104110
mongoc_array_t *set, /* OUT */

src/mongoc/mongoc-topology-description.c

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "mongoc-trace-private.h"
2222
#include "mongoc-util-private.h"
2323
#include "mongoc-read-prefs-private.h"
24+
#include "mongoc-set-private.h"
2425

2526

2627
static void
@@ -487,21 +488,113 @@ mongoc_topology_description_all_sds_have_write_date (const mongoc_topology_descr
487488
return true;
488489
}
489490

491+
/*
492+
*-------------------------------------------------------------------------
493+
*
494+
* _mongoc_topology_description_validate_max_staleness --
495+
*
496+
* If the provided "maxStalenessSeconds" component of the read
497+
* preference is not valid for this topology, fill out @error and
498+
* return false.
499+
*
500+
* Side effects:
501+
* None.
502+
*
503+
*-------------------------------------------------------------------------
504+
*/
505+
bool
506+
_mongoc_topology_description_validate_max_staleness (
507+
const mongoc_topology_description_t *td,
508+
double max_staleness_seconds,
509+
bson_error_t *error)
510+
{
511+
int i;
512+
mongoc_server_description_t *sd;
513+
int64_t idle_write_period_ms = -1;
514+
515+
if (max_staleness_seconds == NO_MAX_STALENESS) {
516+
return true;
517+
}
518+
519+
/* The isMaster response of a replica set member running some future
520+
* MongoDB version may contain idleWritePeriodMillis. Choose the
521+
* primary's value or else the most recently updated secondary's value,
522+
* according to the Server Selection Spec.
523+
*/
524+
if (td->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY) {
525+
mongoc_server_description_t *primary = NULL;
526+
527+
for (i = 0; i < td->servers->items_len; i++) {
528+
sd = (mongoc_server_description_t *) mongoc_set_get_item (
529+
td->servers, i);
530+
531+
if (sd->type == MONGOC_SERVER_RS_PRIMARY) {
532+
primary = sd;
533+
break;
534+
}
535+
}
536+
537+
BSON_ASSERT (primary);
538+
539+
idle_write_period_ms = primary->idle_write_period_ms;
540+
} else if (td->type == MONGOC_TOPOLOGY_RS_NO_PRIMARY) {
541+
mongoc_server_description_t *last_updated = NULL;
542+
543+
for (i = 0; i < td->servers->items_len; i++) {
544+
sd = (mongoc_server_description_t *) mongoc_set_get_item (
545+
td->servers, i);
546+
547+
if (sd->type != MONGOC_SERVER_RS_SECONDARY) {
548+
continue;
549+
}
550+
551+
if (!last_updated ||
552+
sd->last_update_time_usec > last_updated->last_update_time_usec) {
553+
last_updated = sd;
554+
}
555+
}
556+
557+
if (!last_updated) {
558+
/* no secondaries */
559+
return true;
560+
}
561+
562+
idle_write_period_ms = last_updated->idle_write_period_ms;
563+
} else {
564+
/* topology is not a replica set */
565+
return true;
566+
}
567+
568+
if (idle_write_period_ms == -1) {
569+
idle_write_period_ms = MONGOC_DEFAULT_IDLE_WRITE_PERIOD_MS;
570+
}
571+
572+
if (max_staleness_seconds * 1000 <
573+
td->heartbeat_msec + idle_write_period_ms) {
574+
bson_set_error (error, MONGOC_ERROR_COMMAND,
575+
MONGOC_ERROR_COMMAND_INVALID_ARG,
576+
"maxStalenessSeconds must be at least"
577+
" heartbeatFrequencyMS (%" PRId64 ") +"
578+
" server's idleWritePeriodMillis (%" PRId64 ")",
579+
td->heartbeat_msec, idle_write_period_ms);
580+
return false;
581+
}
582+
583+
return true;
584+
}
585+
490586

491587
/*
492588
*-------------------------------------------------------------------------
493589
*
494590
* mongoc_topology_description_suitable_servers --
495591
*
496-
* Return an array of suitable server descriptions for this
497-
* operation and read preference.
592+
* Fill out an array of servers matching the read preference and
593+
* localThresholdMS.
498594
*
499595
* NOTE: this method should only be called while holding the mutex on
500596
* the owning topology object.
501597
*
502-
* Returns:
503-
* Array of server descriptions, or NULL upon failure.
504-
*
505598
* Side effects:
506599
* None.
507600
*

src/mongoc/mongoc-topology.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -395,13 +395,8 @@ mongoc_topology_compatible (const mongoc_topology_description_t *td,
395395
return false;
396396
}
397397

398-
if ((td->type == MONGOC_TOPOLOGY_RS_WITH_PRIMARY ||
399-
td->type == MONGOC_TOPOLOGY_RS_NO_PRIMARY) &&
400-
max_staleness_seconds * 1000 < 2 * td->heartbeat_msec) {
401-
bson_set_error (error, MONGOC_ERROR_COMMAND,
402-
MONGOC_ERROR_COMMAND_INVALID_ARG,
403-
"maxStalenessSeconds must be at least twice "
404-
"heartbeatFrequencyMS");
398+
if (!_mongoc_topology_description_validate_max_staleness (
399+
td, max_staleness_seconds, error)) {
405400
return false;
406401
}
407402
}

tests/json-test.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ test_server_selection_logic_cb (bson_t *test)
387387
sd->last_write_date_ms = bson_iter_as_int64 (&last_write_iter);
388388
}
389389

390+
if (bson_iter_init_find (&sd_iter, &server, "idleWritePeriodMillis")) {
391+
sd->idle_write_period_ms = bson_iter_as_int64 (&sd_iter);
392+
}
393+
390394
if (bson_iter_init_find (&sd_iter, &server, "tags")) {
391395
bson_iter_bson (&sd_iter, &sd->tags);
392396
} else {
@@ -426,9 +430,15 @@ test_server_selection_logic_cb (bson_t *test)
426430

427431
if (bson_iter_init_find (&read_pref_iter, &test_read_pref,
428432
"maxStalenessSeconds")) {
429-
mongoc_read_prefs_set_max_staleness_seconds (
430-
read_prefs,
431-
(double) bson_iter_as_int64 (&read_pref_iter));
433+
if (BSON_ITER_HOLDS_DOUBLE (&read_pref_iter)) {
434+
mongoc_read_prefs_set_max_staleness_seconds (
435+
read_prefs,
436+
bson_iter_double (&read_pref_iter));
437+
} else {
438+
mongoc_read_prefs_set_max_staleness_seconds (
439+
read_prefs,
440+
(double) bson_iter_as_int64 (&read_pref_iter));
441+
}
432442
}
433443

434444
/* get operation type */
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"heartbeatFrequencyMS": 500,
3+
"in_latency_window": [
4+
{
5+
"address": "a:27017",
6+
"avg_rtt_ms": 5,
7+
"idleWritePeriodMillis": 9000,
8+
"lastUpdateTime": 1,
9+
"lastWrite": {
10+
"lastWriteDate": {
11+
"$numberLong": "1"
12+
}
13+
},
14+
"maxWireVersion": 5,
15+
"type": "RSSecondary"
16+
}
17+
],
18+
"read_preference": {
19+
"maxStalenessSeconds": 10,
20+
"mode": "Nearest"
21+
},
22+
"suitable_servers": [
23+
{
24+
"address": "a:27017",
25+
"avg_rtt_ms": 5,
26+
"idleWritePeriodMillis": 9000,
27+
"lastUpdateTime": 1,
28+
"lastWrite": {
29+
"lastWriteDate": {
30+
"$numberLong": "1"
31+
}
32+
},
33+
"maxWireVersion": 5,
34+
"type": "RSSecondary"
35+
},
36+
{
37+
"address": "b:27017",
38+
"avg_rtt_ms": 50,
39+
"idleWritePeriodMillis": 11000,
40+
"lastUpdateTime": 0,
41+
"lastWrite": {
42+
"lastWriteDate": {
43+
"$numberLong": "1"
44+
}
45+
},
46+
"maxWireVersion": 5,
47+
"type": "RSSecondary"
48+
}
49+
],
50+
"topology_description": {
51+
"servers": [
52+
{
53+
"address": "a:27017",
54+
"avg_rtt_ms": 5,
55+
"idleWritePeriodMillis": 9000,
56+
"lastUpdateTime": 1,
57+
"lastWrite": {
58+
"lastWriteDate": {
59+
"$numberLong": "1"
60+
}
61+
},
62+
"maxWireVersion": 5,
63+
"type": "RSSecondary"
64+
},
65+
{
66+
"address": "b:27017",
67+
"avg_rtt_ms": 50,
68+
"idleWritePeriodMillis": 11000,
69+
"lastUpdateTime": 0,
70+
"lastWrite": {
71+
"lastWriteDate": {
72+
"$numberLong": "1"
73+
}
74+
},
75+
"maxWireVersion": 5,
76+
"type": "RSSecondary"
77+
}
78+
],
79+
"type": "ReplicaSetNoPrimary"
80+
}
81+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"error": true,
3+
"heartbeatFrequencyMS": 500,
4+
"read_preference": {
5+
"maxStalenessSeconds": 10.5,
6+
"mode": "Nearest"
7+
},
8+
"topology_description": {
9+
"servers": [
10+
{
11+
"address": "a:27017",
12+
"avg_rtt_ms": 5,
13+
"idleWritePeriodMillis": 9000,
14+
"lastUpdateTime": 0,
15+
"lastWrite": {
16+
"lastWriteDate": {
17+
"$numberLong": "1"
18+
}
19+
},
20+
"maxWireVersion": 5,
21+
"type": "RSSecondary"
22+
},
23+
{
24+
"address": "b:27017",
25+
"avg_rtt_ms": 5,
26+
"idleWritePeriodMillis": 11000,
27+
"lastUpdateTime": 1,
28+
"lastWrite": {
29+
"lastWriteDate": {
30+
"$numberLong": "1"
31+
}
32+
},
33+
"maxWireVersion": 5,
34+
"type": "RSSecondary"
35+
}
36+
],
37+
"type": "ReplicaSetNoPrimary"
38+
}
39+
}

tests/json/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"lastUpdateTime": 25002,
3838
"lastWrite": {
3939
"lastWriteDate": {
40-
"$numberLong": "1"
40+
"$numberLong": "2"
4141
}
4242
},
4343
"maxWireVersion": 5,
@@ -64,7 +64,7 @@
6464
"lastUpdateTime": 25002,
6565
"lastWrite": {
6666
"lastWriteDate": {
67-
"$numberLong": "1"
67+
"$numberLong": "2"
6868
}
6969
},
7070
"maxWireVersion": 5,

0 commit comments

Comments
 (0)