mongo 2.4.3 → 2.5.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -2
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo.rb +3 -2
  5. data/lib/mongo/auth/cr.rb +6 -4
  6. data/lib/mongo/auth/cr/conversation.rb +33 -17
  7. data/lib/mongo/auth/ldap.rb +4 -2
  8. data/lib/mongo/auth/ldap/conversation.rb +19 -9
  9. data/lib/mongo/auth/scram.rb +7 -4
  10. data/lib/mongo/auth/scram/conversation.rb +62 -24
  11. data/lib/mongo/auth/user.rb +10 -0
  12. data/lib/mongo/auth/user/view.rb +44 -22
  13. data/lib/mongo/auth/x509.rb +4 -2
  14. data/lib/mongo/auth/x509/conversation.rb +19 -9
  15. data/lib/mongo/bulk_write.rb +33 -27
  16. data/lib/mongo/bulk_write/combineable.rb +5 -0
  17. data/lib/mongo/bulk_write/transformable.rb +2 -0
  18. data/lib/mongo/bulk_write/validatable.rb +4 -0
  19. data/lib/mongo/client.rb +123 -12
  20. data/lib/mongo/cluster.rb +52 -11
  21. data/lib/mongo/cluster/app_metadata.rb +8 -2
  22. data/lib/mongo/cluster/cursor_reaper.rb +0 -1
  23. data/lib/mongo/cluster/topology.rb +1 -1
  24. data/lib/mongo/collection.rb +114 -27
  25. data/lib/mongo/collection/view.rb +8 -2
  26. data/lib/mongo/collection/view/aggregation.rb +11 -7
  27. data/lib/mongo/collection/view/builder/aggregation.rb +5 -1
  28. data/lib/mongo/collection/view/builder/find_command.rb +5 -3
  29. data/lib/mongo/collection/view/builder/map_reduce.rb +11 -3
  30. data/lib/mongo/collection/view/builder/op_query.rb +1 -1
  31. data/lib/mongo/collection/view/change_stream.rb +160 -0
  32. data/lib/mongo/collection/view/change_stream/retryable.rb +57 -0
  33. data/lib/mongo/collection/view/iterable.rb +11 -10
  34. data/lib/mongo/collection/view/map_reduce.rb +22 -18
  35. data/lib/mongo/collection/view/readable.rb +51 -37
  36. data/lib/mongo/collection/view/writable.rb +72 -40
  37. data/lib/mongo/cursor.rb +25 -4
  38. data/lib/mongo/cursor/builder/get_more_command.rb +4 -2
  39. data/lib/mongo/database.rb +22 -11
  40. data/lib/mongo/database/view.rb +16 -12
  41. data/lib/mongo/error.rb +5 -0
  42. data/lib/mongo/error/invalid_session.rb +36 -0
  43. data/lib/mongo/error/missing_resume_token.rb +39 -0
  44. data/lib/mongo/error/operation_failure.rb +17 -0
  45. data/lib/mongo/error/parser.rb +3 -2
  46. data/lib/mongo/error/unknown_payload_type.rb +41 -0
  47. data/lib/mongo/error/unsupported_array_filters.rb +51 -0
  48. data/lib/mongo/error/unsupported_message_type.rb +23 -0
  49. data/lib/mongo/grid/fs_bucket.rb +5 -4
  50. data/lib/mongo/grid/stream/read.rb +3 -2
  51. data/lib/mongo/grid/stream/write.rb +2 -2
  52. data/lib/mongo/index/view.rb +35 -25
  53. data/lib/mongo/monitoring/event/secure.rb +14 -0
  54. data/lib/mongo/operation.rb +16 -0
  55. data/lib/mongo/operation/commands.rb +1 -0
  56. data/lib/mongo/operation/commands/aggregate.rb +9 -5
  57. data/lib/mongo/operation/commands/aggregate/result.rb +1 -1
  58. data/lib/mongo/operation/commands/collections_info.rb +6 -6
  59. data/lib/mongo/operation/commands/command.rb +2 -1
  60. data/lib/mongo/operation/commands/create.rb +6 -2
  61. data/lib/mongo/operation/commands/drop.rb +6 -2
  62. data/lib/mongo/operation/commands/drop_database.rb +6 -2
  63. data/lib/mongo/operation/commands/explain.rb +27 -0
  64. data/lib/mongo/operation/commands/explain/result.rb +52 -0
  65. data/lib/mongo/operation/commands/indexes.rb +1 -1
  66. data/lib/mongo/operation/commands/list_collections.rb +1 -1
  67. data/lib/mongo/operation/commands/list_collections/result.rb +1 -1
  68. data/lib/mongo/operation/commands/list_indexes.rb +1 -1
  69. data/lib/mongo/operation/commands/list_indexes/result.rb +1 -1
  70. data/lib/mongo/operation/commands/map_reduce.rb +8 -4
  71. data/lib/mongo/operation/commands/map_reduce/result.rb +13 -1
  72. data/lib/mongo/operation/commands/user_query.rb +1 -1
  73. data/lib/mongo/operation/commands/users_info.rb +6 -2
  74. data/lib/mongo/operation/executable.rb +4 -1
  75. data/lib/mongo/operation/read_preference.rb +10 -5
  76. data/lib/mongo/operation/result.rb +26 -2
  77. data/lib/mongo/operation/specifiable.rb +13 -1
  78. data/lib/mongo/operation/uses_command_op_msg.rb +47 -0
  79. data/lib/mongo/operation/write/bulk/bulkable.rb +4 -1
  80. data/lib/mongo/operation/write/bulk/insert/result.rb +4 -4
  81. data/lib/mongo/operation/write/command/create_index.rb +6 -1
  82. data/lib/mongo/operation/write/command/delete.rb +28 -4
  83. data/lib/mongo/operation/write/command/drop_index.rb +6 -1
  84. data/lib/mongo/operation/write/command/insert.rb +22 -18
  85. data/lib/mongo/operation/write/command/update.rb +24 -9
  86. data/lib/mongo/operation/write/command/writable.rb +14 -1
  87. data/lib/mongo/operation/write/insert.rb +4 -1
  88. data/lib/mongo/operation/write/insert/result.rb +2 -2
  89. data/lib/mongo/operation/write/update.rb +7 -1
  90. data/lib/mongo/operation/write/write_command_enabled.rb +20 -3
  91. data/lib/mongo/protocol.rb +3 -0
  92. data/lib/mongo/protocol/bit_vector.rb +2 -2
  93. data/lib/mongo/protocol/compressed.rb +135 -0
  94. data/lib/mongo/protocol/delete.rb +8 -6
  95. data/lib/mongo/protocol/get_more.rb +8 -6
  96. data/lib/mongo/protocol/insert.rb +8 -6
  97. data/lib/mongo/protocol/kill_cursors.rb +8 -6
  98. data/lib/mongo/protocol/message.rb +31 -3
  99. data/lib/mongo/protocol/msg.rb +172 -0
  100. data/lib/mongo/protocol/query.rb +26 -6
  101. data/lib/mongo/protocol/registry.rb +76 -0
  102. data/lib/mongo/protocol/reply.rb +10 -5
  103. data/lib/mongo/protocol/serializers.rb +224 -0
  104. data/lib/mongo/protocol/update.rb +8 -6
  105. data/lib/mongo/retryable.rb +4 -2
  106. data/lib/mongo/server.rb +6 -3
  107. data/lib/mongo/server/connectable.rb +1 -1
  108. data/lib/mongo/server/connection.rb +30 -8
  109. data/lib/mongo/server/description.rb +25 -1
  110. data/lib/mongo/server/description/features.rb +4 -1
  111. data/lib/mongo/server/monitor.rb +5 -0
  112. data/lib/mongo/server/monitor/connection.rb +50 -2
  113. data/lib/mongo/server_selector/nearest.rb +10 -4
  114. data/lib/mongo/server_selector/primary.rb +20 -0
  115. data/lib/mongo/server_selector/primary_preferred.rb +10 -4
  116. data/lib/mongo/server_selector/secondary.rb +10 -4
  117. data/lib/mongo/server_selector/secondary_preferred.rb +24 -4
  118. data/lib/mongo/session.rb +180 -0
  119. data/lib/mongo/session/server_session.rb +73 -0
  120. data/lib/mongo/session/session_pool.rb +161 -0
  121. data/lib/mongo/uri.rb +11 -0
  122. data/lib/mongo/version.rb +1 -1
  123. data/mongo.gemspec +2 -1
  124. data/spec/mongo/auth/cr_spec.rb +12 -0
  125. data/spec/mongo/auth/ldap_spec.rb +2 -0
  126. data/spec/mongo/auth/scram/conversation_spec.rb +6 -6
  127. data/spec/mongo/auth/scram_spec.rb +25 -1
  128. data/spec/mongo/auth/user/view_spec.rb +268 -76
  129. data/spec/mongo/auth/x509_spec.rb +2 -0
  130. data/spec/mongo/bulk_write_spec.rb +435 -5
  131. data/spec/mongo/client_spec.rb +356 -39
  132. data/spec/mongo/cluster/app_metadata_spec.rb +2 -2
  133. data/spec/mongo/cluster_spec.rb +176 -0
  134. data/spec/mongo/collection/view/aggregation_spec.rb +33 -12
  135. data/spec/mongo/collection/view/builder/find_command_spec.rb +46 -6
  136. data/spec/mongo/collection/view/change_stream_spec.rb +814 -0
  137. data/spec/mongo/collection/view/map_reduce_spec.rb +94 -17
  138. data/spec/mongo/collection/view/readable_spec.rb +3 -12
  139. data/spec/mongo/collection_spec.rb +1048 -42
  140. data/spec/mongo/cursor/builder/get_more_command_spec.rb +19 -0
  141. data/spec/mongo/cursor_spec.rb +2 -2
  142. data/spec/mongo/database_spec.rb +50 -1
  143. data/spec/mongo/grid/fs_bucket_spec.rb +225 -137
  144. data/spec/mongo/grid/stream/read_spec.rb +2 -2
  145. data/spec/mongo/index/view_spec.rb +146 -8
  146. data/spec/mongo/monitoring/event/secure_spec.rb +42 -0
  147. data/spec/mongo/operation/read/query_spec.rb +2 -1
  148. data/spec/mongo/operation/specifiable_spec.rb +2 -2
  149. data/spec/mongo/operation/write/command/delete_spec.rb +96 -13
  150. data/spec/mongo/operation/write/command/insert_spec.rb +111 -12
  151. data/spec/mongo/operation/write/command/update_spec.rb +93 -10
  152. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  153. data/spec/mongo/operation/write/insert_spec.rb +1 -1
  154. data/spec/mongo/operation/write/update_spec.rb +1 -1
  155. data/spec/mongo/protocol/compressed_spec.rb +66 -0
  156. data/spec/mongo/protocol/delete_spec.rb +14 -0
  157. data/spec/mongo/protocol/get_more_spec.rb +14 -0
  158. data/spec/mongo/protocol/insert_spec.rb +14 -0
  159. data/spec/mongo/protocol/kill_cursors_spec.rb +14 -0
  160. data/spec/mongo/protocol/msg_spec.rb +499 -0
  161. data/spec/mongo/protocol/query_spec.rb +45 -0
  162. data/spec/mongo/protocol/registry_spec.rb +31 -0
  163. data/spec/mongo/protocol/reply_spec.rb +14 -0
  164. data/spec/mongo/protocol/update_spec.rb +14 -0
  165. data/spec/mongo/retryable_spec.rb +6 -2
  166. data/spec/mongo/sdam_spec.rb +4 -0
  167. data/spec/mongo/server/connection_spec.rb +4 -2
  168. data/spec/mongo/server/description_spec.rb +28 -1
  169. data/spec/mongo/session/server_session_spec.rb +16 -0
  170. data/spec/mongo/session/session_pool_spec.rb +194 -0
  171. data/spec/mongo/uri_spec.rb +31 -2
  172. data/spec/spec_helper.rb +104 -0
  173. data/spec/support/authorization.rb +6 -1
  174. data/spec/support/crud.rb +3 -1
  175. data/spec/support/crud/write.rb +6 -1
  176. data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +69 -0
  177. data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +63 -0
  178. data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +109 -0
  179. data/spec/support/sdam/rs/discover_arbiters.yml +1 -1
  180. data/spec/support/sdam/rs/discover_passives.yml +2 -2
  181. data/spec/support/sdam/rs/discover_primary.yml +1 -1
  182. data/spec/support/sdam/rs/discover_secondary.yml +1 -1
  183. data/spec/support/sdam/rs/discovery.yml +4 -4
  184. data/spec/support/sdam/rs/equal_electionids.yml +1 -0
  185. data/spec/support/sdam/rs/ghost_discovered.yml +1 -1
  186. data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +1 -1
  187. data/spec/support/sdam/rs/ls_timeout.yml +88 -0
  188. data/spec/support/sdam/rs/member_reconfig.yml +2 -2
  189. data/spec/support/sdam/rs/member_standalone.yml +2 -2
  190. data/spec/support/sdam/rs/new_primary.yml +2 -2
  191. data/spec/support/sdam/rs/new_primary_new_electionid.yml +3 -0
  192. data/spec/support/sdam/rs/new_primary_new_setversion.yml +3 -0
  193. data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +2 -2
  194. data/spec/support/sdam/rs/non_rs_member.yml +1 -1
  195. data/spec/support/sdam/rs/normalize_case.yml +1 -1
  196. data/spec/support/sdam/rs/null_election_id.yml +4 -0
  197. data/spec/support/sdam/rs/primary_becomes_standalone.yml +2 -2
  198. data/spec/support/sdam/rs/primary_changes_set_name.yml +2 -2
  199. data/spec/support/sdam/rs/primary_disconnect.yml +2 -2
  200. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +5 -0
  201. data/spec/support/sdam/rs/primary_disconnect_setversion.yml +5 -0
  202. data/spec/support/sdam/rs/primary_hint_from_secondary_with_mismatched_me.yml +58 -0
  203. data/spec/support/sdam/rs/primary_reports_new_member.yml +4 -4
  204. data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +2 -2
  205. data/spec/support/sdam/rs/primary_wrong_set_name.yml +1 -1
  206. data/spec/support/sdam/rs/response_from_removed.yml +2 -2
  207. data/spec/support/sdam/rs/rsother_discovered.yml +1 -1
  208. data/spec/support/sdam/rs/sec_not_auth.yml +1 -1
  209. data/spec/support/sdam/rs/secondary_wrong_set_name.yml +1 -1
  210. data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +2 -2
  211. data/spec/support/sdam/rs/setversion_without_electionid.yml +2 -0
  212. data/spec/support/sdam/rs/stepdown_change_set_name.yml +2 -2
  213. data/spec/support/sdam/rs/unexpected_mongos.yml +1 -1
  214. data/spec/support/sdam/rs/use_setversion_without_electionid.yml +3 -0
  215. data/spec/support/sdam/rs/wrong_set_name.yml +1 -1
  216. data/spec/support/sdam/sharded/ls_timeout_mongos.yml +97 -0
  217. data/spec/support/sdam/sharded/mongos_disconnect.yml +3 -3
  218. data/spec/support/sdam/sharded/multiple_mongoses.yml +1 -1
  219. data/spec/support/sdam/sharded/non_mongos_removed.yml +1 -1
  220. data/spec/support/sdam/sharded/normalize_uri_case.yml +1 -1
  221. data/spec/support/sdam/single/direct_connection_external_ip.yml +1 -1
  222. data/spec/support/sdam/single/direct_connection_mongos.yml +1 -1
  223. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
  224. data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
  225. data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
  226. data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
  227. data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
  228. data/spec/support/sdam/single/ls_timeout_standalone.yml +35 -0
  229. data/spec/support/sdam/single/not_ok_response.yml +1 -1
  230. data/spec/support/sdam/single/standalone_removed.yml +1 -1
  231. data/spec/support/sdam/single/unavailable_seed.yml +1 -1
  232. data/spec/support/server_discovery_and_monitoring.rb +4 -0
  233. data/spec/support/shared/session.rb +236 -0
  234. metadata +53 -15
  235. metadata.gz.sig +0 -0
