mongo 2.10.0 → 2.10.1
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 +3 -2
- data.tar.gz.sig +0 -0
- data/lib/mongo/bulk_write.rb +1 -1
- data/lib/mongo/error.rb +4 -0
- data/lib/mongo/error/auth_error.rb +29 -0
- data/lib/mongo/error/bulk_write_error.rb +1 -1
- data/lib/mongo/error/notable.rb +80 -0
- data/lib/mongo/operation.rb +1 -1
- data/lib/mongo/operation/insert/command.rb +5 -15
- data/lib/mongo/operation/insert/legacy.rb +4 -16
- data/lib/mongo/operation/shared/executable.rb +7 -3
- data/lib/mongo/operation/shared/response_handling.rb +94 -0
- data/lib/mongo/operation/shared/specifiable.rb +0 -40
- data/lib/mongo/operation/shared/write.rb +3 -1
- data/lib/mongo/retryable.rb +45 -17
- data/lib/mongo/version.rb +1 -1
- data/spec/integration/change_stream_spec.rb +4 -4
- data/spec/integration/command_monitoring_spec.rb +1 -1
- data/spec/integration/read_preference_spec.rb +2 -2
- data/spec/integration/retryable_writes_spec.rb +54 -11
- metadata +5 -3
- metadata.gz.sig +0 -0
- data/lib/mongo/operation/shared/unpinnable.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18e71f41caf0b6b8c618c8ea7cedb903ca10248949993c6c25ebf61d6acf3bba
|
4
|
+
data.tar.gz: bd587a35aadbaf790b61c83867f276bd13858c6469fb8ef26bf3907e58a5703a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c923c55b783fb6d0a37d90116684afe65c038d1d7c06dfa1ace59a825eeee441ad7384f42ab45cb47bc7f2abedc16faef6f5f8adef68751631dcc57ddbca8be1
|
7
|
+
data.tar.gz: bff45797b2533f2d842787c9c1d63eef76deab4471244af4d759237ab122b70d3c785d2ad064bf0b79e3d045c86efa5f6f7f47e4b8cdec5607b95ffd323400d3
|
checksums.yaml.gz.sig
CHANGED
@@ -1,2 +1,3 @@
|
|
1
|
-
��
|
2
|
-
�
|
1
|
+
*܉o]���GO�=��S��rhc�ug�0D����}D����җoC&AH�N��9)s����(��p��qo�dh^_���pZ�L)J(m�lܫ��p駴�x���#Fƻkf!��3f�j�0"ٖ|繣��Zy����?j��j�����Бd�1(2�������[D<��ޒ�9���l���m"R
|
2
|
+
�"�G�~����:��
|
3
|
+
q_���=��y=�|�Т[���-�����ވ���`��+Vf!
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/mongo/bulk_write.rb
CHANGED
@@ -23,7 +23,7 @@ require 'mongo/bulk_write/result_combiner'
|
|
23
23
|
module Mongo
|
24
24
|
class BulkWrite
|
25
25
|
extend Forwardable
|
26
|
-
include Operation::
|
26
|
+
include Operation::ResponseHandling
|
27
27
|
|
28
28
|
# @return [ Mongo::Collection ] collection The collection.
|
29
29
|
attr_reader :collection
|
data/lib/mongo/error.rb
CHANGED
@@ -12,11 +12,14 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
require 'mongo/error/notable'
|
16
|
+
|
15
17
|
module Mongo
|
16
18
|
# Base error class for all Mongo related errors.
|
17
19
|
#
|
18
20
|
# @since 2.0.0
|
19
21
|
class Error < StandardError
|
22
|
+
include Notable
|
20
23
|
|
21
24
|
# The error code field.
|
22
25
|
#
|
@@ -141,6 +144,7 @@ module Mongo
|
|
141
144
|
end
|
142
145
|
end
|
143
146
|
|
147
|
+
require 'mongo/error/auth_error'
|
144
148
|
require 'mongo/error/sdam_error_detection'
|
145
149
|
require 'mongo/error/parser'
|
146
150
|
require 'mongo/error/write_retryable'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright (C) 2018-2019 MongoDB, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
class Error
|
17
|
+
|
18
|
+
# Raised when authentication fails.
|
19
|
+
#
|
20
|
+
# Note: This class is derived from RuntimeError for
|
21
|
+
# backwards compatibility reasons. It is subject to
|
22
|
+
# change in future major versions of the driver.
|
23
|
+
#
|
24
|
+
# @since 2.10.1
|
25
|
+
class AuthError < RuntimeError
|
26
|
+
include Notable
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Copyright (C) 2019 MongoDB, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
class Error < StandardError
|
17
|
+
|
18
|
+
# A module encapsulating note tracking functionality, since currently
|
19
|
+
# the driver does not have a single exception hierarchy root.
|
20
|
+
#
|
21
|
+
# @since 2.10.1
|
22
|
+
# @api private
|
23
|
+
module Notable
|
24
|
+
|
25
|
+
# Returns an array of strings with additional information about the
|
26
|
+
# exception.
|
27
|
+
#
|
28
|
+
# @return [ Array<String> ] Additional information strings.
|
29
|
+
#
|
30
|
+
# @since 2.10.1
|
31
|
+
# @api public
|
32
|
+
def notes
|
33
|
+
if @notes
|
34
|
+
@notes.dup
|
35
|
+
else
|
36
|
+
[]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
def add_note(note)
|
42
|
+
unless @notes
|
43
|
+
@notes = []
|
44
|
+
end
|
45
|
+
@notes << note
|
46
|
+
end
|
47
|
+
|
48
|
+
# @api public
|
49
|
+
def message
|
50
|
+
super + notes_tail
|
51
|
+
end
|
52
|
+
|
53
|
+
# @api public
|
54
|
+
def to_s
|
55
|
+
super + notes_tail
|
56
|
+
end
|
57
|
+
|
58
|
+
# @api public
|
59
|
+
def inspect
|
60
|
+
msg = super
|
61
|
+
if msg.end_with?('>')
|
62
|
+
msg[0...msg.length-1] + notes_tail + '>'
|
63
|
+
else
|
64
|
+
msg + notes_tail
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# @api private
|
71
|
+
def notes_tail
|
72
|
+
msg = ''
|
73
|
+
unless notes.empty?
|
74
|
+
msg += " (#{notes.join(', ')})"
|
75
|
+
end
|
76
|
+
msg
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/mongo/operation.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'mongo/operation/result'
|
2
2
|
|
3
|
+
require 'mongo/operation/shared/response_handling'
|
3
4
|
require 'mongo/operation/shared/executable'
|
4
5
|
require 'mongo/operation/shared/executable_no_validate'
|
5
6
|
require 'mongo/operation/shared/executable_transaction_label'
|
@@ -13,7 +14,6 @@ require 'mongo/operation/shared/sessions_supported'
|
|
13
14
|
require 'mongo/operation/shared/causal_consistency_supported'
|
14
15
|
require 'mongo/operation/shared/write'
|
15
16
|
require 'mongo/operation/shared/idable'
|
16
|
-
require 'mongo/operation/shared/unpinnable'
|
17
17
|
require 'mongo/operation/shared/specifiable'
|
18
18
|
require 'mongo/operation/shared/object_id_generator'
|
19
19
|
require 'mongo/operation/shared/op_msg_or_command'
|
@@ -24,28 +24,18 @@ module Mongo
|
|
24
24
|
class Command
|
25
25
|
include Specifiable
|
26
26
|
include Executable
|
27
|
+
include ExecutableNoValidate
|
27
28
|
include Idable
|
28
29
|
include Limited
|
29
30
|
include WriteConcernSupported
|
30
31
|
include BypassDocumentValidation
|
31
32
|
|
32
|
-
# Execute the operation.
|
33
|
-
#
|
34
|
-
# @example
|
35
|
-
# operation.execute(server)
|
36
|
-
#
|
37
|
-
# @param [ Mongo::Server ] server The server to send the operation to.
|
38
|
-
#
|
39
|
-
# @return [ Mongo::Operation::Insert::Result ] The operation result.
|
40
|
-
#
|
41
|
-
# @since 2.5.2
|
42
|
-
def execute(server)
|
43
|
-
result = Result.new(dispatch_message(server), @ids)
|
44
|
-
process_result(result, server)
|
45
|
-
end
|
46
|
-
|
47
33
|
private
|
48
34
|
|
35
|
+
def get_result(server)
|
36
|
+
Result.new(dispatch_message(server), @ids)
|
37
|
+
end
|
38
|
+
|
49
39
|
def selector(server)
|
50
40
|
{ insert: coll_name,
|
51
41
|
documents: send(IDENTIFIER),
|
@@ -28,24 +28,12 @@ module Mongo
|
|
28
28
|
include Executable
|
29
29
|
include Idable
|
30
30
|
|
31
|
-
# Execute the operation.
|
32
|
-
#
|
33
|
-
# @example
|
34
|
-
# operation.execute(server)
|
35
|
-
#
|
36
|
-
# @param [ Mongo::Server ] server The server to send the operation to.
|
37
|
-
#
|
38
|
-
# @return [ Mongo::Operation::Insert::Result ] The operation result.
|
39
|
-
#
|
40
|
-
# @since 2.5.2
|
41
|
-
def execute(server)
|
42
|
-
result = Result.new(dispatch_message(server), @ids)
|
43
|
-
process_result(result, server)
|
44
|
-
result.validate!
|
45
|
-
end
|
46
|
-
|
47
31
|
private
|
48
32
|
|
33
|
+
def get_result(server)
|
34
|
+
Result.new(dispatch_message(server), @ids)
|
35
|
+
end
|
36
|
+
|
49
37
|
def selector
|
50
38
|
send(IDENTIFIER).first
|
51
39
|
end
|
@@ -20,11 +20,15 @@ module Mongo
|
|
20
20
|
# @since 2.5.2
|
21
21
|
module Executable
|
22
22
|
|
23
|
+
include ResponseHandling
|
24
|
+
|
23
25
|
def do_execute(server)
|
24
26
|
unpin_maybe(session) do
|
25
27
|
add_error_labels do
|
26
|
-
|
27
|
-
|
28
|
+
add_server_diagnostics(server) do
|
29
|
+
get_result(server).tap do |result|
|
30
|
+
process_result(result, server)
|
31
|
+
end
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
@@ -32,7 +36,7 @@ module Mongo
|
|
32
36
|
|
33
37
|
def execute(server)
|
34
38
|
do_execute(server).tap do |result|
|
35
|
-
validate_result(result)
|
39
|
+
validate_result(result, server)
|
36
40
|
end
|
37
41
|
end
|
38
42
|
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# Copyright (C) 2019 MongoDB, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
module Operation
|
17
|
+
|
18
|
+
# Shared behavior of response handling for operations.
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
module ResponseHandling
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def validate_result(result, server)
|
26
|
+
unpin_maybe(session) do
|
27
|
+
add_error_labels do
|
28
|
+
add_server_diagnostics(server) do
|
29
|
+
result.validate!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds error labels to exceptions raised in the yielded to block,
|
36
|
+
# which should perform MongoDB operations and raise Mongo::Errors on
|
37
|
+
# failure. This method handles network errors (Error::SocketError)
|
38
|
+
# and server-side errors (Error::OperationFailure); it does not
|
39
|
+
# handle server selection errors (Error::NoServerAvailable), for which
|
40
|
+
# labels are added in the server selection code.
|
41
|
+
def add_error_labels
|
42
|
+
begin
|
43
|
+
yield
|
44
|
+
rescue Mongo::Error::SocketError => e
|
45
|
+
if session && session.in_transaction? && !session.committing_transaction?
|
46
|
+
e.add_label('TransientTransactionError')
|
47
|
+
end
|
48
|
+
if session && session.committing_transaction?
|
49
|
+
e.add_label('UnknownTransactionCommitResult')
|
50
|
+
end
|
51
|
+
raise e
|
52
|
+
rescue Mongo::Error::OperationFailure => e
|
53
|
+
if session && session.committing_transaction?
|
54
|
+
if e.write_retryable? || e.wtimeout? || (e.write_concern_error? &&
|
55
|
+
!Session::UNLABELED_WRITE_CONCERN_CODES.include?(e.write_concern_error_code)
|
56
|
+
) || e.max_time_ms_expired?
|
57
|
+
e.add_label('UnknownTransactionCommitResult')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
raise e
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Unpins the session if the session is pinned and the yielded to block
|
65
|
+
# raises errors that are required to unpin the session.
|
66
|
+
#
|
67
|
+
# @note This method takes the session as an argument because this module
|
68
|
+
# is included in BulkWrite which does not store the session in the
|
69
|
+
# receiver (despite Specifiable doing so).
|
70
|
+
#
|
71
|
+
# @param [ Session | nil ] Session to consider.
|
72
|
+
def unpin_maybe(session)
|
73
|
+
yield
|
74
|
+
rescue Mongo::Error => e
|
75
|
+
if session
|
76
|
+
session.unpin_maybe(e)
|
77
|
+
end
|
78
|
+
raise
|
79
|
+
end
|
80
|
+
|
81
|
+
# Yields to the block and, if the block raises an exception, adds a note
|
82
|
+
# to the exception with the address of the specified server.
|
83
|
+
#
|
84
|
+
# This method is intended to add server address information to exceptions
|
85
|
+
# raised during execution of operations on servers.
|
86
|
+
def add_server_diagnostics(server)
|
87
|
+
yield
|
88
|
+
rescue Mongo::Error, Mongo::Error::AuthError => e
|
89
|
+
e.add_note("on #{server.address.seed}")
|
90
|
+
raise e
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -20,7 +20,6 @@ module Mongo
|
|
20
20
|
#
|
21
21
|
# @since 2.0.0
|
22
22
|
module Specifiable
|
23
|
-
include Unpinnable
|
24
23
|
|
25
24
|
# The field for database name.
|
26
25
|
#
|
@@ -565,45 +564,6 @@ module Mongo
|
|
565
564
|
def acknowledged_write?
|
566
565
|
write_concern.nil? || write_concern.acknowledged?
|
567
566
|
end
|
568
|
-
|
569
|
-
private
|
570
|
-
|
571
|
-
def validate_result(result)
|
572
|
-
unpin_maybe(session) do
|
573
|
-
add_error_labels do
|
574
|
-
result.validate!
|
575
|
-
end
|
576
|
-
end
|
577
|
-
end
|
578
|
-
|
579
|
-
# Adds error labels to exceptions raised in the yielded to block,
|
580
|
-
# which should perform MongoDB operations and raise Mongo::Errors on
|
581
|
-
# failure. This method handles network errors (Error::SocketError)
|
582
|
-
# and server-side errors (Error::OperationFailure); it does not
|
583
|
-
# handle server selection errors (Error::NoServerAvailable), for which
|
584
|
-
# labels are added in the server selection code.
|
585
|
-
def add_error_labels
|
586
|
-
begin
|
587
|
-
yield
|
588
|
-
rescue Mongo::Error::SocketError => e
|
589
|
-
if session && session.in_transaction? && !session.committing_transaction?
|
590
|
-
e.add_label('TransientTransactionError')
|
591
|
-
end
|
592
|
-
if session && session.committing_transaction?
|
593
|
-
e.add_label('UnknownTransactionCommitResult')
|
594
|
-
end
|
595
|
-
raise e
|
596
|
-
rescue Mongo::Error::OperationFailure => e
|
597
|
-
if session && session.committing_transaction?
|
598
|
-
if e.write_retryable? || e.wtimeout? || (e.write_concern_error? &&
|
599
|
-
!Session::UNLABELED_WRITE_CONCERN_CODES.include?(e.write_concern_error_code)
|
600
|
-
) || e.max_time_ms_expired?
|
601
|
-
e.add_label('UnknownTransactionCommitResult')
|
602
|
-
end
|
603
|
-
end
|
604
|
-
raise e
|
605
|
-
end
|
606
|
-
end
|
607
567
|
end
|
608
568
|
end
|
609
569
|
end
|
@@ -20,6 +20,8 @@ module Mongo
|
|
20
20
|
# @since 2.5.2
|
21
21
|
module Write
|
22
22
|
|
23
|
+
include ResponseHandling
|
24
|
+
|
23
25
|
# Execute the operation.
|
24
26
|
#
|
25
27
|
# @example
|
@@ -39,7 +41,7 @@ module Mongo
|
|
39
41
|
else
|
40
42
|
self.class::Command.new(spec).execute(server)
|
41
43
|
end
|
42
|
-
validate_result(result)
|
44
|
+
validate_result(result, server)
|
43
45
|
end
|
44
46
|
|
45
47
|
# Execute the bulk write operation.
|
data/lib/mongo/retryable.rb
CHANGED
@@ -206,19 +206,25 @@ module Mongo
|
|
206
206
|
return legacy_write_with_retry(server, session, &block)
|
207
207
|
end
|
208
208
|
|
209
|
+
txn_num = if session.in_transaction?
|
210
|
+
session.txn_num
|
211
|
+
else
|
212
|
+
session.next_txn_num
|
213
|
+
end
|
209
214
|
begin
|
210
|
-
txn_num = session.in_transaction? ? session.txn_num : session.next_txn_num
|
211
215
|
yield(server, txn_num, false)
|
212
216
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
217
|
+
e.add_note("attempt 1")
|
213
218
|
if session.in_transaction? && !ending_transaction
|
214
|
-
raise
|
219
|
+
raise e
|
215
220
|
end
|
216
221
|
retry_write(e, session, txn_num, &block)
|
217
222
|
rescue Error::OperationFailure => e
|
223
|
+
e.add_note("attempt 1")
|
218
224
|
if e.unsupported_retryable_write?
|
219
225
|
raise_unsupported_error(e)
|
220
226
|
elsif (session.in_transaction? && !ending_transaction) || !e.write_retryable?
|
221
|
-
raise
|
227
|
+
raise e
|
222
228
|
end
|
223
229
|
|
224
230
|
retry_write(e, session, txn_num, &block)
|
@@ -274,16 +280,17 @@ module Mongo
|
|
274
280
|
server ||= select_server(cluster, ServerSelector.primary, session)
|
275
281
|
yield server
|
276
282
|
rescue Error::OperationFailure => e
|
283
|
+
e.add_note("attempt #{attempt + 1}")
|
277
284
|
server = nil
|
278
285
|
if attempt > client.max_write_retries
|
279
|
-
raise
|
286
|
+
raise e
|
280
287
|
end
|
281
288
|
if e.write_retryable? && !(session && session.in_transaction?)
|
282
289
|
log_retry(e, message: 'Legacy write retry')
|
283
290
|
cluster.scan!(false)
|
284
291
|
retry
|
285
292
|
else
|
286
|
-
raise
|
293
|
+
raise e
|
287
294
|
end
|
288
295
|
end
|
289
296
|
end
|
@@ -296,13 +303,15 @@ module Mongo
|
|
296
303
|
begin
|
297
304
|
yield server
|
298
305
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
306
|
+
e.add_note("attempt #{attempt + 1}")
|
299
307
|
if session.in_transaction?
|
300
|
-
raise
|
308
|
+
raise e
|
301
309
|
end
|
302
310
|
retry_read(e, server_selector, session, &block)
|
303
311
|
rescue Error::OperationFailure => e
|
312
|
+
e.add_note("attempt #{attempt + 1}")
|
304
313
|
if session.in_transaction? || !e.write_retryable?
|
305
|
-
raise
|
314
|
+
raise e
|
306
315
|
end
|
307
316
|
retry_read(e, server_selector, session, &block)
|
308
317
|
end
|
@@ -315,23 +324,25 @@ module Mongo
|
|
315
324
|
attempt += 1
|
316
325
|
yield server
|
317
326
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
327
|
+
e.add_note("attempt #{attempt + 1}")
|
318
328
|
if attempt > client.max_read_retries || (session && session.in_transaction?)
|
319
|
-
raise
|
329
|
+
raise e
|
320
330
|
end
|
321
331
|
log_retry(e, message: 'Legacy read retry')
|
322
332
|
server = select_server(cluster, server_selector, session)
|
323
333
|
retry
|
324
334
|
rescue Error::OperationFailure => e
|
335
|
+
e.add_note("attempt #{attempt + 1}")
|
325
336
|
if cluster.sharded? && e.retryable? && !(session && session.in_transaction?)
|
326
337
|
if attempt > client.max_read_retries
|
327
|
-
raise
|
338
|
+
raise e
|
328
339
|
end
|
329
340
|
log_retry(e, message: 'Legacy read retry')
|
330
341
|
sleep(client.read_retry_interval)
|
331
342
|
server = select_server(cluster, server_selector, session)
|
332
343
|
retry
|
333
344
|
else
|
334
|
-
raise
|
345
|
+
raise e
|
335
346
|
end
|
336
347
|
end
|
337
348
|
end
|
@@ -354,7 +365,8 @@ module Mongo
|
|
354
365
|
def retry_read(original_error, server_selector, session, &block)
|
355
366
|
begin
|
356
367
|
server = select_server(cluster, server_selector, session)
|
357
|
-
rescue
|
368
|
+
rescue => e
|
369
|
+
original_error.add_note("later retry failed: #{e.class}: #{e}")
|
358
370
|
raise original_error
|
359
371
|
end
|
360
372
|
|
@@ -363,11 +375,17 @@ module Mongo
|
|
363
375
|
begin
|
364
376
|
yield server, true
|
365
377
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
378
|
+
e.add_note("attempt 2")
|
366
379
|
raise e
|
367
380
|
rescue Error::OperationFailure => e
|
368
|
-
|
381
|
+
unless e.write_retryable?
|
382
|
+
original_error.add_note("later retry failed: #{e.class}: #{e}")
|
383
|
+
raise original_error
|
384
|
+
end
|
385
|
+
e.add_note("attempt 2")
|
369
386
|
raise e
|
370
|
-
rescue
|
387
|
+
rescue => e
|
388
|
+
original_error.add_note("later retry failed: #{e.class}: #{e}")
|
371
389
|
raise original_error
|
372
390
|
end
|
373
391
|
end
|
@@ -379,15 +397,25 @@ module Mongo
|
|
379
397
|
# a socket error or a not master error should have marked the respective
|
380
398
|
# server unknown). Here we just need to wait for server selection.
|
381
399
|
server = select_server(cluster, ServerSelector.primary, session)
|
382
|
-
|
400
|
+
unless server.retry_writes?
|
401
|
+
original_error.add_note('did not retry because server selected for retry does not supoprt retryable writes')
|
402
|
+
raise original_error
|
403
|
+
end
|
383
404
|
log_retry(original_error, message: 'Write retry')
|
384
405
|
yield(server, txn_num, true)
|
385
406
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
407
|
+
e.add_note('attempt 2')
|
386
408
|
raise e
|
387
409
|
rescue Error::OperationFailure => e
|
388
|
-
|
389
|
-
|
390
|
-
|
410
|
+
if e.write_retryable?
|
411
|
+
e.add_note('attempt 2')
|
412
|
+
raise e
|
413
|
+
else
|
414
|
+
original_error.add_note("later retry failed: #{e.class}: #{e}")
|
415
|
+
raise original_error
|
416
|
+
end
|
417
|
+
rescue => e
|
418
|
+
original_error.add_note("later retry failed: #{e.class}: #{e}")
|
391
419
|
raise original_error
|
392
420
|
end
|
393
421
|
|
data/lib/mongo/version.rb
CHANGED
@@ -94,7 +94,7 @@ describe 'Change stream integration', retry: 4 do
|
|
94
94
|
it 'watch raises error' do
|
95
95
|
expect do
|
96
96
|
authorized_collection.watch
|
97
|
-
end.to raise_error(Mongo::Error::OperationFailure,
|
97
|
+
end.to raise_error(Mongo::Error::OperationFailure, /Failing command due to 'failCommand' failpoint \(100\)/)
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
@@ -243,7 +243,7 @@ describe 'Change stream integration', retry: 4 do
|
|
243
243
|
|
244
244
|
expect do
|
245
245
|
enum.next
|
246
|
-
end.to raise_error(Mongo::Error::OperationFailure,
|
246
|
+
end.to raise_error(Mongo::Error::OperationFailure, /Failing command due to 'failCommand' failpoint \(101\)/)
|
247
247
|
end
|
248
248
|
end
|
249
249
|
end
|
@@ -354,7 +354,7 @@ describe 'Change stream integration', retry: 4 do
|
|
354
354
|
|
355
355
|
expect do
|
356
356
|
enum.try_next
|
357
|
-
end.to raise_error(Mongo::Error::OperationFailure,
|
357
|
+
end.to raise_error(Mongo::Error::OperationFailure, /Failing command due to 'failCommand' failpoint \(101\)/)
|
358
358
|
end
|
359
359
|
end
|
360
360
|
|
@@ -377,7 +377,7 @@ describe 'Change stream integration', retry: 4 do
|
|
377
377
|
|
378
378
|
expect do
|
379
379
|
enum.try_next
|
380
|
-
end.to raise_error(Mongo::Error::OperationFailure,
|
380
|
+
end.to raise_error(Mongo::Error::OperationFailure, /Failing command due to 'failCommand' failpoint \(101\)/)
|
381
381
|
end
|
382
382
|
end
|
383
383
|
end
|
@@ -107,7 +107,7 @@ describe 'Command monitoring' do
|
|
107
107
|
subscriber.clear_events!
|
108
108
|
expect do
|
109
109
|
command.execute(server)
|
110
|
-
end.to raise_error(Mongo::Error::OperationFailure,
|
110
|
+
end.to raise_error(Mongo::Error::OperationFailure, /Not enough data-bearing nodes \(100\)/)
|
111
111
|
|
112
112
|
expect(subscriber.started_events.length).to eq(1)
|
113
113
|
event = subscriber.started_events.first
|
@@ -409,7 +409,7 @@ describe 'Read preference' do
|
|
409
409
|
res = collection.find({}, {session: session}.merge(find_options || {})).to_a.count
|
410
410
|
expect(res).to eq(1)
|
411
411
|
end
|
412
|
-
end.to raise_error(Mongo::Error::InvalidTransactionOperation,
|
412
|
+
end.to raise_error(Mongo::Error::InvalidTransactionOperation, /read preference in a transaction must be primary \(requested: secondary\)/)
|
413
413
|
end
|
414
414
|
end
|
415
415
|
|
@@ -478,7 +478,7 @@ describe 'Read preference' do
|
|
478
478
|
res = collection.find({}, {session: session}.merge(find_options || {})).to_a.count
|
479
479
|
expect(res).to eq(1)
|
480
480
|
end
|
481
|
-
end.to raise_error(Mongo::Error::InvalidTransactionOperation,
|
481
|
+
end.to raise_error(Mongo::Error::InvalidTransactionOperation, /read preference in a transaction must be primary \(requested: secondary\)/)
|
482
482
|
end
|
483
483
|
end
|
484
484
|
end
|
@@ -107,6 +107,18 @@ describe 'Retryable writes integration tests' do
|
|
107
107
|
}.to raise_error(Mongo::Error::OperationFailure, /other error/)
|
108
108
|
expect(expectation).to eq(unsuccessful_retry_value)
|
109
109
|
end
|
110
|
+
|
111
|
+
it 'indicates server used for operation' do
|
112
|
+
expect {
|
113
|
+
operation
|
114
|
+
}.to raise_error(Mongo::Error::OperationFailure, /on #{ClusterConfig.instance.primary_address_str}/)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'indicates first attempt' do
|
118
|
+
expect {
|
119
|
+
operation
|
120
|
+
}.to raise_error(Mongo::Error::OperationFailure, /attempt 1/)
|
121
|
+
end
|
110
122
|
end
|
111
123
|
end
|
112
124
|
end
|
@@ -169,16 +181,17 @@ describe 'Retryable writes integration tests' do
|
|
169
181
|
end
|
170
182
|
|
171
183
|
[
|
172
|
-
Mongo::Error::SocketError,
|
173
|
-
Mongo::Error::SocketTimeoutError,
|
174
|
-
Mongo::Error::OperationFailure
|
175
|
-
Mongo::Error::OperationFailure
|
176
|
-
].each do |
|
184
|
+
[Mongo::Error::SocketError],
|
185
|
+
[Mongo::Error::SocketTimeoutError],
|
186
|
+
[Mongo::Error::OperationFailure, 'not master'],
|
187
|
+
[Mongo::Error::OperationFailure, 'node is recovering'],
|
188
|
+
].each do |error_cls, error_msg|
|
189
|
+
# Note: actual exception instances must be different between tests
|
177
190
|
|
178
|
-
context "when the first error is a #{
|
191
|
+
context "when the first error is a #{error_cls}/#{error_msg}" do
|
179
192
|
|
180
193
|
let(:error) do
|
181
|
-
|
194
|
+
error_cls.new(error_msg)
|
182
195
|
end
|
183
196
|
|
184
197
|
before do
|
@@ -197,12 +210,24 @@ describe 'Retryable writes integration tests' do
|
|
197
210
|
Mongo::Error::SocketError
|
198
211
|
end
|
199
212
|
|
200
|
-
it '
|
213
|
+
it 'raises the second error' do
|
201
214
|
expect {
|
202
215
|
operation
|
203
216
|
}.to raise_error(second_error)
|
204
217
|
expect(expectation).to eq(unsuccessful_retry_value)
|
205
218
|
end
|
219
|
+
|
220
|
+
it 'indicates server used for operation' do
|
221
|
+
expect {
|
222
|
+
operation
|
223
|
+
}.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'indicates second attempt' do
|
227
|
+
expect {
|
228
|
+
operation
|
229
|
+
}.to raise_error(Mongo::Error, /attempt 2/)
|
230
|
+
end
|
206
231
|
end
|
207
232
|
|
208
233
|
context 'when the second error is a SocketTimeoutError' do
|
@@ -211,7 +236,7 @@ describe 'Retryable writes integration tests' do
|
|
211
236
|
Mongo::Error::SocketTimeoutError
|
212
237
|
end
|
213
238
|
|
214
|
-
it '
|
239
|
+
it 'raises the second error' do
|
215
240
|
expect {
|
216
241
|
operation
|
217
242
|
}.to raise_error(second_error)
|
@@ -225,7 +250,7 @@ describe 'Retryable writes integration tests' do
|
|
225
250
|
Mongo::Error::OperationFailure.new('not master')
|
226
251
|
end
|
227
252
|
|
228
|
-
it '
|
253
|
+
it 'raises the second error' do
|
229
254
|
expect {
|
230
255
|
operation
|
231
256
|
}.to raise_error(second_error)
|
@@ -253,12 +278,30 @@ describe 'Retryable writes integration tests' do
|
|
253
278
|
StandardError
|
254
279
|
end
|
255
280
|
|
256
|
-
it '
|
281
|
+
it 'raises the first error' do
|
257
282
|
expect {
|
258
283
|
operation
|
259
284
|
}.to raise_error(error)
|
260
285
|
expect(expectation).to eq(unsuccessful_retry_value)
|
261
286
|
end
|
287
|
+
|
288
|
+
it 'indicates server used for operation' do
|
289
|
+
expect {
|
290
|
+
operation
|
291
|
+
}.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'indicates first attempt' do
|
295
|
+
expect {
|
296
|
+
operation
|
297
|
+
}.to raise_error(Mongo::Error, /attempt 1/)
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'indicates retry was performed' do
|
301
|
+
expect {
|
302
|
+
operation
|
303
|
+
}.to raise_error(Mongo::Error, /later retry failed: StandardError/)
|
304
|
+
end
|
262
305
|
end
|
263
306
|
end
|
264
307
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.10.
|
4
|
+
version: 2.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tyler Brock
|
@@ -31,7 +31,7 @@ cert_chain:
|
|
31
31
|
bMYVwXXhV8czdzgkQB/ZPWHSbEWXnmkze1mzvqWBCPOVXYrcnL9cnEl/RoxtS1hr
|
32
32
|
Db6Ac6mCUSYfYHBWpWqxjc45n70i5Xi1
|
33
33
|
-----END CERTIFICATE-----
|
34
|
-
date: 2019-08-
|
34
|
+
date: 2019-08-29 00:00:00.000000000 Z
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: bson
|
@@ -140,6 +140,7 @@ files:
|
|
140
140
|
- lib/mongo/database/view.rb
|
141
141
|
- lib/mongo/dbref.rb
|
142
142
|
- lib/mongo/error.rb
|
143
|
+
- lib/mongo/error/auth_error.rb
|
143
144
|
- lib/mongo/error/bulk_write_error.rb
|
144
145
|
- lib/mongo/error/change_stream_resumable.rb
|
145
146
|
- lib/mongo/error/closed_stream.rb
|
@@ -180,6 +181,7 @@ files:
|
|
180
181
|
- lib/mongo/error/need_primary_server.rb
|
181
182
|
- lib/mongo/error/no_server_available.rb
|
182
183
|
- lib/mongo/error/no_srv_records.rb
|
184
|
+
- lib/mongo/error/notable.rb
|
183
185
|
- lib/mongo/error/operation_failure.rb
|
184
186
|
- lib/mongo/error/parser.rb
|
185
187
|
- lib/mongo/error/pool_closed_error.rb
|
@@ -355,11 +357,11 @@ files:
|
|
355
357
|
- lib/mongo/operation/shared/polymorphic_lookup.rb
|
356
358
|
- lib/mongo/operation/shared/polymorphic_result.rb
|
357
359
|
- lib/mongo/operation/shared/read_preference_supported.rb
|
360
|
+
- lib/mongo/operation/shared/response_handling.rb
|
358
361
|
- lib/mongo/operation/shared/result/aggregatable.rb
|
359
362
|
- lib/mongo/operation/shared/result/use_legacy_error_parser.rb
|
360
363
|
- lib/mongo/operation/shared/sessions_supported.rb
|
361
364
|
- lib/mongo/operation/shared/specifiable.rb
|
362
|
-
- lib/mongo/operation/shared/unpinnable.rb
|
363
365
|
- lib/mongo/operation/shared/write.rb
|
364
366
|
- lib/mongo/operation/shared/write_concern_supported.rb
|
365
367
|
- lib/mongo/operation/update.rb
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# Copyright (C) 2014-2019 MongoDB, Inc.
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
|
15
|
-
module Mongo
|
16
|
-
module Operation
|
17
|
-
module Unpinnable
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
# Unpins the session if the session is pinned and the yielded to block
|
22
|
-
# raises errors that are required to unpin the session.
|
23
|
-
#
|
24
|
-
# @note This method takes the session as an argument because Unpinnable
|
25
|
-
# is included in BulkWrite which does not store the session in the
|
26
|
-
# receiver (despite Specifiable doing so).
|
27
|
-
#
|
28
|
-
# @param [ Session | nil ] Session to consider.
|
29
|
-
def unpin_maybe(session)
|
30
|
-
yield
|
31
|
-
rescue Mongo::Error => e
|
32
|
-
if session
|
33
|
-
session.unpin_maybe(e)
|
34
|
-
end
|
35
|
-
raise
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|