mongo 2.14.1 → 2.15.0.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +4 -1
  4. data/Rakefile +8 -15
  5. data/lib/mongo/auth/aws/conversation.rb +1 -4
  6. data/lib/mongo/auth/base.rb +13 -7
  7. data/lib/mongo/auth/conversation_base.rb +32 -0
  8. data/lib/mongo/auth/cr/conversation.rb +6 -29
  9. data/lib/mongo/auth/gssapi/conversation.rb +4 -15
  10. data/lib/mongo/auth/ldap/conversation.rb +3 -14
  11. data/lib/mongo/auth/sasl_conversation_base.rb +1 -13
  12. data/lib/mongo/auth/scram_conversation_base.rb +7 -34
  13. data/lib/mongo/auth/user/view.rb +16 -9
  14. data/lib/mongo/auth/x509/conversation.rb +4 -25
  15. data/lib/mongo/bulk_write.rb +21 -18
  16. data/lib/mongo/client.rb +82 -6
  17. data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
  18. data/lib/mongo/cluster.rb +19 -2
  19. data/lib/mongo/collection/view/aggregation.rb +1 -1
  20. data/lib/mongo/collection/view/change_stream.rb +1 -1
  21. data/lib/mongo/collection/view/iterable.rb +7 -17
  22. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  23. data/lib/mongo/collection/view/readable.rb +42 -20
  24. data/lib/mongo/collection/view/writable.rb +14 -14
  25. data/lib/mongo/collection.rb +6 -6
  26. data/lib/mongo/cursor.rb +2 -12
  27. data/lib/mongo/database/view.rb +1 -1
  28. data/lib/mongo/database.rb +8 -3
  29. data/lib/mongo/error/bulk_write_error.rb +17 -3
  30. data/lib/mongo/error/internal_driver_error.rb +22 -0
  31. data/lib/mongo/error/operation_failure.rb +21 -2
  32. data/lib/mongo/error/parser.rb +65 -12
  33. data/lib/mongo/error/server_api_conflict.rb +23 -0
  34. data/lib/mongo/error/server_api_not_supported.rb +24 -0
  35. data/lib/mongo/error/unmet_dependency.rb +21 -0
  36. data/lib/mongo/error.rb +9 -1
  37. data/lib/mongo/index/view.rb +21 -11
  38. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +27 -16
  39. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +26 -15
  40. data/lib/mongo/monitoring.rb +13 -4
  41. data/lib/mongo/operation/collections_info/command.rb +2 -2
  42. data/lib/mongo/operation/collections_info.rb +18 -1
  43. data/lib/mongo/operation/context.rb +99 -0
  44. data/lib/mongo/operation/indexes.rb +15 -1
  45. data/lib/mongo/operation/insert/command.rb +2 -2
  46. data/lib/mongo/operation/insert/legacy.rb +2 -2
  47. data/lib/mongo/operation/insert/op_msg.rb +2 -2
  48. data/lib/mongo/operation/list_collections/result.rb +4 -1
  49. data/lib/mongo/operation/parallel_scan/command.rb +2 -1
  50. data/lib/mongo/operation/result.rb +2 -0
  51. data/lib/mongo/operation/shared/executable.rb +24 -14
  52. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  53. data/lib/mongo/operation/shared/op_msg_or_command.rb +1 -7
  54. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +1 -7
  55. data/lib/mongo/operation/shared/polymorphic_operation.rb +39 -0
  56. data/lib/mongo/operation/shared/read_preference_supported.rb +36 -38
  57. data/lib/mongo/operation/shared/response_handling.rb +23 -23
  58. data/lib/mongo/operation/shared/sessions_supported.rb +15 -5
  59. data/lib/mongo/operation/shared/write.rb +8 -18
  60. data/lib/mongo/operation.rb +2 -2
  61. data/lib/mongo/protocol/compressed.rb +51 -5
  62. data/lib/mongo/protocol/message.rb +20 -2
  63. data/lib/mongo/protocol/msg.rb +38 -13
  64. data/lib/mongo/protocol/query.rb +11 -11
  65. data/lib/mongo/query_cache.rb +30 -0
  66. data/lib/mongo/retryable.rb +1 -1
  67. data/lib/mongo/server/app_metadata.rb +52 -18
  68. data/lib/mongo/server/connection.rb +5 -0
  69. data/lib/mongo/server/connection_base.rb +13 -10
  70. data/lib/mongo/server/connection_pool.rb +6 -2
  71. data/lib/mongo/server/description/features.rb +9 -8
  72. data/lib/mongo/server/description.rb +4 -0
  73. data/lib/mongo/server/monitor/app_metadata.rb +1 -1
  74. data/lib/mongo/server/monitor/connection.rb +9 -10
  75. data/lib/mongo/server/monitor.rb +20 -1
  76. data/lib/mongo/server/pending_connection.rb +24 -6
  77. data/lib/mongo/server/push_monitor.rb +11 -1
  78. data/lib/mongo/server.rb +7 -1
  79. data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
  80. data/lib/mongo/session/session_pool.rb +4 -2
  81. data/lib/mongo/session.rb +2 -2
  82. data/lib/mongo/socket/ssl.rb +8 -0
  83. data/lib/mongo/socket.rb +29 -4
  84. data/lib/mongo/uri/options_mapper.rb +38 -0
  85. data/lib/mongo/utils.rb +15 -0
  86. data/lib/mongo/version.rb +1 -1
  87. data/lib/mongo.rb +23 -0
  88. data/spec/README.md +24 -1
  89. data/spec/integration/auth_spec.rb +25 -15
  90. data/spec/integration/bulk_write_error_message_spec.rb +41 -0
  91. data/spec/integration/change_stream_spec.rb +4 -4
  92. data/spec/integration/command_monitoring_spec.rb +2 -2
  93. data/spec/integration/connection_spec.rb +2 -0
  94. data/spec/integration/docs_examples_spec.rb +8 -1
  95. data/spec/integration/fork_reconnect_spec.rb +4 -1
  96. data/spec/integration/ocsp_verifier_spec.rb +13 -7
  97. data/spec/integration/operation_failure_code_spec.rb +1 -1
  98. data/spec/integration/operation_failure_message_spec.rb +90 -0
  99. data/spec/integration/query_cache_spec.rb +0 -45
  100. data/spec/integration/reconnect_spec.rb +1 -1
  101. data/spec/integration/snappy_compression_spec.rb +25 -0
  102. data/spec/integration/srv_monitoring_spec.rb +1 -1
  103. data/spec/integration/transactions_examples_spec.rb +6 -0
  104. data/spec/integration/zlib_compression_spec.rb +1 -1
  105. data/spec/integration/zstd_compression_spec.rb +26 -0
  106. data/spec/lite_spec_helper.rb +7 -1
  107. data/spec/mongo/address_spec.rb +15 -11
  108. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  109. data/spec/mongo/auth/ldap_spec.rb +5 -1
  110. data/spec/mongo/auth/scram_negotiation_spec.rb +1 -1
  111. data/spec/mongo/auth/scram_spec.rb +1 -1
  112. data/spec/mongo/auth/x509/conversation_spec.rb +3 -3
  113. data/spec/mongo/client_construction_spec.rb +207 -33
  114. data/spec/mongo/client_spec.rb +17 -0
  115. data/spec/mongo/cluster_spec.rb +1 -0
  116. data/spec/mongo/collection/view/explainable_spec.rb +1 -1
  117. data/spec/mongo/collection/view/readable_spec.rb +33 -19
  118. data/spec/mongo/collection_crud_spec.rb +4357 -0
  119. data/spec/mongo/collection_ddl_spec.rb +534 -0
  120. data/spec/mongo/collection_spec.rb +5 -4859
  121. data/spec/mongo/database_spec.rb +66 -4
  122. data/spec/mongo/error/bulk_write_error_spec.rb +3 -3
  123. data/spec/mongo/error/parser_spec.rb +37 -6
  124. data/spec/mongo/index/view_spec.rb +4 -0
  125. data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +1 -1
  126. data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +1 -1
  127. data/spec/mongo/operation/aggregate_spec.rb +2 -1
  128. data/spec/mongo/operation/collections_info_spec.rb +4 -1
  129. data/spec/mongo/operation/command_spec.rb +6 -3
  130. data/spec/mongo/operation/create_index_spec.rb +6 -3
  131. data/spec/mongo/operation/create_user_spec.rb +6 -3
  132. data/spec/mongo/operation/delete/bulk_spec.rb +9 -6
  133. data/spec/mongo/operation/delete_spec.rb +11 -7
  134. data/spec/mongo/operation/drop_index_spec.rb +6 -2
  135. data/spec/mongo/operation/find/legacy_spec.rb +3 -1
  136. data/spec/mongo/operation/get_more_spec.rb +3 -1
  137. data/spec/mongo/operation/indexes_spec.rb +5 -1
  138. data/spec/mongo/operation/insert/bulk_spec.rb +10 -7
  139. data/spec/mongo/operation/insert_spec.rb +15 -12
  140. data/spec/mongo/operation/map_reduce_spec.rb +5 -2
  141. data/spec/mongo/operation/read_preference_legacy_spec.rb +19 -9
  142. data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
  143. data/spec/mongo/operation/remove_user_spec.rb +6 -3
  144. data/spec/mongo/operation/result_spec.rb +1 -1
  145. data/spec/mongo/operation/update/bulk_spec.rb +9 -6
  146. data/spec/mongo/operation/update_spec.rb +10 -7
  147. data/spec/mongo/operation/update_user_spec.rb +4 -1
  148. data/spec/mongo/protocol/compressed_spec.rb +26 -12
  149. data/spec/mongo/query_cache_middleware_spec.rb +55 -0
  150. data/spec/mongo/retryable_spec.rb +3 -2
  151. data/spec/mongo/server/app_metadata_shared.rb +7 -33
  152. data/spec/mongo/server/app_metadata_spec.rb +2 -0
  153. data/spec/mongo/server/connection_pool/populator_spec.rb +3 -1
  154. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  155. data/spec/mongo/server/connection_spec.rb +24 -17
  156. data/spec/mongo/server/monitor/connection_spec.rb +17 -7
  157. data/spec/mongo/server/monitor_spec.rb +9 -1
  158. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  159. data/spec/mongo/server_spec.rb +15 -2
  160. data/spec/mongo/socket/ssl_spec.rb +40 -0
  161. data/spec/mongo/socket_spec.rb +2 -2
  162. data/spec/mongo/tls_context_hooks_spec.rb +37 -0
  163. data/spec/runners/connection_string.rb +0 -4
  164. data/spec/runners/crud/requirement.rb +40 -3
  165. data/spec/runners/crud/verifier.rb +8 -0
  166. data/spec/runners/transactions/operation.rb +1 -1
  167. data/spec/runners/transactions/test.rb +1 -0
  168. data/spec/runners/unified/assertions.rb +249 -0
  169. data/spec/runners/unified/change_stream_operations.rb +26 -0
  170. data/spec/runners/unified/crud_operations.rb +199 -0
  171. data/spec/runners/unified/ddl_operations.rb +96 -0
  172. data/spec/runners/unified/entity_map.rb +39 -0
  173. data/spec/runners/unified/error.rb +25 -0
  174. data/spec/runners/unified/event_subscriber.rb +91 -0
  175. data/spec/runners/unified/exceptions.rb +21 -0
  176. data/spec/runners/unified/grid_fs_operations.rb +55 -0
  177. data/spec/runners/unified/support_operations.rb +250 -0
  178. data/spec/runners/unified/test.rb +393 -0
  179. data/spec/runners/unified/test_group.rb +28 -0
  180. data/spec/runners/unified/using_hash.rb +31 -0
  181. data/spec/runners/unified.rb +96 -0
  182. data/spec/shared/lib/mrss/cluster_config.rb +0 -3
  183. data/spec/shared/lib/mrss/docker_runner.rb +0 -3
  184. data/spec/shared/lib/mrss/lite_constraints.rb +0 -16
  185. data/spec/shared/lib/mrss/server_version_registry.rb +0 -3
  186. data/spec/shared/lib/mrss/spec_organizer.rb +0 -3
  187. data/spec/shared/shlib/server.sh +1 -1
  188. data/spec/spec_helper.rb +4 -1
  189. data/spec/spec_tests/crud_unified_spec.rb +10 -0
  190. data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
  191. data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +267 -0
  192. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-4.9.yml +60 -0
  193. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → estimatedDocumentCount-pre4.9.yml} +2 -0
  194. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors-4.9.yml +146 -0
  195. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → estimatedDocumentCount-serverErrors-pre4.9.yml} +2 -0
  196. data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +1 -1
  197. data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
  198. data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +220 -0
  199. data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
  200. data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
  201. data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
  202. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
  203. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
  204. data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
  205. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
  206. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
  207. data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +170 -0
  208. data/spec/spec_tests/data/uri_options/compression-options.yml +1 -1
  209. data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +416 -0
  210. data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +409 -0
  211. data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +67 -0
  212. data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
  213. data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +44 -0
  214. data/spec/spec_tests/data/versioned_api/transaction-handling.yml +180 -0
  215. data/spec/spec_tests/unified_spec.rb +15 -0
  216. data/spec/spec_tests/uri_options_spec.rb +16 -0
  217. data/spec/spec_tests/versioned_api_spec.rb +10 -0
  218. data/spec/support/client_registry.rb +4 -8
  219. data/spec/support/client_registry_macros.rb +4 -4
  220. data/spec/support/common_shortcuts.rb +15 -1
  221. data/spec/support/shared/session.rb +2 -2
  222. data/spec/support/spec_config.rb +42 -11
  223. data/spec/support/utils.rb +64 -3
  224. data.tar.gz.sig +0 -0
  225. metadata +1005 -915
  226. metadata.gz.sig +0 -0
  227. data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +0 -58
  228. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -47
  229. data/spec/integration/secondary_reads_spec.rb +0 -102
  230. data/spec/support/cluster_config.rb +0 -207