@@ -50,7 +50,7 @@ module Mongo
50
50
  def_delegators :view, :collection, :read, :cluster
51
51
 
52
52
  # Delegate necessary operations to the collection.
53
- def_delegators :collection, :database
53
+ def_delegators :collection, :database, :client
54
54
 
55
55
  # Iterate through documents returned by the map/reduce.
56
56
  #
@@ -66,10 +66,10 @@ module Mongo
66
66
  # @yieldparam [ Hash ] Each matching document.
67
67
  def each
68
68
  @cursor = nil
69
- write_with_retry do
70
- server = read.select_server(cluster, false)
71
- result = send_initial_query(server)
72
- @cursor = Cursor.new(view, result, server)
69
+ session = client.send(:get_session, view.options)
70
+ write_with_retry(session, Proc.new { server_selector.select_server(cluster, false) }) do |server|
71
+ result = send_initial_query(server, session)
72
+ @cursor = Cursor.new(view, result, server, session: session)
73
73
  end
74
74
  @cursor.each do |doc|
75
75
  yield doc
@@ -182,20 +182,24 @@ module Mongo
182
182
 
183
183
  private
184
184
 
185
+ def server_selector
186
+ @view.send(:server_selector)
187
+ end
188
+
185
189
  def inline?
186
190
  out.nil? || out == { inline: 1 } || out == { INLINE => 1 }
