mongo 2.13.0.beta1 → 2.13.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -5
  4. data/Rakefile +15 -9
  5. data/lib/mongo.rb +4 -2
  6. data/lib/mongo/auth/aws/request.rb +4 -2
  7. data/lib/mongo/bulk_write.rb +1 -0
  8. data/lib/mongo/client.rb +143 -21
  9. data/lib/mongo/cluster.rb +53 -17
  10. data/lib/mongo/cluster/sdam_flow.rb +13 -10
  11. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +3 -2
  12. data/lib/mongo/cluster/topology/sharded.rb +1 -1
  13. data/lib/mongo/cluster/topology/single.rb +1 -1
  14. data/lib/mongo/collection.rb +17 -13
  15. data/lib/mongo/collection/view/readable.rb +3 -1
  16. data/lib/mongo/collection/view/writable.rb +41 -5
  17. data/lib/mongo/database.rb +31 -4
  18. data/lib/mongo/database/view.rb +19 -4
  19. data/lib/mongo/distinguishing_semaphore.rb +55 -0
  20. data/lib/mongo/error.rb +1 -0
  21. data/lib/mongo/error/invalid_session.rb +2 -1
  22. data/lib/mongo/error/operation_failure.rb +6 -0
  23. data/lib/mongo/error/sessions_not_supported.rb +35 -0
  24. data/lib/mongo/event/base.rb +6 -0
  25. data/lib/mongo/grid/file.rb +5 -0
  26. data/lib/mongo/grid/file/chunk.rb +2 -0
  27. data/lib/mongo/grid/fs_bucket.rb +15 -13
  28. data/lib/mongo/grid/stream/write.rb +9 -3
  29. data/lib/mongo/monitoring.rb +38 -0
  30. data/lib/mongo/monitoring/command_log_subscriber.rb +10 -2
  31. data/lib/mongo/monitoring/event/command_failed.rb +11 -0
  32. data/lib/mongo/monitoring/event/command_started.rb +37 -2
  33. data/lib/mongo/monitoring/event/command_succeeded.rb +11 -0
  34. data/lib/mongo/monitoring/event/server_closed.rb +1 -1
  35. data/lib/mongo/monitoring/event/server_description_changed.rb +27 -4
  36. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +9 -2
  37. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +9 -2
  38. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +9 -2
  39. data/lib/mongo/monitoring/event/server_opening.rb +1 -1
  40. data/lib/mongo/monitoring/event/topology_changed.rb +1 -1
  41. data/lib/mongo/monitoring/event/topology_closed.rb +1 -1
  42. data/lib/mongo/monitoring/event/topology_opening.rb +1 -1
  43. data/lib/mongo/monitoring/publishable.rb +6 -3
  44. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +9 -1
  45. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +1 -1
  46. data/lib/mongo/protocol/message.rb +36 -8
  47. data/lib/mongo/protocol/msg.rb +14 -0
  48. data/lib/mongo/protocol/serializers.rb +5 -2
  49. data/lib/mongo/server.rb +10 -3
  50. data/lib/mongo/server/connection.rb +4 -4
  51. data/lib/mongo/server/connection_base.rb +3 -1
  52. data/lib/mongo/server/description.rb +5 -0
  53. data/lib/mongo/server/monitor.rb +76 -44
  54. data/lib/mongo/server/monitor/connection.rb +55 -7
  55. data/lib/mongo/server/pending_connection.rb +14 -4
  56. data/lib/mongo/server/push_monitor.rb +173 -0
  57. data/{spec/runners/transactions/context.rb → lib/mongo/server/push_monitor/connection.rb} +9 -14
  58. data/lib/mongo/server_selector.rb +0 -1
  59. data/lib/mongo/server_selector/base.rb +579 -1
  60. data/lib/mongo/server_selector/nearest.rb +1 -6
  61. data/lib/mongo/server_selector/primary.rb +1 -6
  62. data/lib/mongo/server_selector/primary_preferred.rb +7 -10
  63. data/lib/mongo/server_selector/secondary.rb +1 -6
  64. data/lib/mongo/server_selector/secondary_preferred.rb +1 -7
  65. data/lib/mongo/session.rb +2 -0
  66. data/lib/mongo/socket.rb +20 -8
  67. data/lib/mongo/socket/ssl.rb +1 -1
  68. data/lib/mongo/socket/tcp.rb +1 -1
  69. data/lib/mongo/topology_version.rb +9 -0
  70. data/lib/mongo/utils.rb +62 -0
  71. data/lib/mongo/version.rb +1 -1
  72. data/spec/README.aws-auth.md +2 -2
  73. data/spec/integration/awaited_ismaster_spec.rb +28 -0
  74. data/spec/integration/change_stream_examples_spec.rb +6 -2
  75. data/spec/integration/check_clean_slate_spec.rb +16 -0
  76. data/spec/integration/client_construction_spec.rb +1 -0
  77. data/spec/integration/connect_single_rs_name_spec.rb +5 -2
  78. data/spec/integration/connection_spec.rb +7 -4
  79. data/spec/integration/crud_spec.rb +4 -4
  80. data/spec/integration/docs_examples_spec.rb +6 -0
  81. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  82. data/spec/integration/heartbeat_events_spec.rb +4 -23
  83. data/spec/integration/read_concern_spec.rb +1 -1
  84. data/spec/integration/retryable_errors_spec.rb +1 -1
  85. data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +2 -2
  86. data/spec/integration/retryable_writes/shared/performs_modern_retries.rb +3 -3
  87. data/spec/integration/retryable_writes/shared/performs_no_retries.rb +2 -2
  88. data/spec/integration/sdam_error_handling_spec.rb +37 -15
  89. data/spec/integration/sdam_events_spec.rb +77 -6
  90. data/spec/integration/sdam_prose_spec.rb +64 -0
  91. data/spec/integration/server_monitor_spec.rb +25 -1
  92. data/spec/integration/size_limit_spec.rb +7 -3
  93. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
  94. data/spec/integration/ssl_uri_options_spec.rb +2 -2
  95. data/spec/integration/zlib_compression_spec.rb +25 -0
  96. data/spec/lite_spec_helper.rb +12 -5
  97. data/spec/mongo/auth/aws/request_spec.rb +76 -0
  98. data/spec/mongo/auth/scram_spec.rb +1 -1
  99. data/spec/mongo/client_construction_spec.rb +207 -0
  100. data/spec/mongo/client_spec.rb +38 -3
  101. data/spec/mongo/cluster/topology/replica_set_spec.rb +52 -9
  102. data/spec/mongo/cluster/topology/single_spec.rb +4 -2
  103. data/spec/mongo/cluster_spec.rb +34 -35
  104. data/spec/mongo/collection/view/change_stream_resume_spec.rb +6 -6
  105. data/spec/mongo/collection_spec.rb +500 -0
  106. data/spec/mongo/database_spec.rb +245 -8
  107. data/spec/mongo/distinguishing_semaphore_spec.rb +63 -0
  108. data/spec/mongo/error/operation_failure_spec.rb +40 -0
  109. data/spec/mongo/index/view_spec.rb +2 -2
  110. data/spec/mongo/monitoring/event/server_description_changed_spec.rb +1 -4
  111. data/spec/mongo/protocol/msg_spec.rb +10 -0
  112. data/spec/mongo/semaphore_spec.rb +51 -0
  113. data/spec/mongo/server/connection_auth_spec.rb +2 -2
  114. data/spec/mongo/server_selector/nearest_spec.rb +23 -23
  115. data/spec/mongo/server_selector/primary_preferred_spec.rb +26 -26
  116. data/spec/mongo/server_selector/primary_spec.rb +9 -9
  117. data/spec/mongo/server_selector/secondary_preferred_spec.rb +22 -22
  118. data/spec/mongo/server_selector/secondary_spec.rb +18 -18
  119. data/spec/mongo/server_selector_spec.rb +4 -4
  120. data/spec/mongo/session_spec.rb +35 -0
  121. data/spec/runners/change_streams/test.rb +2 -2
  122. data/spec/runners/cmap.rb +1 -1
  123. data/spec/runners/command_monitoring.rb +3 -34
  124. data/spec/runners/crud/context.rb +9 -5
  125. data/spec/runners/crud/operation.rb +59 -27
  126. data/spec/runners/crud/spec.rb +0 -8
  127. data/spec/runners/crud/test.rb +1 -1
  128. data/spec/runners/sdam.rb +2 -2
  129. data/spec/runners/server_selection.rb +242 -28
  130. data/spec/runners/transactions.rb +12 -12
  131. data/spec/runners/transactions/operation.rb +151 -25
  132. data/spec/runners/transactions/test.rb +60 -16
  133. data/spec/spec_tests/command_monitoring_spec.rb +22 -12
  134. data/spec/spec_tests/crud_spec.rb +1 -1
  135. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +4 -8
  136. data/spec/spec_tests/data/change_streams/change-streams-resume-whitelist.yml +66 -0
  137. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/MaxStalenessTooSmall.yml +15 -0
  138. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +4 -3
  139. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -0
  140. data/spec/spec_tests/data/sdam_integration/cancel-server-check.yml +96 -0
  141. data/spec/spec_tests/data/sdam_integration/connectTimeoutMS.yml +88 -0
  142. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +83 -0
  143. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +116 -0
  144. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +86 -0
  145. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +115 -0
  146. data/spec/spec_tests/data/sdam_integration/isMaster-command-error.yml +168 -0
  147. data/spec/spec_tests/data/sdam_integration/isMaster-network-error.yml +162 -0
  148. data/spec/spec_tests/data/sdam_integration/isMaster-timeout.yml +229 -0
  149. data/spec/spec_tests/data/sdam_integration/rediscover-quickly-after-step-down.yml +87 -0
  150. data/spec/spec_tests/max_staleness_spec.rb +4 -142
  151. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  152. data/spec/spec_tests/sdam_integration_spec.rb +13 -0
  153. data/spec/spec_tests/sdam_monitoring_spec.rb +1 -2
  154. data/spec/spec_tests/server_selection_spec.rb +4 -116
  155. data/spec/stress/cleanup_spec.rb +17 -2
  156. data/spec/stress/connection_pool_stress_spec.rb +10 -8
  157. data/spec/support/child_process_helper.rb +78 -0
  158. data/spec/support/client_registry.rb +1 -0
  159. data/spec/support/cluster_config.rb +4 -0
  160. data/spec/support/event_subscriber.rb +123 -33
  161. data/spec/support/keyword_struct.rb +26 -0
  162. data/spec/support/shared/server_selector.rb +13 -1
  163. data/spec/support/spec_config.rb +38 -13
  164. data/spec/support/spec_organizer.rb +129 -0
  165. data/spec/support/spec_setup.rb +1 -1
  166. data/spec/support/utils.rb +46 -0
  167. metadata +992 -942
  168. metadata.gz.sig +0 -0
  169. data/lib/mongo/server_selector/selectable.rb +0 -560
  170. data/spec/runners/sdam_monitoring.rb +0 -89
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f5e58cfb13fc60fb774becdceb53b4c79cd1461a2cbd3f2dcfd44216f083da8
4
- data.tar.gz: df770f62315fa3ef4db7a32d796c093759a38c1e6c4e6eaa183789b1700f5ed9
3
+ metadata.gz: db8c88ed58f349728a9361db891376926e93450f4a8ac86aae0bc67599c91a7b
4
+ data.tar.gz: b4f7daaf1d43b55839c1f689504d4f1c212c638e45f6d2211732bc07a41f77e5
5
5
  SHA512:
