mongo 2.10.2 → 2.10.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/mongo/collection/view/readable.rb +2 -2
- data/lib/mongo/cursor/builder/get_more_command.rb +4 -1
- data/lib/mongo/cursor/builder/kill_cursors_command.rb +16 -5
- data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
- data/lib/mongo/cursor/builder/op_kill_cursors.rb +17 -5
- data/lib/mongo/error/operation_failure.rb +3 -3
- data/lib/mongo/protocol/get_more.rb +2 -1
- data/lib/mongo/protocol/kill_cursors.rb +6 -13
- data/lib/mongo/protocol/serializers.rb +10 -4
- data/lib/mongo/retryable.rb +34 -9
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +1 -1
- data/spec/integration/cursor_reaping_spec.rb +1 -1
- data/spec/integration/get_more_spec.rb +32 -0
- data/spec/integration/retryable_errors_spec.rb +265 -0
- data/spec/integration/retryable_writes_spec.rb +36 -36
- data/spec/mongo/bulk_write_spec.rb +2 -2
- data/spec/mongo/cursor/builder/get_more_command_spec.rb +4 -2
- data/spec/mongo/cursor/builder/op_get_more_spec.rb +4 -2
- data/spec/mongo/cursor_spec.rb +3 -3
- data/spec/mongo/retryable_spec.rb +31 -52
- data/spec/runners/sdam/verifier.rb +88 -0
- data/spec/spec_tests/retryable_reads_spec.rb +31 -0
- data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
- data/spec/support/cluster_tools.rb +4 -3
- data/spec/support/command_monitoring.rb +5 -0
- data/spec/support/event_subscriber.rb +7 -0
- data/spec/support/sdam_monitoring.rb +0 -115
- data/spec/support/spec_config.rb +1 -1
- data/spec/support/utils.rb +1 -1
- metadata +10 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 530b40af0e0b87333d108098e0252efb044c9ecd366f4b61990e09373345eeb6
|
4
|
+
data.tar.gz: 0460c43dd38a0f6f372913326cf1da273ff9a9aa62e2d9f2b44dcdae652600b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02632d48133a1102fd13a7d5bab3a2770afe1b3e9a1ca1317eada51cdcdbf99f10204e8cbeff9d3ad309f59a4bb7cd026490566337bcaa9ed05e767a600f24a2
|
7
|
+
data.tar.gz: 3eaf94e796cb099293b19d199dec2b2163e23ef284bbc5c0f85006136b5312dbb1f7abc419c05fa23e9f3b54084f5e825cf20b2d2169fa66a732594227978db5
|
checksums.yaml.gz.sig
CHANGED
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 = {
|
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
|
-
{
|
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
|
-
|
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 [
|
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
|
-
{
|
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
|
-
|
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 [
|
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
|
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(
|
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(
|
129
|
-
|
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
|
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 [
|
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
|
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 [
|
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
|
|
data/lib/mongo/retryable.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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(
|
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(
|
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(
|
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(
|
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(
|
336
|
-
|
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
|
data/lib/mongo/version.rb
CHANGED
data/mongo.gemspec
CHANGED
@@ -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
|