Skip to content

Commit f89afb0

Browse files
committed
CDRIVER-3587 do not reuse invalid server stream
1 parent 4498a73 commit f89afb0

File tree

5 files changed

+71
-6
lines changed

5 files changed

+71
-6
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2962,8 +2962,15 @@ _mongoc_client_end_sessions (mongoc_client_t *client)
29622962
}
29632963
}
29642964

2965-
bson_destroy (&cmd);
29662965
mongoc_cmd_parts_cleanup (&parts);
2966+
2967+
if (!stream->stream) {
2968+
/* The stream was invalidated as a result of a network error, so we
2969+
* stop sending commands. */
2970+
break;
2971+
}
2972+
2973+
bson_destroy (&cmd);
29672974
}
29682975

29692976
bson_destroy (&cmd);

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2895,7 +2895,7 @@ mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster,
28952895
mongoc_rpc_t rpc;
28962896
int32_t msg_len;
28972897
bool ok;
2898-
const mongoc_server_stream_t *server_stream;
2898+
mongoc_server_stream_t *server_stream;
28992899

29002900
server_stream = cmd->server_stream;
29012901
if (!cmd->command_name) {
@@ -2974,6 +2974,7 @@ mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster,
29742974
RUN_CMD_ERR_DECORATE;
29752975
mongoc_cluster_disconnect_node (
29762976
cluster, server_stream->sd->id, true, error);
2977+
server_stream->stream = NULL;
29772978
bson_free (output);
29782979
network_error_reply (reply, cmd);
29792980
_mongoc_buffer_destroy (&buffer);
@@ -2988,6 +2989,7 @@ mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster,
29882989
RUN_CMD_ERR_DECORATE;
29892990
mongoc_cluster_disconnect_node (
29902991
cluster, server_stream->sd->id, true, error);
2992+
server_stream->stream = NULL;
29912993
bson_free (output);
29922994
network_error_reply (reply, cmd);
29932995
_mongoc_buffer_destroy (&buffer);
@@ -3006,6 +3008,7 @@ mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster,
30063008
server_stream->sd->max_msg_size);
30073009
mongoc_cluster_disconnect_node (
30083010
cluster, server_stream->sd->id, true, error);
3011+
server_stream->stream = NULL;
30093012
bson_free (output);
30103013
network_error_reply (reply, cmd);
30113014
_mongoc_buffer_destroy (&buffer);
@@ -3021,6 +3024,7 @@ mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster,
30213024
RUN_CMD_ERR_DECORATE;
30223025
mongoc_cluster_disconnect_node (
30233026
cluster, server_stream->sd->id, true, error);
3027+
server_stream->stream = NULL;
30243028
bson_free (output);
30253029
network_error_reply (reply, cmd);
30263030
_mongoc_buffer_destroy (&buffer);
@@ -3048,6 +3052,7 @@ mongoc_cluster_run_opmsg (mongoc_cluster_t *cluster,
30483052
"Could not decompress message from server");
30493053
mongoc_cluster_disconnect_node (
30503054
cluster, server_stream->sd->id, true, error);
3055+
server_stream->stream = NULL;
30513056
bson_free (output);
30523057
network_error_reply (reply, cmd);
30533058
_mongoc_buffer_destroy (&buffer);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ typedef struct _mongoc_cmd_t {
5858
const uint8_t *payload;
5959
int32_t payload_size;
6060
const char *payload_identifier;
61-
const mongoc_server_stream_t *server_stream;
61+
mongoc_server_stream_t *server_stream;
6262
int64_t operation_id;
6363
mongoc_client_session_t *session;
6464
bool is_acknowledged;
@@ -123,7 +123,7 @@ mongoc_cmd_parts_append_read_write (mongoc_cmd_parts_t *parts,
123123

124124
bool
125125
mongoc_cmd_parts_assemble (mongoc_cmd_parts_t *parts,
126-
const mongoc_server_stream_t *server_stream,
126+
mongoc_server_stream_t *server_stream,
127127
bson_error_t *error);
128128

129129
bool

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ _is_retryable_read (const mongoc_cmd_parts_t *parts,
786786

787787
bool
788788
mongoc_cmd_parts_assemble (mongoc_cmd_parts_t *parts,
789-
const mongoc_server_stream_t *server_stream,
789+
mongoc_server_stream_t *server_stream,
790790
bson_error_t *error)
791791
{
792792
mongoc_server_description_type_t server_type;
@@ -1086,4 +1086,4 @@ _mongoc_cmd_append_payload_as_array (const mongoc_cmd_t *cmd, bson_t *out)
10861086
}
10871087

10881088
bson_append_array_end (out, &bson);
1089-
}
1089+
}

src/libmongoc/tests/test-mongoc-client-session.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,55 @@ test_mock_end_sessions_pooled (void)
497497
_test_mock_end_sessions (true);
498498
}
499499

500+
/* Test for CDRIVER-3587 - Do not reuse server stream that becomes invalid on
501+
* failure to end session */
502+
static void
503+
test_mock_end_sessions_server_disconnect (void)
504+
{
505+
mock_server_t *server;
506+
mongoc_client_t *client;
507+
bson_error_t error;
508+
mongoc_client_session_t *session[12000];
509+
future_t *future;
510+
uint16_t i;
511+
512+
server = mock_mongos_new (WIRE_VERSION_OP_MSG);
513+
mock_server_run (server);
514+
515+
client = mongoc_client_new_from_uri (mock_server_get_uri (server));
516+
517+
for (i = 0; i < 12000; i++) {
518+
session[i] = mongoc_client_start_session (client, NULL, &error);
519+
ASSERT_OR_PRINT (session[i], error);
520+
}
521+
522+
/* Simulate server failure or network failure. Destroy the mock server here
523+
* rather than at the end of the test so that the 'endSessions' commands fail
524+
* to reach the mock server. */
525+
mock_server_destroy (server);
526+
527+
/* The below calls to mongoc_client_session_destroy () will produce a warning
528+
* regarding the inability to send the 'endSessions' command. */
529+
capture_logs (true);
530+
531+
for (i = 0; i < 12000; i++) {
532+
mongoc_client_session_destroy (session[i]);
533+
}
534+
535+
/* The above loop will add each session back to the session pool. If
536+
* CDRIVER-3587 has not been fixed, the mongoc_client_destroy () call below
537+
* will create 'endSessions' commands which will be sent but fail to reach
538+
* the server; the associated server stream will not be correctly
539+
* invalidated. Subsequent reuse of the stream, as in the attempt to send
540+
* the second batch of 10,000 during the attempt to destroy the client, will
541+
* trigger a segfault. */
542+
543+
future = future_client_destroy (client);
544+
545+
future_wait (future);
546+
future_destroy (future);
547+
}
548+
500549
typedef struct {
501550
int started_calls;
502551
int succeeded_calls;
@@ -2687,6 +2736,10 @@ test_session_install (TestSuite *suite)
26872736
"/Session/end/mock/pooled",
26882737
test_mock_end_sessions_pooled,
26892738
test_framework_skip_if_no_crypto);
2739+
TestSuite_AddMockServerTest (suite,
2740+
"/Session/end/mock/disconnected",
2741+
test_mock_end_sessions_server_disconnect,
2742+
test_framework_skip_if_no_crypto);
26902743
TestSuite_AddFull (suite,
26912744
"/Session/end/single",
26922745
test_end_sessions_single,

0 commit comments

Comments
 (0)