mongo 2.9.2 → 2.10.0.rc0

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 (227) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo.rb +1 -0
  5. data/lib/mongo/auth/user/view.rb +4 -4
  6. data/lib/mongo/bulk_write.rb +14 -8
  7. data/lib/mongo/bulk_write/result.rb +1 -1
  8. data/lib/mongo/bulk_write/result_combiner.rb +2 -2
  9. data/lib/mongo/bulk_write/transformable.rb +17 -9
  10. data/lib/mongo/client.rb +107 -16
  11. data/lib/mongo/cluster.rb +47 -25
  12. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +1 -1
  13. data/lib/mongo/cluster_time.rb +139 -0
  14. data/lib/mongo/collection.rb +84 -25
  15. data/lib/mongo/collection/view.rb +7 -3
  16. data/lib/mongo/collection/view/aggregation.rb +4 -4
  17. data/lib/mongo/collection/view/builder/aggregation.rb +31 -6
  18. data/lib/mongo/collection/view/builder/find_command.rb +4 -1
  19. data/lib/mongo/collection/view/builder/map_reduce.rb +4 -1
  20. data/lib/mongo/collection/view/change_stream.rb +54 -66
  21. data/lib/mongo/collection/view/iterable.rb +2 -2
  22. data/lib/mongo/collection/view/map_reduce.rb +6 -4
  23. data/lib/mongo/collection/view/readable.rb +36 -16
  24. data/lib/mongo/collection/view/writable.rb +68 -22
  25. data/lib/mongo/cursor.rb +87 -20
  26. data/lib/mongo/database.rb +47 -43
  27. data/lib/mongo/database/view.rb +54 -11
  28. data/lib/mongo/error.rb +13 -4
  29. data/lib/mongo/error/invalid_write_concern.rb +2 -2
  30. data/lib/mongo/error/operation_failure.rb +65 -11
  31. data/lib/mongo/error/parser.rb +41 -8
  32. data/lib/mongo/grid/fs_bucket.rb +26 -6
  33. data/lib/mongo/grid/stream/read.rb +9 -2
  34. data/lib/mongo/grid/stream/write.rb +21 -5
  35. data/lib/mongo/index/view.rb +3 -3
  36. data/lib/mongo/lint.rb +10 -3
  37. data/lib/mongo/operation.rb +2 -0
  38. data/lib/mongo/operation/aggregate/result.rb +19 -6
  39. data/lib/mongo/operation/collections_info.rb +1 -1
  40. data/lib/mongo/operation/get_more/result.rb +9 -0
  41. data/lib/mongo/operation/list_collections/command.rb +1 -3
  42. data/lib/mongo/operation/list_collections/op_msg.rb +1 -2
  43. data/lib/mongo/operation/parallel_scan/command.rb +4 -1
  44. data/lib/mongo/operation/parallel_scan/op_msg.rb +4 -1
  45. data/lib/mongo/operation/result.rb +27 -4
  46. data/lib/mongo/operation/shared/executable.rb +19 -5
  47. data/lib/mongo/operation/shared/executable_no_validate.rb +1 -2
  48. data/lib/mongo/operation/shared/executable_transaction_label.rb +0 -9
  49. data/lib/mongo/operation/shared/polymorphic_result.rb +9 -1
  50. data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
  51. data/lib/mongo/operation/shared/sessions_supported.rb +42 -32
  52. data/lib/mongo/operation/shared/specifiable.rb +40 -0
  53. data/lib/mongo/operation/shared/unpinnable.rb +39 -0
  54. data/lib/mongo/operation/shared/write.rb +1 -1
  55. data/lib/mongo/protocol/update.rb +6 -2
  56. data/lib/mongo/retryable.rb +79 -39
  57. data/lib/mongo/server/connection.rb +10 -3
  58. data/lib/mongo/server/description.rb +25 -1
  59. data/lib/mongo/server/monitor/connection.rb +1 -1
  60. data/lib/mongo/server_selector.rb +10 -0
  61. data/lib/mongo/server_selector/selectable.rb +172 -32
  62. data/lib/mongo/session.rb +654 -581
  63. data/lib/mongo/session/session_pool.rb +1 -1
  64. data/lib/mongo/socket.rb +7 -28
  65. data/lib/mongo/socket/ssl.rb +26 -1
  66. data/lib/mongo/socket/tcp.rb +3 -0
  67. data/lib/mongo/socket/unix.rb +3 -0
  68. data/lib/mongo/uri.rb +112 -265
  69. data/lib/mongo/uri/srv_protocol.rb +4 -1
  70. data/lib/mongo/version.rb +1 -1
  71. data/lib/mongo/write_concern.rb +10 -29
  72. data/lib/mongo/write_concern/acknowledged.rb +12 -0
  73. data/lib/mongo/write_concern/base.rb +17 -13
  74. data/lib/mongo/write_concern/unacknowledged.rb +12 -0
  75. data/spec/atlas/atlas_connectivity_spec.rb +7 -37
  76. data/spec/atlas/operations_spec.rb +25 -0
  77. data/spec/integration/change_stream_examples_spec.rb +45 -31
  78. data/spec/integration/change_stream_spec.rb +305 -5
  79. data/spec/integration/client_spec.rb +44 -0
  80. data/spec/integration/command_monitoring_spec.rb +1 -0
  81. data/spec/integration/command_spec.rb +7 -1
  82. data/spec/integration/mmapv1_spec.rb +28 -0
  83. data/spec/integration/mongos_pinning_spec.rb +34 -0
  84. data/spec/integration/operation_failure_code_spec.rb +2 -2
  85. data/spec/integration/{read_concern.rb → read_concern_spec.rb} +7 -1
  86. data/spec/integration/read_preference_spec.rb +485 -0
  87. data/spec/integration/retryable_writes_spec.rb +8 -19
  88. data/spec/integration/sdam_error_handling_spec.rb +1 -1
  89. data/spec/integration/sdam_events_spec.rb +2 -2
  90. data/spec/integration/server_description_spec.rb +14 -17
  91. data/spec/integration/server_selector_spec.rb +7 -3
  92. data/spec/integration/server_spec.rb +48 -0
  93. data/spec/integration/ssl_uri_options_spec.rb +1 -1
  94. data/spec/integration/step_down_spec.rb +10 -4
  95. data/spec/integration/transactions_examples_spec.rb +11 -10
  96. data/spec/lite_spec_helper.rb +19 -16
  97. data/spec/mongo/auth/scram/negotiation_spec.rb +11 -8
  98. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +6 -6
  99. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +4 -4
  100. data/spec/mongo/bulk_write_spec.rb +12 -2
  101. data/spec/mongo/client_construction_spec.rb +160 -8
  102. data/spec/mongo/client_spec.rb +5 -4
  103. data/spec/mongo/cluster_spec.rb +6 -6
  104. data/spec/mongo/cluster_time_spec.rb +148 -0
  105. data/spec/mongo/collection/view/aggregation_spec.rb +34 -15
  106. data/spec/mongo/collection/view/change_stream_spec.rb +62 -3
  107. data/spec/mongo/collection/view/map_reduce_spec.rb +7 -5
  108. data/spec/mongo/collection/view/readable_spec.rb +4 -4
  109. data/spec/mongo/collection_spec.rb +331 -14
  110. data/spec/mongo/cursor_spec.rb +117 -5
  111. data/spec/mongo/database_spec.rb +240 -8
  112. data/spec/mongo/error/operation_failure_spec.rb +47 -1
  113. data/spec/mongo/error/parser_spec.rb +160 -23
  114. data/spec/mongo/operation/insert/bulk_spec.rb +2 -1
  115. data/spec/mongo/operation/result_spec.rb +27 -0
  116. data/spec/mongo/operation/update/bulk_spec.rb +1 -0
  117. data/spec/mongo/retryable_spec.rb +2 -0
  118. data/spec/mongo/server/app_metadata_spec.rb +2 -2
  119. data/spec/mongo/server/connection_spec.rb +13 -17
  120. data/spec/mongo/server/monitor/connection_spec.rb +13 -10
  121. data/spec/mongo/server_selector_spec.rb +34 -2
  122. data/spec/mongo/session/session_pool_spec.rb +14 -3
  123. data/spec/mongo/session_spec.rb +3 -3
  124. data/spec/mongo/session_transaction_spec.rb +4 -3
  125. data/spec/mongo/socket/ssl_spec.rb +19 -5
  126. data/spec/mongo/socket_spec.rb +1 -62
  127. data/spec/mongo/uri/srv_protocol_spec.rb +14 -20
  128. data/spec/mongo/uri_option_parsing_spec.rb +94 -8
  129. data/spec/mongo/uri_spec.rb +23 -10
  130. data/spec/mongo/write_concern_spec.rb +56 -3
  131. data/spec/spec_tests/change_streams_spec.rb +2 -1
  132. data/spec/spec_tests/cmap_spec.rb +1 -1
  133. data/spec/spec_tests/crud_spec.rb +12 -2
  134. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +24 -1
  135. data/spec/spec_tests/data/change_streams/change-streams.yml +172 -3
  136. data/spec/spec_tests/data/command_monitoring/bulkWrite.yml +1 -1
  137. data/spec/spec_tests/data/command_monitoring/updateMany.yml +0 -2
  138. data/spec/spec_tests/data/command_monitoring/updateOne.yml +0 -5
  139. data/spec/spec_tests/data/crud/read/aggregate-out.yml +0 -6
  140. data/spec/spec_tests/data/crud/read/count-empty.yml +29 -0
  141. data/spec/spec_tests/data/crud/write/bulkWrite-arrayFilters.yml +1 -0
  142. data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +101 -0
  143. data/spec/spec_tests/data/crud/write/bulkWrite.yml +401 -0
  144. data/spec/spec_tests/data/crud/write/insertMany.yml +58 -2
  145. data/spec/spec_tests/data/crud/write/updateMany-arrayFilters.yml +3 -0
  146. data/spec/spec_tests/data/crud/write/updateOne-arrayFilters.yml +6 -1
  147. data/spec/spec_tests/data/crud_v2/aggregate-merge.yml +103 -0
  148. data/spec/spec_tests/data/crud_v2/aggregate-out-readConcern.yml +110 -0
  149. data/spec/spec_tests/data/crud_v2/bulkWrite-arrayFilters.yml +81 -0
  150. data/spec/spec_tests/data/crud_v2/db-aggregate.yml +38 -0
  151. data/spec/spec_tests/data/crud_v2/updateWithPipelines.yml +92 -0
  152. data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +2 -2
  153. data/spec/spec_tests/data/transactions/abort.yml +3 -0
  154. data/spec/spec_tests/data/transactions/bulk.yml +3 -8
  155. data/spec/spec_tests/data/transactions/causal-consistency.yml +3 -8
  156. data/spec/spec_tests/data/transactions/commit.yml +3 -1
  157. data/spec/spec_tests/data/transactions/count.yml +3 -0
  158. data/spec/spec_tests/data/transactions/delete.yml +3 -0
  159. data/spec/spec_tests/data/transactions/error-labels.yml +4 -1
  160. data/spec/spec_tests/data/transactions/errors-client.yml +56 -0
  161. data/spec/spec_tests/data/transactions/errors.yml +3 -0
  162. data/spec/spec_tests/data/transactions/findOneAndDelete.yml +3 -0
  163. data/spec/spec_tests/data/transactions/findOneAndReplace.yml +3 -0
  164. data/spec/spec_tests/data/transactions/findOneAndUpdate.yml +3 -0
  165. data/spec/spec_tests/data/transactions/insert.yml +3 -0
  166. data/spec/spec_tests/data/transactions/isolation.yml +3 -0
  167. data/spec/spec_tests/data/transactions/mongos-pin-auto.yml +1671 -0
  168. data/spec/spec_tests/data/transactions/mongos-recovery-token.yml +347 -0
  169. data/spec/spec_tests/data/transactions/pin-mongos.yml +557 -0
  170. data/spec/spec_tests/data/transactions/read-concern.yml +3 -0
  171. data/spec/spec_tests/data/transactions/read-pref.yml +3 -0
  172. data/spec/spec_tests/data/transactions/reads.yml +3 -0
  173. data/spec/spec_tests/data/transactions/retryable-abort.yml +5 -2
  174. data/spec/spec_tests/data/transactions/retryable-commit.yml +4 -1
  175. data/spec/spec_tests/data/transactions/retryable-writes.yml +3 -0
  176. data/spec/spec_tests/data/transactions/run-command.yml +3 -0
  177. data/spec/spec_tests/data/transactions/transaction-options.yml +6 -0
  178. data/spec/spec_tests/data/transactions/update.yml +3 -8
  179. data/spec/spec_tests/data/transactions/write-concern.yml +348 -38
  180. data/spec/spec_tests/data/transactions_api/callback-aborts.yml +6 -0
  181. data/spec/spec_tests/data/transactions_api/callback-commits.yml +5 -0
  182. data/spec/spec_tests/data/transactions_api/callback-retry.yml +7 -2
  183. data/spec/spec_tests/data/transactions_api/commit-retry.yml +70 -15
  184. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror-4.2.yml +3 -0
  185. data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror.yml +3 -0
  186. data/spec/spec_tests/data/transactions_api/commit-writeconcernerror.yml +59 -109
  187. data/spec/spec_tests/data/transactions_api/commit.yml +5 -0
  188. data/spec/spec_tests/data/transactions_api/transaction-options.yml +10 -0
  189. data/spec/spec_tests/retryable_reads_spec.rb +5 -2
  190. data/spec/spec_tests/retryable_writes_spec.rb +5 -2
  191. data/spec/spec_tests/sdam_monitoring_spec.rb +3 -3
  192. data/spec/spec_tests/sdam_spec.rb +2 -2
  193. data/spec/spec_tests/transactions_api_spec.rb +1 -67
  194. data/spec/spec_tests/transactions_spec.rb +2 -66
  195. data/spec/support/authorization.rb +4 -0
  196. data/spec/support/change_streams.rb +30 -10
  197. data/spec/support/change_streams/operation.rb +27 -0
  198. data/spec/support/client_registry.rb +44 -25
  199. data/spec/support/cluster_config.rb +25 -14
  200. data/spec/support/cluster_tools.rb +32 -10
  201. data/spec/support/command_monitoring.rb +1 -1
  202. data/spec/support/common_shortcuts.rb +30 -0
  203. data/spec/support/connection_string.rb +8 -3
  204. data/spec/support/constraints.rb +34 -0
  205. data/spec/support/crud.rb +31 -16
  206. data/spec/support/crud/context.rb +23 -0
  207. data/spec/support/crud/operation.rb +311 -14
  208. data/spec/support/crud/spec.rb +2 -1
  209. data/spec/support/crud/test.rb +24 -27
  210. data/spec/support/crud/test_base.rb +22 -0
  211. data/spec/support/crud/verifier.rb +15 -1
  212. data/spec/support/event_subscriber.rb +12 -0
  213. data/spec/support/sdam_formatter_integration.rb +12 -6
  214. data/spec/support/shared/server_selector.rb +10 -0
  215. data/spec/support/shared/session.rb +13 -12
  216. data/spec/support/spec_config.rb +32 -22
  217. data/spec/support/spec_setup.rb +2 -2
  218. data/spec/support/transactions.rb +87 -0
  219. data/spec/support/transactions/context.rb +33 -0
  220. data/spec/support/transactions/operation.rb +99 -349
  221. data/spec/support/transactions/spec.rb +1 -3
  222. data/spec/support/transactions/test.rb +110 -49
  223. data/spec/support/utils.rb +74 -1
  224. metadata +52 -10
  225. metadata.gz.sig +0 -0
  226. data/spec/support/crud/read.rb +0 -265
  227. data/spec/support/crud/write.rb +0 -284
