Skip to content

Commit 320f6b2

Browse files
Thread-safe pool for server session objects
1 parent 0d6a8ba commit 320f6b2

10 files changed

+317
-193
lines changed

src/libmongoc/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,7 @@ set (SOURCES ${SOURCES}
558558
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-topology-description.c
559559
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-topology-description-apm.c
560560
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-topology-scanner.c
561+
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-ts-pool.c
561562
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-uri.c
562563
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-util.c
563564
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-version-functions.c
@@ -615,6 +616,7 @@ set (HEADERS
615616
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-stream-gridfs.h
616617
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-stream-socket.h
617618
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-topology-description.h
619+
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-ts-pool.h
618620
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-uri.h
619621
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-version-functions.h
620622
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-write-concern.h

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ mongoc_client_pool_destroy (mongoc_client_pool_t *pool)
185185
EXIT;
186186
}
187187

188-
if (pool->topology->session_pool) {
188+
if (!mongoc_ts_pool_is_empty (pool->topology->session_pool)) {
189189
client = mongoc_client_pool_pop (pool);
190190
_mongoc_client_end_sessions (client);
191191
mongoc_client_pool_push (pool, client);

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,17 @@ _mongoc_client_session_handle_reply (mongoc_client_session_t *session,
102102
const char *cmd_name,
103103
const bson_t *reply);
104104

105-
mongoc_server_session_t *
106-
_mongoc_server_session_new (bson_error_t *error);
105+
extern bool
106+
_mongoc_server_session_init (mongoc_server_session_t *session,
107+
bson_error_t *error);
108+
109+
extern void
110+
_mongoc_server_session_dtor (mongoc_server_session_t *session);
107111

108112
bool
109113
_mongoc_server_session_timed_out (const mongoc_server_session_t *server_session,
110114
int64_t session_timeout_minutes);
111115

112-
void
113-
_mongoc_server_session_destroy (mongoc_server_session_t *server_session);
114-
115116
mongoc_client_session_t *
116117
_mongoc_client_session_new (mongoc_client_t *client,
117118
mongoc_server_session_t *server_session,

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

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -709,34 +709,28 @@ _mongoc_client_session_handle_reply (mongoc_client_session_t *session,
709709
}
710710
}
711711

712-
713-
mongoc_server_session_t *
714-
_mongoc_server_session_new (bson_error_t *error)
712+
bool
713+
_mongoc_server_session_init (mongoc_server_session_t *self, bson_error_t *error)
715714
{
716715
uint8_t uuid_data[16];
717-
mongoc_server_session_t *s;
718-
719716
ENTRY;
720717

721-
if (!_mongoc_server_session_uuid (uuid_data, error)) {
722-
RETURN (NULL);
723-
}
724-
725-
s = bson_malloc0 (sizeof (mongoc_server_session_t));
726-
s->last_used_usec = SESSION_NEVER_USED;
727-
s->prev = NULL;
728-
s->next = NULL;
729-
bson_init (&s->lsid);
730-
bson_append_binary (
731-
&s->lsid, "id", 2, BSON_SUBTYPE_UUID, uuid_data, sizeof uuid_data);
732-
718+
self->last_used_usec = SESSION_NEVER_USED;
719+
self->prev = NULL;
720+
self->next = NULL;
721+
bson_init (&self->lsid);
733722
/* transaction number is a positive integer and will be incremented before
734723
* each use, so ensure it is initialized to zero. */
735-
s->txn_number = 0;
724+
self->txn_number = 0;
736725

737-
RETURN (s);
738-
}
726+
if (!_mongoc_server_session_uuid (uuid_data, error)) {
727+
RETURN (false);
728+
}
729+
BSON_APPEND_BINARY (
730+
&self->lsid, "id", BSON_SUBTYPE_UUID, uuid_data, sizeof uuid_data);
739731

732+
RETURN (true);
733+
}
740734

741735
bool
742736
_mongoc_server_session_timed_out (const mongoc_server_session_t *server_session,
@@ -766,14 +760,9 @@ _mongoc_server_session_timed_out (const mongoc_server_session_t *server_session,
766760

767761

768762
void
769-
_mongoc_server_session_destroy (mongoc_server_session_t *server_session)
763+
_mongoc_server_session_dtor (mongoc_server_session_t *self)
770764
{
771-
ENTRY;
772-
773-
bson_destroy (&server_session->lsid);
774-
bson_free (server_session);
775-
776-
EXIT;
765+
bson_destroy (&self->lsid);
777766
}
778767

779768

@@ -806,7 +795,8 @@ _mongoc_client_session_new (mongoc_client_t *client,
806795
DEFAULT_MAX_COMMIT_TIME_MS);
807796

808797
if (opts) {
809-
mongoc_optional_copy (&opts->causal_consistency, &session->opts.causal_consistency);
798+
mongoc_optional_copy (&opts->causal_consistency,
799+
&session->opts.causal_consistency);
810800
mongoc_optional_copy (&opts->snapshot, &session->opts.snapshot);
811801
txn_opts_set (&session->opts.default_txn_opts,
812802
opts->default_txn_opts.read_concern,
@@ -1686,7 +1676,8 @@ mongoc_client_session_destroy (mongoc_client_session_t *session)
16861676
} else {
16871677
/* If the client has been reset, destroy the server session instead of
16881678
pushing it back into the topology's pool. */
1689-
_mongoc_server_session_destroy (session->server_session);
1679+
mongoc_ts_pool_free_item (session->client->topology->session_pool,
1680+
session->server_session);
16901681
}
16911682

16921683
txn_opts_cleanup (&session->opts.default_txn_opts);

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3013,7 +3013,7 @@ _mongoc_client_end_sessions (mongoc_client_t *client)
30133013
mongoc_cluster_t *cluster = &client->cluster;
30143014
bool r;
30153015

3016-
if (t->session_pool) {
3016+
while (!mongoc_ts_pool_is_empty (t->session_pool)) {
30173017
prefs = mongoc_read_prefs_new (MONGOC_READ_PRIMARY_PREFERRED);
30183018
server_id =
30193019
mongoc_topology_select_server_id (t, MONGOC_SS_READ, prefs, &error);
@@ -3087,7 +3087,7 @@ mongoc_client_reset (mongoc_client_t *client)
30873087
client->client_sessions = mongoc_set_new (8, NULL, NULL);
30883088

30893089
/* Server sessions are owned by us, so we clear the pool on reset. */
3090-
_mongoc_topology_clear_session_pool (client->topology);
3090+
mongoc_ts_pool_clear (client->topology->session_pool);
30913091
}
30923092

30933093
mongoc_change_stream_t *

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "mongoc-uri.h"
2828
#include "mongoc-client-session-private.h"
2929
#include "mongoc-crypt-private.h"
30+
#include "mongoc-ts-pool-private.h"
3031

3132
#define MONGOC_TOPOLOGY_MIN_HEARTBEAT_FREQUENCY_MS 500
3233
#define MONGOC_TOPOLOGY_SOCKET_CHECK_INTERVAL_MS 5000
@@ -102,7 +103,7 @@ typedef struct _mongoc_topology_t {
102103
bool single_threaded;
103104
bool stale;
104105

105-
mongoc_server_session_t *session_pool;
106+
mongoc_ts_pool session_pool;
106107

107108
/* Is client side encryption enabled? */
108109
bool cse_enabled;
@@ -255,7 +256,7 @@ _mongoc_topology_handle_app_error (mongoc_topology_t *topology,
255256
void
256257
_mongoc_topology_clear_connection_pool (mongoc_topology_t *topology,
257258
uint32_t server_id,
258-
const bson_oid_t* service_id);
259+
const bson_oid_t *service_id);
259260

260261
void
261262
mongoc_topology_rescan_srv (mongoc_topology_t *topology);

src/libmongoc/src/mongoc/mongoc-topology.c

Lines changed: 44 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,9 @@ mongoc_topology_new (const mongoc_uri_t *uri, bool single_threaded)
260260
#endif
261261

262262
topology = (mongoc_topology_t *) bson_malloc0 (sizeof *topology);
263-
topology->session_pool = NULL;
263+
topology->session_pool =
264+
mongoc_ts_pool_new (sizeof (mongoc_server_session_t),
265+
(void (*) (void *)) _mongoc_server_session_dtor);
264266
heartbeat_default =
265267
single_threaded ? MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_SINGLE_THREADED
266268
: MONGOC_TOPOLOGY_HEARTBEAT_FREQUENCY_MS_MULTI_THREADED;
@@ -569,47 +571,14 @@ mongoc_topology_destroy (mongoc_topology_t *topology)
569571
mongoc_uri_destroy (topology->uri);
570572
mongoc_topology_description_destroy (&topology->description);
571573
mongoc_topology_scanner_destroy (topology->scanner);
572-
573-
/* If we are single-threaded, the client will try to call
574-
_mongoc_topology_end_sessions_cmd when it dies. This removes
575-
sessions from the pool as it calls endSessions on them. In
576-
case this does not succeed, we clear the pool again here. */
577-
_mongoc_topology_clear_session_pool (topology);
574+
mongoc_ts_pool_free (topology->session_pool);
578575

579576
mongoc_cond_destroy (&topology->cond_client);
580577
bson_mutex_destroy (&topology->mutex);
581578

582579
bson_free (topology);
583580
}
584581

585-
/*
586-
*--------------------------------------------------------------------------
587-
*
588-
* _mongoc_topology_clear_session_pool --
589-
*
590-
* Clears the pool of server sessions without sending endSessions.
591-
*
592-
* Returns:
593-
* Nothing.
594-
*
595-
* Side effects:
596-
* Server session pool will be emptied.
597-
*
598-
*--------------------------------------------------------------------------
599-
*/
600-
601-
void
602-
_mongoc_topology_clear_session_pool (mongoc_topology_t *topology)
603-
{
604-
mongoc_server_session_t *ss, *tmp1, *tmp2;
605-
606-
CDL_FOREACH_SAFE (topology->session_pool, ss, tmp1, tmp2)
607-
{
608-
_mongoc_server_session_destroy (ss);
609-
}
610-
topology->session_pool = NULL;
611-
}
612-
613582
/* Returns false if none of the hosts were valid. */
614583
bool
615584
mongoc_topology_apply_scanned_srv_hosts (mongoc_uri_t *uri,
@@ -1570,45 +1539,49 @@ _mongoc_topology_pop_server_session (mongoc_topology_t *topology,
15701539
bson_mutex_unlock (&topology->mutex);
15711540
if (!mongoc_topology_select_server_id (
15721541
topology, MONGOC_SS_READ, NULL, error)) {
1573-
RETURN (NULL);
1542+
ss = NULL;
1543+
goto done;
15741544
}
15751545

15761546
bson_mutex_lock (&topology->mutex);
15771547
timeout = td->session_timeout_minutes;
15781548
}
15791549

15801550
if (timeout == MONGOC_NO_SESSIONS) {
1581-
bson_mutex_unlock (&topology->mutex);
15821551
bson_set_error (error,
15831552
MONGOC_ERROR_CLIENT,
15841553
MONGOC_ERROR_CLIENT_SESSION_FAILURE,
15851554
"Server does not support sessions");
1586-
RETURN (NULL);
1555+
ss = NULL;
1556+
bson_mutex_unlock (&topology->mutex);
1557+
goto done;
15871558
}
15881559
}
1560+
bson_mutex_unlock (&topology->mutex);
15891561

1590-
while (topology->session_pool) {
1591-
ss = topology->session_pool;
1592-
CDL_DELETE (topology->session_pool, ss);
1593-
/* Sessions do not expire when the topology type is load balanced. */
1594-
if (loadbalanced) {
1562+
while (true) {
1563+
bool got_session;
1564+
ss = mongoc_ts_pool_try_pop (topology->session_pool, &got_session);
1565+
if (!got_session) {
1566+
/* The pool is empty */
1567+
ss = mongoc_ts_pool_alloc_item (topology->session_pool);
1568+
if (!_mongoc_server_session_init (ss, error)) {
1569+
mongoc_ts_pool_free_item (topology->session_pool, ss);
1570+
ss = NULL;
1571+
goto done;
1572+
}
15951573
break;
15961574
}
15971575

15981576
if (_mongoc_server_session_timed_out (ss, timeout)) {
1599-
_mongoc_server_session_destroy (ss);
1577+
mongoc_ts_pool_free_item (topology->session_pool, ss);
16001578
ss = NULL;
1601-
} else {
1602-
break;
1579+
continue;
16031580
}
1581+
break;
16041582
}
16051583

1606-
bson_mutex_unlock (&topology->mutex);
1607-
1608-
if (!ss) {
1609-
ss = _mongoc_server_session_new (error);
1610-
}
1611-
1584+
done:
16121585
RETURN (ss);
16131586
}
16141587

@@ -1633,46 +1606,25 @@ _mongoc_topology_push_server_session (mongoc_topology_t *topology,
16331606
ENTRY;
16341607

16351608
bson_mutex_lock (&topology->mutex);
1636-
16371609
timeout = topology->description.session_timeout_minutes;
16381610
loadbalanced = topology->description.type == MONGOC_TOPOLOGY_LOAD_BALANCED;
1611+
bson_mutex_unlock (&topology->mutex);
16391612

1640-
/* start at back of queue and reap timed-out sessions */
1641-
while (topology->session_pool && topology->session_pool->prev) {
1642-
ss = topology->session_pool->prev;
1643-
/* Sessions do not expire when the topology type is load balanced. */
1644-
if (!loadbalanced && _mongoc_server_session_timed_out (ss, timeout)) {
1645-
BSON_ASSERT (ss->next); /* silences clang scan-build */
1646-
CDL_DELETE (topology->session_pool, ss);
1647-
_mongoc_server_session_destroy (ss);
1648-
} else {
1649-
/* if ss is not timed out, sessions in front of it are ok too */
1650-
break;
1651-
}
1652-
}
1653-
1654-
/* If session is expiring or "dirty" (a network error occurred on it), do not
1655-
* return it to the pool. Sessions do not expire when the topology type is
1656-
* load balanced. */
16571613
if ((!loadbalanced &&
16581614
_mongoc_server_session_timed_out (server_session, timeout)) ||
16591615
server_session->dirty) {
1660-
_mongoc_server_session_destroy (server_session);
1661-
} else {
1662-
/* silences clang scan-build */
1663-
BSON_ASSERT (!topology->session_pool || (topology->session_pool->next &&
1664-
topology->session_pool->prev));
1665-
1616+
/* If session is expiring or "dirty" (a network error occurred on it), do
1617+
* not return it to the pool. Sessions do not expire when the topology
1618+
* type is load balanced. */
1619+
mongoc_ts_pool_free_item (topology->session_pool, server_session);
1620+
} else if (server_session->last_used_usec == SESSION_NEVER_USED) {
16661621
/* add server session (lsid) to session pool to be reused only if the
16671622
* server session has been used (the server is aware of the session) */
1668-
if (server_session->last_used_usec == SESSION_NEVER_USED) {
1669-
_mongoc_server_session_destroy (server_session);
1623+
mongoc_ts_pool_free_item (topology->session_pool, server_session);
16701624
} else {
1671-
CDL_PREPEND (topology->session_pool, server_session);
1672-
}
1625+
mongoc_ts_pool_push (topology->session_pool, server_session);
16731626
}
16741627

1675-
bson_mutex_unlock (&topology->mutex);
16761628

16771629
EXIT;
16781630
}
@@ -1701,26 +1653,24 @@ _mongoc_topology_push_server_session (mongoc_topology_t *topology,
17011653
bool
17021654
_mongoc_topology_end_sessions_cmd (mongoc_topology_t *topology, bson_t *cmd)
17031655
{
1704-
mongoc_server_session_t *ss, *tmp1, *tmp2;
1705-
char buf[16];
1706-
const char *key;
1707-
uint32_t i;
17081656
bson_t ar;
1657+
int i = 0;
17091658

17101659
bson_init (cmd);
17111660
BSON_APPEND_ARRAY_BEGIN (cmd, "endSessions", &ar);
17121661

1713-
i = 0;
1714-
CDL_FOREACH_SAFE (topology->session_pool, ss, tmp1, tmp2)
1715-
{
1716-
bson_uint32_to_string (i, &key, buf, sizeof buf);
1717-
BSON_APPEND_DOCUMENT (&ar, key, &ss->lsid);
1718-
CDL_DELETE (topology->session_pool, ss);
1719-
_mongoc_server_session_destroy (ss);
1720-
1721-
if (++i == 10000) {
1662+
for (; i < 10000; ++i) {
1663+
char buf[16];
1664+
const char *key;
1665+
bool did_pop;
1666+
mongoc_server_session_t *ss =
1667+
mongoc_ts_pool_try_pop (topology->session_pool, &did_pop);
1668+
if (!did_pop) {
17221669
break;
17231670
}
1671+
bson_uint32_to_string (i, &key, buf, sizeof buf);
1672+
BSON_APPEND_DOCUMENT (&ar, key, &ss->lsid);
1673+
mongoc_ts_pool_free_item (topology->session_pool, ss);
17241674
}
17251675

17261676
bson_append_array_end (cmd, &ar);

0 commit comments

Comments
 (0)