187
191
  end
188
192
 
189
- def map_reduce_spec
190
- Builder::MapReduce.new(map, reduce, view, options).specification
193
+ def map_reduce_spec(session)
194
+ Builder::MapReduce.new(map, reduce, view, options.merge(session: session)).specification
191
195
  end
192
196
 
193
197
  def new(options)
194
198
  MapReduce.new(view, map, reduce, options)
195
199
  end
196
200
 
197
- def initial_query_op
198
- Operation::Commands::MapReduce.new(map_reduce_spec)
201
+ def initial_query_op(session)
202
+ Operation::Commands::MapReduce.new(map_reduce_spec(session))
199
203
  end
200
204
 
201
205
  def valid_server?(server)
@@ -206,34 +210,34 @@ module Mongo
206
210
  out.respond_to?(:keys) && out.keys.first.to_s.downcase == INLINE
207
211
  end
208
212
 
209
- def send_initial_query(server)
213
+ def send_initial_query(server, session)
210
214
  unless valid_server?(server)
211
215
  log_warn(REROUTE)
212
216
  server = cluster.next_primary(false)
213
217
  end
214
218
  validate_collation!(server)
215
- result = initial_query_op.execute(server)
216
- inline? ? result : send_fetch_query(server)
219
+ result = initial_query_op(session).execute(server)
220
+ inline? ? result : send_fetch_query(server, session)
217
221
  end
