mongo 2.10.2 → 2.10.3

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 (35) 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/collection/view/readable.rb +2 -2
  5. data/lib/mongo/cursor/builder/get_more_command.rb +4 -1
  6. data/lib/mongo/cursor/builder/kill_cursors_command.rb +16 -5
  7. data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
  8. data/lib/mongo/cursor/builder/op_kill_cursors.rb +17 -5
  9. data/lib/mongo/error/operation_failure.rb +3 -3
  10. data/lib/mongo/protocol/get_more.rb +2 -1
  11. data/lib/mongo/protocol/kill_cursors.rb +6 -13
  12. data/lib/mongo/protocol/serializers.rb +10 -4
  13. data/lib/mongo/retryable.rb +34 -9
  14. data/lib/mongo/version.rb +1 -1
  15. data/mongo.gemspec +1 -1
  16. data/spec/integration/cursor_reaping_spec.rb +1 -1
  17. data/spec/integration/get_more_spec.rb +32 -0
  18. data/spec/integration/retryable_errors_spec.rb +265 -0
  19. data/spec/integration/retryable_writes_spec.rb +36 -36
  20. data/spec/mongo/bulk_write_spec.rb +2 -2
  21. data/spec/mongo/cursor/builder/get_more_command_spec.rb +4 -2
  22. data/spec/mongo/cursor/builder/op_get_more_spec.rb +4 -2
  23. data/spec/mongo/cursor_spec.rb +3 -3
  24. data/spec/mongo/retryable_spec.rb +31 -52
  25. data/spec/runners/sdam/verifier.rb +88 -0
  26. data/spec/spec_tests/retryable_reads_spec.rb +31 -0
  27. data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
  28. data/spec/support/cluster_tools.rb +4 -3
  29. data/spec/support/command_monitoring.rb +5 -0
  30. data/spec/support/event_subscriber.rb +7 -0
  31. data/spec/support/sdam_monitoring.rb +0 -115
  32. data/spec/support/spec_config.rb +1 -1
  33. data/spec/support/utils.rb +1 -1
  34. metadata +10 -4
  35. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d640dac0ce599ea7aa742522d55ead0bd20a2f3f4d9a8c632c28eb5090d38b44
4
- data.tar.gz: cb6993b9aa97c89f93e6e4018aaa7f2f5de0473566162364d5f8beb6f49df2b8
3
+ metadata.gz: 530b40af0e0b87333d108098e0252efb044c9ecd366f4b61990e09373345eeb6
4
+ data.tar.gz: 0460c43dd38a0f6f372913326cf1da273ff9a9aa62e2d9f2b44dcdae652600b3
5
5
  SHA512:
6
- metadata.gz: 11e03d68d1209e627911032bc2e818c77d100afde0f7b5b0b3166c4b52be2224f50299d086edbfb41b20151e5ea8985cb1c79b095047d72c313830836fd8b4b3
7
- data.tar.gz: f450cba2ee21f571c4eb9e94029dc1d883158409fb9e7d2012633466b4445cb659264e0d2f971a0b3b96d699c631cc6d444e20ff5183a18a428b1ced7518f463
6
+ metadata.gz: 02632d48133a1102fd13a7d5bab3a2770afe1b3e9a1ca1317eada51cdcdbf99f10204e8cbeff9d3ad309f59a4bb7cd026490566337bcaa9ed05e767a600f24a2
7
+ data.tar.gz: 3eaf94e796cb099293b19d199dec2b2163e23ef284bbc5c0f85006136b5312dbb1f7abc419c05fa23e9f3b54084f5e825cf20b2d2169fa66a732594227978db5
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -602,7 +602,7 @@ module Mongo
602
602
  cmd.execute(server).cursor_ids.map do |cursor_id|
603
603
  result = if server.features.find_command_enabled?
