Skip to content

Commit fbe7dca

Browse files
committed
CDRIVER-1895 clean up topology locking in callback
1 parent b698499 commit fbe7dca

File tree

5 files changed

+116
-29
lines changed

5 files changed

+116
-29
lines changed

src/mongoc/mongoc-topology-scanner-private.h

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535

3636
BSON_BEGIN_DECLS
3737

38+
typedef void (*mongoc_topology_scanner_setup_err_cb_t)(uint32_t id,
39+
void *data,
40+
const bson_error_t *error /* IN */);
41+
3842
typedef void (*mongoc_topology_scanner_cb_t)(uint32_t id,
3943
const bson_t *bson,
4044
int64_t rtt,
@@ -74,14 +78,15 @@ typedef struct mongoc_topology_scanner
7478
bool handshake_ok_to_send;
7579
const char *appname;
7680

77-
mongoc_topology_scanner_cb_t cb;
78-
void *cb_data;
79-
bool in_progress;
80-
const mongoc_uri_t *uri;
81-
mongoc_async_cmd_setup_t setup;
82-
mongoc_stream_initiator_t initiator;
83-
void *initiator_context;
84-
bson_error_t error;
81+
mongoc_topology_scanner_setup_err_cb_t setup_err_cb;
82+
mongoc_topology_scanner_cb_t cb;
83+
void *cb_data;
84+
bool in_progress;
85+
const mongoc_uri_t *uri;
86+
mongoc_async_cmd_setup_t setup;
87+
mongoc_stream_initiator_t initiator;
88+
void *initiator_context;
89+
bson_error_t error;
8590

8691
#ifdef MONGOC_ENABLE_SSL
8792
mongoc_ssl_opt_t *ssl_opts;
@@ -92,9 +97,10 @@ typedef struct mongoc_topology_scanner
9297
} mongoc_topology_scanner_t;
9398

9499
mongoc_topology_scanner_t *
95-
mongoc_topology_scanner_new (const mongoc_uri_t *uri,
96-
mongoc_topology_scanner_cb_t cb,
97-
void *data);
100+
mongoc_topology_scanner_new (const mongoc_uri_t *uri,
101+
mongoc_topology_scanner_setup_err_cb_t setup_err_cb,
102+
mongoc_topology_scanner_cb_t cb,
103+
void *data);
98104

99105
void
100106
mongoc_topology_scanner_destroy (mongoc_topology_scanner_t *ts);

src/mongoc/mongoc-topology-scanner.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,10 @@ _begin_ismaster_cmd (mongoc_topology_scanner_t *ts,
127127

128128

129129
mongoc_topology_scanner_t *
130-
mongoc_topology_scanner_new (const mongoc_uri_t *uri,
131-
mongoc_topology_scanner_cb_t cb,
132-
void *data)
130+
mongoc_topology_scanner_new (const mongoc_uri_t *uri,
131+
mongoc_topology_scanner_setup_err_cb_t setup_err_cb,
132+
mongoc_topology_scanner_cb_t cb,
133+
void *data)
133134
{
134135
mongoc_topology_scanner_t *ts = (mongoc_topology_scanner_t *)bson_malloc0 (sizeof (*ts));
135136

@@ -139,6 +140,7 @@ mongoc_topology_scanner_new (const mongoc_uri_t *uri,
139140
_add_ismaster (&ts->ismaster_cmd);
140141
bson_init (&ts->ismaster_cmd_with_handshake);
141142

143+
ts->setup_err_cb = setup_err_cb;
142144
ts->cb = cb;
143145
ts->cb_data = data;
144146
ts->uri = uri;
@@ -396,6 +398,7 @@ mongoc_topology_scanner_ismaster_handler (mongoc_async_cmd_result_t async_status
396398
ts->cb (node->id, ismaster_response, rtt_msec, ts->cb_data, error);
397399
}
398400

401+
399402
/*
400403
*--------------------------------------------------------------------------
401404
*
@@ -598,8 +601,7 @@ mongoc_topology_scanner_node_setup (mongoc_topology_scanner_node_t *node,
598601
_mongoc_topology_scanner_monitor_heartbeat_failed (node->ts, &node->host,
599602
error);
600603

601-
/* Pass a rtt of -1 if we couldn't initialize a stream in node_setup */
602-
node->ts->cb (node->id, NULL, -1, node->ts->cb_data, error);
604+
node->ts->setup_err_cb (node->id, node->ts->cb_data, error);
603605
return false;
604606
}
605607

src/mongoc/mongoc-topology.c

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,36 @@ _mongoc_topology_update_no_lock (uint32_t id,
9999
}
100100

101101

102+
/*
103+
*-------------------------------------------------------------------------
104+
*
105+
* _mongoc_topology_scanner_setup_err_cb --
106+
*
107+
* Callback method to handle errors during topology scanner node
108+
* setup, typically DNS or SSL errors.
109+
*
110+
*-------------------------------------------------------------------------
111+
*/
112+
113+
void
114+
_mongoc_topology_scanner_setup_err_cb (uint32_t id,
115+
void *data,
116+
const bson_error_t *error /* IN */)
117+
{
118+
mongoc_topology_t *topology;
119+
120+
BSON_ASSERT (data);
121+
122+
topology = (mongoc_topology_t *) data;
123+
124+
mongoc_topology_description_handle_ismaster (&topology->description,
125+
id,
126+
NULL /* ismaster reply */,
127+
-1 /* rtt_msec */,
128+
error);
129+
}
130+
131+
102132
/*
103133
*-------------------------------------------------------------------------
104134
*
@@ -125,22 +155,12 @@ _mongoc_topology_scanner_cb (uint32_t id,
125155

126156
topology = (mongoc_topology_t *)data;
127157

128-
if (rtt_msec >= 0) {
129-
/* If the scanner failed to create a socket for this server, that means
130-
* we're in scanner_start, which means we're under the mutex. So don't
131-
* take the mutex for rtt < 0 */
132-
133-
mongoc_mutex_lock (&topology->mutex);
134-
}
135-
158+
mongoc_mutex_lock (&topology->mutex);
136159
_mongoc_topology_update_no_lock (id, ismaster_response, rtt_msec, topology,
137160
error);
138161

139162
mongoc_cond_broadcast (&topology->cond_client);
140-
141-
if (rtt_msec >= 0) {
142-
mongoc_mutex_unlock (&topology->mutex);
143-
}
163+
mongoc_mutex_unlock (&topology->mutex);
144164
}
145165

