Skip to content

Commit 0f7fcad

Browse files
authored
CDRIVER-5864 Do not parse BSON in mongoc_server_description_new_copy (#1835)
* do not parse BSON in `mongoc_server_description_new_copy` * remove unnecessary atomic modification of `round_trip_time_msec` * add tests for copying
1 parent 6159250 commit 0f7fcad

File tree

2 files changed

+197
-37
lines changed

2 files changed

+197
-37
lines changed

src/libmongoc/src/mongoc/mongoc-server-description.c

+83-37
Original file line numberDiff line numberDiff line change
@@ -485,11 +485,9 @@ mongoc_server_description_update_rtt (mongoc_server_description_t *server, int64
485485
return;
486486
}
487487
if (server->round_trip_time_msec == MONGOC_RTT_UNSET) {
488-
mcommon_atomic_int64_exchange (&server->round_trip_time_msec, rtt_msec, mcommon_memory_order_relaxed);
488+
server->round_trip_time_msec = rtt_msec;
489489
} else {
490-
mcommon_atomic_int64_exchange (&server->round_trip_time_msec,
491-
(int64_t) (ALPHA * rtt_msec + (1 - ALPHA) * server->round_trip_time_msec),
492-
mcommon_memory_order_relaxed);
490+
server->round_trip_time_msec = (int64_t) (ALPHA * rtt_msec + (1 - ALPHA) * server->round_trip_time_msec);
493491
}
494492
}
495493