218
222
 
219
223
  def fetch_query_spec
220
224
  Builder::MapReduce.new(map, reduce, view, options).query_specification
221
225
  end
222
226
 
223
- def find_command_spec
224
- Builder::MapReduce.new(map, reduce, view, options).command_specification
227
+ def find_command_spec(session)
228
+ Builder::MapReduce.new(map, reduce, view, options.merge(session: session)).command_specification
225
229
  end
226
230
 
227
- def fetch_query_op(server)
231
+ def fetch_query_op(server, session)
228
232
  if server.features.find_command_enabled?
229
- Operation::Commands::Find.new(find_command_spec)
233
+ Operation::Commands::Find.new(find_command_spec(session))
230
234
  else
231
235
  Operation::Read::Query.new(fetch_query_spec)
232
236
  end
233
237
  end
234
238
 
235
- def send_fetch_query(server)
236
- fetch_query_op(server).execute(server)
239
+ def send_fetch_query(server, session)
240
+ fetch_query_op(server, session).execute(server)
237
241
  end
238
242
 
239
243
  def validate_collation!(server)
@@ -133,20 +133,24 @@ module Mongo
133
133
  cmd[:limit] = opts[:limit] if opts[:limit]
134
134
  cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
135
135
  cmd[:readConcern] = collection.read_concern if collection.read_concern
