mongo 2.10.0 → 2.10.1
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 +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
|