Skip to content

Commit d551dab

Browse files
RUST-1585 Do not perform server selection to determine sessions support (#854)
1 parent 573aa54 commit d551dab

File tree

18 files changed

+213
-273
lines changed

18 files changed

+213
-273
lines changed

src/client/csfle/state_machine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
error::{Error, Result},
2020
operation::{RawOutput, RunCommand},
2121
options::ReadConcern,
22-
runtime::{AsyncStream, Process, TlsConfig},
22+
runtime::{process::Process, AsyncStream, TlsConfig},
2323
Client,
2424
Namespace,
2525
};

src/client/executor.rs

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,7 @@ use crate::{
5151
Retryability,
5252
},
5353
options::{ChangeStreamOptions, SelectionCriteria},
54-
sdam::{
55-
HandshakePhase,
56-
SelectedServer,
57-
ServerType,
58-
SessionSupportStatus,
59-
TopologyType,
60-
TransactionSupportStatus,
61-
},
54+
sdam::{HandshakePhase, SelectedServer, ServerType, TopologyType, TransactionSupportStatus},
6255
selection_criteria::ReadPreference,
6356
ClusterTime,
6457
};
@@ -349,8 +342,16 @@ impl Client {
349342
}
350343
};
351344

352-
if session.is_none() {
353-
implicit_session = self.start_implicit_session(&op).await?;
345+
if !conn.supports_sessions() && session.is_some() {
346+
return Err(ErrorKind::SessionsNotSupported.into());
347+
}
348+
349+
if conn.supports_sessions()
350+
&& session.is_none()
351+
&& op.supports_sessions()
352+
&& op.is_acknowledged()
353+
{
354+
implicit_session = Some(ClientSession::new(self.clone(), None, true).await);
354355
session = implicit_session.as_mut();
355356
}
356357

@@ -790,19 +791,6 @@ impl Client {
790791
})
791792
}
792793

