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.
- 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
|