@@ -28,6 +28,7 @@ module Mongo
28
28
  include Monitoring::Publishable
29
29
  include Event::Subscriber
30
30
  include Loggable
31
+ include ClusterTime::Consumer
31
32
 
32
33
  # The default number of legacy read retries.
33
34
  #
@@ -53,6 +54,7 @@ module Mongo
53
54
  # The cluster time key in responses from mongos servers.
54
55
  #
55
56
  # @since 2.5.0
57
+ # @deprecated
56
58
  CLUSTER_TIME = 'clusterTime'.freeze
57
59
 
58
60
  # Instantiate the new cluster.
@@ -74,18 +76,23 @@ module Mongo
74
76
  # @param [ Hash ] options Options. Client constructor forwards its
75
77
  # options to Cluster constructor, although Cluster recognizes
76
78
  # only a subset of the options recognized by Client.
77
- # @option options [ true, false ] :scan Whether to scan all seeds
79
+ # @option options [ true | false ] :scan Whether to scan all seeds
78
80
  # in constructor. The default in driver version 2.x is to do so;
79
81
  # driver version 3.x will not scan seeds in constructor. Opt in to the
80
82
  # new behavior by setting this option to false. *Note:* setting
81
83
  # this option to nil enables scanning seeds in constructor in driver
82
84
  # version 2.x. Driver version 3.x will recognize this option but
