Skip to content

Commit 6f73903

Browse files
committed
CDRIVER-3324 Session not pinned when not relying on server selection
1 parent 5974268 commit 6f73903

File tree

3 files changed

+139
-3
lines changed

3 files changed

+139
-3
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ mongoc_server_stream_t *
133133
mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster,
134134
uint32_t server_id,
135135
bool reconnect_ok,
136-
const mongoc_client_session_t *cs,
136+
mongoc_client_session_t *cs,
137137
bson_t *reply,
138138
bson_error_t *error);
139139

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,7 +1883,7 @@ mongoc_server_stream_t *
18831883
mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster,
18841884
uint32_t server_id,
18851885
bool reconnect_ok,
1886-
const mongoc_client_session_t *cs,
1886+
mongoc_client_session_t *cs,
18871887
bson_t *reply,
18881888
bson_error_t *error)
18891889
{
@@ -1915,6 +1915,17 @@ mongoc_cluster_stream_for_server (mongoc_cluster_t *cluster,
19151915
mongoc_cluster_disconnect_node (cluster, server_id, true, error);
19161916
}
19171917

1918+
if (_in_sharded_txn (cs)) {
1919+
_mongoc_client_session_pin (cs, server_id);
1920+
} else {
1921+
/* Transactions Spec: Additionally, any non-transaction operation using
1922+
* a pinned ClientSession MUST unpin the session and the operation MUST
1923+
* perform normal server selection. */
1924+
if (cs && !_mongoc_client_session_in_txn_or_ending (cs)) {
1925+
_mongoc_client_session_unpin (cs);
1926+
}
1927+
}
1928+
19181929
RETURN (server_stream);
19191930
}
19201931

@@ -2179,7 +2190,9 @@ _mongoc_cluster_select_server_id (mongoc_client_session_t *cs,
21792190
if (!server_id) {
21802191
server_id = mongoc_topology_select_server_id (
21812192
topology, optype, read_prefs, error);
2182-
_mongoc_client_session_pin (cs, server_id);
2193+
if (server_id) {
2194+
_mongoc_client_session_pin (cs, server_id);
2195+
}
21832196
}
21842197
} else {
21852198
server_id =

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

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,121 @@ test_transaction_recovery_token_cleared (void *ctx)
852852
mongoc_client_destroy (client);
853853
}
854854