@@ -768,48 +766,96 @@ mongoc_server_description_handle_hello (mongoc_server_description_t *sd,
768766
mongoc_server_description_t *
769767
mongoc_server_description_new_copy (const mongoc_server_description_t *description)
770768
{
771-
mongoc_server_description_t *copy;
769+
#define COPY_FIELD(FIELD) \
770+
if (1) { \
771+
copy->FIELD = description->FIELD; \
772+
} else \
773+
(void) 0
774+
775+
776+
#define COPY_BSON_FIELD(FIELD) \
777+
if (1) { \
778+
bson_copy_to (&description->FIELD, &copy->FIELD); \
779+
} else \
780+
(void) 0
781+
782+
// COPY_INTERNAL_BSON_FIELD copies a `bson_t` that references data in `last_hello_response`.
783+
#define COPY_INTERNAL_BSON_FIELD(FIELD) \
784+
if (1) { \
785+
if (!bson_empty (&description->FIELD)) { \
786+
ptrdiff_t offset = bson_get_data (&description->FIELD) - bson_get_data (&description->last_hello_response); \
787+
MONGOC_DEBUG_ASSERT (offset >= 0); \
788+
const uint8_t *data = bson_get_data (&copy->last_hello_response) + offset; \
789+
uint32_t len = description->FIELD.len; \
790+
MONGOC_DEBUG_ASSERT (offset + len <= copy->last_hello_response.len); \
791+
bson_init_static (&copy->FIELD, data, len); \
792+
} else { \
793+
bson_init (&copy->FIELD); \
794+
} \
795+
} else \
796+
(void) 0
797+
798+
// COPY_INTERNAL_STRING_FIELD copies a `const char*` that references data in `last_hello_response`.
799+
#define COPY_INTERNAL_STRING_FIELD(FIELD) \
800+
if (1) { \
801+
if (description->FIELD) { \
802+
ptrdiff_t offset = (char *) description->FIELD - (char *) bson_get_data (&description->last_hello_response); \
803+
MONGOC_DEBUG_ASSERT (offset >= 0); \
804+
copy->FIELD = (char *) bson_get_data (&copy->last_hello_response) + offset; \
805+
MONGOC_DEBUG_ASSERT (offset + strlen (description->FIELD) <= copy->last_hello_response.len); \
806+
} else { \
807+
copy->FIELD = NULL; \
808+
} \
809+
} else \
810+
(void) 0
811+
772812

773813
if (!description) {
774814
return NULL;
775815
}
776816

777-
copy = BSON_ALIGNED_ALLOC0 (mongoc_server_description_t);
778-
779-
copy->id = description->id;
780-
copy->opened = description->opened;
781-
memcpy (&copy->host, &description->host, sizeof (copy->host));
782-
copy->round_trip_time_msec = MONGOC_RTT_UNSET;
817+
mongoc_server_description_t *copy = BSON_ALIGNED_ALLOC (mongoc_server_description_t);
783818

819+
COPY_FIELD (id);
820+
COPY_FIELD (host);
821+
COPY_FIELD (round_trip_time_msec);
822+
COPY_FIELD (last_update_time_usec);
823+
COPY_BSON_FIELD (last_hello_response);
824+
COPY_FIELD (has_hello_response);
825+
COPY_FIELD (hello_ok);
784826
copy->connection_address = copy->host.host_and_port;
785-
bson_init (&copy->last_hello_response);
786-
bson_init (&copy->hosts);
787-
bson_init (&copy->passives);
788-
bson_init (&copy->arbiters);
789-
bson_init (&copy->tags);
790-
bson_init (&copy->compressors);
791-
bson_copy_to (&description->topology_version, &copy->topology_version);
792-
bson_oid_copy (&description->service_id, &copy->service_id);
793-
copy->server_connection_id = description->server_connection_id;
794-
795-
if (description->has_hello_response) {
796-
/* calls mongoc_server_description_reset */
797-
int64_t last_rtt_ms =
798-
mcommon_atomic_int64_fetch (&description->round_trip_time_msec, mcommon_memory_order_relaxed);
799-
mongoc_server_description_handle_hello (
800-
copy, &description->last_hello_response, last_rtt_ms, &description->error);
801-
} else {
802-
mongoc_server_description_reset (copy);
803-
/* preserve the original server description type, which is manually set
804-
* for a LoadBalancer server */
805-
copy->type = description->type;
806-
}
827+
COPY_INTERNAL_STRING_FIELD (me);
828+
COPY_FIELD (opened);
829+
COPY_INTERNAL_STRING_FIELD (set_name);
830+
COPY_FIELD (error);
831+
COPY_FIELD (type);
832+
COPY_FIELD (min_wire_version);
833+
COPY_FIELD (max_wire_version);
834+
COPY_FIELD (max_msg_size);
835+
COPY_FIELD (max_bson_obj_size);
836+
COPY_FIELD (max_write_batch_size);
837+
COPY_FIELD (session_timeout_minutes);
838+
COPY_INTERNAL_BSON_FIELD (hosts);
839+
COPY_INTERNAL_BSON_FIELD (passives);
840+
COPY_INTERNAL_BSON_FIELD (arbiters);
841+
COPY_INTERNAL_BSON_FIELD (tags);
842+
COPY_INTERNAL_STRING_FIELD (current_primary);
843+
COPY_FIELD (set_version);
844+
COPY_FIELD (election_id);
845+
COPY_FIELD (last_write_date_ms);
846+
COPY_INTERNAL_BSON_FIELD (compressors);
847+
// `topology_version` does not refer to data in `last_hello_response`. It needs to outlive `last_hello_response`.
848+
COPY_BSON_FIELD (topology_version);
849+
COPY_FIELD (generation);
850+
copy->_generation_map_ = mongoc_generation_map_copy (mc_tpl_sd_generation_map_const (description));
851+
COPY_FIELD (service_id);
852+
COPY_FIELD (server_connection_id);
807853

808-
/* Preserve the error */
809-
memcpy (&copy->error, &description->error, sizeof copy->error);
854+
#undef COPY_INTERNAL_STRING_FIELD
855+
#undef COPY_INTERNAL_BSON_FIELD
856+
#undef COPY_BSON_FIELD
857+
#undef COPY_FIELD
810858

811-
copy->generation = description->generation;
812-
copy->_generation_map_ = mongoc_generation_map_copy (mc_tpl_sd_generation_map_const (description));
813859
return copy;
814860
}
815861

src/libmongoc/tests/test-mongoc-server-description.c

+114
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,119 @@ test_server_description_hello_type_error (void)
458458
mongoc_server_description_cleanup (&sd);
459459
}
460460