136
- preference = ServerSelector.get(opts[:read] || read)
136
+ read_pref = opts[:read] || read_preference
137
+ selector = ServerSelector.get(read_pref || server_selector)
137
138
  read_with_retry do
138
- server = preference.select_server(cluster, false)
139
+ server = selector.select_server(cluster, false)
139
140
  apply_collation!(cmd, server, opts)
140
- Operation::Commands::Command.new({
141
- :selector => cmd,
142
- :db_name => database.name,
143
- :options => { :limit => -1 },
144
- :read => preference,
145
- }).execute(server).n.to_i
146
-
141
+ with_session do |session|
142
+ Operation::Commands::Command.new({
143
+ :selector => cmd,
144
+ :db_name => database.name,
145
+ :options => {:limit => -1},
146
+ :read => read_pref,
147
+ :session => session
148
+ }).execute(server)
149
+ end.n.to_i
147
150
  end
148
151
  end
149
152
 
153
+
150
154
  # Get a list of distinct values for a specific field.
151
155
  #
152
156
  # @example Get the distinct values.
@@ -169,17 +173,20 @@ module Mongo
169
173
  :query => filter }
170
174
  cmd[:maxTimeMS] = opts[:max_time_ms] if opts[:max_time_ms]
171
175
  cmd[:readConcern] = collection.read_concern if collection.read_concern
172
- preference = ServerSelector.get(opts[:read] || read)
176
+ read_pref = opts[:read] || read_preference
177
+ selector = ServerSelector.get(read_pref || server_selector)
173
178
  read_with_retry do