83
85
  # will ignore it and will never scan seeds in the constructor.
84
- # @option options [ true, false ] :monitoring_io For internal driver
86
+ # @option options [ true | false ] :monitoring_io For internal driver
85
87
  # use only. Set to false to prevent SDAM-related I/O from being
86
88
  # done by this cluster or servers under it. Note: setting this option
87
89
  # to false will make the cluster non-functional. It is intended for
88
90
  # use in tests which manually invoke SDAM state transitions.
91
+ # @option options [ true | false ] :cleanup For internal driver use only.
92
+ # Set to false to prevent endSessions command being sent to the server
93
+ # to clean up server sessions when the cluster is disconnected, and to
94
+ # to not start the periodic executor. If :monitoring_io is false,
95
+ # :cleanup automatically defaults to false as well.
89
96
  #
90
97
  # @since 2.0.0
91
98
  def initialize(seeds, monitoring, options = Options::Redacted.new)
@@ -93,6 +100,11 @@ module Mongo
93
100
  raise ArgumentError, 'Need server selection semaphore'
94
101
  end
95
102
 
103
+ if options[:monitoring_io] == false && !options.key?(:cleanup)
104
+ options = options.dup
105
+ options[:cleanup] = false
106
+ end
107
+
96
108
  @servers = []
97
109
  @monitoring = monitoring