461+
static void
462+
test_copy (const char *hello_json)
463+
{
464+
mongoc_server_description_t sd, *sd_copy;
465+
mongoc_server_description_init (&sd, "host:1234", 1);
466+
bson_error_t empty_error = {0};
467+
mongoc_server_description_handle_hello (&sd, tmp_bson (hello_json), 0, &empty_error);
468+
sd_copy = mongoc_server_description_new_copy (&sd);
469+
470+
// Check server descriptions compare equal by "Server Description Equality" rules. Not all fields are considered.
471+
ASSERT (_mongoc_server_description_equal (&sd, sd_copy));
472+
473+
// Check all fields:
474+
ASSERT_CMPUINT32 (sd.id, ==, sd_copy->id);
475+
ASSERT_CMPSTR (sd.host.host_and_port, sd_copy->host.host_and_port);
476+
ASSERT_CMPINT64 (sd.round_trip_time_msec, ==, sd_copy->round_trip_time_msec);
477+
ASSERT_CMPINT64 (sd.last_update_time_usec, ==, sd_copy->last_update_time_usec);
478+
ASSERT_EQUAL_BSON (&sd.last_hello_response, &sd_copy->last_hello_response);
479+
ASSERT_CMPINT ((int) sd.has_hello_response, ==, (int) sd_copy->has_hello_response);
480+
ASSERT_CMPINT ((int) sd.hello_ok, ==, (int) sd_copy->hello_ok);
481+
ASSERT_CMPSTR (sd.connection_address, sd_copy->connection_address);
482+
ASSERT_CMPSTR (sd.me, sd_copy->me);
483+
ASSERT_CMPINT ((int) sd.opened, ==, (int) sd_copy->opened);
484+
ASSERT_CMPSTR (sd.set_name, sd_copy->set_name);
485+
ASSERT_MEMCMP (&sd.error, &sd_copy->error, (int) sizeof (bson_error_t));
486+
ASSERT_CMPINT ((int) sd.type, ==, (int) sd_copy->type);
487+
ASSERT_CMPINT32 (sd.min_wire_version, ==, sd_copy->min_wire_version);
488+
ASSERT_CMPINT32 (sd.max_wire_version, ==, sd_copy->max_wire_version);
489+
ASSERT_CMPINT32 (sd.max_msg_size, ==, sd_copy->max_msg_size);
490+
ASSERT_CMPINT32 (sd.max_bson_obj_size, ==, sd_copy->max_bson_obj_size);
491+
ASSERT_CMPINT32 (sd.max_write_batch_size, ==, sd_copy->max_write_batch_size);
492+
ASSERT_CMPINT64 (sd.session_timeout_minutes, ==, sd_copy->session_timeout_minutes);
493+
ASSERT_EQUAL_BSON (&sd.hosts, &sd_copy->hosts);
494+
ASSERT_EQUAL_BSON (&sd.passives, &sd_copy->passives);
495+
ASSERT_EQUAL_BSON (&sd.arbiters, &sd_copy->arbiters);
496+
ASSERT_EQUAL_BSON (&sd.tags, &sd_copy->tags);
497+
ASSERT_CMPSTR (sd.current_primary, sd_copy->current_primary);
498+
ASSERT_CMPINT64 (sd.set_version, ==, sd_copy->set_version);
499+
ASSERT_MEMCMP (&sd.election_id, &sd_copy->election_id, (int) sizeof (bson_oid_t));
500+
ASSERT_CMPINT64 (sd.last_write_date_ms, ==, sd_copy->last_write_date_ms);
501+
ASSERT_EQUAL_BSON (&sd.compressors, &sd_copy->compressors);
502+
ASSERT_EQUAL_BSON (&sd.topology_version, &sd_copy->topology_version);
503+
ASSERT_CMPUINT32 (sd.generation, ==, sd_copy->generation);
504+
ASSERT (sd_copy->_generation_map_ != NULL); // Do not compare entries. Just ensure non-NULL.
505+
ASSERT_MEMCMP (&sd.service_id, &sd_copy->service_id, (int) sizeof (bson_oid_t));
506+
ASSERT_CMPINT64 (sd.server_connection_id, ==, sd_copy->server_connection_id);
507+
508+
mongoc_server_description_cleanup (&sd);
509+
mongoc_server_description_destroy (sd_copy);
510+
}
511+
512+
static void
513+
test_server_description_copy (void)
514+
{
515+
const char *hello_mongod = BSON_STR ({
516+
"topologyVersion" : {"processId" : {"$oid" : "6792ef87965dee8797402adb"}, "counter" : 6},
517+
"hosts" : ["localhost:27017"],
518+
"setName" : "rs0",
519+
"setVersion" : 1,
520+
"isWritablePrimary" : true,
521+
"secondary" : false,
522+
"primary" : "localhost:27017",
523+
"me" : "localhost:27017",
524+
"electionId" : {"$oid" : "7fffffff0000000000000016"},
525+
"lastWrite" : {
526+
"opTime" : {"ts" : {"$timestamp" : {"t" : 1737682844, "i" : 1}}, "t" : 22},
527+
"lastWriteDate" : {"$date" : "2025-01-24T01:40:44Z"},
528+
"majorityOpTime" : {"ts" : {"$timestamp" : {"t" : 1737682844, "i" : 1}}, "t" : 22},
529+
"majorityWriteDate" : {"$date" : "2025-01-24T01:40:44Z"}
530+
},
531+
"maxBsonObjectSize" : 16777216,
532+
"maxMessageSizeBytes" : 48000000,
533+
"maxWriteBatchSize" : 100000,
534+
"localTime" : {"$date" : "2025-01-24T01:40:51.968Z"},
535+
"logicalSessionTimeoutMinutes" : 30,
536+
"connectionId" : 13,
537+
"minWireVersion" : 0,
538+
"maxWireVersion" : 25,
539+
"readOnly" : false,
540+
"ok" : 1.0,
541+
"$clusterTime" : {
542+
"clusterTime" : {"$timestamp" : {"t" : 1737682844, "i" : 1}},
543+
"signature" :
544+
{"hash" : {"$binary" : {"base64" : "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "subType" : "00"}}, "keyId" : 0}
545+
},
546+
"operationTime" : {"$timestamp" : {"t" : 1737682844, "i" : 1}}
547+
});
548+
549+
const char *hello_mongos = BSON_STR ({
550+
"isWritablePrimary" : true,
551+
"msg" : "isdbgrid",
552+
"topologyVersion" : {"processId" : {"$oid" : "6791af1181771f367602ec40"}, "counter" : 0},
553+
"maxBsonObjectSize" : 16777216,
554+
"maxMessageSizeBytes" : 48000000,
555+
"maxWriteBatchSize" : 100000,
556+
"localTime" : {"$date" : "2025-01-24T01:24:57.217Z"},
557+
"logicalSessionTimeoutMinutes" : 30,
558+
"connectionId" : 3310,
559+
"maxWireVersion" : 25,
560+
"minWireVersion" : 0,
561+
"ok" : 1.0,
562+
"$clusterTime" : {
563+
"clusterTime" : {"$timestamp" : {"t" : 1737681896, "i" : 1}},
564+
"signature" :
565+
{"hash" : {"$binary" : {"base64" : "AAAAAAAAAAAAAAAAAAAAAAAAAAA=", "subType" : "00"}}, "keyId" : 0}
566+
},
567+
"operationTime" : {"$timestamp" : {"t" : 1737681896, "i" : 1}}
568+
});
569+
570+
test_copy (hello_mongod);
571+
test_copy (hello_mongos);
572+
}
573+
461574
void
462575
test_server_description_install (TestSuite *suite)
463576
{
@@ -470,4 +583,5 @@ test_server_description_install (TestSuite *suite)
470583
TestSuite_Add (suite, "/server_description/legacy_hello_ok", test_server_description_legacy_hello_ok);
471584
TestSuite_Add (suite, "/server_description/connection_id", test_server_description_connection_id);
472585
TestSuite_Add (suite, "/server_description/hello_type_error", test_server_description_hello_type_error);
586+
TestSuite_Add (suite, "/server_description/copy", test_server_description_copy);
473587
}

0 commit comments

Comments
 (0)