174
- server = preference.select_server(cluster, false)
179
+ server = selector.select_server(cluster, false)
175
180
  apply_collation!(cmd, server, opts)
176
- Operation::Commands::Command.new({
177
- :selector => cmd,
178
- :db_name => database.name,
179
- :options => { :limit => -1 },
180
- :read => preference
181
- }).execute(server).first['values']
182
-
181
+ with_session do |session|
182
+ Operation::Commands::Command.new({
183
+ :selector => cmd,
184
+ :db_name => database.name,
185
+ :options => {:limit => -1},
186
+ :read => read_pref,
187
+ :session => session
188
+ }).execute(server)
189
+ end.first['values']
183
190
  end
184
191
  end
185
192
 
@@ -313,9 +320,8 @@ module Mongo
313
320
  #
314
321
  # @since 2.0.0
315
322
  def read(value = nil)
316
- return default_read if value.nil?
317
- selector = ServerSelector.get(value)
318
- configure(:read, selector)
323
+ return read_preference if value.nil?
324
+ configure(:read, value)
319
325
  end
320
326
 
321
327
  # Set whether to return only the indexed field or fields.
@@ -457,33 +463,41 @@ module Mongo
457
463
  configure(:collation, doc)
458
464
  end
459
465
 
460
- def default_read
461
- options[:read] || collection.read_preference
466
+ def read_preference
467
+ @read_preference ||= (options[:read] || collection.read_preference)
468
+ end
469
+
470
+ def server_selector
471
+ @server_selector ||= ServerSelector.get(read_preference || collection.server_selector)
462
472
  end
463
473
 
464
474
  def parallel_scan(cursor_count, options = {})
465
- server = read.select_server(cluster, false)
475
+ session = client.send(:get_session, @options)
476
+ server = server_selector.select_server(cluster, false)
466
477
  cmd = Operation::Commands::ParallelScan.new({
467
478
  :coll_name => collection.name,
468
479
  :db_name => database.name,
469
480
  :cursor_count => cursor_count,
470
- :read_concern => collection.read_concern
481
+ :read_concern => collection.read_concern,
482
+ :session => session
471
483
  }.merge!(options))
472
484
  cmd.execute(server).cursor_ids.map do |cursor_id|
473
485
  result = if server.features.find_command_enabled?
474
- Operation::Commands::GetMore.new({
475
- :selector => { :getMore => cursor_id, :collection => collection.name },
476
- :db_name => database.name
477
- }).execute(server)
478
- else
479
- Operation::Read::GetMore.new({
480
- :to_return => 0,
481
- :cursor_id => cursor_id,
482
- :db_name => database.name,
483
- :coll_name => collection.name
484
- }).execute(server)
486
+ Operation::Commands::GetMore.new({
487
+ :selector => {:getMore => cursor_id,
488
+ :collection => collection.name},
489
+ :db_name => database.name,
490
+ :session => session
491
+ }).execute(server)
492
+ else
493
+ Operation::Read::GetMore.new({
494
+ :to_return => 0,
495
+ :cursor_id => cursor_id,
496
+ :db_name => database.name,
497
+ :coll_name => collection.name
498
+ }).execute(server)
485
499
  end
486
- Cursor.new(self, result, server)
500
+ Cursor.new(self, result, server, session: session)
487
501
  end
488
502
  end
489
503
 
@@ -21,6 +21,11 @@ module Mongo
21
21
  # @since 2.0.0
22
22
  module Writable
23
23
 
24
+ # The array filters field constant.
25
+ #
26
+ # @since 2.5.0
27
+ ARRAY_FILTERS = 'array_filters'.freeze
28
+
24
29
  # Finds a single document in the database via findAndModify and deletes
25
30
  # it, returning the original document.
26
31
  #
@@ -41,15 +46,16 @@ module Mongo
41
46
  cmd[:maxTimeMS] = max_time_ms if max_time_ms
42
47
  cmd[:writeConcern] = write_concern.options if write_concern
43
48
 
44
- write_with_retry do
45
- server = next_primary
46
- apply_collation!(cmd, server, opts)
47
-
48
- Operation::Commands::Command.new({
49
- :selector => cmd,
50
- :db_name => database.name
51
- }).execute(server).first['value']
52
- end
49
+ with_session do |session|
50
+ write_with_retry(session, Proc.new { next_primary }) do |server|
51
+ apply_collation!(cmd, server, opts)
52
+ Operation::Commands::Command.new({
53
+ :selector => cmd,
54
+ :db_name => database.name,
55
+ :session => session
56
+ }).execute(server)
57
+ end
58
+ end.first['value']
53
59
  end