98
110
  @event_listeners = Event::Listeners.new
@@ -148,12 +160,14 @@ module Mongo
148
160
  return
149
161
  end
150
162
 
151
- @cursor_reaper = CursorReaper.new
152
- @socket_reaper = SocketReaper.new(self)
153
- @periodic_executor = PeriodicExecutor.new(@cursor_reaper, @socket_reaper)
154
- @periodic_executor.run!
163
+ if options[:cleanup] != false
164
+ @cursor_reaper = CursorReaper.new
165
+ @socket_reaper = SocketReaper.new(self)
166
+ @periodic_executor = PeriodicExecutor.new(@cursor_reaper, @socket_reaper)
167
+ @periodic_executor.run!
155
168
 
156
- ObjectSpace.define_finalizer(self, self.class.finalize({}, @periodic_executor, @session_pool))
169
+ ObjectSpace.define_finalizer(self, self.class.finalize({}, @periodic_executor, @session_pool))
170
+ end
157
171
 
158
172
  @connecting = false
159
173
  @connected = true
@@ -225,11 +239,6 @@ module Mongo
225
239
  # @since 2.4.0
226
240
  attr_reader :app_metadata
227
241
 
228
- # @return [ BSON::Document ] The latest cluster time seen.
229
- #
230
- # @since 2.5.0
231
- attr_reader :cluster_time
232
-
233
242
  # @return [ Array<String> ] The addresses of seed servers. Contains