146166
/*
@@ -206,8 +226,10 @@ mongoc_topology_new (const mongoc_uri_t *uri,
206226
topology->uri = mongoc_uri_copy (uri);
207227
topology->scanner_state = MONGOC_TOPOLOGY_SCANNER_OFF;
208228
topology->scanner = mongoc_topology_scanner_new (topology->uri,
229+
_mongoc_topology_scanner_setup_err_cb,
209230
_mongoc_topology_scanner_cb,
210231
topology);
232+
211233
topology->single_threaded = single_threaded;
212234
if (single_threaded) {
213235
/* Server Selection Spec:

tests/test-mongoc-topology-scanner.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ _test_topology_scanner(bool with_ssl)
5757
#endif
5858

5959
topology_scanner = mongoc_topology_scanner_new (
60-
NULL, &test_topology_scanner_helper, &finished);
60+
NULL, NULL, &test_topology_scanner_helper, &finished);
6161

6262
#ifdef MONGOC_ENABLE_SSL
6363
if (with_ssl) {

tests/test-mongoc-topology.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,61 @@ test_rtt (void *ctx)
929929
}
930930

931931

932+
/* mongoc_topology_scanner_add_and_scan is called within the topology mutex, it
933+
* adds a discovered node and calls getaddrinfo on its host immediately - test
934+
* that this doesn't cause a recursive acquire on the topology mutex */
935+
static void
936+
test_add_and_scan_failure (void)
937+
{
938+
mock_server_t *server;
939+
mongoc_uri_t *uri;
940+
mongoc_client_pool_t *pool;
941+
mongoc_client_t *client;
942+
future_t *future;
943+
request_t *request;
944+
bson_error_t error;
945+
mongoc_server_description_t *sd;
946+
947+
server = mock_server_new ();
948+
mock_server_run (server);
949+
/* client will discover "fake" host and fail to connect */
950+
mock_server_auto_ismaster (server,
951+
"{'ok': 1,"
952+
" 'ismaster': true,"
953+
" 'setName': 'rs',"
954+
" 'hosts': ['%s', 'fake:1']}",
955+
mock_server_get_host_and_port (server));
956+
957+
uri = mongoc_uri_copy (mock_server_get_uri (server));
958+
mongoc_uri_set_option_as_utf8 (uri, "replicaSet", "rs");
959+
pool = mongoc_client_pool_new (uri);
960+
client = mongoc_client_pool_pop (pool);
961+
future = future_client_command_simple (client, "db",
962+
tmp_bson ("{'ping': 1}"),
963+
NULL, NULL, &error);
964+
965+
request = mock_server_receives_command (server, "db", MONGOC_QUERY_NONE,
966+
"{'ping': 1}");
967+
mock_server_replies_ok_and_destroys (request);
968+
ASSERT_OR_PRINT (future_get_bool (future), error);
969+
970+
sd = mongoc_topology_server_by_id (client->topology, 1, NULL);
971+
ASSERT (sd);
972+
ASSERT_CMPSTR (mongoc_server_description_type (sd), "RSPrimary");
973+
mongoc_server_description_destroy (sd);
974+
975+
sd = mongoc_topology_server_by_id (client->topology, 2, NULL);
976+
ASSERT (sd);
977+
ASSERT_CMPSTR (mongoc_server_description_type (sd), "Unknown");
978+
mongoc_server_description_destroy (sd);
979+
980+
future_destroy (future);
981+
mongoc_client_pool_push (pool, client);
982+
mongoc_client_pool_destroy (pool);
983+
mongoc_uri_destroy (uri);
984+
mock_server_destroy (server);
985+
}
986+
932987
void
933988
test_topology_install (TestSuite *suite)
934989
{
@@ -967,4 +1022,6 @@ test_topology_install (TestSuite *suite)
9671022
test_server_removed_during_handshake_pooled);
9681023
TestSuite_AddFull (suite, "/Topology/rtt", test_rtt, NULL, NULL,
9691024
test_framework_skip_if_slow);
1025+
TestSuite_AddLive (suite, "/Topology/add_and_scan_failure",
1026+
test_add_and_scan_failure);
9701027
}

0 commit comments

Comments
 (0)