@@ -29,6 +29,7 @@ use crate::{
29
29
wire:: { next_request_id, Message } ,
30
30
PinnedConnectionHandle ,
31
31
} ,
32
+ Command ,
32
33
ConnectionPool ,
33
34
RawCommandResponse ,
34
35
} ,
@@ -58,7 +59,7 @@ use crate::{
58
59
Retryability ,
59
60
} ,
60
61
options:: { ChangeStreamOptions , SelectionCriteria } ,
61
- sdam:: { HandshakePhase , SelectedServer , ServerType , TopologyType , TransactionSupportStatus } ,
62
+ sdam:: { HandshakePhase , ServerType , TopologyType , TransactionSupportStatus } ,
62
63
selection_criteria:: ReadPreference ,
63
64
tracking_arc:: TrackingArc ,
64
65
ClusterTime ,
@@ -309,7 +310,7 @@ impl Client {
309
310
let mut retry: Option < ExecutionRetry > = None ;
310
311
let mut implicit_session: Option < ClientSession > = None ;
311
312
loop {
312
- op. update_for_topology ( & self . inner . topology . description ( ) ) ;
313
+ // op.update_for_topology(&self.inner.topology.description());
313
314
314
315
if retry. is_some ( ) {
315
316
op. update_for_retry ( ) ;
@@ -320,15 +321,15 @@ impl Client {
320
321
. and_then ( |s| s. transaction . pinned_mongos ( ) )
321
322
. or_else ( || op. selection_criteria ( ) ) ;
322
323
323
- let server = match self
324
+ let ( server, effective_criteria ) = match self
324
325
. select_server (
325
326
selection_criteria,
326
327
op. name ( ) ,
327
328
retry. as_ref ( ) . map ( |r| & r. first_server ) ,
328
329
)
329
330
. await
330
331
{
331
- Ok ( server ) => server ,
332
+ Ok ( out ) => out ,
332
333
Err ( mut err) => {
333
334
retry. first_error ( ) ?;
334
335
@@ -389,14 +390,11 @@ impl Client {
389
390
. and_then ( |r| r. prior_txn_number )
390
391
. or_else ( || get_txn_number ( & mut session, retryability) ) ;
391
392
393
+ let cmd =
394
+ self . build_command ( op, & mut conn, & mut session, txn_number, effective_criteria) ?;
395
+
392
396
let details = match self
393
- . execute_operation_on_connection (
394
- op,
395
- & mut conn,
396
- & mut session,
397
- txn_number,
398
- retryability,
399
- )
397
+ . execute_command_on_connection ( cmd, op, & mut conn, & mut session, retryability)
400
398
. await
401
399
{
402
400
Ok ( output) => ExecutionDetails {
@@ -485,19 +483,14 @@ impl Client {
485
483
}
486
484
}
487
485
488
- /// Executes an operation on a given connection, optionally using a provided session.
489
- async fn execute_operation_on_connection < T : Operation > (
486
+ fn build_command < T : Operation > (
490
487
& self ,
491
488
op : & mut T ,
492
489
connection : & mut PooledConnection ,
493
490
session : & mut Option < & mut ClientSession > ,
494
491
txn_number : Option < i64 > ,
495
- retryability : Retryability ,
496
- ) -> Result < T :: O > {
497
- if let Some ( wc) = op. write_concern ( ) {
498
- wc. validate ( ) ?;
499
- }
500
-
492
+ _effective_critera : SelectionCriteria ,
493
+ ) -> Result < Command > {
501
494
let stream_description = connection. stream_description ( ) ?;
502
495
let is_sharded = stream_description. initial_server_type == ServerType :: Mongos ;
503
496
let mut cmd = op. build ( stream_description) ?;
@@ -605,16 +598,30 @@ impl Client {
605
598
cmd. set_cluster_time ( cluster_time) ;
606
599
}
607
600
608
- let connection_info = connection. info ( ) ;
609
- let service_id = connection. service_id ( ) ;
610
- let request_id = next_request_id ( ) ;
611
-
612
601
if let Some ( ref server_api) = self . inner . options . server_api {
613
602
cmd. set_server_api ( server_api) ;
614
603
}
615
604
616
- let should_redact = cmd. should_redact ( ) ;
605
+ Ok ( cmd)
606
+ }
617
607
608
+ /// Executes a command on a given connection, optionally using a provided session.
609
+ async fn execute_command_on_connection < T : Operation > (
610
+ & self ,
611
+ cmd : Command ,
612
+ op : & mut T ,
613
+ connection : & mut PooledConnection ,
614
+ session : & mut Option < & mut ClientSession > ,
615
+ retryability : Retryability ,
616
+ ) -> Result < T :: O > {
617
+ if let Some ( wc) = op. write_concern ( ) {
618
+ wc. validate ( ) ?;
619
+ }
620
+
621
+ let connection_info = connection. info ( ) ;
622
+ let service_id = connection. service_id ( ) ;
623
+ let request_id = next_request_id ( ) ;
624
+ let should_redact = cmd. should_redact ( ) ;
618
625
let cmd_name = cmd. name . clone ( ) ;
619
626
let target_db = cmd. target_db . clone ( ) ;
620
627
@@ -653,78 +660,9 @@ impl Client {
653
660
let start_time = Instant :: now ( ) ;
654
661
let command_result = match connection. send_message ( message) . await {
655
662
Ok ( response) => {
656
- async fn handle_response < T : Operation > (
657
- client : & Client ,
658
- op : & T ,
659
- session : & mut Option < & mut ClientSession > ,
660
- is_sharded : bool ,
661
- response : RawCommandResponse ,
662
- ) -> Result < RawCommandResponse > {
663
- let raw_doc = RawDocument :: from_bytes ( response. as_bytes ( ) ) ?;
664
-
665
- let ok = match raw_doc. get ( "ok" ) ? {
666
- Some ( b) => crate :: bson_util:: get_int_raw ( b) . ok_or_else ( || {
667
- ErrorKind :: InvalidResponse {
668
- message : format ! (
669
- "expected ok value to be a number, instead got {:?}" ,
670
- b
671
- ) ,
672
- }
673
- } ) ?,
674
- None => {
675
- return Err ( ErrorKind :: InvalidResponse {
676
- message : "missing 'ok' value in response" . to_string ( ) ,
677
- }
678
- . into ( ) )
679
- }
680
- } ;
681
-
682
- let cluster_time: Option < ClusterTime > = raw_doc
683
- . get ( "$clusterTime" ) ?
684
- . and_then ( RawBsonRef :: as_document)
685
- . map ( |d| bson:: from_slice ( d. as_bytes ( ) ) )
686
- . transpose ( ) ?;
687
-
688
- let at_cluster_time = op. extract_at_cluster_time ( raw_doc) ?;
689
-
690
- client
691
- . update_cluster_time ( cluster_time, at_cluster_time, session)
692
- . await ;
693
-
694
- if let ( Some ( session) , Some ( ts) ) = (
695
- session. as_mut ( ) ,
696
- raw_doc
697
- . get ( "operationTime" ) ?
698
- . and_then ( RawBsonRef :: as_timestamp) ,
699
- ) {
700
- session. advance_operation_time ( ts) ;
701
- }
702
-
703
- if ok == 1 {
704
- if let Some ( ref mut session) = session {
705
- if is_sharded && session. in_transaction ( ) {
706
- let recovery_token = raw_doc
707
- . get ( "recoveryToken" ) ?
708
- . and_then ( RawBsonRef :: as_document)
709
- . map ( |d| bson:: from_slice ( d. as_bytes ( ) ) )
710
- . transpose ( ) ?;
711
- session. transaction . recovery_token = recovery_token;
712
- }
713
- }
714
-
715
- Ok ( response)
716
- } else {
717
- Err ( response
718
- . body :: < CommandErrorBody > ( )
719
- . map ( |error_response| error_response. into ( ) )
720
- . unwrap_or_else ( |e| {
721
- Error :: from ( ErrorKind :: InvalidResponse {
722
- message : format ! ( "error deserializing command error: {}" , e) ,
723
- } )
724
- } ) )
725
- }
726
- }
727
- handle_response ( self , op, session, is_sharded, response) . await
663
+ let is_sharded =
664
+ connection. stream_description ( ) ?. initial_server_type == ServerType :: Mongos ;
665
+ Self :: parse_response ( self , op, session, is_sharded, response) . await
728
666
}
729
667
Err ( err) => Err ( err) ,
730
668
} ;
@@ -811,6 +749,75 @@ impl Client {
811
749
}
812
750
}
813
751
752
+ async fn parse_response < T : Operation > (
753
+ client : & Client ,
754
+ op : & T ,
755
+ session : & mut Option < & mut ClientSession > ,
756
+ is_sharded : bool ,
757
+ response : RawCommandResponse ,
758
+ ) -> Result < RawCommandResponse > {
759
+ let raw_doc = RawDocument :: from_bytes ( response. as_bytes ( ) ) ?;
760
+
761
+ let ok = match raw_doc. get ( "ok" ) ? {
762
+ Some ( b) => {
763
+ crate :: bson_util:: get_int_raw ( b) . ok_or_else ( || ErrorKind :: InvalidResponse {
764
+ message : format ! ( "expected ok value to be a number, instead got {:?}" , b) ,
765
+ } ) ?
766
+ }
767
+ None => {
768
+ return Err ( ErrorKind :: InvalidResponse {
769
+ message : "missing 'ok' value in response" . to_string ( ) ,
770
+ }
771
+ . into ( ) )
772
+ }
773
+ } ;
774
+
775
+ let cluster_time: Option < ClusterTime > = raw_doc
776
+ . get ( "$clusterTime" ) ?
777
+ . and_then ( RawBsonRef :: as_document)
778
+ . map ( |d| bson:: from_slice ( d. as_bytes ( ) ) )
779
+ . transpose ( ) ?;
780
+
781
+ let at_cluster_time = op. extract_at_cluster_time ( raw_doc) ?;
782
+
783
+ client
784
+ . update_cluster_time ( cluster_time, at_cluster_time, session)
785
+ . await ;
786
+
787
+ if let ( Some ( session) , Some ( ts) ) = (
788
+ session. as_mut ( ) ,
789
+ raw_doc
790
+ . get ( "operationTime" ) ?
791
+ . and_then ( RawBsonRef :: as_timestamp) ,
792
+ ) {
793
+ session. advance_operation_time ( ts) ;
794
+ }
795
+
796
+ if ok == 1 {
797
+ if let Some ( ref mut session) = session {
798
+ if is_sharded && session. in_transaction ( ) {
799
+ let recovery_token = raw_doc
800
+ . get ( "recoveryToken" ) ?
801
+ . and_then ( RawBsonRef :: as_document)
802
+ . map ( |d| bson:: from_slice ( d. as_bytes ( ) ) )
803
+ . transpose ( ) ?;
804
+ session. transaction . recovery_token = recovery_token;
805
+ }
806
+ }
807
+
808
+ Ok ( response)
809
+ } else {
810
+ Err ( response
811
+ . body :: < CommandErrorBody > ( )
812
+ . map ( |error_response| error_response. into ( ) )
813
+ . unwrap_or_else ( |e| {
814
+ Error :: from ( ErrorKind :: InvalidResponse {
815
+ message : format ! ( "error deserializing command error: {}" , e) ,
816
+ } )
817
+ } ) )
818
+ }
819
+ }
820
+
814
821
#[ cfg( feature = "in-use-encryption" ) ]
815
822
fn auto_encrypt < ' a > (
816
823
& ' a self ,
@@ -846,7 +853,7 @@ impl Client {
846
853
( matches ! ( topology_type, TopologyType :: Single ) && server_type. is_available ( ) )
847
854
|| server_type. is_data_bearing ( )
848
855
} ) ) ;
849
- let _: SelectedServer = self
856
+ let _ = self
850
857
. select_server ( Some ( & criteria) , operation_name, None )
851
858
. await ?;
852
859
Ok ( ( ) )
0 commit comments