mongo 2.20.1 → 2.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/Rakefile +2 -2
- data/lib/mongo/address.rb +22 -3
- data/lib/mongo/auth/aws/credentials_retriever.rb +70 -17
- data/lib/mongo/auth/base.rb +1 -1
- data/lib/mongo/bulk_write.rb +35 -2
- data/lib/mongo/client.rb +38 -6
- data/lib/mongo/client_encryption.rb +6 -3
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -1
- data/lib/mongo/cluster/sdam_flow.rb +20 -7
- data/lib/mongo/cluster.rb +14 -4
- data/lib/mongo/collection/helpers.rb +1 -1
- data/lib/mongo/collection/view/aggregation/behavior.rb +131 -0
- data/lib/mongo/collection/view/aggregation.rb +33 -99
- data/lib/mongo/collection/view/builder/aggregation.rb +1 -7
- data/lib/mongo/collection/view/change_stream.rb +80 -27
- data/lib/mongo/collection/view/iterable.rb +76 -60
- data/lib/mongo/collection/view/map_reduce.rb +25 -8
- data/lib/mongo/collection/view/readable.rb +79 -30
- data/lib/mongo/collection/view/writable.rb +109 -48
- data/lib/mongo/collection/view.rb +43 -3
- data/lib/mongo/collection.rb +158 -23
- data/lib/mongo/crypt/auto_encrypter.rb +4 -6
- data/lib/mongo/crypt/binding.rb +4 -4
- data/lib/mongo/crypt/context.rb +20 -14
- data/lib/mongo/crypt/encryption_io.rb +56 -26
- data/lib/mongo/crypt/explicit_encrypter.rb +49 -20
- data/lib/mongo/crypt/explicit_encryption_context.rb +17 -11
- data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +22 -6
- data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +29 -4
- data/lib/mongo/csot_timeout_holder.rb +119 -0
- data/lib/mongo/cursor/kill_spec.rb +5 -2
- data/lib/mongo/cursor/nontailable.rb +27 -0
- data/lib/mongo/cursor.rb +86 -24
- data/lib/mongo/cursor_host.rb +82 -0
- data/lib/mongo/database/view.rb +81 -14
- data/lib/mongo/database.rb +88 -18
- data/lib/mongo/error/operation_failure.rb +209 -204
- data/lib/mongo/error/server_timeout_error.rb +12 -0
- data/lib/mongo/error/socket_timeout_error.rb +3 -1
- data/lib/mongo/error/timeout_error.rb +23 -0
- data/lib/mongo/error.rb +2 -0
- data/lib/mongo/grid/fs_bucket.rb +45 -12
- data/lib/mongo/grid/stream/read.rb +15 -1
- data/lib/mongo/grid/stream/write.rb +21 -4
- data/lib/mongo/index/view.rb +77 -16
- data/lib/mongo/operation/context.rb +40 -2
- data/lib/mongo/operation/create_search_indexes/op_msg.rb +2 -2
- data/lib/mongo/operation/delete/op_msg.rb +2 -1
- data/lib/mongo/operation/drop_search_index/op_msg.rb +2 -2
- data/lib/mongo/operation/find/op_msg.rb +45 -0
- data/lib/mongo/operation/get_more/op_msg.rb +33 -0
- data/lib/mongo/operation/insert/op_msg.rb +3 -2
- data/lib/mongo/operation/insert/result.rb +4 -2
- data/lib/mongo/operation/list_collections/result.rb +1 -1
- data/lib/mongo/operation/map_reduce/result.rb +1 -1
- data/lib/mongo/operation/op_msg_base.rb +3 -1
- data/lib/mongo/operation/result.rb +26 -5
- data/lib/mongo/operation/shared/executable.rb +12 -1
- data/lib/mongo/operation/shared/op_msg_executable.rb +4 -1
- data/lib/mongo/operation/shared/response_handling.rb +3 -3
- data/lib/mongo/operation/shared/sessions_supported.rb +1 -1
- data/lib/mongo/operation/shared/timed.rb +52 -0
- data/lib/mongo/operation/shared/write.rb +4 -1
- data/lib/mongo/operation/update/op_msg.rb +2 -1
- data/lib/mongo/operation/update_search_index/op_msg.rb +2 -2
- data/lib/mongo/operation.rb +1 -0
- data/lib/mongo/protocol/message.rb +1 -4
- data/lib/mongo/protocol/msg.rb +2 -2
- data/lib/mongo/retryable/read_worker.rb +69 -29
- data/lib/mongo/retryable/write_worker.rb +49 -18
- data/lib/mongo/retryable.rb +8 -2
- data/lib/mongo/server/connection.rb +11 -5
- data/lib/mongo/server/connection_base.rb +22 -2
- data/lib/mongo/server/connection_pool.rb +32 -14
- data/lib/mongo/server/description/features.rb +1 -1
- data/lib/mongo/server/description.rb +18 -5
- data/lib/mongo/server/monitor.rb +7 -4
- data/lib/mongo/server/pending_connection.rb +7 -3
- data/lib/mongo/server/{round_trip_time_averager.rb → round_trip_time_calculator.rb} +25 -7
- data/lib/mongo/server.rb +11 -6
- data/lib/mongo/server_selector/base.rb +25 -9
- data/lib/mongo/session.rb +78 -9
- data/lib/mongo/socket/ssl.rb +109 -17
- data/lib/mongo/socket/tcp.rb +40 -6
- data/lib/mongo/socket.rb +154 -25
- data/lib/mongo/uri/options_mapper.rb +1 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo.rb +1 -0
- data/spec/atlas/atlas_connectivity_spec.rb +4 -0
- data/spec/atlas/operations_spec.rb +4 -0
- data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +2 -1
- data/spec/integration/client_side_encryption/auto_encryption_spec.rb +494 -487
- data/spec/integration/client_side_encryption/on_demand_aws_credentials_spec.rb +1 -1
- data/spec/integration/client_side_encryption/range_explicit_encryption_prose_spec.rb +66 -22
- data/spec/integration/client_side_operations_timeout/encryption_prose_spec.rb +131 -0
- data/spec/integration/connection_pool_populator_spec.rb +2 -0
- data/spec/integration/cursor_pinning_spec.rb +15 -60
- data/spec/integration/cursor_reaping_spec.rb +1 -1
- data/spec/integration/docs_examples_spec.rb +1 -1
- data/spec/integration/operation_failure_code_spec.rb +1 -1
- data/spec/integration/operation_failure_message_spec.rb +3 -3
- data/spec/integration/retryable_errors_spec.rb +2 -2
- data/spec/integration/sdam_error_handling_spec.rb +2 -1
- data/spec/integration/search_indexes_prose_spec.rb +4 -0
- data/spec/integration/server_spec.rb +4 -3
- data/spec/integration/transactions_api_examples_spec.rb +2 -0
- data/spec/kerberos/kerberos_spec.rb +4 -0
- data/spec/lite_spec_helper.rb +3 -1
- data/spec/mongo/auth/user/view_spec.rb +1 -1
- data/spec/mongo/caching_cursor_spec.rb +1 -1
- data/spec/mongo/client_encryption_spec.rb +1 -0
- data/spec/mongo/client_spec.rb +158 -4
- data/spec/mongo/collection/view/aggregation_spec.rb +14 -39
- data/spec/mongo/collection/view/change_stream_spec.rb +3 -3
- data/spec/mongo/collection_spec.rb +5 -6
- data/spec/mongo/crypt/auto_encrypter_spec.rb +14 -12
- data/spec/mongo/crypt/data_key_context_spec.rb +3 -1
- data/spec/mongo/crypt/explicit_encryption_context_spec.rb +2 -2
- data/spec/mongo/crypt/handle_spec.rb +1 -1
- data/spec/mongo/cursor_spec.rb +26 -9
- data/spec/mongo/error/operation_failure_heavy_spec.rb +2 -2
- data/spec/mongo/operation/context_spec.rb +79 -0
- data/spec/mongo/operation/create/op_msg_spec.rb +106 -110
- data/spec/mongo/operation/delete/op_msg_spec.rb +6 -5
- data/spec/mongo/operation/find/op_msg_spec.rb +66 -0
- data/spec/mongo/operation/get_more/op_msg_spec.rb +65 -0
- data/spec/mongo/operation/insert/op_msg_spec.rb +128 -131
- data/spec/mongo/operation/shared/csot/examples.rb +113 -0
- data/spec/mongo/query_cache_spec.rb +243 -225
- data/spec/mongo/retryable_spec.rb +1 -0
- data/spec/mongo/server/round_trip_time_calculator_spec.rb +120 -0
- data/spec/mongo/socket/ssl_spec.rb +0 -10
- data/spec/runners/change_streams/test.rb +2 -2
- data/spec/runners/crud/operation.rb +1 -1
- data/spec/runners/crud/verifier.rb +3 -1
- data/spec/runners/transactions/operation.rb +4 -6
- data/spec/runners/unified/ambiguous_operations.rb +13 -0
- data/spec/runners/unified/assertions.rb +4 -0
- data/spec/runners/unified/change_stream_operations.rb +14 -24
- data/spec/runners/unified/crud_operations.rb +82 -59
- data/spec/runners/unified/ddl_operations.rb +38 -7
- data/spec/runners/unified/grid_fs_operations.rb +37 -2
- data/spec/runners/unified/support_operations.rb +43 -4
- data/spec/runners/unified/test.rb +22 -10
- data/spec/runners/unified.rb +1 -1
- data/spec/solo/clean_exit_spec.rb +2 -0
- data/spec/spec_tests/client_side_operations_timeout_spec.rb +15 -0
- data/spec/spec_tests/data/change_streams_unified/change-streams-clusterTime.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-disambiguatedPaths.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-errors.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-pre_and_post_images.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-resume-allowlist.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +1 -1
- data/spec/spec_tests/data/client_side_encryption/badQueries.yml +2 -1
- data/spec/spec_tests/data/client_side_encryption/timeoutMS.yml +67 -0
- data/spec/spec_tests/data/client_side_operations_timeout/bulkWrite.yml +87 -0
- data/spec/spec_tests/data/client_side_operations_timeout/change-streams.yml +358 -0
- data/spec/spec_tests/data/client_side_operations_timeout/close-cursors.yml +129 -0
- data/spec/spec_tests/data/client_side_operations_timeout/command-execution.yml +250 -0
- data/spec/spec_tests/data/client_side_operations_timeout/convenient-transactions.yml +113 -0
- data/spec/spec_tests/data/client_side_operations_timeout/cursors.yml +70 -0
- data/spec/spec_tests/data/client_side_operations_timeout/deprecated-options.yml +3982 -0
- data/spec/spec_tests/data/client_side_operations_timeout/error-transformations.yml +96 -0
- data/spec/spec_tests/data/client_side_operations_timeout/global-timeoutMS.yml +3236 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-advanced.yml +207 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-delete.yml +152 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-download.yml +182 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-find.yml +100 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-upload.yml +249 -0
- data/spec/spec_tests/data/client_side_operations_timeout/legacy-timeouts.yml +204 -0
- data/spec/spec_tests/data/client_side_operations_timeout/non-tailable-cursors.yml +307 -0
- data/spec/spec_tests/data/client_side_operations_timeout/override-collection-timeoutMS.yml +1877 -0
- data/spec/spec_tests/data/client_side_operations_timeout/override-operation-timeoutMS.yml +1918 -0
- data/spec/spec_tests/data/client_side_operations_timeout/retryability-legacy-timeouts.yml +1676 -0
- data/spec/spec_tests/data/client_side_operations_timeout/retryability-timeoutMS.yml +2824 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-inherit-timeoutMS.yml +168 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-operation-timeoutMS.yml +171 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-timeoutMS.yml +168 -0
- data/spec/spec_tests/data/client_side_operations_timeout/tailable-awaitData.yml +247 -0
- data/spec/spec_tests/data/client_side_operations_timeout/tailable-non-awaitData.yml +181 -0
- data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +4 -0
- data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +4 -0
- data/spec/spec_tests/data/crud_unified/find-test-all-options.yml +29 -0
- data/spec/spec_tests/server_selection_rtt_spec.rb +6 -6
- data/spec/support/certificates/atlas-ocsp-ca.crt +81 -83
- data/spec/support/certificates/atlas-ocsp.crt +107 -107
- data/spec/support/cluster_tools.rb +3 -3
- data/spec/support/common_shortcuts.rb +2 -2
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Date.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalNoPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoubleNoPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoublePrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Int.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Long.json +1 -1
- data/spec/support/shared/session.rb +2 -2
- data/spec/support/spec_setup.rb +2 -2
- data/spec/support/utils.rb +3 -1
- metadata +78 -91
- data/spec/mongo/server/round_trip_time_averager_spec.rb +0 -48
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Correctness.yml +0 -423
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Update.yml +0 -253
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Aggregate.yml +0 -1688
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Correctness.yml +0 -294
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Delete.yml +0 -906
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-FindOneAndUpdate.yml +0 -1685
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-InsertFind.yml +0 -1681
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Update.yml +0 -1698
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Aggregate.yml +0 -330
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Correctness.yml +0 -425
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Delete.yml +0 -227
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.yml +0 -328
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-InsertFind.yml +0 -320
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Update.yml +0 -337
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Aggregate.yml +0 -914
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Correctness.yml +0 -293
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Delete.yml +0 -519
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-FindOneAndUpdate.yml +0 -912
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-InsertFind.yml +0 -908
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Update.yml +0 -925
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Aggregate.yml +0 -326
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Correctness.yml +0 -425
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Delete.yml +0 -225
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-FindOneAndUpdate.yml +0 -324
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-InsertFind.yml +0 -320
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Update.yml +0 -339
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Correctness.yml +0 -424
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Update.yml +0 -255
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Correctness.yml +0 -423
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Update.yml +0 -255
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-WrongType.yml +0 -44
@@ -18,242 +18,247 @@ require 'mongo/error/read_write_retryable'
|
|
18
18
|
|
19
19
|
module Mongo
|
20
20
|
class Error
|
21
|
-
|
22
21
|
# Raised when an operation fails for some reason.
|
23
|
-
#
|
24
|
-
# @since 2.0.0
|
25
22
|
class OperationFailure < Error
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
# Implements the behavior for an OperationFailure error. Other errors
|
24
|
+
# (e.g. ServerTimeoutError) may also implement this, so that they may
|
25
|
+
# be recognized and treated as OperationFailure errors.
|
26
|
+
module OperationFailure::Family
|
27
|
+
extend Forwardable
|
28
|
+
include SdamErrorDetection
|
29
|
+
include ReadWriteRetryable
|
29
30
|
|
30
|
-
|
31
|
+
def_delegators :@result, :operation_time
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
# @!method connection_description
|
34
|
+
#
|
35
|
+
# @return [ Server::Description ] Server description of the server that
|
36
|
+
# the operation that this exception refers to was performed on.
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
def_delegator :@result, :connection_description
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
# @return [ Integer ] The error code parsed from the document.
|
42
|
+
#
|
43
|
+
# @since 2.6.0
|
44
|
+
attr_reader :code
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
# @return [ String ] The error code name parsed from the document.
|
47
|
+
#
|
48
|
+
# @since 2.6.0
|
49
|
+
attr_reader :code_name
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
# @return [ String ] The server-returned error message
|
52
|
+
# parsed from the response.
|
53
|
+
#
|
54
|
+
# @api experimental
|
55
|
+
attr_reader :server_message
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
57
|
+
# Error codes and code names that should result in a failing getMore
|
58
|
+
# command on a change stream NOT being resumed.
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
CHANGE_STREAM_RESUME_ERRORS = [
|
62
|
+
{code_name: 'HostUnreachable', code: 6},
|
63
|
+
{code_name: 'HostNotFound', code: 7},
|
64
|
+
{code_name: 'NetworkTimeout', code: 89},
|
65
|
+
{code_name: 'ShutdownInProgress', code: 91},
|
66
|
+
{code_name: 'PrimarySteppedDown', code: 189},
|
67
|
+
{code_name: 'ExceededTimeLimit', code: 262},
|
68
|
+
{code_name: 'SocketException', code: 9001},
|
69
|
+
{code_name: 'NotMaster', code: 10107},
|
70
|
+
{code_name: 'InterruptedAtShutdown', code: 11600},
|
71
|
+
{code_name: 'InterruptedDueToReplStateChange', code: 11602},
|
72
|
+
{code_name: 'NotPrimaryNoSecondaryOk', code: 13435},
|
73
|
+
{code_name: 'NotMasterOrSecondary', code: 13436},
|
73
74
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
{code_name: 'StaleShardVersion', code: 63},
|
76
|
+
{code_name: 'FailedToSatisfyReadPreference', code: 133},
|
77
|
+
{code_name: 'StaleEpoch', code: 150},
|
78
|
+
{code_name: 'RetryChangeStream', code: 234},
|
79
|
+
{code_name: 'StaleConfig', code: 13388},
|
80
|
+
].freeze
|
80
81
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
82
|
+
# Change stream can be resumed when these error messages are encountered.
|
83
|
+
#
|
84
|
+
# @since 2.6.0
|
85
|
+
# @api private
|
86
|
+
CHANGE_STREAM_RESUME_MESSAGES = ReadWriteRetryable::WRITE_RETRY_MESSAGES
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
88
|
+
# Can the change stream on which this error occurred be resumed,
|
89
|
+
# provided the operation that triggered this error was a getMore?
|
90
|
+
#
|
91
|
+
# @example Is the error resumable for the change stream?
|
92
|
+
# error.change_stream_resumable?
|
93
|
+
#
|
94
|
+
# @return [ true, false ] Whether the error is resumable.
|
95
|
+
#
|
96
|
+
# @since 2.6.0
|
97
|
+
def change_stream_resumable?
|
98
|
+
if @result && @result.is_a?(Mongo::Operation::GetMore::Result)
|
99
|
+
# CursorNotFound exceptions are always resumable because the server
|
100
|
+
# is not aware of the cursor id, and thus cannot determine if
|
101
|
+
# the cursor is a change stream and cannot add the
|
102
|
+
# ResumableChangeStreamError label.
|
103
|
+
return true if code == 43
|
103
104
|
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
# Connection description is not populated for unacknowledged writes.
|
106
|
+
if connection_description.max_wire_version >= 9
|
107
|
+
label?('ResumableChangeStreamError')
|
108
|
+
else
|
109
|
+
change_stream_resumable_code?
|
110
|
+
end
|
107
111
|
else
|
108
|
-
|
112
|
+
false
|
109
113
|
end
|
110
|
-
else
|
111
|
-
false
|
112
114
|
end
|
113
|
-
end
|
114
115
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
def change_stream_resumable_code?
|
117
|
+
CHANGE_STREAM_RESUME_ERRORS.any? { |e| e[:code] == code }
|
118
|
+
end
|
119
|
+
private :change_stream_resumable_code?
|
119
120
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
121
|
+
# @return [ true | false ] Whether the failure includes a write
|
122
|
+
# concern error. A failure may have a top level error and a write
|
123
|
+
# concern error or either one of the two.
|
124
|
+
#
|
125
|
+
# @since 2.10.0
|
126
|
+
def write_concern_error?
|
127
|
+
!!@write_concern_error_document
|
128
|
+
end
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
# Returns the write concern error document as it was reported by the
|
131
|
+
# server, if any.
|
132
|
+
#
|
133
|
+
# @return [ Hash | nil ] Write concern error as reported to the server.
|
134
|
+
attr_reader :write_concern_error_document
|
134
135
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
136
|
+
# @return [ Integer | nil ] The error code for the write concern error,
|
137
|
+
# if a write concern error is present and has a code.
|
138
|
+
#
|
139
|
+
# @since 2.10.0
|
140
|
+
attr_reader :write_concern_error_code
|
140
141
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
142
|
+
# @return [ String | nil ] The code name for the write concern error,
|
143
|
+
# if a write concern error is present and has a code name.
|
144
|
+
#
|
145
|
+
# @since 2.10.0
|
146
|
+
attr_reader :write_concern_error_code_name
|
146
147
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
148
|
+
# @return [ String | nil ] The details of the error.
|
149
|
+
# For WriteConcernErrors this is `document['writeConcernError']['errInfo']`.
|
150
|
+
# For WriteErrors this is `document['writeErrors'][0]['errInfo']`.
|
151
|
+
# For all other errors this is nil.
|
152
|
+
attr_reader :details
|
152
153
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
154
|
+
# @return [ BSON::Document | nil ] The server-returned error document.
|
155
|
+
#
|
156
|
+
# @api experimental
|
157
|
+
attr_reader :document
|
157
158
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
#
|
163
|
-
# @example Create the error object with a code and a code name
|
164
|
-
# OperationFailure.new(message, result, :code => code, :code_name => code_name)
|
165
|
-
#
|
166
|
-
# @param [ String ] message The error message.
|
167
|
-
# @param [ Operation::Result ] result The result object.
|
168
|
-
# @param [ Hash ] options Additional parameters.
|
169
|
-
#
|
170
|
-
# @option options [ Integer ] :code Error code.
|
171
|
-
# @option options [ String ] :code_name Error code name.
|
172
|
-
# @option options [ BSON::Document ] :document The server-returned
|
173
|
-
# error document.
|
174
|
-
# @option options [ String ] server_message The server-returned
|
175
|
-
# error message parsed from the response.
|
176
|
-
# @option options [ Hash ] :write_concern_error_document The
|
177
|
-
# server-supplied write concern error document, if any.
|
178
|
-
# @option options [ Integer ] :write_concern_error_code Error code for
|
179
|
-
# write concern error, if any.
|
180
|
-
# @option options [ String ] :write_concern_error_code_name Error code
|
181
|
-
# name for write concern error, if any.
|
182
|
-
# @option options [ Array<String> ] :write_concern_error_labels Error
|
183
|
-
# labels for the write concern error, if any.
|
184
|
-
# @option options [ Array<String> ] :labels The set of labels associated
|
185
|
-
# with the error.
|
186
|
-
# @option options [ true | false ] :wtimeout Whether the error is a wtimeout.
|
187
|
-
def initialize(message = nil, result = nil, options = {})
|
188
|
-
@details = retrieve_details(options[:document])
|
189
|
-
super(append_details(message, @details))
|
159
|
+
# @return [ Operation::Result ] the result object for the operation.
|
160
|
+
#
|
161
|
+
# @api private
|
162
|
+
attr_reader :result
|
190
163
|
|
191
|
-
|
192
|
-
|
193
|
-
@
|
194
|
-
@
|
195
|
-
@
|
196
|
-
|
197
|
-
@
|
198
|
-
@
|
199
|
-
@
|
200
|
-
|
201
|
-
@
|
202
|
-
|
164
|
+
# Create the operation failure.
|
165
|
+
#
|
166
|
+
# @param [ String ] message The error message.
|
167
|
+
# @param [ Operation::Result ] result The result object.
|
168
|
+
# @param [ Hash ] options Additional parameters.
|
169
|
+
#
|
170
|
+
# @option options [ Integer ] :code Error code.
|
171
|
+
# @option options [ String ] :code_name Error code name.
|
172
|
+
# @option options [ BSON::Document ] :document The server-returned
|
173
|
+
# error document.
|
174
|
+
# @option options [ String ] server_message The server-returned
|
175
|
+
# error message parsed from the response.
|
176
|
+
# @option options [ Hash ] :write_concern_error_document The
|
177
|
+
# server-supplied write concern error document, if any.
|
178
|
+
# @option options [ Integer ] :write_concern_error_code Error code for
|
179
|
+
# write concern error, if any.
|
180
|
+
# @option options [ String ] :write_concern_error_code_name Error code
|
181
|
+
# name for write concern error, if any.
|
182
|
+
# @option options [ Array<String> ] :write_concern_error_labels Error
|
183
|
+
# labels for the write concern error, if any.
|
184
|
+
# @option options [ Array<String> ] :labels The set of labels associated
|
185
|
+
# with the error.
|
186
|
+
# @option options [ true | false ] :wtimeout Whether the error is a wtimeout.
|
187
|
+
def initialize(message = nil, result = nil, options = {})
|
188
|
+
@details = retrieve_details(options[:document])
|
189
|
+
super(append_details(message, @details))
|
203
190
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
191
|
+
@result = result
|
192
|
+
@code = options[:code]
|
193
|
+
@code_name = options[:code_name]
|
194
|
+
@write_concern_error_document = options[:write_concern_error_document]
|
195
|
+
@write_concern_error_code = options[:write_concern_error_code]
|
196
|
+
@write_concern_error_code_name = options[:write_concern_error_code_name]
|
197
|
+
@write_concern_error_labels = options[:write_concern_error_labels] || []
|
198
|
+
@labels = options[:labels] || []
|
199
|
+
@wtimeout = !!options[:wtimeout]
|
200
|
+
@document = options[:document]
|
201
|
+
@server_message = options[:server_message]
|
202
|
+
end
|
212
203
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
204
|
+
# Whether the error is a write concern timeout.
|
205
|
+
#
|
206
|
+
# @return [ true | false ] Whether the error is a write concern timeout.
|
207
|
+
#
|
208
|
+
# @since 2.7.1
|
209
|
+
def wtimeout?
|
210
|
+
@wtimeout
|
211
|
+
end
|
221
212
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
#
|
232
|
-
#
|
233
|
-
|
234
|
-
|
213
|
+
# Whether the error is MaxTimeMSExpired.
|
214
|
+
#
|
215
|
+
# @return [ true | false ] Whether the error is MaxTimeMSExpired.
|
216
|
+
#
|
217
|
+
# @since 2.10.0
|
218
|
+
def max_time_ms_expired?
|
219
|
+
code == 50 # MaxTimeMSExpired
|
220
|
+
end
|
221
|
+
|
222
|
+
# Whether the error is caused by an attempted retryable write
|
223
|
+
# on a storage engine that does not support retryable writes.
|
224
|
+
#
|
225
|
+
# @return [ true | false ] Whether the error is caused by an attempted
|
226
|
+
# retryable write on a storage engine that does not support retryable writes.
|
227
|
+
#
|
228
|
+
# @since 2.10.0
|
229
|
+
def unsupported_retryable_write?
|
230
|
+
# code 20 is IllegalOperation.
|
231
|
+
# Note that the document is expected to be a BSON::Document, thus
|
232
|
+
# either having string keys or providing indifferent access.
|
233
|
+
code == 20 && server_message&.start_with?("Transaction numbers") || false
|
234
|
+
end
|
235
235
|
|
236
|
-
|
236
|
+
private
|
237
237
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
238
|
+
# Retrieve the details from a document
|
239
|
+
#
|
240
|
+
# @return [ Hash | nil ] the details extracted from the document
|
241
|
+
def retrieve_details(document)
|
242
|
+
return nil unless document
|
243
|
+
if wce = document['writeConcernError']
|
244
|
+
return wce['errInfo']
|
245
|
+
elsif we = document['writeErrors']&.first
|
246
|
+
return we['errInfo']
|
247
|
+
end
|
247
248
|
end
|
248
|
-
end
|
249
249
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
250
|
+
# Append the details to the message
|
251
|
+
#
|
252
|
+
# @return [ String ] the message with the details appended to it
|
253
|
+
def append_details(message, details)
|
254
|
+
return message unless details && message
|
255
|
+
message + " -- #{details.to_json}"
|
256
|
+
end
|
256
257
|
end
|
258
|
+
|
259
|
+
# OperationFailure is the canonical implementor of the
|
260
|
+
# OperationFailure::Family concern.
|
261
|
+
include OperationFailure::Family
|
257
262
|
end
|
258
263
|
end
|
259
264
|
end
|
@@ -15,13 +15,15 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
|
+
require 'mongo/error/timeout_error'
|
19
|
+
|
18
20
|
module Mongo
|
19
21
|
class Error
|
20
22
|
|
21
23
|
# Raised when a socket connection times out.
|
22
24
|
#
|
23
25
|
# @since 2.0.0
|
24
|
-
class SocketTimeoutError <
|
26
|
+
class SocketTimeoutError < TimeoutError
|
25
27
|
include WriteRetryable
|
26
28
|
include ChangeStreamResumable
|
27
29
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2015-present MongoDB Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
module Mongo
|
18
|
+
class Error
|
19
|
+
# Raised when a Client Side Operation Timeout times out.
|
20
|
+
class TimeoutError < Error
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/mongo/error.rb
CHANGED
@@ -217,7 +217,9 @@ require 'mongo/error/missing_service_id'
|
|
217
217
|
require 'mongo/error/server_api_conflict'
|
218
218
|
require 'mongo/error/server_api_not_supported'
|
219
219
|
require 'mongo/error/server_not_usable'
|
220
|
+
require 'mongo/error/server_timeout_error'
|
220
221
|
require 'mongo/error/transactions_not_supported'
|
222
|
+
require 'mongo/error/timeout_error'
|
221
223
|
require 'mongo/error/unknown_payload_type'
|
222
224
|
require 'mongo/error/unmet_dependency'
|
223
225
|
require 'mongo/error/unsupported_option'
|
data/lib/mongo/grid/fs_bucket.rb
CHANGED
@@ -201,8 +201,8 @@ module Mongo
|
|
201
201
|
# @return [ Result ] The result of the remove.
|
202
202
|
#
|
203
203
|
# @since 2.0.0
|
204
|
-
def delete_one(file)
|
205
|
-
delete(file.id)
|
204
|
+
def delete_one(file, opts = {})
|
205
|
+
delete(file.id, opts)
|
206
206
|
end
|
207
207
|
|
208
208
|
# Remove a single file, identified by its id from the GridFS.
|
@@ -217,9 +217,14 @@ module Mongo
|
|
217
217
|
# @raise [ Error::FileNotFound ] If the file is not found.
|
218
218
|
#
|
219
219
|
# @since 2.1.0
|
220
|
-
def delete(id)
|
221
|
-
|
222
|
-
|
220
|
+
def delete(id, opts = {})
|
221
|
+
timeout_holder = CsotTimeoutHolder.new(operation_timeouts: operation_timeouts(opts))
|
222
|
+
result = files_collection
|
223
|
+
.find({ :_id => id }, @options.merge(timeout_ms: timeout_holder.remaining_timeout_ms))
|
224
|
+
.delete_one(timeout_ms: timeout_holder.remaining_timeout_ms)
|
225
|
+
chunks_collection
|
226
|
+
.find({ :files_id => id }, @options.merge(timeout_ms: timeout_holder.remaining_timeout_ms))
|
227
|
+
.delete_many(timeout_ms: timeout_holder.remaining_timeout_ms)
|
223
228
|
raise Error::FileNotFound.new(id, :id) if result.n == 0
|
224
229
|
result
|
225
230
|
end
|
@@ -485,9 +490,10 @@ module Mongo
|
|
485
490
|
end
|
486
491
|
|
487
492
|
# Drop the collections that implement this bucket.
|
488
|
-
def drop
|
489
|
-
|
490
|
-
|
493
|
+
def drop(opts = {})
|
494
|
+
context = Operation::Context.new(operation_timeouts: operation_timeouts(opts))
|
495
|
+
files_collection.drop(timeout_ms: context.remaining_timeout_ms)
|
496
|
+
chunks_collection.drop(timeout_ms: context.remaining_timeout_ms)
|
491
497
|
end
|
492
498
|
|
493
499
|
private
|
@@ -512,12 +518,24 @@ module Mongo
|
|
512
518
|
"#{prefix}.#{Grid::File::Info::COLLECTION}"
|
513
519
|
end
|
514
520
|
|
515
|
-
def ensure_indexes!
|
516
|
-
|
521
|
+
def ensure_indexes!(timeout_holder = nil)
|
522
|
+
fc_idx = files_collection.find(
|
523
|
+
{},
|
524
|
+
limit: 1,
|
525
|
+
projection: { _id: 1 },
|
526
|
+
timeout_ms: timeout_holder&.remaining_timeout_ms
|
527
|
+
).first
|
528
|
+
if fc_idx.nil?
|
517
529
|
create_index_if_missing!(files_collection, FSBucket::FILES_INDEX)
|
518
530
|
end
|
519
531
|
|
520
|
-
|
532
|
+
cc_idx = chunks_collection.find(
|
533
|
+
{},
|
534
|
+
limit: 1,
|
535
|
+
projection: { _id: 1 },
|
536
|
+
timeout_ms: timeout_holder&.remaining_timeout_ms
|
537
|
+
).first
|
538
|
+
if cc_idx.nil?
|
521
539
|
create_index_if_missing!(chunks_collection, FSBucket::CHUNKS_INDEX, :unique => true)
|
522
540
|
end
|
523
541
|
end
|
@@ -528,7 +546,7 @@ module Mongo
|
|
528
546
|
if indexes_view.get(index_spec).nil?
|
529
547
|
indexes_view.create_one(index_spec, options)
|
530
548
|
end
|
531
|
-
rescue Mongo::Error::OperationFailure => e
|
549
|
+
rescue Mongo::Error::OperationFailure::Family => e
|
532
550
|
# proceed with index creation if a NamespaceNotFound error is thrown
|
533
551
|
if e.code == 26
|
534
552
|
indexes_view.create_one(index_spec, options)
|
@@ -537,6 +555,21 @@ module Mongo
|
|
537
555
|
end
|
538
556
|
end
|
539
557
|
end
|
558
|
+
|
559
|
+
# @return [ Hash ] timeout_ms value set on the operation level (if any),
|
560
|
+
# and/or timeout_ms that is set on collection/database/client level (if any).
|
561
|
+
#
|
562
|
+
# @api private
|
563
|
+
def operation_timeouts(opts = {})
|
564
|
+
# TODO: We should re-evaluate if we need two timeouts separately.
|
565
|
+
{}.tap do |result|
|
566
|
+
if opts[:timeout_ms].nil?
|
567
|
+
result[:inherited_timeout_ms] = database.timeout_ms
|
568
|
+
else
|
569
|
+
result[:operation_timeout_ms] = opts[:timeout_ms]
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
540
573
|
end
|
541
574
|
end
|
542
575
|
end
|
@@ -59,6 +59,12 @@ module Mongo
|
|
59
59
|
@file_id = @options.delete(:file_id)
|
60
60
|
@options.freeze
|
61
61
|
@open = true
|
62
|
+
@timeout_holder = CsotTimeoutHolder.new(
|
63
|
+
operation_timeouts: {
|
64
|
+
operation_timeout_ms: options[:timeout_ms],
|
65
|
+
inherited_timeout_ms: fs.database.timeout_ms
|
66
|
+
}
|
67
|
+
)
|
62
68
|
end
|
63
69
|
|
64
70
|
# Iterate through chunk data streamed from the FSBucket.
|
@@ -178,7 +184,11 @@ module Mongo
|
|
178
184
|
# @since 2.1.0
|
179
185
|
def file_info
|
180
186
|
@file_info ||= begin
|
181
|
-
doc = options[:file_info_doc] ||
|
187
|
+
doc = options[:file_info_doc] ||
|
188
|
+
fs.files_collection.find(
|
189
|
+
{ _id: file_id },
|
190
|
+
{ timeout_ms: @timeout_holder.remaining_timeout_ms! }
|
191
|
+
).first
|
182
192
|
if doc
|
183
193
|
File::Info.new(Options::Mapper.transform(doc, File::Info::MAPPINGS.invert))
|
184
194
|
else
|
@@ -209,6 +219,10 @@ module Mongo
|
|
209
219
|
else
|
210
220
|
options
|
211
221
|
end
|
222
|
+
if @timeout_holder.csot?
|
223
|
+
opts[:timeout_ms] = @timeout_holder.remaining_timeout_ms!
|
224
|
+
opts[:timeout_mode] = :cursor_lifetime
|
225
|
+
end
|
212
226
|
|
213
227
|
fs.chunks_collection.find({ :files_id => file_id }, opts).sort(:n => 1)
|
214
228
|
end
|