data/lib/mongo/client.rb CHANGED
@@ -85,6 +85,7 @@ module Mongo
85
85
  :retry_writes,
86
86
  :scan,
87
87
  :sdam_proc,
88
+ :server_api,
88
89
  :server_selection_timeout,
89
90
  :socket_timeout,
90
91
  :ssl,
@@ -114,7 +115,16 @@ module Mongo
114
115
  # The compression algorithms supported by the driver.
115
116
  #
116
117
  # @since 2.5.0
117
- VALID_COMPRESSORS = [ Mongo::Protocol::Compressed::ZLIB ].freeze
118
+ VALID_COMPRESSORS = [
119
+ Mongo::Protocol::Compressed::ZSTD,
120
+ Mongo::Protocol::Compressed::SNAPPY,
121
+ Mongo::Protocol::Compressed::ZLIB
122
+ ].freeze
123
+
124
+ # The known server API versions.
125
+ VALID_SERVER_API_VERSIONS = %w(
126
+ 1
127
+ ).freeze
118
128
 
119
129
  # @return [ Mongo::Cluster ] cluster The cluster of servers for the client.
120
130
  attr_reader :cluster
@@ -223,7 +233,7 @@ module Mongo
223
233
  # @option options [ Array<String> ] :compressors A list of potential
