@@ -53,6 +53,7 @@ defmodule Mongo do
53
53
alias Mongo.TopologyDescription
54
54
alias Mongo.Topology
55
55
alias Mongo.UrlParser
56
+ alias Mongo.Session.ServerSession
56
57
57
58
@ timeout 15000 # 5000
58
59
@@ -285,35 +286,62 @@ defmodule Mongo do
285
286
sort: opts [ :sort ] ,
286
287
upsert: opts [ :upsert ] ,
287
288
collation: opts [ :collation ] ,
288
- lsid: opts [ :lsid ]
289
+ lsid: opts [ :lsid ] || :implicit
289
290
] |> filter_nils ( )
290
291
291
292
opts = Keyword . drop ( opts , ~w( bypass_document_validation max_time projection return_document sort upsert collation) a )
292
293
293
- with { :ok , doc } <- call_command_for_type ( topology_pid , cmd , :write , tops ) do
294
+ with { :ok , _conn , doc } <- issue_command ( topology_pid , cmd , :write , opts ) do
294
295
{ :ok , doc [ "value" ] }
295
296
end
296
297
297
298
end
298
299
299
- def call_command_for_type ( topology_pid , cmd , :write , opts ) do
300
- with { :ok , conn , _ , _ , session_id } <- select_server ( topology_pid , :write , opts ) ,
301
- { :ok , doc } <- exec_command ( conn , update_session_id ( cmd , session_id ) , opts ) do
302
- { :ok , doc }
300
+ @ doc """
301
+ This function is very fundamental. First a server is selected. If no explicit session id is found, then
302
+ the Topology-Module returns an implicit session id. The `opts` is updated for using the new session id.
303
+ Then is command is sent to the server and executed. On return implicit session id is checked in into the
304
+ session pool for reuse.
305
+ """
306
+ def issue_command ( topology_pid , cmd , :write , opts ) do
307
+ with { :ok , conn , _ , _ , session_id } <- Topology . select_server ( topology_pid , :write , opts ) ,
308
+ { :ok , doc } <- exec_command ( conn , update_session_id ( cmd , session_id ) , opts ) ,
309
+ ok <- checkin_session_id ( topology_pid , cmd , session_id ) do
310
+ { :ok , conn , doc }
311
+ else
312
+ { :new_connection , _server } ->
313
+ IO . puts "too fast, call it again"
314
+ issue_command ( topology_pid , cmd , :write , opts )
303
315
end
304
316
end
305
- def call_command_for_type ( topology_pid , cmd , :read , opts ) do
306
- with { :ok , conn , slave_ok , _ , session_id } <- select_server ( topology_pid , :read , opts ) ,
307
- { :ok , doc } <- exec_command ( conn , update_session_id ( cmd , session_id ) , opts ) do
308
- { :ok , doc }
317
+ def issue_command ( topology_pid , cmd , :read , opts ) do
318
+
319
+ IO . puts "issue_command: read #{ inspect cmd } "
320
+ with { :ok , conn , slave_ok , _ , session_id } <- Topology . select_server ( topology_pid , :read , opts ) ,
321
+ opts = Keyword . put ( opts , :slave_ok , slave_ok ) ,
322
+ { :ok , doc } <- exec_command ( conn , update_session_id ( cmd , session_id ) , opts ) ,
323
+ ok <- checkin_session_id ( topology_pid , cmd , session_id ) do
324
+ { :ok , conn , doc }
325
+ else
326
+ { :new_connection , _server } ->
327
+ IO . puts "too fast, call it again"
328
+ issue_command ( topology_pid , cmd , :read , opts )
309
329
end
310
330
end
311
331
312
332
defp update_session_id ( cmd , nil ) do
313
333
cmd
314
334
end
315
- defp update_session_id ( cmd , session_id ) do
316
- Keyword . merge ( cmd , [ lsid: session_id ] )
335
+ defp update_session_id ( cmd , % ServerSession { :session_id => session_id } ) do
336
+ IO . puts "update_session_id #{ inspect session_id } "
337
+ Keyword . merge ( cmd , [ lsid: % { id: session_id } ] )
338
+ end
339
+ defp checkin_session_id ( topology_pid , cmd , nil ) , do: :ok
340
+ defp checkin_session_id ( topology_pid , cmd , session_id ) do
341
+ case Keyword . get ( cmd , :lsid , :implicit ) do
342
+ :implicit -> Topology . checkin_session_id ( topology_pid , session_id )
343
+ _ -> :ok
344
+ end
317
345
end
318
346
319
347
@ doc """
@@ -353,8 +381,7 @@ defmodule Mongo do
353
381
354
382
opts = Keyword . drop ( opts , ~w( bypass_document_validation max_time projection return_document sort upsert collation) a )
355
383
356
- with { :ok , conn , _ , _ } <- select_server ( topology_pid , :write , opts ) ,
357
- { :ok , doc } <- exec_command ( conn , cmd , opts ) , do: { :ok , doc [ "value" ] }
384
+ with { :ok , _conn , doc } <- issue_command ( topology_pid , cmd , :write , opts ) , do: { :ok , doc [ "value" ] }
358
385
end
359
386
360
387
defp should_return_new ( :after ) , do: true
@@ -385,8 +412,7 @@ defmodule Mongo do
385
412
] |> filter_nils ( )
386
413
opts = Keyword . drop ( opts , ~w( max_time projection sort collation) a )
387
414
388
- with { :ok , conn , _ , _ } <- select_server ( topology_pid , :write , opts ) ,
389
- { :ok , doc } <- exec_command ( conn , cmd , opts ) , do: { :ok , doc [ "value" ] }
415
+ with { :ok , _conn , doc } <- issue_command ( topology_pid , cmd , :write , opts ) , do: { :ok , doc [ "value" ] }
390
416
end
391
417
392
418
@ doc false
@@ -490,10 +516,7 @@ defmodule Mongo do
490
516
491
517
opts = Keyword . drop ( opts , ~w( max_time) a )
492
518
493
- with { :ok , conn , slave_ok , _ } <- select_server ( topology_pid , :read , opts ) ,
494
- opts = Keyword . put ( opts , :slave_ok , slave_ok ) ,
495
- { :ok , doc } <- exec_command ( conn , cmd , opts ) ,
496
- do: { :ok , doc [ "values" ] }
519
+ with { :ok , _conn , doc } <- issue_command ( topology_pid , cmd , :read , opts ) , do: { :ok , doc [ "values" ] }
497
520
end
498
521
499
522
@ doc """
@@ -545,7 +568,7 @@ defmodule Mongo do
545
568
maxTimeMS: opts [ :max_time ] ,
546
569
skip: opts [ :skip ] ,
547
570
sort: opts [ :sort ] ,
548
- lsid: opts [ :lsid ]
571
+ lsid: opts [ :lsid ] || :implicit
549
572
]
550
573
551
574
cmd = filter_nils ( cmd )
@@ -568,8 +591,7 @@ defmodule Mongo do
568
591
569
592
Mongo.find_one(top, "jobs", %{}, read_concern: %{level: "local"})
570
593
"""
571
- @ spec find_one ( GenServer . server , collection , BSON . document , Keyword . t ) ::
572
- BSON . document | nil
594
+ @ spec find_one ( GenServer . server , collection , BSON . document , Keyword . t ) :: BSON . document | nil
573
595
def find_one ( conn , coll , filter , opts \\ [ ] ) do
574
596
opts = opts
575
597
|> Keyword . delete ( :sort )
@@ -590,9 +612,9 @@ defmodule Mongo do
590
612
def command ( topology_pid , cmd , opts \\ [ ] ) do
591
613
rp = ReadPreference . defaults ( % { mode: :primary } )
592
614
rp_opts = [ read_preference: Keyword . get ( opts , :read_preference , rp ) ]
593
- with { :ok , conn , slave_ok , _ } <- select_server ( topology_pid , :read , rp_opts ) ,
594
- opts = Keyword . put ( opts , :slave_ok , slave_ok ) ,
595
- do: exec_command ( conn , cmd , opts )
615
+ with { :ok , _conn , doc } <- Mongo . issue_command ( topology_pid , cmd , :read , rp_opts ) do
616
+ { :ok , doc }
617
+ end
596
618
end
597
619
598
620
@ doc false
@@ -601,6 +623,8 @@ defmodule Mongo do
601
623
def exec_command ( conn , cmd , opts ) do
602
624
action = % Query { action: :command }
603
625
626
+ IO . puts "Executing cmd #{ inspect cmd } "
627
+
604
628
with { :ok , _cmd , doc } <- DBConnection . execute ( conn , action , [ cmd ] , defaults ( opts ) ) ,
605
629
{ :ok , doc } <- check_for_error ( doc ) do
606
630
{ :ok , doc }
@@ -675,11 +699,10 @@ defmodule Mongo do
675
699
ordered: Keyword . get ( opts , :ordered ) ,
676
700
writeConcern: write_concern ,
677
701
bypassDocumentValidation: Keyword . get ( opts , :bypass_document_validation ) ,
678
- lsid: Keyword . get ( opts , :lsid )
702
+ lsid: Keyword . get ( opts , :lsid , :implicit )
679
703
] |> filter_nils ( )
680
704
681
- with { :ok , conn , _ , _ } <- select_server ( topology_pid , :write , opts ) ,
682
- { :ok , doc } <- exec_command ( conn , cmd , opts ) do
705
+ with { :ok , _conn , doc } <- Mongo . issue_command ( topology_pid , cmd , :write , opts ) do
683
706
case doc do
684
707
% { "writeErrors" => _ } -> { :error , % Mongo.WriteError { n: doc [ "n" ] , ok: doc [ "ok" ] , write_errors: doc [ "writeErrors" ] } }
685
708
_ ->
@@ -733,8 +756,7 @@ defmodule Mongo do
733
756
lsid: Keyword . get ( opts , :lsid )
734
757
] |> filter_nils ( )
735
758
736
- with { :ok , conn , _ , _ } <- select_server ( topology_pid , :write , opts ) ,
737
- { :ok , doc } <- exec_command ( conn , cmd , opts ) do
759
+ with { :ok , _conn , doc } <- issue_command ( topology_pid , cmd , :write , opts ) do
738
760
case doc do
739
761
% { "writeErrors" => _ } -> { :error , % Mongo.WriteError { n: doc [ "n" ] , ok: doc [ "ok" ] , write_errors: doc [ "writeErrors" ] } }
740
762
_ ->
@@ -805,8 +827,7 @@ defmodule Mongo do
805
827
lsid: Keyword . get ( opts , :lsid )
806
828
] |> filter_nils ( )
807
829
808
- with { :ok , conn , _ , _ } <- select_server ( topology_pid , :write , opts ) ,
809
- { :ok , doc } <- exec_command ( conn , cmd , opts ) do
830
+ with { :ok , _conn , doc } <- issue_command ( topology_pid , cmd , :write , opts ) do
810
831
case doc do
811
832
% { "writeErrors" => _ } -> { :error , % Mongo.WriteError { n: doc [ "n" ] , ok: doc [ "ok" ] , write_errors: doc [ "writeErrors" ] } }
812
833
% { "ok" => _ok , "n" => n } ->
@@ -927,8 +948,7 @@ defmodule Mongo do
927
948
] |> filter_nils ( )
928
949
929
950
930
- with { :ok , conn , _ , _ } <- select_server ( topology_pid , :write , opts ) ,
931
- { :ok , doc } <- exec_command ( conn , cmd , opts ) do
951
+ with { :ok , _conn , doc } <- issue_command ( topology_pid , cmd , :write , opts ) do
932
952
933
953
case doc do
934
954
@@ -1015,61 +1035,6 @@ defmodule Mongo do
1015
1035
|> Stream . map ( fn coll -> coll [ "name" ] end )
1016
1036
end
1017
1037
1018
- @ doc """
1019
- Determines the appropriate connection depending on the type (:read, :write). The result is
1020
- a tuple with the connection, slave_ok flag and mongos flag. Possibly you have to set slave_ok == true in
1021
- the options for the following request because you are requesting a secondary server.
1022
- """
1023
- def select_server ( topology_pid , type , opts \\ [ ] ) do
1024
- with { :ok , servers , slave_ok , mongos? , session_id } <- select_servers ( topology_pid , type , opts ) do
1025
- if Enum . empty? servers do
1026
- { :ok , nil , slave_ok , mongos? , session_id }
1027
- else
1028
- with { :ok , connection } <- servers |> Enum . take_random ( 1 ) |> Enum . at ( 0 )
1029
- |> get_connection ( topology_pid ) do
1030
- { :ok , connection , slave_ok , mongos? , session_id }
1031
- end
1032
- end
1033
- end
1034
- end
1035
-
1036
- defp select_servers ( topology_pid , type , opts ) , do: select_servers ( topology_pid , type , opts , System . monotonic_time )
1037
- @ sel_timeout 30000
1038
- # NOTE: Should think about the handling completely in the Topology GenServer
1039
- # in order to make the entire operation atomic instead of querying
1040
- # and then potentially having an outdated topology when waiting for the
1041
- # connection.
1042
- defp select_servers ( topology_pid , type , opts , start_time ) do
1043
- topology = Topology . topology ( topology_pid )
1044
-
1045
- case TopologyDescription . select_servers ( topology , type , opts ) do
1046
-
1047
- :empty ->
1048
- case Topology . wait_for_connection ( topology_pid , @ sel_timeout , start_time ) do
1049
- { :ok , _servers } -> select_servers ( topology_pid , type , opts , start_time ) ##todo wait a little
1050
- { :error , :selection_timeout } = error -> error
1051
- end
1052
-
1053
- { :ok , result } -> result
1054
-
1055
- error -> error
1056
- end
1057
-
1058
- # with {:ok, servers, slave_ok, mongos?, session_id} <- TopologyDescription.select_servers(topology, type, opts) do
1059
- # case servers do
1060
- # [] ->
1061
- # case Topology.wait_for_connection(topology_pid, @sel_timeout, start_time) do
1062
- # {:ok, _servers} -> select_servers(topology_pid, type, opts, start_time) ##todo wait a little
1063
- # {:error, :selection_timeout} = error -> error
1064
- # end
1065
- # _full -> {:ok, servers, slave_ok, mongos?, session_id}
1066
- # end
1067
- # end
1068
- end
1069
-
1070
- defp get_connection ( nil , _pid ) , do: { :ok , nil }
1071
- defp get_connection ( server , pid ) , do: Topology . connection_for_address ( pid , server )
1072
-
1073
1038
defp modifier_docs ( [ { key , _ } | _ ] , type ) , do: key |> key_to_string |> modifier_key ( type )
1074
1039
defp modifier_docs ( map , _type ) when is_map ( map ) and map_size ( map ) == 0 , do: :ok
1075
1040
defp modifier_docs ( map , type ) when is_map ( map ) , do: Enum . at ( map , 0 ) |> elem ( 0 ) |> key_to_string |> modifier_key ( type )
0 commit comments