54
60
 
55
61
  # Finds a single document and replaces it.
@@ -67,7 +73,7 @@ module Mongo
67
73
  # @option opts [ true, false ] :upsert Whether to upsert if the document doesn't exist.
68
74
  # @option opts [ true, false ] :bypass_document_validation Whether or
69
75
  # not to skip document level validation.
70
- # @option options [ Hash ] :write_concern The write concern options.
76
+ # @option opts [ Hash ] :write_concern The write concern options.
71
77
  # Defaults to the collection's write concern.
72
78
  # @option opts [ Hash ] :collation The collation to use.
73
79
  #
@@ -93,6 +99,8 @@ module Mongo
93
99
  # @option opts [ Hash ] :write_concern The write concern options.
94
100
  # Defaults to the collection's write concern.
95
101
  # @option opts [ Hash ] :collation The collation to use.
102
+ # @options opts [ Array ] :array_filters A set of filters specifying to which array elements
103
+ # an update should apply.
96
104
  #
97
105
  # @return [ BSON::Document ] The document.
98
106
  #
@@ -108,15 +116,17 @@ module Mongo
108
116
  cmd[:bypassDocumentValidation] = !!opts[:bypass_document_validation]
109
117
  cmd[:writeConcern] = write_concern.options if write_concern
110
118
 
111
- value = write_with_retry do
112
- server = next_primary
113
- apply_collation!(cmd, server, opts)
114
-
115
- Operation::Commands::Command.new({
116
- :selector => cmd,
117
- :db_name => database.name
118
- }).execute(server).first['value']
119
- end
119
+ value = with_session do |session|
120
+ write_with_retry(session, Proc.new { next_primary }) do |server|
121
+ apply_collation!(cmd, server, opts)
122
+ apply_array_filters!(cmd, server, opts)
123
+ Operation::Commands::Command.new(
124
+ :selector => cmd,
125
+ :db_name => database.name,
126
+ :session => session
127
+ ).execute(server)
128
+ end
129
+ end.first['value']
120
130
  value unless value.nil? || value.empty?
121
131
  end
122
132
 
@@ -182,6 +192,8 @@ module Mongo
182
192
  # @option opts [ true, false ] :upsert Whether to upsert if the
183
193
  # document doesn't exist.
184
194
  # @option opts [ Hash ] :collation The collation to use.
195
+ # @option opts [ Array ] :array_filters A set of filters specifying to which array elements
196
+ # an update should apply.
185
197
  #
186
198
  # @return [ Result ] The response from the database.
187
199
  #
@@ -201,6 +213,8 @@ module Mongo
201
213
  # @option opts [ true, false ] :upsert Whether to upsert if the
202
214
  # document doesn't exist.
203
215
  # @option opts [ Hash ] :collation The collation to use.
216
+ # @option opts [ Array ] :array_filters A set of filters specifying to which array elements
217
+ # an update should apply.
204
218
  #
205
219
  # @return [ Result ] The response from the database.
206
220
  #
@@ -213,16 +227,18 @@ module Mongo
213
227
 
214
228
  def remove(value, opts = {})
215
229
  delete_doc = { Operation::Q => filter, Operation::LIMIT => value }
216
- write_with_retry do
217
- server = next_primary
218
- apply_collation!(delete_doc, server, opts)
219
-
220
- Operation::Write::Delete.new(
221
- :delete => delete_doc,
222
- :db_name => collection.database.name,
223
- :coll_name => collection.name,
224
- :write_concern => collection.write_concern
225
- ).execute(server)
230
+
231
+ with_session do |session|
232
+ write_with_retry(session, Proc.new { next_primary }) do |server|
233
+ apply_collation!(delete_doc, server, opts)
234
+ Operation::Write::Delete.new(
235
+ :delete => delete_doc,
236
+ :db_name => collection.database.name,
237
+ :coll_name => collection.name,
238
+ :write_concern => collection.write_concern,
239
+ :session => session
240
+ ).execute(server)
241
+ end
226
242
  end
227
243
  end
228
244
 
@@ -231,17 +247,33 @@ module Mongo
231
247
  Operation::U => spec,
232
248
  Operation::MULTI => multi,
233
249
  Operation::UPSERT => !!opts[:upsert] }