224
234
  # compressors to use, in order of preference. The driver chooses the
225
235
  # first compressor that is also supported by the server. Currently the
226
- # driver only supports 'zlib'.
236
+ # driver only supports 'zstd, 'snappy' and 'zlib'.
227
237
  # @option options [ true | false ] :direct_connection Whether to connect
228
238
  # directly to the specified seed, bypassing topology discovery. Exactly
229
239
  # one seed must be provided.
@@ -312,6 +322,11 @@ module Mongo
312
322
  # in particular the cluster is nil at this time. sdam_proc should
313
323
  # limit itself to calling #subscribe and #unsubscribe methods on the
314
324
  # client only.
325
+ # @option options [ Hash ] :server_api The requested server API version.
326
+ # This hash can have the following items:
327
+ # - *:version* -- string
328
+ # - *:strict* -- boolean
329
+ # - *:deprecation_errors* -- boolean
315
330
  # @option options [ Integer ] :server_selection_timeout The timeout in seconds
316
331
  # for selecting a server for an operation.
317
332
  # @option options [ Float ] :socket_timeout The timeout, in seconds, to
@@ -465,6 +480,18 @@ module Mongo
465
480
 
466
481
  options = self.class.canonicalize_ruby_options(options)
467
482
 
483
+ # The server API version is specified to be a string.
484
+ # However, it is very annoying to always provide the number 1 as a string,
485
+ # therefore cast to the string type here.
486
+ if server_api = options[:server_api]
487
+ if server_api.is_a?(Hash)
488
+ server_api = Options::Redacted.new(server_api)
489
+ if (version = server_api[:version]).is_a?(Integer)
490
+ options[:server_api] = server_api.merge(version: version.to_s)
491
+ end
492
+ end
493
+ end
494
+
468
495
  # Special handling for sdam_proc as it is only used during client