6
- metadata.gz: a51aa55384766e936b0bbc4ad2f99c9fb22ad03d10e04a4f65a5492c16764c92495ae17c5e1ba521c96e3fe25c5b2d787ab985939947eeffd0957a54ceef4078
7
- data.tar.gz: 6d8ca3220081914ec39479c4c9ebb4a6f070be7f4840fa98f0b6cf28f9c3a9c8082264e9b3b7b0d588cda54f97c9f687e36fd467576a396527d80b493c8a52e7
6
+ metadata.gz: 22471d116179fff42716707a40fa18ebc3c53492a6313bb16be96f447db725110b8ed0b3ee8e199026098a59b8f2941290cd1493249c8e9120ec2849e0229fa1
7
+ data.tar.gz: 8965e04c6926343e4363110d010e14b1a8fde146eb4e239f620005f251ff24b63393bc13f5f332ac4d8aa39cc790a66f080401d9b0923c54a8b40b7d80aa25ea
Binary file
data.tar.gz.sig CHANGED
@@ -1,5 +1 @@
1
- �⋎�L��`�*Vd��
2
- �J���5_E:���
3
- �&E�!��Z�E:���%-%sZY��_��5 �o�����I�AB�׵X��������������R��7�88_}lB�<&06�.W�����eJu�A�
4
- M��QhuF-0�)��_ b���y��i�9q
5
- Q��E:8�H��7 0'� �����º���q�<����[�_���[��k_s���� >��RՐ;�5iq.�[��~��'9�������%
1
+ �7�$��7�NEQg��KLJ
data/Rakefile CHANGED
@@ -45,16 +45,16 @@ namespace :spec do
45
45
  client = ClientRegistry.instance.global_client('authorized')
46
46
  client.database.command(ping: 1)
47
47
  deadline = Time.now + 300
48
- while Time.now < deadline
49
- if client.cluster.send(:sessions_supported?)
48
+ loop do
49
+ begin
50
+ client.cluster.validate_session_support!
50
51
  break
52
+ rescue Mongo::Error::SessionsNotSupported
53
+ if Time.now >= deadline
54
+ raise "Sessions did not become supported in 300 seconds"
55
+ end
56
+ client.cluster.scan!
51
57
  end
52
- sleep 1
53
- client.close
54
- client.reconnect
55
- end
56
- unless client.cluster.send(:sessions_supported?)
57
- raise "Sessions did not become supported in the allowed time"
58
58
  end
59
59
  end
60
60
 
@@ -71,7 +71,13 @@ namespace :spec do
71
71
  SpecConfig.instance.print_summary
72
72
  end
73
73
 
74
- task :ci => ['spec:prepare', :spec]
74
+ task :ci => ['spec:prepare'] do
75
+ $: << File.join(File.dirname(__FILE__), 'spec')
76
+
77
+ require 'support/spec_organizer'
78
+
79
+ SpecOrganizer.new.run
80
+ end
75
81
  end
76
82
 
77
83
  namespace :release do
@@ -34,6 +34,7 @@ require 'bson'
34
34
  require 'mongo/id'
35
35
  require 'mongo/bson'
36
36
  require 'mongo/semaphore'
37
+ require 'mongo/distinguishing_semaphore'
37
38
  require 'mongo/options'
38
39
  require 'mongo/loggable'
39
40
  require 'mongo/cluster_time'
@@ -54,9 +55,11 @@ require 'mongo/collection'
54
55
  require 'mongo/database'
55
56
  require 'mongo/crypt'
56
57
  require 'mongo/client' # Purposely out-of-order so that database is loaded first
58
+ require 'mongo/client_encryption'
57
59
  require 'mongo/dbref'
58
60
  require 'mongo/grid'
59
61
  require 'mongo/index'
62
+ require 'mongo/lint'
60
63
  require 'mongo/server'
61
64
  require 'mongo/server_selector'
62
65
  require 'mongo/session'
@@ -66,5 +69,4 @@ require 'mongo/timeout'
66
69
  require 'mongo/uri'
67
70
  require 'mongo/version'
68
71
  require 'mongo/write_concern'
69
- require 'mongo/lint'
70
- require 'mongo/client_encryption'
72
+ require 'mongo/utils'
@@ -12,7 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- autoload :Net, 'net/http'
15
+ module Net
16
+ autoload :HTTP, 'net/http'
17
+ end
16
18
 
17
19
  module Mongo
18
20
  module Auth
@@ -86,7 +88,7 @@ module Mongo
86
88
  # @return [ String ] formatted_time ISO8601-formatted time of the
87
89
  # request, as would be used in X-Amz-Date header.
88
90
  def formatted_time
89
- @formatted_time ||= @time.utc.strftime('%Y%m%dT%H%M%SZ')
91
+ @formatted_time ||= @time.getutc.strftime('%Y%m%dT%H%M%SZ')
90
92
  end
91
93
 
92
94
  # @return [ String ] formatted_date YYYYMMDD formatted date of the request.
@@ -170,6 +170,7 @@ module Mongo
170
170
  :ordered => ordered?,
171
171
  :operation_id => operation_id,
172
172
  :bypass_document_validation => !!options[:bypass_document_validation],
173
+ :max_time_ms => options[:max_time_ms],
173
174
  :options => options,
174
175
  :id_generator => client.options[:id_generator],
175
176
  :session => session
@@ -55,6 +55,7 @@ module Mongo
55
55
  :auth_mech_properties,
56
56
  :auth_source,
57
57
  :auto_encryption_options,
58
+ :bg_error_backtrace,
58
59
  :cleanup,
59
60
  :compressors,
60
61
  :direct_connection,
@@ -213,6 +214,10 @@ module Mongo
213
214
  # use. One of :mongodb_cr, :mongodb_x509, :plain, :scram, :scram256
214
215
  # @option options [ Hash ] :auth_mech_properties
215
216
  # @option options [ String ] :auth_source The source to authenticate from.
217
+ # @option options [ true | false | nil | Integer ] :bg_error_backtrace
218
+ # Experimental. Set to true to log complete backtraces for errors in
219
+ # background threads. Set to false or nil to not log backtraces. Provide
220
+ # a positive integer to log up to that many backtrace lines.
216
221
  # @option options [ Array<String> ] :compressors A list of potential
217
222
  # compressors to use, in order of preference. The driver chooses the
218
223
  # first compressor that is also supported by the server. Currently the
@@ -443,6 +448,12 @@ module Mongo
443
448
  @srv_records = uri.srv_records
444
449
  else
445
450
  addresses = addresses_or_uri
451
+ addresses.each do |addr|
452
+ if addr =~ /\Amongodb(\+srv)?:\/\//i
453
+ raise ArgumentError, "Host '#{addr}' should not contain protocol. Did you mean to not use an array?"
454
+ end
455
+ end
456
+
446
457
  @srv_records = nil
447
458
  end
448
459
 
@@ -489,7 +500,6 @@ module Mongo
489
500
  end
490
501
  end
491
502
 
492
- yield(self) if block_given?
493
503
  rescue
494
504
  begin
495
505
  @cluster.disconnect!
@@ -499,6 +509,14 @@ module Mongo
499
509
  end
500
510
  raise
501
511
  end
512
+
513
+ if block_given?
514
+ begin
515
+ yield(self)
516
+ ensure
517
+ close
518
+ end
519
+ end
502
520
  end
503
521
 
504
522
  # @api private
@@ -802,6 +820,13 @@ module Mongo
802
820
  # @param [ Hash ] filter The filter criteria for getting a list of databases.
803
821
  # @param [ Hash ] opts The command options.
804
822
  #
823
+ # @option opts [ true, false ] :authorized_databases A flag that determines
824
+ # which databases are returned based on user privileges when access control
825
+ # is enabled
826
+ #
827
+ # See https://docs.mongodb.com/manual/reference/command/listDatabases/
828
+ # for more information and usage.
829
+ #
805
830
  # @return [ Array<String> ] The names of the databases.
806
831
  #
807
832
  # @since 2.0.5
@@ -818,6 +843,13 @@ module Mongo
818
843
  # @param [ true, false ] name_only Whether to only return each database name without full metadata.
819
844
  # @param [ Hash ] opts The command options.
820
845
  #
846
+ # @option opts [ true, false ] :authorized_databases A flag that determines
847
+ # which databases are returned based on user privileges when access control
848
+ # is enabled
849
+ #
850
+ # See https://docs.mongodb.com/manual/reference/command/listDatabases/
851
+ # for more information and usage.
852
+ #
821
853
  # @return [ Array<Hash> ] The info for each database.
822
854
  #
823
855
  # @since 2.0.5
@@ -825,6 +857,7 @@ module Mongo
825
857
  cmd = { listDatabases: 1 }
826
858
  cmd[:nameOnly] = !!name_only
827
859
  cmd[:filter] = filter unless filter.empty?
860
+ cmd[:authorizedDatabases] = true if opts[:authorized_databases]
828
861
  use(Database::ADMIN).database.read_command(cmd, opts).first[Database::DATABASES]
829
862
  end
830
863
 
@@ -865,8 +898,16 @@ module Mongo
865
898
  #
866
899
  # @since 2.5.0
867
900
  def start_session(options = {})
868
- get_session(options.merge(implicit: false)) or
869
- raise Error::InvalidSession.new(Session::SESSIONS_NOT_SUPPORTED)
901
+ session = get_session!(options.merge(implicit: false))
902
+ if block_given?
903
+ begin
904
+ yield session
905
+ ensure
906
+ session.end_session
907
+ end
908
+ else
909
+ session
910
+ end
870
911
  end
871
912
 
872
913
  # As of version 3.6 of the MongoDB server, a ``$changeStream`` pipeline stage is supported
@@ -912,6 +953,59 @@ module Mongo
912
953
  options)
913
954
  end
914
955
 
956
+ # Returns a session to use for operations if possible.
957
+ #
958
+ # If :session option is set, validates that session and returns it.
959
+ # Otherwise, if deployment supports sessions, creates a new session and
960
+ # returns it. When a new session is created, the session will be implicit
961
+ # (lifecycle is managed by the driver) if the :implicit option is given,
962
+ # otherwise the session will be explicit (lifecycle managed by the
963
+ # application). If deployment does not support session, returns nil.
964
+ #
965
+ # @option options [ true | false ] :implicit When no session is passed in,
966
+ # whether to create an implicit session.
967
+ # @option options [ Session ] :session The session to validate and return.
968
+ #
969
+ # @return [ Session | nil ] Session object or nil if sessions are not
970
+ # supported by the deployment.
971
+ #
972
+ # @api private
973
+ def get_session(options = {})
974
+ get_session!(options)
975
+ rescue Error::SessionsNotSupported
976
+ nil
977
+ end
978
+
979
+ # Creates a session to use for operations if possible and yields it to
980
+ # the provided block.
981
+ #
982
+ # If :session option is set, validates that session and uses it.
983
+ # Otherwise, if deployment supports sessions, creates a new session and
984
+ # uses it. When a new session is created, the session will be implicit
985
+ # (lifecycle is managed by the driver) if the :implicit option is given,
986
+ # otherwise the session will be explicit (lifecycle managed by the
987
+ # application). If deployment does not support session, yields nil to
988
+ # the block.
989
+ #
990
+ # When the block finishes, if the session was created and was implicit,
991
+ # or if an implicit session was passed in, the session is ended which
992
+ # returns it to the pool of available sessions.
993
+ #
994
+ # @option options [ true | false ] :implicit When no session is passed in,
995
+ # whether to create an implicit session.
996
+ # @option options [ Session ] :session The session to validate and return.
997
+ #
998
+ # @api private
999
+ def with_session(options = {}, &block)
1000
+ session = get_session(options)
1001
+
1002
+ yield session
1003
+ ensure
1004
+ if session && session.implicit?
1005
+ session.end_session
1006
+ end
1007
+ end
1008
+
915
1009
  private
916
1010
 
917
1011
  # Create a new encrypter object using the client's auto encryption options
@@ -944,30 +1038,34 @@ module Mongo
944
1038
  close_encrypter
945
1039
  end
946
1040
 
947
- # If options[:session] is set, validates that session and returns it.
948
- # If deployment supports sessions, creates a new session and returns it.
949
- # The session is implicit unless options[:implicit] is given.
950
- # If deployment does not support session, returns nil.
1041
+ # Returns a session to use for operations.
951
1042
  #
952
- # @return [ Session | nil ] Session object or nil if sessions are not
953
- # supported by the deployment.
954
- def get_session(options = {})
1043
+ # If :session option is set, validates that session and returns it.
1044
+ # Otherwise, if deployment supports sessions, creates a new session and
1045
+ # returns it. When a new session is created, the session will be implicit
1046
+ # (lifecycle is managed by the driver) if the :implicit option is given,
1047
+ # otherwise the session will be explicit (lifecycle managed by the
1048
+ # application). If deployment does not support session, raises
1049
+ # Error::InvalidSession.
1050
+ #
1051
+ # @option options [ true | false ] :implicit When no session is passed in,
1052
+ # whether to create an implicit session.
1053
+ # @option options [ Session ] :session The session to validate and return.
1054
+ #
1055
+ # @return [ Session ] A session object.
1056
+ #
1057
+ # @raise Error::SessionsNotSupported if sessions are not supported by
1058
+ # the deployment.
1059
+ #
1060
+ # @api private
1061
+ def get_session!(options = {})
955
1062
  if options[:session]
956
1063
  return options[:session].validate!(self)
957
1064
  end
958
1065
 
959
- if cluster.sessions_supported?
960
- Session.new(cluster.session_pool.checkout, self, { implicit: true }.merge(options))
961
- end
962
- end
1066
+ cluster.validate_session_support!
963
1067
 
964
- def with_session(options = {}, &block)
965
- session = get_session(options)
966
- yield(session)
967
- ensure
968
- if session && session.implicit?
969
- session.end_session
970
- end
1068
+ Session.new(cluster.session_pool.checkout, self, { implicit: true }.merge(options))
971
1069
  end
972
1070
 
973
1071
  def initialize_copy(original)
@@ -1038,6 +1136,30 @@ module Mongo
1038
1136
  if options[:direct_connection] == false && options[:connect] && options[:connect].to_sym == :direct
1039
1137
  raise ArgumentError, "Conflicting client options: direct_connection=false and connect=#{options[:connect]}"
1040
1138
  end
1139
+
1140
+ %i(connect_timeout socket_timeout).each do |key|
1141
+ if value = options[key]
1142
+ unless Numeric === value
1143
+ raise ArgumentError, "#{key} must be a non-negative number: #{value}"
1144
+ end
1145
+ if value < 0
1146
+ raise ArgumentError, "#{key} must be a non-negative number: #{value}"
1147
+ end
1148
+ end
1149
+ end
1150
+
1151
+ if value = options[:bg_error_backtrace]
1152
+ case value
1153
+ when Integer
1154
+ if value <= 0
1155
+ raise ArgumentError, ":bg_error_backtrace option value must be true, false, nil or a positive integer: #{value}"
1156
+ end
1157
+ when true
1158
+ # OK
1159
+ else
1160
+ raise ArgumentError, ":bg_error_backtrace option value must be true, false, nil or a positive integer: #{value}"
1161
+ end
1162
+ end
1041
1163
  end
1042
1164
 
1043
1165
  # Validates all authentication-related options after they are set on the client
@@ -395,7 +395,7 @@ module Mongo
395
395
  #
396
396
  # @since 2.0.0
397
397
  def servers
398
- topology.servers(servers_list.compact).compact
398
+ topology.servers(servers_list)
399
399
  end
400
400
 
401
401
  # The addresses in the cluster.
@@ -599,11 +599,14 @@ module Mongo
599
599
  # respective server is cleared. Set this option to true to keep the
600
600
  # existing connection pool (required when handling not master errors
601
601
  # on 4.2+ servers).
602
+ # @option aptions [ true | false ] :awaited Whether the updated description
603
+ # was a result of processing an awaited ismaster.
602
604
  #
603
605
  # @api private
604
606
  def run_sdam_flow(previous_desc, updated_desc, options = {})
605
607
  @sdam_flow_lock.synchronize do
606
- flow = SdamFlow.new(self, previous_desc, updated_desc)
608
+ flow = SdamFlow.new(self, previous_desc, updated_desc,
609
+ awaited: options[:awaited])
607
610
  flow.server_description_changed
608
611
 
609
612
  # SDAM flow may alter the updated description - grab the final
@@ -886,21 +889,26 @@ module Mongo
886
889
  end
887
890
  end
888
891
 
889
- # Returns whether the deployment that the driver is connected to supports
890
- # sessions.
892
+ # Raises Error::SessionsNotAvailable if the deployment that the driver
893
+ # is connected to does not support sessions.
891
894
  #
892
895
  # Session support may change over time, for example due to servers in the
893
- # deployment being upgraded or downgraded. This method returns the
894
- # current information if the client is connected to at least one data
895
- # bearing server. If the client is currently not connected to any data
896
- # bearing servers, this method returns the last known value for whether
897
- # the deployment supports sessions.
896
+ # deployment being upgraded or downgraded. If the client is currently not
897
+ # connected to any data bearing servers, this method considers the state
898
+ # of session support as of when the client was last connected to at
899
+ # least one server. If the client has never connected to any servers,
900
+ # the deployment is considered to not support sessions.
898
901
  #
899
- # @return [ true | false ] Whether deployment supports sessions.
900
902
  # @api private
901
- def sessions_supported?
902
- if topology.data_bearing_servers?
903
- return !!topology.logical_session_timeout
903
+ def validate_session_support!
904
+ @state_change_lock.synchronize do
905
+ @sdam_flow_lock.synchronize do
906
+ if topology.data_bearing_servers?
907
+ unless topology.logical_session_timeout
908
+ raise_sessions_not_supported
909
+ end
910
+ end
911
+ end
904
912
  end
905
913
 
906
914
  # No data bearing servers known - perform server selection to try to
@@ -908,12 +916,24 @@ module Mongo
908
916
  # assessment of whether sessions are currently supported.
909
917
  begin
910
918
  ServerSelector.get(mode: :primary_preferred).select_server(self)
911
- !!topology.logical_session_timeout
919
+ @state_change_lock.synchronize do
920
+ @sdam_flow_lock.synchronize do
921
+ unless topology.logical_session_timeout
922
+ raise_sessions_not_supported
923
+ end
924
+ end
925
+ end
912
926
  rescue Error::NoServerAvailable
913
927
  # We haven't been able to contact any servers - use last known
914
- # value for esssion support.
915
- @update_lock.synchronize do
916
- @sessions_supported || false
928
+ # value for session support.
929
+ @state_change_lock.synchronize do
930
+ @sdam_flow_lock.synchronize do
931
+ @update_lock.synchronize do
932
+ unless @sessions_supported
933
+ raise_sessions_not_supported
934
+ end
935
+ end
936
+ end
917
937
  end
918
938
  end
919
939
  end
@@ -952,6 +972,22 @@ module Mongo
952
972
  end
953
973
  end
954
974
  end
975
+
976
+ def raise_sessions_not_supported
977
+ # Intentionally using @servers instead of +servers+ here because we
978
+ # are supposed to be already holding the @update_lock and we cannot
979
+ # recursively acquire it again.
980
+ offending_servers = @servers.select do |server|
981
+ server.description.data_bearing? && server.logical_session_timeout.nil?
982
+ end
983
+ reason = if offending_servers.empty?
984
+ "There are no known data bearing servers (current seeds: #{@servers.map(&:address).map(&:seed).join(', ')})"
985
+ else
986
+ "The following servers have null logical session timeout: #{offending_servers.map(&:address).map(&:seed).join(', ')}"
987
+ end
988
+ msg = "The deployment that the driver is connected to does not support sessions: #{reason}"
989
+ raise Error::SessionsNotSupported, msg
990
+ end
955
991
  end
956
992
  end
957
993