234
- write_with_retry do
235
- server = next_primary
236
- apply_collation!(update_doc, server, opts)
237
-
238
- Operation::Write::Update.new(
239
- :update => update_doc,
240
- :db_name => collection.database.name,
241
- :coll_name => collection.name,
242
- :write_concern => collection.write_concern,
243
- :bypass_document_validation => !!opts[:bypass_document_validation]
244
- ).execute(server)
250
+
251
+ with_session do |session|
252
+ write_with_retry(session, Proc.new { next_primary }) do |server|
253
+ apply_collation!(update_doc, server, opts)
254
+ apply_array_filters!(update_doc, server, opts)
255
+ Operation::Write::Update.new(
256
+ :update => update_doc,
257
+ :db_name => collection.database.name,
258
+ :coll_name => collection.name,
259
+ :write_concern => collection.write_concern,
260
+ :bypass_document_validation => !!opts[:bypass_document_validation],
261
+ :session => session
262
+ ).execute(server)
263
+ end
264
+ end
265
+ end
266
+
267
+ def apply_array_filters!(doc, server, opts = {})
268
+ if filters = opts[:array_filters] || opts[ARRAY_FILTERS]
269
+ validate_array_filters!(server, filters)
270
+ doc[:arrayFilters] = filters
271
+ end
272
+ end
273
+
274
+ def validate_array_filters!(server, filters)
275
+ if filters && !server.features.array_filters_enabled?
276
+ raise Error::UnsupportedArrayFilters.new
245
277
  end
246
278
  end
247
279
  end
data/lib/mongo/cursor.rb CHANGED
@@ -35,7 +35,7 @@ module Mongo
35
35
  include Enumerable
36
36
  include Retryable
37
37
 
38
- def_delegators :@view, :collection, :limit
38
+ def_delegators :@view, :collection
39
39
  def_delegators :collection, :client, :database
40
40
  def_delegators :@server, :cluster
41
41
 
@@ -50,15 +50,21 @@ module Mongo
50
50
  # @param [ CollectionView ] view The +CollectionView+ defining the query.
51
51
  # @param [ Operation::Result ] result The result of the first execution.
52
52
  # @param [ Server ] server The server this cursor is locked to.
53
+ # @param [ Hash ] options The cursor options.
54
+ #
55
+ # @option options [ true, false ] :disable_retry Whether to disable retrying on
56
+ # error when sending getmores.
53
57
  #
54
58
  # @since 2.0.0
55
- def initialize(view, result, server)
59
+ def initialize(view, result, server, options = {})
56
60
  @view = view
57
61
  @server = server
58
62
  @initial_result = result
59
63
  @remaining = limit if limited?
60
64
  @cursor_id = result.cursor_id
61
65
  @coll_name = nil
66
+ @options = options
67
+ @session = @options[:session]
62
68
  register
63
69
  ObjectSpace.define_finalizer(self, self.class.finalize(result.cursor_id,
64
70
  cluster,
@@ -185,14 +191,18 @@ module Mongo
185
191
  end
186
192
 
187
193
  def get_more
188
- read_with_retry do
194
+ if @options[:disable_retry]
189
195
  process(get_more_operation.execute(@server))
196
+ else
197
+ read_with_retry do
198
+ process(get_more_operation.execute(@server))
199
+ end
190
200
  end
191
201
  end
192
202
 
193
203
  def get_more_operation
194
204
  if @server.features.find_command_enabled?
195
- Operation::Commands::GetMore.new(Builder::GetMoreCommand.new(self).specification)
205
+ Operation::Commands::GetMore.new(Builder::GetMoreCommand.new(self, @session).specification)
196
206
  else
197
207
  Operation::Read::GetMore.new(Builder::OpGetMore.new(self).specification)
198
208
  end
@@ -203,6 +213,13 @@ module Mongo
203
213
  read_with_one_retry do
204
214
  kill_cursors_operation.execute(@server)
205
215
  end
216
+ ensure
217
+ end_session
218
+ @cursor_id = 0
219
+ end
220
+
221
+ def end_session
222
+ @session.end_implicit_session if @session
206
223
  end
207
224
 
208
225
  def kill_cursors_operation
@@ -241,6 +258,10 @@ module Mongo
241
258
  limited? && batch_size >= @remaining
242
259
  end
243
260
 
261
+ def limit
262
+ @view.send(:limit)
263
+ end
264
+
244
265
  def register
245
266
  cluster.register_cursor(@cursor_id)
246
267
  end