604
604
  Operation::GetMore.new({
605
- :selector => {:getMore => cursor_id,
605
+ :selector => {:getMore => BSON::Int64.new(cursor_id),
606
606
  :collection => collection.name},
607
607
  :db_name => database.name,
608
608
  :session => session,
@@ -610,7 +610,7 @@ module Mongo
610
610
  else
611
611
  Operation::GetMore.new({
612
612
  :to_return => 0,
613
- :cursor_id => cursor_id,
613
+ :cursor_id => BSON::Int64.new(cursor_id),
614
614
  :db_name => database.name,
615
615
  :coll_name => collection.name
616
616
  }).execute(server)
@@ -57,7 +57,10 @@ module Mongo
57
57
  private
58
58
 
59
59
  def get_more_command
60
- command = { :getMore => cursor.id, :collection => collection_name }
60
+ command = {
61
+ :getMore => BSON::Int64.new(cursor.id),
62
+ :collection => collection_name,
63
+ }
61
64
  command[:batchSize] = batch_size.abs if batch_size && batch_size != 0
62
65
  # If the max_await_time_ms option is set, then we set maxTimeMS on
63
66
  # the get more command.
@@ -54,7 +54,10 @@ module Mongo
54
54
  private
55
55
 
56
56
  def kill_cursors_command
57
- { :killCursors => collection_name, :cursors => [ cursor.id ] }
57
+ {
58
+ killCursors: collection_name,
59
+ cursors: [ BSON::Int64.new(cursor.id) ],
60
+ }
58
61
  end
59
62
 
60
63
  class << self
@@ -65,11 +68,19 @@ module Mongo
65
68
  # KillCursorsCommand.update_cursors(spec, ids)
66
69
  #
67
70
  # @return [ Hash ] The specification.
68
- # @return [ Array ] The ids to update with.
71
+ # @return [ Array<Integer> ] The ids to update with.
69
72
  #
70
73
  # @since 2.3.0
71
74
  def update_cursors(spec, ids)
72
- spec[:selector].merge!(cursors: spec[:selector][:cursors] & ids)
75
+ # Ruby 2.5+ can & BSON::Int64 instances.
76
+ # Ruby 2.4 and earlier cannot.
77
+ # Convert stored ids to Ruby integers for compatibility with
78
+ # older Rubies.
79
+ ids = get_cursors_list(spec) & ids
80
+ ids = ids.map do |cursor_id|
81
+ BSON::Int64.new(cursor_id)
82
+ end
83
+ spec[:selector].merge!(cursors: ids)
73
84
  end
74
85
 
75
86
  # Get the list of cursor ids from a spec generated by this Builder.
@@ -77,11 +88,11 @@ module Mongo
77
88
  # @example Get the list of cursor ids.
78
89
  # KillCursorsCommand.cursors(spec)
79
90
  #
80
- # @return [ Hash ] The specification.
91
+ # @return [ Array<Integer> ] The cursor ids.
81
92
  #
82
93
  # @since 2.3.0
83
94
  def get_cursors_list(spec)
84
- spec[:selector][:cursors]
95
+ spec[:selector][:cursors].map(&:value)
85
96
  end
86
97
  end
87
98
  end
@@ -50,9 +50,9 @@ module Mongo
50
50
  def specification
51
51
  {
52
52
  :to_return => to_return,
53
- :cursor_id => cursor.id,
53
+ :cursor_id => BSON::Int64.new(cursor.id),
54
54
  :db_name => database.name,
55
- :coll_name => collection_name
55
+ :coll_name => collection_name,
56
56
  }
57
57
  end
58
58
  end
@@ -48,7 +48,11 @@ module Mongo
48
48
  #
49
49
  # @since 2.2.0
50
50
  def specification
51
- { :coll_name => collection_name, :db_name => database.name, :cursor_ids => [ cursor.id ] }
51
+ {
52
+ coll_name: collection_name,
53
+ db_name: database.name,
54
+ cursor_ids: [ BSON::Int64.new(cursor.id) ],
55
+ }
52
56
  end
53
57
 
54
58
  class << self
@@ -59,11 +63,19 @@ module Mongo
59
63
  # OpKillCursors.update_cursors(spec, ids)
60
64
  #
61
65
  # @return [ Hash ] The specification.
62
- # @return [ Array ] The ids to update with.
66
+ # @return [ Array<Integer> ] The ids to update with.
63
67
  #
64
68
  # @since 2.3.0
65
69
  def update_cursors(spec, ids)
66
- spec.merge!(cursor_ids: spec[:cursor_ids] & ids)
70
+ # Ruby 2.5+ can & BSON::Int64 instances.
71
+ # Ruby 2.4 and earlier cannot.
72
+ # Convert stored ids to Ruby integers for compatibility with
73
+ # older Rubies.
74
+ ids = get_cursors_list(spec) & ids
75
+ ids = ids.map do |cursor_id|
76
+ BSON::Int64.new(cursor_id)
77
+ end
78
+ spec.merge!(cursor_ids: ids)
67
79
  end
68
80
 
69
81
  # Get the list of cursor ids from a spec generated by this Builder.
@@ -71,11 +83,11 @@ module Mongo
71
83
  # @example Get the list of cursor ids.
72
84
  # OpKillCursors.cursors(spec)
73
85
  #
74
- # @return [ Hash ] The specification.
86
+ # @return [ Array<Integer> ] The cursor ids.
75
87
  #
76
88
  # @since 2.3.0
77
89
  def get_cursors_list(spec)
78
- spec[:cursor_ids]
90
+ spec[:cursor_ids].map(&:value)
79
91
  end
80
92
  end
81
93
  end
@@ -80,15 +80,15 @@ module Mongo
80
80
  # @since 2.6.0
81
81
  attr_reader :code_name
82
82
 
83
- # Whether the error is a retryable error according to the legacy read retry
84
- # logic.
83
+ # Whether the error is a retryable error according to the legacy
84
+ # read retry logic.
85
85
  #
86
86
  # @return [ true, false ]
87
87
  #
88
88
  # @since 2.1.1
89
89
  # @deprecated
90
90
  def retryable?
91
- RETRY_MESSAGES.any?{ |m| message.include?(m) }
91
+ write_retryable? || RETRY_MESSAGES.any?{ |m| message.include?(m) }
92
92
  end
93
93
 
94
94
  # Whether the error is a retryable error according to the modern retryable
@@ -110,6 +110,7 @@ module Mongo
110
110
  # The get more constant.
111
111
  #
112
112
  # @since 2.2.0
113
+ # @deprecated
113
114
  GET_MORE = 'getMore'.freeze
114
115
 
115
116
  # @return [ String ] collection The name of the collection.
@@ -148,7 +149,7 @@ module Mongo
148
149
  # @since 2.1.0
149
150
  def command
150
151
  document = BSON::Document.new
151
- document.store(GET_MORE, cursor_id)
152
+ document.store('getMore', BSON::Int64.new(cursor_id))
152
153
  document.store(Message::BATCH_SIZE, number_to_return)
153
154
  document.store(Message::COLLECTION, collection)
154
155
  document
@@ -52,7 +52,7 @@ module Mongo
52
52
  command_name: 'killCursors',
53
53
  database_name: @database,
54
54
  command: upconverter.command,
55
- request_id: request_id
55
+ request_id: request_id,
56
56
  )
57
57
  end
58
58
 
@@ -85,16 +85,6 @@ module Mongo
85
85
  # @since 2.1.0
86
86
  class Upconverter
87
87
 
88
- # The kill cursors constant.
89
- #
90
- # @since 2.2.0
91
- KILL_CURSORS = 'killCursors'.freeze
92
-
93
- # The cursors constant.
94
- #
95
- # @since 2.2.0
96
- CURSORS = 'cursors'.freeze
97
-
98
88
  # @return [ String ] collection The name of the collection.
99
89
  attr_reader :collection
100
90
 
@@ -125,8 +115,11 @@ module Mongo
125
115
  # @since 2.1.0
126
116
  def command
127
117
  document = BSON::Document.new
128
- document.store(KILL_CURSORS, collection)
129
- document.store(CURSORS, cursor_ids)
118
+ document.store('killCursors', collection)
119
+ store_ids = cursor_ids.map do |cursor_id|
120
+ BSON::Int64.new(cursor_id)
121
+ end
122
+ document.store('cursors', store_ids)
130
123
  document
131
124
  end
132
125
  end
@@ -102,13 +102,16 @@ module Mongo
102
102
  # Serializes and de-serializes one 32-bit integer.
103
103
  module Int32
104
104
 
105
- # Serializes a fixnum to a 4-byte 32-bit integer
105
+ # Serializes a number to a 32-bit integer
106
106
  #
107
107
  # @param buffer [ String ] Buffer to receive the serialized Int32.
108
- # @param value [ Fixnum ] 32-bit integer to be serialized.
108
+ # @param value [ Integer | BSON::Int32 ] 32-bit integer to be serialized.
109
109
  #
110
110
  # @return [String] Buffer with serialized value.
111
111
  def self.serialize(buffer, value, validating_keys = BSON::Config.validating_keys?)
112
+ if value.is_a?(BSON::Int32)
113
+ value = value.value
114
+ end
112
115
  buffer.put_int32(value)
113
116
  end
114
117
 
@@ -127,13 +130,16 @@ module Mongo
127
130
  # Serializes and de-serializes one 64-bit integer.
128
131
  module Int64
129
132
 
130
- # Serializes a fixnum to an 8-byte 64-bit integer
133
+ # Serializes a number to a 64-bit integer
131
134
  #
132
135
  # @param buffer [ String ] Buffer to receive the serialized Int64.
133
- # @param value [ Fixnum ] 64-bit integer to be serialized.
136
+ # @param value [ Integer | BSON::Int64 ] 64-bit integer to be serialized.
134
137
  #
135
138
  # @return [ String ] Buffer with serialized value.
136
139
  def self.serialize(buffer, value, validating_keys = BSON::Config.validating_keys?)
140
+ if value.is_a?(BSON::Int64)
141
+ value = value.value
142
+ end
137
143
  buffer.put_int64(value)
138
144
  end
139
145
 
@@ -119,7 +119,12 @@ module Mongo
119
119
  legacy_read_with_retry(session, server_selector, &block)
120
120
  else
121
121
  server = select_server(cluster, server_selector, session)
122
- yield server
122
+ begin
123
+ yield server
124
+ rescue Error::SocketError, Error::SocketTimeoutError, Error::OperationFailure => e
125
+ e.add_note('retries disabled')
126
+ raise e
127
+ end
123
128
  end
124
129
  end
125
130
 
@@ -214,12 +219,14 @@ module Mongo
214
219
  begin
215
220
  yield(server, txn_num, false)
216
221
  rescue Error::SocketError, Error::SocketTimeoutError => e
222
+ e.add_note('modern retry')
217
223
  e.add_note("attempt 1")
218
224
  if session.in_transaction? && !ending_transaction
219
225
  raise e
220
226
  end
221
227
  retry_write(e, session, txn_num, &block)
222
228
  rescue Error::OperationFailure => e
229
+ e.add_note('modern retry')
223
230
  e.add_note("attempt 1")
224
231
  if e.unsupported_retryable_write?
225
232
  raise_unsupported_error(e)
@@ -250,7 +257,12 @@ module Mongo
250
257
  def nro_write_with_retry(session, write_concern, &block)
251
258
  if session && session.client.options[:retry_writes]
252
259
  server = select_server(cluster, ServerSelector.primary, session)
253
- yield server
260
+ begin
261
+ yield server
262
+ rescue Error::SocketError, Error::SocketTimeoutError, Error::OperationFailure => e
263
+ e.add_note('retries disabled')
264
+ raise e
265
+ end
254
266
  else
255
267
  legacy_write_with_retry(nil, session, &block)
256
268
  end
@@ -280,7 +292,8 @@ module Mongo
280
292
  server ||= select_server(cluster, ServerSelector.primary, session)
281
293
  yield server
282
294
  rescue Error::OperationFailure => e
283
- e.add_note("attempt #{attempt + 1}")
295
+ e.add_note('legacy retry')
296
+ e.add_note("attempt #{attempt}")
284
297
  server = nil
285
298
  if attempt > client.max_write_retries
286
299
  raise e
@@ -298,18 +311,19 @@ module Mongo
298
311
  private
299
312
 
300
313
  def modern_read_with_retry(session, server_selector, &block)
301
- attempt = 0
302
314
  server = select_server(cluster, server_selector, session)
303
315
  begin
304
316
  yield server
305
317
  rescue Error::SocketError, Error::SocketTimeoutError => e
306
- e.add_note("attempt #{attempt + 1}")
318
+ e.add_note('modern retry')
319
+ e.add_note("attempt 1")
307
320
  if session.in_transaction?
308
321
  raise e
309
322
  end
310
323
  retry_read(e, server_selector, session, &block)
311
324
  rescue Error::OperationFailure => e
312
- e.add_note("attempt #{attempt + 1}")
325
+ e.add_note('modern retry')
326
+ e.add_note("attempt 1")
313
327
  if session.in_transaction? || !e.write_retryable?
314
328
  raise e
315
329
  end
@@ -324,7 +338,8 @@ module Mongo
324
338
  attempt += 1
325
339
  yield server
326
340
  rescue Error::SocketError, Error::SocketTimeoutError => e
327
- e.add_note("attempt #{attempt + 1}")
341
+ e.add_note('legacy retry')
342
+ e.add_note("attempt #{attempt}")
328
343
  if attempt > client.max_read_retries || (session && session.in_transaction?)
329
344
  raise e
330
345
  end
@@ -332,8 +347,9 @@ module Mongo
332
347
  server = select_server(cluster, server_selector, session)
333
348
  retry
334
349
  rescue Error::OperationFailure => e
335
- e.add_note("attempt #{attempt + 1}")
336
- if cluster.sharded? && e.retryable? && !(session && session.in_transaction?)
350
+ e.add_note('legacy retry')
351
+ e.add_note("attempt #{attempt}")
352
+ if e.retryable? && !(session && session.in_transaction?)
337
353
  if attempt > client.max_read_retries
338
354
  raise e
339
355
  end
@@ -375,9 +391,11 @@ module Mongo
375
391
  begin
376
392
  yield server, true
377
393
  rescue Error::SocketError, Error::SocketTimeoutError => e
394
+ e.add_note('modern retry')
378
395
  e.add_note("attempt 2")
379
396
  raise e
380
397
  rescue Error::OperationFailure => e
398
+ e.add_note('modern retry')
381
399
  unless e.write_retryable?
382
400
  original_error.add_note("later retry failed: #{e.class}: #{e}")
383
401
  raise original_error
@@ -385,6 +403,7 @@ module Mongo
385
403
  e.add_note("attempt 2")
386
404
  raise e
387
405
  rescue => e
406
+ e.add_note('modern retry')
388
407
  original_error.add_note("later retry failed: #{e.class}: #{e}")
389
408
  raise original_error
390
409
  end
@@ -398,15 +417,19 @@ module Mongo
398
417
  # server unknown). Here we just need to wait for server selection.
399
418
  server = select_server(cluster, ServerSelector.primary, session)
400
419
  unless server.retry_writes?
420
+ # Do not need to add "modern retry" here, it should already be on
421
+ # the first exception.
401
422
  original_error.add_note('did not retry because server selected for retry does not supoprt retryable writes')
402
423
  raise original_error
403
424
  end
404
425
  log_retry(original_error, message: 'Write retry')
405
426
  yield(server, txn_num, true)
406
427
  rescue Error::SocketError, Error::SocketTimeoutError => e
428
+ e.add_note('modern retry')
407
429
  e.add_note('attempt 2')
408
430
  raise e
409
431
  rescue Error::OperationFailure => e
432
+ e.add_note('modern retry')
410
433
  if e.write_retryable?
411
434
  e.add_note('attempt 2')
412
435
  raise e
@@ -415,6 +438,8 @@ module Mongo
415
438
  raise original_error
416
439
  end
417
440
  rescue => e
441
+ # Do not need to add "modern retry" here, it should already be on
442
+ # the first exception.
418
443
  original_error.add_note("later retry failed: #{e.class}: #{e}")
419
444
  raise original_error
420
445
  end
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.10.2'.freeze
20
+ VERSION = '2.10.3'.freeze
21
21
  end
@@ -32,5 +32,5 @@ Gem::Specification.new do |s|
32
32
  s.require_paths = ['lib']
33
33
  s.bindir = 'bin'
34
34
 
35
- s.add_dependency 'bson', '>=4.4.2', '<5.0.0'
35
+ s.add_dependency 'bson', '>=4.6.0', '<5.0.0'
36
36
  end
@@ -59,7 +59,7 @@ describe 'Cursor reaping' do
59
59
  client.cluster.instance_variable_get('@periodic_executor').execute
60
60
 
61
61
  started_event = EventSubscriber.started_events.detect do |event|
62
- event.command['killCursors'] && event.command['cursors'].include?(cursor_id)
62
+ event.command['killCursors'] && event.command['cursors'].map(&:value).include?(cursor_id)
63
63
  end
64
64
 
65
65
  expect(started_event).not_to be_nil
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'getMore operation' do
4
+ # https://jira.mongodb.org/browse/RUBY-1987
5
+ min_server_fcv '3.2'
6
+
7
+ let(:collection) do
8
+ subscribed_client['get_more_spec']
9
+ end
10
+
11
+ let(:scope) do
12
+ collection.find.batch_size(1).each
13
+ end
14
+
15
+ before do
16
+ collection.delete_many
17
+ collection.insert_one(a: 1)
18
+ #collection.insert_one(a: 2)
19
+ EventSubscriber.clear_events!
20
+ end
21
+
22
+ let(:get_more_command) do
23
+ event = EventSubscriber.single_command_started_event('getMore')
24
+ event.command['getMore']
25
+ end
26
+
27
+ it 'sends cursor id as int64' do
28
+ scope.to_a
29
+
30
+ expect(get_more_command).to be_a(BSON::Int64)
31
+ end
32
+ end