469
496
  # construction
470
497
  sdam_proc = options.delete(:sdam_proc)
@@ -499,7 +526,9 @@ module Mongo
499
526
  validate_options!(addresses)
500
527
  validate_authentication_options!
501
528
 
502
- @database = Database.new(self, @options[:database], @options)
529
+ database_options = @options.dup
530
+ database_options.delete(:server_api)
531
+ @database = Database.new(self, @options[:database], database_options)
503
532
 
504
533
  # Temporarily set monitoring so that event subscriptions can be
505
534
  # set up without there being a cluster
@@ -697,9 +726,9 @@ module Mongo
697
726
  # @return [ Mongo::Client ] A new client instance.
698
727
  #
699
728
  # @since 2.0.0
700
- def with(new_options = Options::Redacted.new)
729
+ def with(new_options = nil)
701
730
  clone.tap do |client|
702
- opts = client.update_options(new_options)
731
+ opts = client.update_options(new_options || Options::Redacted.new)
703
732
  Database.create(client)
704
733
  # We can't use the same cluster if some options that would affect it
705
734
  # have changed.
@@ -726,6 +755,8 @@ module Mongo
726
755
  def update_options(new_options)
727
756
  old_options = @options
728
757
 
758
+ new_options = self.class.canonicalize_ruby_options(new_options || {})
759
+
729
760
  validate_new_options!(new_options).tap do |opts|
730
761
  # Our options are frozen
731
762
  options = @options.dup
@@ -1127,7 +1158,7 @@ module Mongo
1127
1158
  # The argument may contain a subset of options that the client will
1128
1159
  # eventually have; this method validates each of the provided options
1129
1160
  # but does not check for interactions between combinations of options.
1130
- def validate_new_options!(opts = Options::Redacted.new)
1161
+ def validate_new_options!(opts)
1131
1162
  return Options::Redacted.new unless opts
1132
1163
  if opts[:read_concern]
1133
1164
  # Raise an error for non user-settable options
@@ -1146,6 +1177,23 @@ module Mongo
1146
1177
  end
1147
1178
  end
1148
1179
 
1180
+ if server_api = opts[:server_api]
1181
+ unless server_api.is_a?(Hash)
1182
+ raise ArgumentError, ":server_api value must be a hash: #{server_api}"
1183
+ end
1184
+
1185
+ extra_keys = server_api.keys - %w(version strict deprecation_errors)
1186
+ unless extra_keys.empty?
1187
+ raise ArgumentError, "Unknown keys under :server_api: #{extra_keys.map(&:inspect).join(', ')}"
1188
+ end
1189
+
1190
+ if version = server_api[:version]
1191
+ unless VALID_SERVER_API_VERSIONS.include?(version)
1192
+ raise ArgumentError, "Unknown server API version: #{version}"
1193
+ end
1194
+ end
1195
+ end
1196
+
1149
1197
  Lint.validate_underscore_read_preference(opts[:read])
1150
1198
  Lint.validate_read_concern_option(opts[:read_concern])
1151
1199
  opts.each.inject(Options::Redacted.new) do |_options, (k, v)|
@@ -1155,6 +1203,15 @@ module Mongo
1155
1203
  validate_read!(key, opts)
1156
1204
  if key == :compressors
