mongo 2.14.1 → 2.15.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
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