855+
static void
856+
test_selected_server_is_pinned_to_mongos (void *ctx)
857+
{
858+
mongoc_uri_t *uri = NULL;
859+
mongoc_client_t *client = NULL;
860+
mongoc_set_t *servers = NULL;
861+
mongoc_transaction_opt_t *txn_opts = NULL;
862+
mongoc_session_opt_t *session_opts = NULL;
863+
mongoc_client_session_t *session = NULL;
864+
mongoc_server_stream_t *server_stream = NULL;
865+
bson_error_t error;
866+
bson_t reply;
867+
bson_t *insert_opts = NULL;
868+
mongoc_database_t *db = NULL;
869+
mongoc_collection_t *coll = NULL;
870+
bool r;
871+
uint32_t expected_id;
872+
uint32_t actual_id;
873+
mongoc_server_description_t *sd = NULL;
874+
int i;
875+
876+
uri = test_framework_get_uri ();
877+
ASSERT_OR_PRINT (
878+
mongoc_uri_upsert_host_and_port (uri, "localhost:27018", &error), error);
879+
880+
client = mongoc_client_new_from_uri (uri);
881+
BSON_ASSERT (client);
882+
883+
txn_opts = mongoc_transaction_opts_new ();
884+
session_opts = mongoc_session_opts_new ();
885+
886+
session = mongoc_client_start_session (client, session_opts, &error);
887+
ASSERT_OR_PRINT (session, error);
888+
889+
/* set the server id to an arbitrary value */
890+
_mongoc_client_session_pin (session, 42);
891+
BSON_ASSERT (42 == mongoc_client_session_get_server_id (session));
892+
893+
/* starting a transaction should clear the server id */
894+
r = mongoc_client_session_start_transaction (session, txn_opts, &error);
895+
ASSERT_OR_PRINT (r, error);
896+
BSON_ASSERT (0 == mongoc_client_session_get_server_id (session));
897+
898+
expected_id = mongoc_topology_select_server_id (
899+
client->topology, MONGOC_SS_WRITE, NULL, &error);
900+
ASSERT_OR_PRINT (expected_id, error);
901+
902+
/* session should still be unpinned */
903+
BSON_ASSERT (0 == mongoc_client_session_get_server_id (session));
904+
905+
/* should pin to the expected server id */
906+
server_stream = mongoc_cluster_stream_for_server (
907+
&client->cluster, expected_id, true, session, NULL, &error);
908+
ASSERT_OR_PRINT (server_stream, error);
909+
ASSERT_CMPINT32 (
910+
expected_id, ==, mongoc_client_session_get_server_id (session));
911+
912+
db = mongoc_client_get_database (client, "db");
913+
coll = mongoc_database_create_collection (db, "coll", NULL, &error);
914+
915+
insert_opts = bson_new ();
916+
r = mongoc_client_session_append (session, insert_opts, &error);
917+
ASSERT_OR_PRINT (r, error);
918+
919+
/* this should not override the expected server id */
920+
r = mongoc_collection_insert_one (
921+
coll, tmp_bson ("{}"), insert_opts, NULL, &error);
922+
ASSERT_OR_PRINT (r, error);
923+
actual_id = mongoc_client_session_get_server_id (session);
924+
925+
ASSERT_CMPINT32 (actual_id, ==, expected_id);
926+
927+
/* get a valid server id that's different from the pinned server id */
928+
servers = client->topology->description.servers;
929+
for (i = 0; i < servers->items_len; i++) {
930+
sd = (mongoc_server_description_t *) mongoc_set_get_item (servers, i);
931+
if (sd && sd->id != actual_id) {
932+
break;
933+
}
934+
}
935+
936+
/* attempting to pin to a different but valid server id should fail */
937+
BSON_ASSERT (sd);
938+
r = mongoc_client_command_with_opts (
939+
client,
940+
"db",
941+
tmp_bson ("{'ping': 1}"),
942+
NULL,
943+
tmp_bson ("{'serverId': %d, 'sessionId': {'$numberLong': '%ld'}}",
944+
sd->id,
945+
session->client_session_id),
946+
&reply,
947+
&error);
948+
949+
BSON_ASSERT (!r);
950+
ASSERT_ERROR_CONTAINS (
951+
error,
952+
MONGOC_ERROR_COMMAND,
953+
MONGOC_ERROR_SERVER_SELECTION_INVALID_ID,
954+
"Requested server id does not matched pinned server id");
955+
956+
r = mongoc_client_session_abort_transaction (session, &error);
957+
ASSERT_OR_PRINT (r, error);
958+
959+
bson_destroy (insert_opts);
960+
mongoc_collection_destroy (coll);
961+
mongoc_database_destroy (db);
962+
mongoc_session_opts_destroy (session_opts);
963+
mongoc_transaction_opts_destroy (txn_opts);
964+
mongoc_server_stream_cleanup (server_stream);
965+
mongoc_client_session_destroy (session);
966+
mongoc_client_destroy (client);
967+
mongoc_uri_destroy (uri);
968+
}
969+
855970
void
856971
test_transactions_install (TestSuite *suite)
857972
{
@@ -919,4 +1034,12 @@ test_transactions_install (TestSuite *suite)
9191034
test_framework_skip_if_no_crypto,
9201035
test_framework_skip_if_max_wire_version_less_than_8,
9211036
test_framework_skip_if_not_mongos);
1037+
TestSuite_AddFull (suite,
1038+
"/transactions/selected_server_pinned_to_mongos",
1039+
test_selected_server_is_pinned_to_mongos,
1040+
NULL,
1041+
NULL,
1042+
test_framework_skip_if_no_sessions,
1043+
test_framework_skip_if_max_wire_version_less_than_8,
1044+
test_framework_skip_if_not_mongos);
9221045
}

0 commit comments

Comments
 (0)