1157
1205
  compressors = valid_compressors(v)
1206
+
1207
+ if compressors.include?('snappy')
1208
+ validate_snappy_compression!
1209
+ end
1210
+
1211
+ if compressors.include?('zstd')
1212
+ validate_zstd_compression!
1213
+ end
1214
+
1158
1215
  _options[key] = compressors unless compressors.empty?
1159
1216
  else
1160
1217
  _options[key] = v
@@ -1311,11 +1368,30 @@ module Mongo
1311
1368
  "This compressor will not be used.")
1312
1369
  false
1313
1370
  else
1371
+
1314
1372
  true
1315
1373
  end
1316
1374
  end
1317
1375
  end
1318
1376
 
1377
+ def validate_snappy_compression!
1378
+ return if defined?(Snappy)
1379
+ require 'snappy'
1380
+ rescue LoadError => e
1381
+ raise Error::UnmetDependency, "Cannot enable snappy compression because the snappy gem " \
1382
+ "has not been installed. Add \"gem 'snappy'\" to your Gemfile and run " \
1383
+ "\"bundle install\" to install the gem. (#{e.class}: #{e})"
1384
+ end
1385
+
1386
+ def validate_zstd_compression!
1387
+ return if defined?(Zstd)
1388
+ require 'zstd-ruby'
1389
+ rescue LoadError => e
1390
+ raise Error::UnmetDependency, "Cannot enable zstd compression because the zstd-ruby gem " \
1391
+ "has not been installed. Add \"gem 'zstd-ruby'\" to your Gemfile and run " \
1392
+ "\"bundle install\" to install the gem. (#{e.class}: #{e})"
1393
+ end
1394
+
1319
1395
  def validate_max_min_pool_size!(option, opts)
1320
1396
  if option == :min_pool_size && opts[:min_pool_size]
1321
1397
  max = opts[:max_pool_size] || Server::ConnectionPool::DEFAULT_MAX_SIZE
@@ -130,16 +130,20 @@ module Mongo
130
130
  end
131
131
 
132
132
  to_kill_copy.each do |server, op_specs|
133
+ options = {
134
+ server_api: server.options[:server_api],
135
+ }
136
+ context = Operation::Context.new(options: options)
133
137
  op_specs.each do |op_spec|
134
138
  if server.features.find_command_enabled?
135
139
  Cursor::Builder::KillCursorsCommand.update_cursors(op_spec, active_cursors_copy.to_a)
136
140
  if Cursor::Builder::KillCursorsCommand.get_cursors_list(op_spec).size > 0
137
- Operation::KillCursors.new(op_spec).execute(server, client: nil)
141
+ Operation::KillCursors.new(op_spec).execute(server, context: context)
138
142
  end
139
143
  else
140
144
  Cursor::Builder::OpKillCursors.update_cursors(op_spec, active_cursors_copy.to_a)
141
145
  if Cursor::Builder::OpKillCursors.get_cursors_list(op_spec).size > 0
142
- Operation::KillCursors.new(op_spec).execute(server, client: nil)
146
+ Operation::KillCursors.new(op_spec).execute(server, context: context)
143
147
  end
144
148
  end
145
149
  end
data/lib/mongo/cluster.rb CHANGED
@@ -107,6 +107,11 @@ module Mongo
107
107
  # for the server monitor to refresh its description via ismaster.
108
108
  # @option options [ Hash ] :resolv_options For internal driver use only.
109
109
  # Options to pass through to Resolv::DNS constructor for SRV lookups.
110
+ # @option options [ Hash ] :server_api The requested server API version.
111
+ # This hash can have the following items:
112
+ # - *:version* -- string
113
+ # - *:strict* -- boolean
114
+ # - *:deprecation_errors* -- boolean
110
115
  #
111
116
  # @since 2.0.0
112
117
  def initialize(seeds, monitoring, options = Options::Redacted.new)
@@ -129,7 +134,9 @@ module Mongo
129
134
  @servers = []
130
135
  @monitoring = monitoring
131
136
  @event_listeners = Event::Listeners.new
132
- @app_metadata = Server::AppMetadata.new(@options)
137
+ @app_metadata = Server::AppMetadata.new(@options.merge(purpose: :application))
138
+ @monitor_app_metadata = Server::Monitor::AppMetadata.new(@options.merge(purpose: :monitor))
139
+ @push_monitor_app_metadata = Server::Monitor::AppMetadata.new(@options.merge(purpose: :push_monitor))
133
140
  @cluster_time_lock = Mutex.new
134
141
  @cluster_time = nil
135
142
  @srv_monitor_lock = Mutex.new
@@ -241,7 +248,11 @@ module Mongo
241
248
  # the servers list above and the wait call below, we should not
242
249
  # wait for the full remaining time - wait for up to 1 second, then
243
250
  # recheck the state.
244
- server_selection_semaphore.wait([time_remaining, 1].min)
251
+ begin
252
+ server_selection_semaphore.wait([time_remaining, 1].min)
253
+ rescue ::Timeout::Error
254
+ # nothing
255
+ end
245
256
  end
246
257
  end
247
258
 
@@ -285,6 +296,12 @@ module Mongo
285
296
  # @since 2.4.0
