Skip to content

Commit e7e1500

Browse files
jmikolaeramongodbkevinAlbs
authored
CDRIVER-3723 finalize URI during client/pool construction (#921)
Introduces new mongoc_client_new_from_uri_with_error and mongoc_client_pool_new_with_error methods. Also addresses topology leak in mongoc_client_new_from_uri (CDRIVER-4251). * Remove redundant warnings about unused results * Explain why we need not handle null result from _mongoc_client_new_from_topology * Log URI errors in mongoc_client_new as warnings * Clear logs between /Client/max_staleness assertions * Set error instead of logging in mongoc_client_pool_new_with_error * Remove test expecting a client with an invalid topology * Revise assertions in /loadbalanced/client_uri_validation test This no longer requires constructing a client and expecting an error through server selection. * Use tracing macro for return statement * Check MONGOC_ENABLE_SSL in mongoc_client_new_from_uri_with_error Moving the check up from _mongoc_client_new_from_topology makes mongoc_client_new_from_uri_with_error consistent with mongoc_client_pool_new_with_error. Additionally, we add log message assertions to corresponding tests. * Anticipate null pool or client in SRV error tests * Remove obsolete tests for invalid LB topologies These tests were previously introduced in CDRIVER-4184 but no longer apply now that we prohibit construction of clients and pools with an invalid topology. * _mongoc_client_new_from_topology should require a valid topology * Document precondition for _mongoc_client_new_from_topology Co-authored-by: Ezra Chung <[email protected]> Co-authored-by: Kevin Albertson <[email protected]>
1 parent 6d08ea5 commit e7e1500

20 files changed

+248
-326
lines changed

src/libmongoc/doc/mongoc_client_new.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Parameters
2121
Returns
2222
-------
2323

24-
A newly allocated :symbol:`mongoc_client_t` if the URI parsed successfully, otherwise ``NULL``.
24+
A newly allocated :symbol:`mongoc_client_t` that should be freed with :symbol:`mongoc_client_destroy()` when no longer in use. On error, ``NULL`` is returned and an error or warning will be logged.
2525

2626
.. seealso::
2727

src/libmongoc/doc/mongoc_client_new_from_uri.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,9 @@ Parameters
2222
Returns
2323
-------
2424

25-
A newly allocated :symbol:`mongoc_client_t` that should be freed with :symbol:`mongoc_client_destroy()` when no longer in use.
25+
A newly allocated :symbol:`mongoc_client_t` that should be freed with :symbol:`mongoc_client_destroy()` when no longer in use. On error, ``NULL`` is returned and an error will be logged.
26+
27+
.. seealso::
28+
29+
| :symbol:`mongoc_client_new_from_uri_with_error()`
2630
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
:man_page: mongoc_client_new_from_uri_with_error
2+
3+
mongoc_client_new_from_uri_with_error()
4+
=======================================
5+
6+
Synopsis
7+
--------
8+
9+
.. code-block:: c
10+
11+
mongoc_client_t *
12+
mongoc_client_new_from_uri_with_error (const mongoc_uri_t *uri,
13+
bson_error_t *error)
14+
BSON_GNUC_WARN_UNUSED_RESULT;
15+
16+
Creates a new :symbol:`mongoc_client_t` using the :symbol:`mongoc_uri_t` provided.
17+
18+
Parameters
19+
----------
20+
21+
* ``uri``: A :symbol:`mongoc_uri_t`.
22+
* ``error``: An optional location for a :symbol:`bson_error_t <errors>` or ``NULL``.
23+
24+
Returns
25+
-------
26+
27+
A newly allocated :symbol:`mongoc_client_t` that should be freed with :symbol:`mongoc_client_destroy()` when no longer in use. On error, ``NULL`` is returned and ``error`` will be populated with the error description.
28+

src/libmongoc/doc/mongoc_client_pool_new.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@ Parameters
2121
Returns
2222
-------
2323

24-
A newly allocated :symbol:`mongoc_client_pool_t` that should be freed with :symbol:`mongoc_client_pool_destroy()` when no longer in use.
24+
A newly allocated :symbol:`mongoc_client_pool_t` that should be freed with :symbol:`mongoc_client_pool_destroy()` when no longer in use. On error, ``NULL`` is returned and an error may be logged.
25+
26+
.. seealso::
27+
28+
| :symbol:`mongoc_client_pool_new_with_error()`
2529
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
:man_page: mongoc_client_pool_new_with_error
2+
3+
mongoc_client_pool_new_with_error()
4+
===================================
5+
6+
Synopsis
7+
--------
8+
9+
.. code-block:: c
10+
11+
mongoc_client_pool_t *
12+
mongoc_client_pool_new_with_error (const mongoc_uri_t *uri,
13+
bson_error_t *error)
14+
BSON_GNUC_WARN_UNUSED_RESULT;
15+
16+
This function creates a new :symbol:`mongoc_client_pool_t` using the :symbol:`mongoc_uri_t` provided.
17+
18+
Parameters
19+
----------
20+
21+
* ``uri``: A :symbol:`mongoc_uri_t`.
22+
* ``error``: An optional location for a :symbol:`bson_error_t <errors>` or ``NULL``.
23+
24+
Returns
25+
-------
26+
27+
A newly allocated :symbol:`mongoc_client_pool_t` that should be freed with :symbol:`mongoc_client_pool_destroy()` when no longer in use. On error, ``NULL`` is returned and ``error`` will be populated with the error description.
28+

src/libmongoc/doc/mongoc_client_pool_t.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ Example
3535
mongoc_client_pool_max_size
3636
mongoc_client_pool_min_size
3737
mongoc_client_pool_new
38+
mongoc_client_pool_new_with_error
3839
mongoc_client_pool_pop
3940
mongoc_client_pool_push
4041
mongoc_client_pool_set_apm_callbacks

src/libmongoc/doc/mongoc_client_t.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Example
7373
mongoc_client_get_write_concern
7474
mongoc_client_new
7575
mongoc_client_new_from_uri
76+
mongoc_client_new_from_uri_with_error
7677
mongoc_client_read_command_with_opts
7778
mongoc_client_read_write_command_with_opts
7879
mongoc_client_reset

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

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ _mongoc_client_pool_set_internal_tls_opts (
9898

9999
mongoc_client_pool_t *
100100
mongoc_client_pool_new (const mongoc_uri_t *uri)
101+
{
102+
mongoc_client_pool_t *pool;
103+
bson_error_t error = {0};
104+
105+
if (!(pool = mongoc_client_pool_new_with_error (uri, &error))) {
106+
MONGOC_ERROR ("%s", error.message);
107+
}
108+
109+
return pool;
110+
}
111+
112+
113+
mongoc_client_pool_t *
114+
mongoc_client_pool_new_with_error (const mongoc_uri_t *uri, bson_error_t *error)
101115
{
102116
mongoc_topology_t *topology;
103117
mongoc_client_pool_t *pool;
@@ -112,12 +126,27 @@ mongoc_client_pool_new (const mongoc_uri_t *uri)
112126

113127
#ifndef MONGOC_ENABLE_SSL
114128
if (mongoc_uri_get_tls (uri)) {
115-
MONGOC_ERROR ("Can't create SSL client pool,"
116-
" SSL not enabled in this build.");
129+
bson_set_error (error,
130+
MONGOC_ERROR_COMMAND,
131+
MONGOC_ERROR_COMMAND_INVALID_ARG,
132+
"Can't create SSL client pool, SSL not enabled in this "
133+
"build.");
117134
return NULL;
118135
}
119136
#endif
120137

138+
topology = mongoc_topology_new (uri, false);
139+
140+
if (!topology->valid) {
141+
if (error) {
142+
memcpy (error, &topology->scanner->error, sizeof (bson_error_t));
143+
}
144+
145+
mongoc_topology_destroy (topology);
146+
147+
RETURN (NULL);
148+
}
149+
121150
pool = (mongoc_client_pool_t *) bson_malloc0 (sizeof *pool);
122151
bson_mutex_init (&pool->mutex);
123152
mongoc_cond_init (&pool->cond);
@@ -126,8 +155,6 @@ mongoc_client_pool_new (const mongoc_uri_t *uri)
126155
pool->min_pool_size = 0;
127156
pool->max_pool_size = 100;
128157
pool->size = 0;
129-
130-
topology = mongoc_topology_new (uri, false);
131158
pool->topology = topology;
132159
pool->error_api_version = MONGOC_ERROR_API_VERSION_LEGACY;
133160

@@ -278,7 +305,8 @@ mongoc_client_pool_pop (mongoc_client_pool_t *pool)
278305
again:
279306
if (!(client = (mongoc_client_t *) _mongoc_queue_pop_head (&pool->queue))) {
280307
if (pool->size < pool->max_pool_size) {
281-
client = _mongoc_client_new_from_uri (pool->topology);
308+
client = _mongoc_client_new_from_topology (pool->topology);
309+
BSON_ASSERT (client);
282310
_initialize_new_client (pool, client);
283311
pool->size++;
284312
} else {
@@ -321,7 +349,8 @@ mongoc_client_pool_try_pop (mongoc_client_pool_t *pool)
321349

322350
if (!(client = (mongoc_client_t *) _mongoc_queue_pop_head (&pool->queue))) {
323351
if (pool->size < pool->max_pool_size) {
324-
client = _mongoc_client_new_from_uri (pool->topology);
352+
client = _mongoc_client_new_from_topology (pool->topology);
353+
BSON_ASSERT (client);
325354
_initialize_new_client (pool, client);
326355
pool->size++;
327356
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ typedef struct _mongoc_client_pool_t mongoc_client_pool_t;
3939

4040
MONGOC_EXPORT (mongoc_client_pool_t *)
4141
mongoc_client_pool_new (const mongoc_uri_t *uri) BSON_GNUC_WARN_UNUSED_RESULT;
42+
MONGOC_EXPORT (mongoc_client_pool_t *)
43+
mongoc_client_pool_new_with_error (const mongoc_uri_t *uri, bson_error_t *error)
44+
BSON_GNUC_WARN_UNUSED_RESULT;
4245
MONGOC_EXPORT (void)
4346
mongoc_client_pool_destroy (mongoc_client_pool_t *pool);
4447
MONGOC_EXPORT (mongoc_client_t *)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ _mongoc_client_get_rr (const char *hostname,
161161
bson_error_t *error);
162162

163163
mongoc_client_t *
164-
_mongoc_client_new_from_uri (mongoc_topology_t *topology);
164+
_mongoc_client_new_from_topology (mongoc_topology_t *topology);
165165

166166
bool
167167
_mongoc_client_set_apm_callbacks_private (mongoc_client_t *client,

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

Lines changed: 56 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -982,48 +982,27 @@ _mongoc_client_recv (mongoc_client_t *client,
982982
}
983983

984984

985-
/*
986-
*--------------------------------------------------------------------------
987-
*
988-
* mongoc_client_new --
989-
*
990-
* Create a new mongoc_client_t using the URI provided.
991-
*
992-
* @uri should be a MongoDB URI string such as "mongodb://localhost/"
993-
* More information on the format can be found at
994-
* http://docs.mongodb.org/manual/reference/connection-string/
995-
*
996-
* Returns:
997-
* A newly allocated mongoc_client_t or NULL if @uri_string is
998-
* invalid.
999-
*
1000-
* Side effects:
1001-
* None.
1002-
*
1003-
*--------------------------------------------------------------------------
1004-
*/
1005985
mongoc_client_t *
1006986
mongoc_client_new (const char *uri_string)
1007987
{
1008-
mongoc_topology_t *topology;
1009988
mongoc_client_t *client;
1010989
mongoc_uri_t *uri;
1011-
990+
bson_error_t error = {0};
1012991

1013992
if (!uri_string) {
1014993
uri_string = "mongodb://127.0.0.1/";
1015994
}
1016995

1017-
if (!(uri = mongoc_uri_new (uri_string))) {
996+
if (!(uri = mongoc_uri_new_with_error (uri_string, &error))) {
997+
/* Log URI errors as a warning for consistency with mongoc_uri_new */
998+
MONGOC_WARNING ("Error parsing URI: '%s'", error.message);
1018999
return NULL;
10191000
}
10201001

1021-
topology = mongoc_topology_new (uri, true);
1022-
1023-
client = _mongoc_client_new_from_uri (topology);
1024-
if (!client) {
1025-
mongoc_topology_destroy (topology);
1002+
if (!(client = mongoc_client_new_from_uri_with_error (uri, &error))) {
1003+
MONGOC_ERROR ("%s", error.message);
10261004
}
1005+
10271006
mongoc_uri_destroy (uri);
10281007

10291008
return client;
@@ -1084,54 +1063,65 @@ mongoc_client_set_ssl_opts (mongoc_client_t *client,
10841063
#endif
10851064

10861065

1087-
/*
1088-
*--------------------------------------------------------------------------
1089-
*
1090-
* mongoc_client_new_from_uri --
1091-
*
1092-
* Create a new mongoc_client_t for a mongoc_uri_t.
1093-
*
1094-
* Returns:
1095-
* A newly allocated mongoc_client_t.
1096-
*
1097-
* Side effects:
1098-
* None.
1099-
*
1100-
*--------------------------------------------------------------------------
1101-
*/
1102-
11031066
mongoc_client_t *
11041067
mongoc_client_new_from_uri (const mongoc_uri_t *uri)
11051068
{
1069+
mongoc_client_t *client;
1070+
bson_error_t error = {0};
1071+
1072+
if (!(client = mongoc_client_new_from_uri_with_error (uri, &error))) {
1073+
MONGOC_ERROR ("%s", error.message);
1074+
}
1075+
1076+
return client;
1077+
}
1078+
1079+
1080+
mongoc_client_t *
1081+
mongoc_client_new_from_uri_with_error (const mongoc_uri_t *uri,
1082+
bson_error_t *error)
1083+
{
1084+
mongoc_client_t *client;
11061085
mongoc_topology_t *topology;
11071086

1087+
1088+
ENTRY;
1089+
1090+
BSON_ASSERT (uri);
1091+
1092+
#ifndef MONGOC_ENABLE_SSL
1093+
if (mongoc_uri_get_tls (uri)) {
1094+
bson_set_error (
1095+
error,
1096+
MONGOC_ERROR_COMMAND,
1097+
MONGOC_ERROR_COMMAND_INVALID_ARG,
1098+
"Can't create SSL client, SSL not enabled in this build.");
1099+
RETURN (NULL);
1100+
}
1101+
#endif
1102+
11081103
topology = mongoc_topology_new (uri, true);
11091104

1110-
/* topology->uri may be different from uri: if this is a mongodb+srv:// URI
1111-
* then mongoc_topology_new has fetched SRV and TXT records and updated its
1112-
* uri from them.
1113-
*/
1114-
return _mongoc_client_new_from_uri (topology);
1105+
if (!topology->valid) {
1106+
if (error) {
1107+
memcpy (error, &topology->scanner->error, sizeof (bson_error_t));
1108+
}
1109+
1110+
mongoc_topology_destroy (topology);
1111+
1112+
RETURN (NULL);
1113+
}
1114+
1115+
client = _mongoc_client_new_from_topology (topology);
1116+
BSON_ASSERT (client);
1117+
1118+
RETURN (client);
11151119
}
11161120

1117-
/*
1118-
*--------------------------------------------------------------------------
1119-
*
1120-
* _mongoc_client_new_from_uri --
1121-
*
1122-
* Create a new mongoc_client_t for a given topology object.
1123-
*
1124-
* Returns:
1125-
* A newly allocated mongoc_client_t.
1126-
*
1127-
* Side effects:
1128-
* None.
1129-
*
1130-
*--------------------------------------------------------------------------
1131-
*/
11321121

1122+
/* precondition: topology is valid */
11331123
mongoc_client_t *
1134-
_mongoc_client_new_from_uri (mongoc_topology_t *topology)
1124+
_mongoc_client_new_from_topology (mongoc_topology_t *topology)
11351125
{
11361126
mongoc_client_t *client;
11371127
const mongoc_read_prefs_t *read_prefs;
@@ -1140,13 +1130,7 @@ _mongoc_client_new_from_uri (mongoc_topology_t *topology)
11401130
const char *appname;
11411131

11421132
BSON_ASSERT (topology);
1143-
1144-
#ifndef MONGOC_ENABLE_SSL
1145-
if (mongoc_uri_get_tls (topology->uri)) {
1146-
MONGOC_ERROR ("Can't create SSL client, SSL not enabled in this build.");
1147-
return NULL;
1148-
}
1149-
#endif
1133+
BSON_ASSERT (topology->valid);
11501134

11511135
client = (mongoc_client_t *) bson_malloc0 (sizeof *client);
11521136
client->uri = mongoc_uri_copy (topology->uri);

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ mongoc_client_new (const char *uri_string) BSON_GNUC_WARN_UNUSED_RESULT;
107107
MONGOC_EXPORT (mongoc_client_t *)
108108
mongoc_client_new_from_uri (const mongoc_uri_t *uri)
109109
BSON_GNUC_WARN_UNUSED_RESULT;
110+
MONGOC_EXPORT (mongoc_client_t *)
111+
mongoc_client_new_from_uri_with_error (
112+
const mongoc_uri_t *uri, bson_error_t *error) BSON_GNUC_WARN_UNUSED_RESULT;
110113
MONGOC_EXPORT (const mongoc_uri_t *)
111114
mongoc_client_get_uri (const mongoc_client_t *client);
112115
MONGOC_EXPORT (void)

0 commit comments

Comments
 (0)