Skip to content

Commit b39e2eb

Browse files
CDRIVER-4718 store recoveryToken for Load Balanced topology (#1417)
* add regression test * format mongoc-cluster.c * store recoveryToken for loadBalanced topology * make `_in_sharded_txn` static * use `static` Co-authored-by: Kyle Kloberdanz <[email protected]> * removing redundant calls to `_mongoc_topology_get_type` Co-authored-by: Kyle Kloberdanz <[email protected]>
1 parent 2baa45c commit b39e2eb

File tree

2 files changed

+120
-3
lines changed

2 files changed

+120
-3
lines changed

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

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,14 +493,32 @@ mongoc_cluster_run_command_opquery (mongoc_cluster_t *cluster,
493493
RETURN (ret);
494494
}
495495

496-
bool
496+
static bool
497497
_in_sharded_txn (const mongoc_client_session_t *session)
498498
{
499499
return session && _mongoc_client_session_in_txn_or_ending (session) &&
500500
_mongoc_topology_get_type (session->client->topology) ==
501501
MONGOC_TOPOLOGY_SHARDED;
502502
}
503503

504+
static bool
505+
_in_sharded_or_loadbalanced_txn (const mongoc_client_session_t *session)
506+
{
507+
if (!session) {
508+
return false;
509+
}
510+
511+
if (!_mongoc_client_session_in_txn_or_ending (session)) {
512+
return false;
513+
}
514+
515+
mongoc_topology_description_type_t type =
516+
_mongoc_topology_get_type (session->client->topology);
517+
518+
return (type == MONGOC_TOPOLOGY_SHARDED) ||
519+
(type == MONGOC_TOPOLOGY_LOAD_BALANCED);
520+
}
521+
504522
static void
505523
_handle_txn_error_labels (bool cmd_ret,
506524
const bson_error_t *cmd_err,
@@ -655,7 +673,7 @@ mongoc_cluster_run_command_monitored (mongoc_cluster_t *cluster,
655673

656674
_handle_txn_error_labels (retval, error, cmd, reply);
657675

658-
if (retval && _in_sharded_txn (cmd->session) &&
676+
if (retval && _in_sharded_or_loadbalanced_txn (cmd->session) &&
659677
bson_iter_init_find (&iter, reply, "recoveryToken")) {
660678
bson_destroy (cmd->session->recovery_token);
661679
if (BSON_ITER_HOLDS_DOCUMENT (&iter)) {
@@ -893,7 +911,7 @@ _stream_run_hello (mongoc_cluster_t *cluster,
893911
if (negotiate_sasl_supported_mechs) {
894912
bsonParse (reply,
895913
find (allOf (key ("ok"), isFalse), //
896-
do({
914+
do ({
897915
/* hello response returned ok: 0. According to
898916
* auth spec: "If the hello of the MongoDB
899917
* Handshake fails with an error, drivers MUST

src/libmongoc/tests/test-mongoc-loadbalanced.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,98 @@ skip_if_not_loadbalanced (void)
823823
return test_framework_is_loadbalanced () ? 1 : 0;
824824
}
825825

826+
static void
827+
store_last_command_started_callback (const mongoc_apm_command_started_t *event)
828+
{
829+
bson_t **last_command = mongoc_apm_command_started_get_context (event);
830+
const bson_t *cmd = mongoc_apm_command_started_get_command (event);
831+
bson_destroy (*last_command);
832+
*last_command = bson_copy (cmd);
833+
}
834+
835+
// `test_loadbalanced_sends_recoveryToken` is a regression test for
836+
// CDRIVER-4718. Ensure that a `recoveryToken` is included in the outgoing
837+
// `commitTransaction` and `abortTransaction` commands when connected to a load
838+
// balanced cluster.
839+
static void
840+
test_loadbalanced_sends_recoveryToken (void *unused)
841+
{
842+
mongoc_client_t *client;
843+
bson_error_t error;
844+
bson_t *last_command = NULL;
845+
846+
BSON_UNUSED (unused);
847+
848+
client = test_framework_new_default_client ();
849+
// Set a callback to store the most recent command started.
850+
{
851+
mongoc_apm_callbacks_t *cbs = mongoc_apm_callbacks_new ();
852+
mongoc_apm_set_command_started_cb (cbs,
853+
store_last_command_started_callback);
854+
mongoc_client_set_apm_callbacks (client, cbs, &last_command);
855+
mongoc_apm_callbacks_destroy (cbs);
856+
}
857+
858+
mongoc_client_session_t *session =
859+
mongoc_client_start_session (client, NULL /* opts */, &error);
860+
ASSERT_OR_PRINT (session, error);
861+
862+
mongoc_collection_t *coll =
863+
mongoc_client_get_collection (client, "db", "coll");
864+
865+
// Commit a transaction. Expect `commitTransaction` to include
866+
// `recoveryToken`.
867+
{
868+
bool ok = mongoc_client_session_start_transaction (
869+
session, NULL /* opts */, &error);
870+
ASSERT_OR_PRINT (ok, error);
871+
872+
bson_t *insert_opts = tmp_bson ("{}");
873+
ok = mongoc_client_session_append (session, insert_opts, &error);
874+
ASSERT_OR_PRINT (ok, error);
875+
876+
ok = mongoc_collection_insert_one (
877+
coll, tmp_bson ("{}"), insert_opts, NULL, &error);
878+
ASSERT_OR_PRINT (ok, error);
879+
880+
ok = mongoc_client_session_commit_transaction (
881+
session, NULL /* reply */, &error);
882+
ASSERT_OR_PRINT (ok, error);
883+
884+
ASSERT_MATCH (
885+
last_command,
886+
"{'commitTransaction': 1, 'recoveryToken': { '$exists': true } }");
887+
}
888+
889+
// Abort a transaction. Expect `abortTransaction` to include
890+
// `recoveryToken`.
891+
{
892+
bool ok = mongoc_client_session_start_transaction (
893+
session, NULL /* opts */, &error);
894+
ASSERT_OR_PRINT (ok, error);
895+
896+
bson_t *insert_opts = tmp_bson ("{}");
897+
ok = mongoc_client_session_append (session, insert_opts, &error);
898+
ASSERT_OR_PRINT (ok, error);
899+
900+
ok = mongoc_collection_insert_one (
901+
coll, tmp_bson ("{}"), insert_opts, NULL, &error);
902+
ASSERT_OR_PRINT (ok, error);
903+
904+
ok = mongoc_client_session_abort_transaction (session, &error);
905+
ASSERT_OR_PRINT (ok, error);
906+
907+
ASSERT_MATCH (
908+
last_command,
909+
"{'abortTransaction': 1, 'recoveryToken': { '$exists': true } }");
910+
}
911+
912+
mongoc_collection_destroy (coll);
913+
mongoc_client_session_destroy (session);
914+
mongoc_client_destroy (client);
915+
bson_destroy (last_command);
916+
}
917+
826918
void
827919
test_loadbalanced_install (TestSuite *suite)
828920
{
@@ -893,4 +985,11 @@ test_loadbalanced_install (TestSuite *suite)
893985
suite,
894986
"/loadbalanced/post_handshake_error_clears_pool",
895987
test_post_handshake_error_clears_pool);
988+
989+
TestSuite_AddFull (suite,
990+
"/loadbalanced/sends_recoveryToken",
991+
test_loadbalanced_sends_recoveryToken,
992+
NULL /* ctx */,
993+
NULL /* dtor */,
994+
skip_if_not_loadbalanced);
896995
}

0 commit comments

Comments
 (0)