234
243
  # addresses that were given to Cluster when it was instantiated, not
235
244
  # current addresses that the cluster is using as a result of SDAM.
@@ -245,7 +254,14 @@ module Mongo
245
254
 
246
255
  def_delegators :topology, :replica_set?, :replica_set_name, :sharded?,
247
256
  :single?, :unknown?
248
- def_delegators :@cursor_reaper, :register_cursor, :schedule_kill_cursor, :unregister_cursor
257
+
258
+ [:register_cursor, :schedule_kill_cursor, :unregister_cursor].each do |m|
259
+ define_method(m) do |*args|
260
+ if options[:cleanup] != false
261
+ @cursor_reaper.send(m, *args)
262
+ end
263
+ end
264
+ end
249
265
 
250
266
  # Get the maximum number of times the client can retry a read operation
251
267
  # when using legacy read retries.
@@ -393,7 +409,12 @@ module Mongo
393
409
  unless @connecting || @connected
394
410
  return true
395
411
  end
396
- @periodic_executor.stop!
412
+ if options[:cleanup] != false
413
+ if wait
414
+ session_pool.end_sessions
415
+ end
416
+ @periodic_executor.stop!(wait)
417
+ end
397
418
  @servers.each do |server|
398
419
  if server.connected?
399
420
  server.disconnect!(wait)
@@ -519,16 +540,16 @@ module Mongo
519
540
  # @example Get the next primary server.
520
541
  # cluster.next_primary
521
542
  #
522
- # @param [ true, false ] ping Whether to ping the server before selection. Deprecated,
523
- # not necessary with the implementation of the Server Selection specification.
524
- #
543
+ # @param [ true, false ] ping Whether to ping the server before selection.
544
+ # Deprecated and ignored.
545
+ # @param [ Session | nil ] session Optional session to take into account
546
+ # for mongos pinning.
525
547
  #
526
548
  # @return [ Mongo::Server ] A primary server.
527
549
  #
528
550
  # @since 2.0.0
529
- def next_primary(ping = true)
530
- @primary_selector ||= ServerSelector.get(ServerSelector::PRIMARY)
531
- @primary_selector.select_server(self)
551
+ def next_primary(ping = nil, session = nil)
552
+ ServerSelector.primary.select_server(self, nil, session)
532
553
  end
533
554
 
534
555
  # Get the connection pool for the server.
@@ -559,11 +580,7 @@ module Mongo
559
580
  def update_cluster_time(result)
560
581
  if cluster_time_doc = result.cluster_time
561
582
  @cluster_time_lock.synchronize do
562
- if @cluster_time.nil?
563
- @cluster_time = cluster_time_doc
564
- elsif cluster_time_doc[CLUSTER_TIME] > @cluster_time[CLUSTER_TIME]
565
- @cluster_time = cluster_time_doc
566
- end
583
+ advance_cluster_time(cluster_time_doc)
567
584
  end
568
585
  end
569
586
  end
@@ -670,6 +687,11 @@ module Mongo
670
687
  # @note If the cluster has no data bearing servers, for example because
671
688
  # the deployment is in the middle of a failover, this method returns
672
689
  # false.
690
+ #
691
+ # @note This method returns as soon as the driver connects to any single
692
+ # server in the deployment. Whether deployment overall supports sessions
693
+ # can change depending on how many servers have been contacted, if
694
+ # the servers are configured differently.
673
695
  def sessions_supported?
674
696
  if topology.data_bearing_servers?
675
697
  return !!topology.logical_session_timeout
@@ -74,7 +74,7 @@ module Mongo
74
74
  #
75
75
  # @since 2.4.0
76
76
  def has_readable_server?(cluster, server_selector = nil)
77
- (server_selector || ServerSelector.get(mode: :primary)).candidates(cluster).any?
77
+ (server_selector || ServerSelector.primary).candidates(cluster).any?
78
78
  end
79
79
 
80
80
  # Determine if the topology would select a writable server for the