793-
/// Start an implicit session if the operation and write concern are compatible with sessions.
794-
async fn start_implicit_session<T: Operation>(&self, op: &T) -> Result<Option<ClientSession>> {
795-
match self.get_session_support_status().await? {
796-
SessionSupportStatus::Supported {
797-
logical_session_timeout,
798-
} if op.supports_sessions() && op.is_acknowledged() => Ok(Some(
799-
self.start_session_with_timeout(logical_session_timeout, None, true)
800-
.await,
801-
)),
802-
_ => Ok(None),
803-
}
804-
}
805-
806794
async fn select_data_bearing_server(&self, operation_name: &str) -> Result<()> {
807795
let topology_type = self.inner.topology.topology_type();
808796
let criteria = SelectionCriteria::Predicate(Arc::new(move |server_info| {
@@ -814,24 +802,6 @@ impl Client {
814802
Ok(())
815803
}
816804

817-
/// Gets whether the topology supports sessions, and if so, returns the topology's logical
818-
/// session timeout. If it has yet to be determined if the topology supports sessions, this
819-
/// method will perform a server selection that will force that determination to be made.
820-
pub(crate) async fn get_session_support_status(&self) -> Result<SessionSupportStatus> {
821-
let initial_status = self.inner.topology.session_support_status();
822-
823-
// Need to guarantee that we're connected to at least one server that can determine if
824-
// sessions are supported or not.
825-
match initial_status {
826-
SessionSupportStatus::Undetermined => {
827-
self.select_data_bearing_server(crate::client::SESSIONS_SUPPORT_OP_NAME)
828-
.await?;
829-
Ok(self.inner.topology.session_support_status())
830-
}
831-
_ => Ok(initial_status),
832-
}
833-
}
834-
835805
/// Gets whether the topology supports transactions. If it has yet to be determined if the
836806
/// topology supports transactions, this method will perform a server selection that will force
837807
/// that determination to be made.

src/client/mod.rs

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use crate::{
4646
SessionOptions,
4747
},
4848
results::DatabaseSpecification,
49-
sdam::{server_selection, SelectedServer, SessionSupportStatus, Topology},
49+
sdam::{server_selection, SelectedServer, Topology},
5050
ClientSession,
5151
};
5252

@@ -56,8 +56,6 @@ pub(crate) use session::{ClusterTime, SESSIONS_UNSUPPORTED_COMMANDS};
5656
use session::{ServerSession, ServerSessionPool};
5757

5858
const DEFAULT_SERVER_SELECTION_TIMEOUT: Duration = Duration::from_secs(30);
59-
// TODO: RUST-1585 Remove this constant.
60-
pub(crate) const SESSIONS_SUPPORT_OP_NAME: &str = "Check sessions support status";
6159

6260
/// This is the main entry point for the API. A `Client` is used to connect to a MongoDB cluster.
6361
/// By default, it will monitor the topology of the cluster, keeping track of any changes, such
@@ -367,14 +365,7 @@ impl Client {
367365
if let Some(ref options) = options {
368366
options.validate()?;
369367
}
370-
match self.get_session_support_status().await? {
371-
SessionSupportStatus::Supported {
372-
logical_session_timeout,
373-
} => Ok(self
374-
.start_session_with_timeout(logical_session_timeout, options, false)
375-
.await),
376-
_ => Err(ErrorKind::SessionsNotSupported.into()),
377-
}
368+
Ok(ClientSession::new(self.clone(), options, false).await)
378369
}
379370

380371
/// Starts a new [`ChangeStream`] that receives events for all changes in the cluster. The
@@ -428,42 +419,11 @@ impl Client {
428419
.await
429420
}
430421

431-
/// Check in a server session to the server session pool.
432-
/// If the session is expired or dirty, or the topology no longer supports sessions, the session
433-
/// will be discarded.
422+
/// Check in a server session to the server session pool. The session will be discarded if it is
423+
/// expired or dirty.
434424
pub(crate) async fn check_in_server_session(&self, session: ServerSession) {
435-
let session_support_status = self.inner.topology.session_support_status();
436-
if let SessionSupportStatus::Supported {
437-
logical_session_timeout,
438-
} = session_support_status
439-
{
440-
self.inner
441-
.session_pool
442-
.check_in(session, logical_session_timeout)
443-
.await;
444-
}
445-
}
446-
447-
/// Starts a `ClientSession`.
448-
///
449-
/// This method will attempt to re-use server sessions from the pool which are not about to
450-
/// expire according to the provided logical session timeout. If no such sessions are
451-
/// available, a new one will be created.
452-
pub(crate) async fn start_session_with_timeout(
453-
&self,
454-
logical_session_timeout: Option<Duration>,
455-
options: Option<SessionOptions>,
456-
is_implicit: bool,
457-
) -> ClientSession {
458-
ClientSession::new(
459-
self.inner
460-
.session_pool
461-
.check_out(logical_session_timeout)
462-
.await,
463-
self.clone(),
464-
options,
465-
is_implicit,
466-
)
425+
let timeout = self.inner.topology.logical_session_timeout();
426+
self.inner.session_pool.check_in(session, timeout).await;
467427
}
468428

469429
#[cfg(test)]
@@ -601,7 +561,7 @@ impl Client {
601561
}
602562

603563
#[cfg(test)]
604-
pub(crate) fn topology(&self) -> &crate::sdam::Topology {
564+
pub(crate) fn topology(&self) -> &Topology {
605565
&self.inner.topology
606566
}
607567

src/client/session/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,13 +202,15 @@ pub(crate) enum TransactionPin {
202202
}
203203

204204
impl ClientSession {
205-
/// Creates a new `ClientSession` wrapping the provided server session.
206-
pub(crate) fn new(
207-
server_session: ServerSession,
205+
/// Creates a new `ClientSession` by checking out a corresponding `ServerSession` from the
206+
/// provided client's session pool.
207+
pub(crate) async fn new(
208208
client: Client,
209209
options: Option<SessionOptions>,
210210
is_implicit: bool,
211211
) -> Self {
212+
let timeout = client.inner.topology.logical_session_timeout();
213+
let server_session = client.inner.session_pool.check_out(timeout).await;
212214
Self {
213215
client,
214216
server_session,

src/client/session/test/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ async fn pool_is_lifo() {
215215
let _guard: RwLockReadGuard<()> = LOCK.run_concurrently().await;
216216

217217
let client = TestClient::new().await;
218+
// Wait for the implicit sessions created in TestClient::new to be returned to the pool.
219+
runtime::delay_for(Duration::from_millis(500)).await;
218220

219221
if client.is_standalone() {
220222
return;

src/cmap/conn/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,14 @@ impl Connection {
431431
pub(crate) fn is_streaming(&self) -> bool {
432432
self.more_to_come
433433
}
434+
435+
/// Whether the connection supports sessions.
436+
pub(crate) fn supports_sessions(&self) -> bool {
437+
self.stream_description
438+
.as_ref()
439+
.and_then(|sd| sd.logical_session_timeout)
440+
.is_some()
441+
}
434442
}
435443

436444
impl Drop for Connection {

src/runtime/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ mod http;
33
#[cfg(feature = "async-std-runtime")]
44
mod interval;
55
mod join_handle;
6-
#[cfg(feature = "in-use-encryption-unstable")]
7-
mod process;
6+
#[cfg(any(
7+
feature = "in-use-encryption-unstable",
8+
all(test, not(feature = "sync"), not(feature = "tokio-sync"))
9+
))]
10+
pub(crate) mod process;
811
mod resolver;
912
pub(crate) mod stream;
1013
mod sync_read_ext;
@@ -16,8 +19,6 @@ mod worker_handle;
1619

1720
use std::{future::Future, net::SocketAddr, time::Duration};
1821

19-
#[cfg(feature = "in-use-encryption-unstable")]
20-
pub(crate) use self::process::Process;
2122
pub(crate) use self::{
2223
acknowledged_message::AcknowledgedMessage,
2324
join_handle::AsyncJoinHandle,

0 commit comments

Comments
 (0)