Skip to content

Commit f14370e

Browse files
authored
CDRIVER-4193 Ensure OP_MSG for handshakes and fix RPC op_egress counters (#1256)
* Move SHM count function into mongoc-counters-private.h * Declare test_framework_has_compressors in test-libmongoc.h * Allow /counters/op_msg and /counters/op_compressed with auth * Add _mongoc_rpc_op_egress_inc * CDRIVER-4193 RTT thread should also use hello if serverApi is given * Do not increment RPC op_egress counters in mock server * Add /counters/rpc/op_egress tests * CDRIVER-4121 Add /counters/rpc/egress/auth * CDRIVER-4622 RPC op_egress increment: mongoc_async_cmd_new -> mongoc_async_cmd_phase_send * Add mongoc_<object>_uses_loadbalanced * CDRIVER-4265 Use OP_MSG for handshakes when loadBalanced=true * Clarify meaning of RPC op_egress counters in documentation
1 parent 49318c2 commit f14370e

17 files changed

+1389
-113
lines changed

src/libmongoc/doc/basic-troubleshooting.rst

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ The following is a short list of things to check when you have a problem.
1717
Performance Counters
1818
--------------------
1919

20-
The MongoDB C driver comes with an optional unique feature to help developers and sysadmins troubleshoot problems in production.
21-
Performance counters are available for each process using the driver.
20+
The MongoDB C Driver comes with an optional and unique feature to help developers and sysadmins troubleshoot problems in production.
21+
Performance counters are available for each process using the C Driver.
2222
If available, the counters can be accessed outside of the application process via a shared memory segment.
23-
This means that you can graph statistics about your application process easily from tools like Munin or Nagios.
24-
Your author often uses ``watch --interval=0.5 -d mongoc-stat $PID`` to monitor an application.
23+
The counters may be used graph statistics about your application process easily from tools like Munin or Nagios.
24+
For example, the command ``watch --interval=0.5 -d mongoc-stat $PID`` may be used to monitor an application.
2525

26-
Performance counters are only available on Linux platforms and macOS arm64 platforms supporting shared memory segments.
27-
On supported platforms they are enabled by default.
28-
Applications can be built without the counters by specifying the cmake option ``-DENABLE_SHM_COUNTERS=OFF``. Additionally, if
29-
performance counters are already compiled, they can be disabled at runtime by specifying the environment variable ``MONGOC_DISABLE_SHM``.
26+
Performance counters are only available on Linux platforms and macOS arm64 platforms that support shared memory segments.
27+
On supported platforms, they are enabled by default.
28+
Applications can be built without the counters by specifying the cmake option ``-DENABLE_SHM_COUNTERS=OFF``.
29+
Additionally, if performance counters are already compiled, they can be disabled at runtime by specifying the environment variable ``MONGOC_DISABLE_SHM``.
3030

3131
Performance counters keep track of the following:
3232

@@ -37,6 +37,10 @@ Performance counters keep track of the following:
3737
* Authentication successes and failures.
3838
* Number of wire protocol errors.
3939

40+
.. note::
41+
An operation is considered "sent" when one or more bytes of the corresponding message is written to the stream, regardless of whether the entire message is successfully written or if the operation ultimately succeeds or fails.
42+
This does not include bytes that may be written during the stream connection process, such as TLS handshake messages.
43+
4044
To access counters for a given process, simply provide the process id to the ``mongoc-stat`` program installed with the MongoDB C Driver.
4145

4246
.. code-block:: none

src/libmongoc/src/mongoc/mongoc-async-cmd.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ _mongoc_async_cmd_phase_send (mongoc_async_cmd_t *acmd)
347347
used_temp_iovec = true;
348348
}
349349

350+
_mongoc_rpc_op_egress_inc (&acmd->rpc);
350351
bytes = mongoc_stream_writev (acmd->stream, iovec, niovec, 0);
351352