@@ -0,0 +1,139 @@
1
+ # Copyright (C) 2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Mongo
16
+ # ClusterTime encapsulates cluster time storage and operations.
17
+ #
18
+ # The primary operation performed on the cluster time is advancing it:
19
+ # given another cluster time, pick the newer of the two.
20
+ #
21
+ # This class provides comparison methods that are used to figure out which
22
+ # cluster time is newer, and provides diagnostics in lint mode when
23
+ # the actual time is missing from a cluster time document.
24
+ #
25
+ # @api private
26
+ class ClusterTime < BSON::Document
27
+ def initialize(elements = nil)
28
+ super
29
+
30
+ if Lint.enabled? && !self['clusterTime']
31
+ raise ArgumentError, 'Creating a cluster time without clusterTime field'
32
+ end
33
+ end
34
+
35
+ # Advances the cluster time in the receiver to the cluster time in +other+.
36
+ #
37
+ # +other+ can be nil or be behind the cluster time in the receiver; in
38
+ # these cases the receiver is returned unmodified. If receiver is advanced,
39
+ # a new ClusterTime object is returned.
40
+ #
41
+ # Return value is nil or a ClusterTime instance.
42
+ def advance(other)
43
+ if self['clusterTime'] && other['clusterTime'] &&
44
+ other['clusterTime'] > self['clusterTime']
45
+ then
46
+ ClusterTime[other]
47
+ else
48
+ self
49
+ end
50
+ end
51
+
52
+ # Compares two ClusterTime instances by comparing their timestamps.
53
+ def <=>(other)
54
+ if self['clusterTime'] && other['clusterTime']
55
+ self['clusterTime'] <=> other['clusterTime']
56
+ elsif !self['clusterTime']
57
+ raise ArgumentError, "Cannot compare cluster times when receiver is missing clusterTime key: #{inspect}"
58
+ else other['clusterTime']
59
+ raise ArgumentError, "Cannot compare cluster times when other is missing clusterTime key: #{other.inspect}"
60
+ end
61
+ end
62
+
63
+ # Older Rubies do not implement other logical operators through <=>.
64
+ # TODO revise whether these methods are needed when
65
+ # https://jira.mongodb.org/browse/RUBY-1622 is implemented.
66
+ def >=(other)
67
+ (self <=> other) != -1
68
+ end
69
+ def >(other)
70
+ (self <=> other) == 1
71
+ end
72
+ def <=(other)
73
+ (self <=> other) != 1
74
+ end
75
+ def <(other)
76
+ (self <=> other) == -1
77
+ end
78
+
79
+ # Compares two ClusterTime instances by comparing their timestamps.
80
+ def ==(other)
81
+ if self['clusterTime'] && other['clusterTime'] &&
82
+ self['clusterTime'] == other['clusterTime']
83
+ then
84
+ true
85
+ else
86
+ false
87
+ end
88
+ end
89
+
90
+ class << self
91
+ # Converts a BSON::Document to a ClusterTime.
92
+ #
93
+ # +doc+ can be nil, in which case nil is returned.
94
+ def [](doc)
95
+ if doc.nil? || doc.is_a?(ClusterTime)
96
+ doc
97
+ else
98
+ ClusterTime.new(doc)
99
+ end
100
+ end
101
+ end
102
+
103
+ # This module provides common cluster time tracking behavior.
104
+ #
105
+ # @note Although attributes and methods defined in this module are part of
106
+ # the public API for the classes including this module, the fact that
107
+ # the methods are defined on this module and not directly on the
108
+ # including classes is not part of the public API.
109
+ module Consumer
110
+
111
+ # The cluster time tracked by the object including this module.
112
+ #
113
+ # @return [ nil | ClusterTime ] The cluster time.
114
+ #
115
+ # Changed in version 2.9.0: This attribute became an instance of
116
+ # ClusterTime, which is a subclass of BSON::Document.
117
+ # Previously it was an instance of BSON::Document.
118
+ #
119
+ # @since 2.5.0
120
+ attr_reader :cluster_time
121
+
122
+ # Advance the tracked cluster time document for the object including
123
+ # this module.
124
+ #
125
+ # @param [ BSON::Document ] new_cluster_time The new cluster time document.
126
+ #
127
+ # @return [ ClusterTime ] The resulting cluster time.
128
+ #
129
+ # @since 2.5.0
130
+ def advance_cluster_time(new_cluster_time)
131
+ if @cluster_time
132
+ @cluster_time = @cluster_time.advance(new_cluster_time)
133
+ else
134
+ @cluster_time = ClusterTime[new_cluster_time]
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -53,7 +53,7 @@ module Mongo
53
53
  # Options that can be updated on a new Collection instance via the #with method.
54
54
  #
55
55
  # @since 2.1.0
56
- CHANGEABLE_OPTIONS = [ :read, :read_concern, :write ].freeze
56
+ CHANGEABLE_OPTIONS = [ :read, :read_concern, :write, :write_concern ].freeze
57
57
 