286
297
  attr_reader :app_metadata
287
298
 
299
+ # @api private
300
+ attr_reader :monitor_app_metadata
301
+
302
+ # @api private
303
+ attr_reader :push_monitor_app_metadata
304
+
288
305
  # @return [ Array<String> ] The addresses of seed servers. Contains
289
306
  # addresses that were given to Cluster when it was instantiated, not
290
307
  # current addresses that the cluster is using as a result of SDAM.
@@ -134,7 +134,7 @@ module Mongo
134
134
  server = cluster.next_primary(nil, session)
135
135
  end
136
136
  validate_collation!(server)
137
- initial_query_op(session).execute(server, client: client)
137
+ initial_query_op(session).execute(server, context: Operation::Context.new(client: client, session: session))
138
138
  end
139
139
 
140
140
  def validate_collation!(server)
@@ -346,7 +346,7 @@ module Mongo
346
346
  end
347
347
 
348
348
  def send_initial_query(server, session)
349
- initial_query_op(session).execute(server, client: client)
349
+ initial_query_op(session).execute(server, context: Operation::Context.new(client: client, session: session))
350
350
  end
351
351
 
352
352
  def time_to_bson_timestamp(time)
@@ -35,28 +35,18 @@ module Mongo
35
35
  #
36
36
  # @yieldparam [ Hash ] Each matching document.
37
37
  def each
38
- # If the caching cursor is closed and was not fully iterated,
39
- # the documents we have in it are not the complete result set and
40
- # we have no way of completing that iteration.
41
- # Therefore, discard that cursor and start iteration again.
42
- # The case of the caching cursor not being closed and not having
43
- # been fully iterated isn't tested - see RUBY-2773.
44
- @cursor = if use_query_cache? && cached_cursor && (
45
- cached_cursor.fully_iterated? || !cached_cursor.closed?
46
- )
38
+ @cursor = if use_query_cache? && cached_cursor
47
39
  cached_cursor
48
40
  else
49
41
  session = client.send(:get_session, @options)
50
- select_cursor(session).tap do |cursor|
51
- if use_query_cache?
52
- # No need to store the cursor in the query cache if there is
53
- # already a cached cursor stored at this key.
54
- QueryCache.set(cursor, **cache_options)
55
- end
56
- end
42
+ select_cursor(session)
57
43
  end
58
44
 
59
45
  if use_query_cache?
46
+ # No need to store the cursor in the query cache if there is
47
+ # already a cached cursor stored at this key.
48
+ QueryCache.set(@cursor, **cache_options) unless cached_cursor
49
+
60
50
  # If a query with a limit is performed, the query cache will
61
51
  # re-use results from an earlier query with the same or larger
62
52
  # limit, and then impose the lower limit during iteration.
@@ -167,7 +157,7 @@ module Mongo
167
157
 
168
158
  def send_initial_query(server, session = nil)
169
159
  validate_collation!(server, collation)
170
- initial_query_op(server, session).execute(server, client: client)
160
+ initial_query_op(server, session).execute(server, context: Operation::Context.new(client: client, session: session))
171
161
  end
172
162
 
173
163
  def use_query_cache?
@@ -242,7 +242,7 @@ module Mongo
242
242
  server = cluster.next_primary(nil, session)
243
243
  end
244
244
  validate_collation!(server)
245
- initial_query_op(session).execute(server, client: client)
245
+ initial_query_op(session).execute(server, context: Operation::Context.new(client: client, session: session))
246
246
  end
247
247
 
248
248
  def fetch_query_spec
@@ -262,7 +262,7 @@ module Mongo
262
262
  end
263
263
 
264
264
  def send_fetch_query(server, session)
265
- fetch_query_op(server, session).execute(server, client: client)
265
+ fetch_query_op(server, session).execute(server, context: Operation::Context.new(client: client, session: session))
266
266
  end
267
267
 
268
268
  def validate_collation!(server)
@@ -172,8 +172,8 @@ module Mongo
172
172
  :db_name => database.name,
173
173
  :options => {:limit => -1},
174
174
  :read => read_pref,
175
- :session => session
176
- ).execute(server, client: client)
175
+ :session => session,
176
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
177
177
  end.n.to_i
178
178
  end
179
179
  end
@@ -230,24 +230,46 @@ module Mongo
230
230
  raise ArgumentError, "Cannot call estimated_document_count when querying with a filter"
231
231
  end
232
232
 
233
- cmd = { count: collection.name }
234
- cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
235
- if read_concern
236
- cmd[:readConcern] = Options::Mapper.transform_values_to_strings(
237
- read_concern)
238
- end
239
233
  Mongo::Lint.validate_underscore_read_preference(opts[:read])
240
234
  read_pref = opts[:read] || read_preference
241
235
  selector = ServerSelector.get(read_pref || server_selector)
242
236
  with_session(opts) do |session|
237
+ context = Operation::Context.new(client: client, session: session)
243
238
  read_with_retry(session, selector) do |server|