352353
if (used_temp_iovec) {

src/libmongoc/src/mongoc/mongoc-client-private.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,17 @@ mongoc_client_connect (bool buffered,
226226
bson_error_t *error);
227227

228228

229-
/* Returns true if a versioned server API has been selected,
230-
* otherwise returns false. */
229+
/* Returns true if a versioned server API has been selected, otherwise returns
230+
* false. */
231231
bool
232232
mongoc_client_uses_server_api (const mongoc_client_t *client);
233233

234+
235+
/* Returns true if load balancing mode has been selected, otherwise returns
236+
* false. */
237+
bool
238+
mongoc_client_uses_loadbalanced (const mongoc_client_t *client);
239+
234240
BSON_END_DECLS
235241

236242
#endif /* MONGOC_CLIENT_PRIVATE_H */

src/libmongoc/src/mongoc/mongoc-client.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3184,3 +3184,9 @@ mongoc_client_uses_server_api (const mongoc_client_t *client)
31843184
{
31853185
return mongoc_topology_uses_server_api (client->topology);
31863186
}
3187+
3188+
bool
3189+
mongoc_client_uses_loadbalanced (const mongoc_client_t *client)
3190+
{
3191+
return mongoc_topology_uses_loadbalanced (client->topology);
3192+
}

src/libmongoc/src/mongoc/mongoc-cluster-private.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,11 +234,16 @@ _mongoc_cluster_get_auth_cmd_x509 (const mongoc_uri_t *uri,
234234
bson_t *cmd /* OUT */,
235235
bson_error_t *error /* OUT */);
236236

237-
/* Returns true if a versioned server API has been selected,
238-
* otherwise returns false. */
237+
/* Returns true if a versioned server API has been selected, otherwise returns
238+
* false. */
239239
bool
240240
mongoc_cluster_uses_server_api (const mongoc_cluster_t *cluster);
241241

242+
/* Returns true if load balancing mode has been selected, otherwise returns
243+
* false. */
244+
bool
245+
mongoc_cluster_uses_loadbalanced (const mongoc_cluster_t *cluster);
246+
242247
#ifdef MONGOC_ENABLE_CRYPTO
243248
void
244249
_mongoc_cluster_init_scram (const mongoc_cluster_t *cluster,

src/libmongoc/src/mongoc/mongoc-cluster.c

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ mongoc_cluster_run_command_opquery (mongoc_cluster_t *cluster,
312312
/*
313313
* send and receive
314314
*/
315+
_mongoc_rpc_op_egress_inc (&rpc);
315316
if (!_mongoc_stream_writev_full (stream,
316317
cluster->iov.data,
317318
cluster->iov.len,
@@ -635,6 +636,14 @@ mongoc_cluster_run_command_monitored (mongoc_cluster_t *cluster,
635636
}
636637

637638

639+
static bool
640+
_should_use_op_msg (const mongoc_cluster_t *cluster)
641+
{
642+
return mongoc_cluster_uses_server_api (cluster) ||
643+
mongoc_cluster_uses_loadbalanced (cluster);
644+
}
645+
646+
638647
/*
639648
*--------------------------------------------------------------------------
640649
*
@@ -676,7 +685,7 @@ mongoc_cluster_run_command_private (mongoc_cluster_t *cluster,
676685

677686
server_stream = cmd->server_stream;
678687

679-
if (mongoc_cluster_uses_server_api (cluster) ||
688+
if (_should_use_op_msg (cluster) ||
680689
server_stream->sd->max_wire_version >= WIRE_VERSION_MIN) {
681690
retval = mongoc_cluster_run_opmsg (cluster, cmd, reply, error);
682691
} else {
@@ -818,24 +827,22 @@ _stream_run_hello (mongoc_cluster_t *cluster,
818827
to either an op_msg or op_query: */
819828
memset (&hello_cmd, 0, sizeof (hello_cmd));
820829

821-
822-
hello_cmd.db_name = "admin";
823-
hello_cmd.command = &handshake_command;
824-
hello_cmd.command_name = _mongoc_get_command_name (&handshake_command);
825-
hello_cmd.server_stream = server_stream;
826-
827-
hello_cmd.is_acknowledged = true;
828-
829830
/* Use OP_QUERY for the handshake, unless the user has specified an
830831
* API version; the correct hello_cmd has already been selected: */
831-
if (!mongoc_cluster_uses_server_api (cluster)) {
832+
if (!_should_use_op_msg (cluster)) {
832833
/* Complete OPCODE_QUERY setup: */
833834
hello_cmd.query_flags = MONGOC_QUERY_SECONDARY_OK;
834835
} else {
835836
/* We're using OP_MSG, and require some additional doctoring: */
836837
bson_append_utf8 (&handshake_command, "$db", 3, "admin", 5);
837838
}
838839

840+
hello_cmd.db_name = "admin";
841+
hello_cmd.command = &handshake_command;
842+
hello_cmd.command_name = _mongoc_get_command_name (&handshake_command);
843+
hello_cmd.server_stream = server_stream;
844+
hello_cmd.is_acknowledged = true;
845+
839846
if (!mongoc_cluster_run_command_private (
840847
cluster, &hello_cmd, &reply, error)) {
841848
if (negotiate_sasl_supported_mechs) {
@@ -1345,9 +1352,17 @@ _mongoc_cluster_auth_node_x509 (mongoc_cluster_t *cluster,
13451352
bool
13461353
mongoc_cluster_uses_server_api (const mongoc_cluster_t *cluster)
13471354
{
1355+
BSON_ASSERT_PARAM (cluster);
13481356
return mongoc_client_uses_server_api (cluster->client);
13491357
}
13501358

1359+
bool
1360+
mongoc_cluster_uses_loadbalanced (const mongoc_cluster_t *cluster)
1361+
{
1362+
BSON_ASSERT_PARAM (cluster);
1363+
return mongoc_client_uses_loadbalanced (cluster->client);
1364+
}
1365+
13511366
#ifdef MONGOC_ENABLE_CRYPTO
13521367
void
13531368
_mongoc_cluster_init_scram (const mongoc_cluster_t *cluster,
@@ -3287,6 +3302,7 @@ mongoc_cluster_legacy_rpc_sendv_to_server (
32873302
GOTO (done);
32883303
}
32893304

3305+
_mongoc_rpc_op_egress_inc (rpc);
32903306
if (!_mongoc_stream_writev_full (server_stream->stream,
32913307
cluster->iov.data,
32923308
cluster->iov.len,
@@ -3561,11 +3577,14 @@ mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster,
35613577
}
35623578
}
35633579
}
3580+
3581+
_mongoc_rpc_op_egress_inc (&rpc);
35643582
ok = _mongoc_stream_writev_full (server_stream->stream,
35653583
(mongoc_iovec_t *) cluster->iov.data,
35663584
cluster->iov.len,
35673585
cluster->sockettimeoutms,
35683586
error);
3587+
35693588
if (!ok) {
35703589
/* add info about the command to writev_full's error message */
35713590
RUN_CMD_ERR_DECORATE;

src/libmongoc/src/mongoc/mongoc-cmd.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,7 @@ mongoc_cmd_parts_assemble (mongoc_cmd_parts_t *parts,
837837
}
838838

839839
if (mongoc_client_uses_server_api (parts->client) ||
840+
mongoc_client_uses_loadbalanced (parts->client) ||
840841
server_stream->sd->max_wire_version >= WIRE_VERSION_MIN) {
841842
if (!bson_has_field (parts->body, "$db")) {
842843
BSON_APPEND_UTF8 (&parts->extra, "$db", parts->assembled.db_name);

src/libmongoc/src/mongoc/mongoc-counters-private.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,23 @@ enum {
179179
bson_atomic_int64_exchange (counter, 0, bson_memory_order_seq_cst); \
180180
} \
181181
bson_atomic_thread_fence (); \
182+
} \
183+
static BSON_INLINE int32_t mongoc_counter_##ident##_count (void) \
184+
{ \
185+
int32_t _sum = 0; \
186+
uint32_t _i; \
187+
for (_i = 0; _i < _mongoc_get_cpu_count (); _i++) { \
188+
const int64_t *counter = \
189+
&BSON_CONCAT (__mongoc_counter_, ident) \
190+
.cpus[_i] \
191+
.slots[BSON_CONCAT (COUNTER_, ident) % SLOTS_PER_CACHELINE]; \
192+
_sum += bson_atomic_int64_fetch (counter, bson_memory_order_seq_cst); \
193+
} \
194+
return _sum; \
182195
}
183196
#include "mongoc-counters.defs"
184197
#undef COUNTER
198+
185199
#else
186200
/* when counters are disabled, these functions are no-ops */
187201
#define COUNTER(ident, Category, Name, Description) \
@@ -196,6 +210,9 @@ enum {
196210
} \
197211
static BSON_INLINE void mongoc_counter_##ident##_reset (void) \
198212
{ \
213+
} \
214+
static BSON_INLINE void mongoc_counter_##ident##_count (void) \
215+
{ \
199216
}
200217
#include "mongoc-counters.defs"
201218
#undef COUNTER

src/libmongoc/src/mongoc/mongoc-rpc-private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ BSON_STATIC_ASSERT2 (sizeof_reply_header,
136136
void
137137
_mongoc_rpc_gather (mongoc_rpc_t *rpc, mongoc_array_t *array);
138138
void
139+
_mongoc_rpc_op_egress_inc (const mongoc_rpc_t *rpc);
140+
void
139141
_mongoc_rpc_swab_to_le (mongoc_rpc_t *rpc);
140142
void
141143
_mongoc_rpc_swab_from_le (mongoc_rpc_t *rpc);

src/libmongoc/src/mongoc/mongoc-rpc.c

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -577,67 +577,44 @@
577577
#undef CHECKSUM_FIELD
578578

579579

580-
/*
581-
*--------------------------------------------------------------------------
582-
*
583-
* _mongoc_rpc_gather --
584-
*
585-
* Takes a (native endian) rpc struct and gathers the buffer.
586-
* Caller should swab to little endian after calling gather.
587-
*
588-
* Gather, swab, compress write.
589-
* Read, scatter, uncompress, swab
590-
*
591-
*--------------------------------------------------------------------------
592-
*/
593-
594580
void
595581
_mongoc_rpc_gather (mongoc_rpc_t *rpc, mongoc_array_t *array)
596582
{
597-
mongoc_counter_op_egress_total_inc ();
598583
switch ((mongoc_opcode_t) rpc->header.opcode) {
599584
case MONGOC_OPCODE_REPLY:
600585
_mongoc_rpc_gather_reply (&rpc->reply, &rpc->header, array);
601586
return;
602587

603588
case MONGOC_OPCODE_MSG:
604589
_mongoc_rpc_gather_msg (&rpc->msg, &rpc->header, array);
605-
mongoc_counter_op_egress_msg_inc ();
606590
return;
607591

608592
case MONGOC_OPCODE_UPDATE:
609593
_mongoc_rpc_gather_update (&rpc->update, &rpc->header, array);
610-
mongoc_counter_op_egress_update_inc ();
611594
return;
612595

613596
case MONGOC_OPCODE_INSERT:
614597
_mongoc_rpc_gather_insert (&rpc->insert, &rpc->header, array);
615-
mongoc_counter_op_egress_insert_inc ();
616598
return;
617599

618600
case MONGOC_OPCODE_QUERY:
619601
_mongoc_rpc_gather_query (&rpc->query, &rpc->header, array);
620-
mongoc_counter_op_egress_query_inc ();
621602
return;
622603

623604
case MONGOC_OPCODE_GET_MORE:
624605
_mongoc_rpc_gather_get_more (&rpc->get_more, &rpc->header, array);
625-
mongoc_counter_op_egress_getmore_inc ();
626606
return;
627607

628608
case MONGOC_OPCODE_DELETE:
629609
_mongoc_rpc_gather_delete (&rpc->delete_, &rpc->header, array);
630-
mongoc_counter_op_egress_delete_inc ();
631610
return;
632611

633612
case MONGOC_OPCODE_KILL_CURSORS:
634613
_mongoc_rpc_gather_kill_cursors (&rpc->kill_cursors, &rpc->header, array);
635-
mongoc_counter_op_egress_killcursors_inc ();
636614
return;
637615

638616
case MONGOC_OPCODE_COMPRESSED:
639617
_mongoc_rpc_gather_compressed (&rpc->compressed, &rpc->header, array);
640-
mongoc_counter_op_egress_compressed_inc ();
641618
return;
642619

643620
default:
@@ -648,6 +625,67 @@ _mongoc_rpc_gather (mongoc_rpc_t *rpc, mongoc_array_t *array)
648625
}
649626

650627

628+
void
629+
_mongoc_rpc_op_egress_inc (const mongoc_rpc_t *rpc)
630+
{
631+
mongoc_opcode_t opcode =
632+
(mongoc_opcode_t) BSON_UINT32_FROM_LE (rpc->header.opcode);
633+
634+
if (opcode == MONGOC_OPCODE_COMPRESSED) {
635+
mongoc_counter_op_egress_compressed_inc ();
636+
mongoc_counter_op_egress_total_inc ();
637+
638+
opcode = (mongoc_opcode_t) BSON_UINT32_FROM_LE (
639+
rpc->compressed.original_opcode);
640+
}
641+
642+
mongoc_counter_op_egress_total_inc ();
643+
644+
switch (opcode) {
645+
case MONGOC_OPCODE_REPLY:
646+
return;
647+
648+
case MONGOC_OPCODE_MSG:
649+
mongoc_counter_op_egress_msg_inc ();
650+
return;
651+
652+
case MONGOC_OPCODE_UPDATE:
653+
mongoc_counter_op_egress_update_inc ();
654+
return;
655+
656+
case MONGOC_OPCODE_INSERT:
657+
mongoc_counter_op_egress_insert_inc ();
658+
return;
659+
660+
case MONGOC_OPCODE_QUERY:
661+
mongoc_counter_op_egress_query_inc ();
662+
return;
663+
664+
case MONGOC_OPCODE_GET_MORE:
665+
mongoc_counter_op_egress_getmore_inc ();
666+
return;
667+
668+
case MONGOC_OPCODE_DELETE:
669+
mongoc_counter_op_egress_delete_inc ();
670+
return;
671+
672+
case MONGOC_OPCODE_KILL_CURSORS:
673+
mongoc_counter_op_egress_killcursors_inc ();
674+
return;
675+
676+
case MONGOC_OPCODE_COMPRESSED:
677+
MONGOC_WARNING ("Compressed an OP_COMPRESSED message!?");
678+
BSON_ASSERT (false);
679+
return;
680+
681+
default:
682+
MONGOC_WARNING ("Unknown rpc type: 0x%08x", opcode);
683+
BSON_ASSERT (false);
684+
break;
685+
}
686+
}
687+
688+
651689
void
652690
_mongoc_rpc_swab_to_le (mongoc_rpc_t *rpc)
653691
{

0 commit comments

Comments
 (0)