58
58
  # Check if a collection is equal to another object. Will check the name and
59
59
  # the database for equality.
@@ -80,12 +80,28 @@ module Mongo
80
80
  # @param [ String, Symbol ] name The collection name.
81
81
  # @param [ Hash ] options The collection options.
82
82
  #
83
+ # @option options [ Hash ] :write Deprecated. Equivalent to :write_concern
84
+ # option.
85
+ # @option options [ Hash ] :write_concern The write concern options.
86
+ # Can be :w => Integer|String, :fsync => Boolean, :j => Boolean.
87
+ #
83
88
  # @since 2.0.0
84
89
  def initialize(database, name, options = {})
85
90
  raise Error::InvalidCollectionName.new unless name
91
+ if options[:write] && options[:write_concern] && options[:write] != options[:write_concern]
92
+ raise ArgumentError, "If :write and :write_concern are both given, they must be identical: #{options.inspect}"
93
+ end
86
94
  @database = database
87
95
  @name = name.to_s.freeze
88
- @options = options.freeze
96
+ @options = options.dup
97
+ =begin WriteConcern object support
98
+ if @options[:write_concern].is_a?(WriteConcern::Base)
99
+ # Cache the instance so that we do not needlessly reconstruct it.
100
+ @write_concern = @options[:write_concern]
101
+ @options[:write_concern] = @write_concern.options
102
+ end
103
+ =end
104
+ @options.freeze
89
105
  end
90
106
 
91
107
  # Get the read concern for this collection instance.
@@ -133,17 +149,40 @@ module Mongo
133
149
  #
134
150
  # @since 2.0.0
135
151
  def write_concern
136
- @write_concern ||= WriteConcern.get(options[:write] || database.write_concern)
152
+ @write_concern ||= WriteConcern.get(
153
+ options[:write_concern] || options[:write] || database.write_concern)
154
+ end
155
+
156
+ # Get the write concern for the collection, given the session.
157
+ #
158
+ # If the session is in a transaction and the collection
159
+ # has an unacknowledged write concern, remove the write
160
+ # concern's :w option. Otherwise, return the unmodified
161
+ # write concern.
162
+ #
163
+ # @return [ Mongo::WriteConcern ] The write concern.
164
+ #
165
+ # @api private
166
+ def write_concern_with_session(session)
167
+ wc = write_concern
168
+ if session && session.in_transaction?
169
+ if wc && !wc.acknowledged?
170
+ opts = wc.options.dup
171
+ opts.delete(:w)
172
+ return WriteConcern.get(opts)
173
+ end
174
+ end
175
+ wc
137
176
  end
138
177
 
139
178
  # Provides a new collection with either a new read preference or new write concern
140
179
  # merged over the existing read preference / write concern.
141
180
  #
142
- # @example Get a collection with changed read preference.
143
- # collection.with(:read => { :mode => :primary_preferred })
181
+ # @example Get a collection with a changed read preference.
182
+ # collection.with(read: { mode: :primary_preferred })
144
183
  #
145
- # @example Get a collection with changed write concern.
146
- # collection.with(:write => { w: 3 })
184
+ # @example Get a collection with a changed write concern.
185
+ # collection.with(write_concern: { w: 3 })
147
186
 
148
187
  # @param [ Hash ] new_options The new options to use.
149
188
  #
@@ -154,7 +193,14 @@ module Mongo
154
193
  new_options.keys.each do |k|
155
194
  raise Error::UnchangeableCollectionOption.new(k) unless CHANGEABLE_OPTIONS.include?(k)
156
195
  end
157
- Collection.new(database, name, options.merge(new_options))
196
+ options = @options.dup
197
+ if options[:write] && new_options[:write_concern]
198
+ options.delete(:write)
199
+ end
200
+ if options[:write_concern] && new_options[:write]
201
+ options.delete(:write_concern)
202
+ end
203
+ Collection.new(database, name, options.update(new_options))
158
204
  end
159
205
 
160
206
  # Is the collection capped?
@@ -166,7 +212,7 @@ module Mongo
166
212
  #
167
213
  # @since 2.0.0
168
214
  def capped?
169
- database.read_command(:collstats => name).documents[0][CAPPED]
215
+ database.command(:collstats => name).documents[0][CAPPED]
170
216
  end
171
217
 
172
218
  # Force the collection to be created in the database.
@@ -182,13 +228,22 @@ module Mongo
182
228
  #
183
229
  # @since 2.0.0
184
230
  def create(opts = {})
231
+ # Passing read options to create command causes it to break.
232
+ # Filter the read options out.
233
+ # TODO put the list of read options in a class-level constant when
234
+ # we figure out what the full set of them is.
235
+ options = Hash[self.options.reject do |key, value|
236
+ %w(read read_preference).include?(key.to_s)
237
+ end]
185
238
  operation = { :create => name }.merge(options)