244
- Operation::Count.new(
245
- selector: cmd,
246
- db_name: database.name,
247
- read: read_pref,
248
- session: session
249
- ).execute(server, client: client)
250
- end.n.to_i
239
+ if server.description.server_version_gte?('5.0')
240
+ pipeline = [
241
+ {'$collStats' => {'count' => {}}},
242
+ {'$group' => {'_id' => 1, 'n' => {'$sum' => '$count'}}},
243
+ ]
244
+ spec = Builder::Aggregation.new(pipeline, self, options.merge(session: session)).specification
245
+ result = Operation::Aggregate.new(spec).execute(server, context: context)
246
+ result.documents.first.fetch('n')
247
+ else
248
+ cmd = { count: collection.name }
249
+ cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
250
+ if read_concern
251
+ cmd[:readConcern] = Options::Mapper.transform_values_to_strings(
252
+ read_concern)
253
+ end
254
+ result = Operation::Count.new(
255
+ selector: cmd,
256
+ db_name: database.name,
257
+ read: read_pref,
258
+ session: session,
259
+ ).execute(server, context: context)
260
+ result.n.to_i
261
+ end
262
+ end
263
+ end
264
+ rescue Error::OperationFailure => exc
265
+ if exc.code == 26
266
+ # NamespaceNotFound
267
+ # This should only happen with the aggregation pipeline path
268
+ # (server 4.9+). Previous servers should return 0 for nonexistent
269
+ # collections.
270
+ 0
271
+ else
272
+ raise
251
273
  end
252
274
  end
253
275
 
@@ -290,8 +312,8 @@ module Mongo
290
312
  :db_name => database.name,
291
313
  :options => {:limit => -1},
292
314
  :read => read_pref,
293
- :session => session
294
- }).execute(server, client: client)
315
+ :session => session,
316
+ }).execute(server, context: Operation::Context.new(client: client, session: session))
295
317
  end.first['values']
296
318
  end
297
319
  end
@@ -626,21 +648,21 @@ module Mongo
626
648
  :read_concern => read_concern,
627
649
  :session => session,
628
650
  }.merge!(options))
629
- cmd.execute(server, client: client).cursor_ids.map do |cursor_id|
651
+ cmd.execute(server, context: Operation::Context.new(client: client, session: session)).cursor_ids.map do |cursor_id|
630
652
  result = if server.with_connection { |connection| connection.features }.find_command_enabled?
631
653
  Operation::GetMore.new({
632
654
  :selector => {:getMore => BSON::Int64.new(cursor_id),
633
655
  :collection => collection.name},
634
656
  :db_name => database.name,
635
657
  :session => session,
636
- }).execute(server, client: client)
658
+ }).execute(server, context: Operation::Context.new(client: client, session: session))
637
659
  else
638
660
  Operation::GetMore.new({
639
661
  :to_return => 0,
640
662
  :cursor_id => BSON::Int64.new(cursor_id),
641
663
  :db_name => database.name,
642
664
  :coll_name => collection.name
643
- }).execute(server, client: client)
665
+ }).execute(server, context: Operation::Context.new(client: client, session: session))
644
666
  end
645
667
  Cursor.new(self, result, server, session: session)
646
668
  end
@@ -69,8 +69,8 @@ module Mongo
69
69
  :selector => cmd,
70
70
  :db_name => database.name,
71
71
  :session => session,
72
- :txn_num => txn_num
73
- ).execute(server, client: client)
72
+ :txn_num => txn_num,
73
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
74
74
  end
75
75
  end.first['value']
76
76
  end
@@ -154,8 +154,8 @@ module Mongo
154
154
  :selector => cmd,
155
155
  :db_name => database.name,
156
156
  :session => session,
157
- :txn_num => txn_num
158
- ).execute(server, client: client)
157
+ :txn_num => txn_num,
158
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
159
159
  end
160
160
  end.first['value']
161
161
  value unless value.nil? || value.empty?
@@ -198,8 +198,8 @@ module Mongo
198
198
  :coll_name => collection.name,
199
199
  :write_concern => write_concern,
200
200
  :bypass_document_validation => !!opts[:bypass_document_validation],
201
- :session => session
202
- ).execute(server, client: client)
201
+ :session => session,
202
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
203
203
  end
204
204
  end
205
205
  end
@@ -242,8 +242,8 @@ module Mongo
242
242
  :write_concern => write_concern,
243
243
  :bypass_document_validation => !!opts[:bypass_document_validation],
244
244
  :session => session,
245
- :txn_num => txn_num
246
- ).execute(server, client: client)
245
+ :txn_num => txn_num,
246
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
247
247
  end
248
248
  end
249
249
  end
@@ -298,8 +298,8 @@ module Mongo
298
298
  :write_concern => write_concern,
299
299
  :bypass_document_validation => !!opts[:bypass_document_validation],
300
300
  :session => session,
301
- :txn_num => txn_num
302
- ).execute(server, client: client)
301
+ :txn_num => txn_num,
302
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
303
303
  end
304
304
  end
305
305
  end
@@ -355,8 +355,8 @@ module Mongo
355
355
  :coll_name => collection.name,
356
356
  :write_concern => write_concern,
357
357
  :bypass_document_validation => !!opts[:bypass_document_validation],
