mongo 2.10.2 → 2.10.3

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