186
239
  operation.delete(:write)
187
- server = next_primary
188
- if (options[:collation] || options[Operation::COLLATION]) && !server.features.collation_enabled?
189
- raise Error::UnsupportedCollation.new
190
- end
240
+ operation.delete(:write_concern)
191
241
  client.send(:with_session, opts) do |session|
242
+ server = next_primary(nil, session)
243
+ if (options[:collation] || options[Operation::COLLATION]) && !server.features.collation_enabled?
244
+ raise Error::UnsupportedCollation
245
+ end
246
+
192
247
  Operation::Create.new({
193
248
  selector: operation,
194
249
  db_name: database.name,
@@ -220,7 +275,7 @@ module Mongo
220
275
  db_name: database.name,
221
276
  write_concern: write_concern,
222
277
  session: session
223
- }).execute(next_primary)
278
+ }).execute(next_primary(nil, session))
224
279
  end
225
280
  rescue Error::OperationFailure => ex
226
281
  raise ex unless ex.message =~ /ns not found/
@@ -277,18 +332,21 @@ module Mongo
277
332
  # @param [ Array<Hash> ] pipeline The aggregation pipeline.
278
333
  # @param [ Hash ] options The aggregation options.
279
334
  #
280
- # @option options [ true, false ] :allow_disk_use Set to true if disk usage is allowed during
281
- # the aggregation.
282
- # @option options [ Integer ] :batch_size The number of documents to return per batch.
283
- # @option options [ Integer ] :max_time_ms The maximum amount of time in milliseconds to allow the
284
- # aggregation to run.
285
- # @option options [ true, false ] :use_cursor Indicates whether the command will request that the server
286
- # provide results using a cursor. Note that as of server version 3.6, aggregations always provide results
287
- # using a cursor and this option is therefore not valid.
335
+ # @option options [ true, false ] :allow_disk_use Set to true if disk
336
+ # usage is allowed during the aggregation.
337
+ # @option options [ Integer ] :batch_size The number of documents to return
338
+ # per batch.
288
339
  # @option options [ true, false ] :bypass_document_validation Whether or
289
340
  # not to skip document level validation.
290
341
  # @option options [ Hash ] :collation The collation to use.
291
342
  # @option options [ String ] :comment Associate a comment with the aggregation.
343
+ # @option options [ String ] :hint The index to use for the aggregation.
344
+ # @option options [ Integer ] :max_time_ms The maximum amount of time in
345
+ # milliseconds to allow the aggregation to run.
346
+ # @option options [ true, false ] :use_cursor Indicates whether the command
347
+ # will request that the server provide results using a cursor. Note that
348
+ # as of server version 3.6, aggregations always provide results using a
349
+ # cursor and this option is therefore not valid.
292
350
  # @option options [ Session ] :session The session to use.
293
351
  #
294
352
  # @return [ Aggregation ] The aggregation object.
@@ -475,6 +533,7 @@ module Mongo
475
533
  # @since 2.0.0
476
534
  def insert_one(document, opts = {})
477
535
  client.send(:with_session, opts) do |session|
536
+ write_concern = write_concern_with_session(session)
478
537
  write_with_retry(session, write_concern) do |server, txn_num|
479
538
  Operation::Insert.new(
480
539
  :documents => [ document ],
@@ -620,7 +679,7 @@ module Mongo
620
679
  # collection.update_many({ name: 'test'}, '$set' => { name: 'test1' })
621
680
  #
622
681
  # @param [ Hash ] filter The filter to use.
623
- # @param [ Hash ] update The update statement.
682
+ # @param [ Hash | Array<Hash> ] update The update document or pipeline.
624
683
  # @param [ Hash ] options The options.
625
684
  #
626
685
  # @option options [ true, false ] :upsert Whether to upsert if the
@@ -645,7 +704,7 @@ module Mongo
645
704
  # collection.update_one({ name: 'test'}, '$set' => { name: 'test1'})
646
705
  #
647
706
  # @param [ Hash ] filter The filter to use.
648
- # @param [ Hash ] update The update statement.
707
+ # @param [ Hash | Array<Hash> ] update The update document or pipeline.
649
708
  # @param [ Hash ] options The options.
650
709
  #
651
710
  # @option options [ true, false ] :upsert Whether to upsert if the
@@ -700,7 +759,7 @@ module Mongo
700
759
  # collection.find_one_and_update({ name: 'test' }, { "$set" => { name: 'test1' }}, :return_document => :after)
701
760
  #
702
761
  # @param [ Hash ] filter The filter to use.
703
- # @param [ BSON::Document ] update The update statement.
762
+ # @param [ Hash | Array<Hash> ] update The update document or pipeline.
704
763
  # @param [ Hash ] options The options.
705
764
  #
706
765
  # @option options [ Integer ] :max_time_ms The maximum amount of time to allow the command