358
- :session => session
359
- ).execute(server, client: client)
358
+ :session => session,
359
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
360
360
  end
361
361
  end
362
362
  end
@@ -412,8 +412,8 @@ module Mongo
412
412
  :write_concern => write_concern,
413
413
  :bypass_document_validation => !!opts[:bypass_document_validation],
414
414
  :session => session,
415
- :txn_num => txn_num
416
- ).execute(server, client: client)
415
+ :txn_num => txn_num,
416
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
417
417
  end
418
418
  end
419
419
  end
@@ -254,8 +254,8 @@ module Mongo
254
254
  selector: operation,
255
255
  db_name: database.name,
256
256
  write_concern: write_concern,
257
- session: session
258
- }).execute(server, client: client)
257
+ session: session,
258
+ }).execute(server, context: Operation::Context.new(client: client, session: session))
259
259
  end
260
260
  end
261
261
 
@@ -287,8 +287,8 @@ module Mongo
287
287
  selector: { :drop => name },
288
288
  db_name: database.name,
289
289
  write_concern: write_concern,
290
- session: session
291
- }).execute(next_primary(nil, session), client: client)
290
+ session: session,
291
+ }).execute(next_primary(nil, session), context: Operation::Context.new(client: client, session: session))
292
292
  end
293
293
  rescue Error::OperationFailure => ex
294
294
  # NamespaceNotFound
@@ -579,8 +579,8 @@ module Mongo
579
579
  :options => opts,
580
580
  :id_generator => client.options[:id_generator],
581
581
  :session => session,
582
- :txn_num => txn_num
583
- ).execute(server, client: client)
582
+ :txn_num => txn_num,
583
+ ).execute(server, context: Operation::Context.new(client: client, session: session))
584
584
  end
585
585
  end
586
586
  end
data/lib/mongo/cursor.rb CHANGED
@@ -209,12 +209,10 @@ module Mongo
209
209
  unless closed?
210
210
  if exhausted?
211
211
  close
212
- @fully_iterated = true
213
212
  raise StopIteration
214
213
  end
215
214
  @documents = get_more
216
215
  else
217
- @fully_iterated = true
218
216
  raise StopIteration
219
217
  end
220
218
  else
@@ -231,9 +229,6 @@ module Mongo
231
229
  # over the last document, or if the batch is empty
232
230
  if @documents.size <= 1
233
231
  cache_batch_resume_token
234
- if closed?
235
- @fully_iterated = true
236
- end
237
232
  end
238
233
 
239
234
  return @documents.shift
@@ -275,7 +270,7 @@ module Mongo
275
270
 
276
271
  unregister
277
272
  read_with_one_retry do
278
- kill_cursors_operation.execute(@server, client: client)
273
+ kill_cursors_operation.execute(@server, context: Operation::Context.new(client: client, session: @session))
279
274
  end
280
275
 
281
276
  nil
@@ -350,12 +345,7 @@ module Mongo
350
345
  # doing so may result in silent data loss, the driver no longer retries
351
346
  # getMore operations in any circumstance.
352
347
  # https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.rst#qa
353
- process(get_more_operation.execute(@server, client: client))
354
- end
355
-
356
- # @api private
357
- def fully_iterated?
358
- !!@fully_iterated
348
+ process(get_more_operation.execute(@server, context: Operation::Context.new(client: client, session: @session)))
359
349
  end
360
350
 
361
351
  private
@@ -189,7 +189,7 @@ module Mongo
189
189
  end
190
190
 
191
191
  def send_initial_query(server, session, options = {})
192
- initial_query_op(session, options).execute(server, client: client)
192
+ initial_query_op(session, options).execute(server, context: Operation::Context.new(client: client, session: session))
193
193
  end
194
194
  end
195
195
  end
@@ -104,6 +104,9 @@ module Mongo
104
104
  #
105
105
  # @since 2.0.0
106
106
  def [](collection_name, options = {})
107
+ if options[:server_api]
108
+ raise ArgumentError, 'The :server_api option cannot be specified for collection objects. It can only be specified on Client level'
109
+ end
107
110
  Collection.new(self, collection_name, options)
108
111
  end
109
112
  alias_method :collection, :[]
@@ -219,7 +222,9 @@ module Mongo
219
222
  :session => session
220
223
  )
221
224
 
222
- op.execute(server, client: client, options: execution_opts)
225
+ op.execute(server,
226
+ context: Operation::Context.new(client: client, session: session),
227
+ options: execution_opts)
223
228
  end
224
229
  end
225
230
 
@@ -250,7 +255,7 @@ module Mongo
250
255
  :db_name => name,
251
256
  :read => preference,
252
257
  :session => session
253
- }).execute(server, client: client)
258
+ }).execute(server, context: Operation::Context.new(client: client, session: session))
254
259
  end
255
260
  end
256
261
  end
@@ -281,7 +286,7 @@ module Mongo
281
286
  db_name: name,
282
287
  write_concern: write_concern,
283
288
  session: session
284
- }).execute(next_primary(nil, session), client: client)
289
+ }).execute(next_primary(nil, session), context: Operation::Context.new(client: client, session: session))
285
290
  end
286
291
  end
287
292