mongo 2.8.0 → 2.9.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Rakefile +12 -0
- data/lib/mongo.rb +15 -1
- data/lib/mongo/address/ipv6.rb +0 -2
- data/lib/mongo/auth/scram/conversation.rb +0 -3
- data/lib/mongo/bulk_write/result_combiner.rb +12 -2
- data/lib/mongo/client.rb +59 -6
- data/lib/mongo/cluster.rb +19 -8
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +0 -2
- data/lib/mongo/cluster/reapers/socket_reaper.rb +12 -9
- data/lib/mongo/collection.rb +1 -1
- data/lib/mongo/collection/view/aggregation.rb +5 -1
- data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +30 -10
- data/lib/mongo/collection/view/iterable.rb +13 -6
- data/lib/mongo/collection/view/map_reduce.rb +12 -10
- data/lib/mongo/collection/view/readable.rb +19 -14
- data/lib/mongo/cursor.rb +12 -8
- data/lib/mongo/database.rb +10 -7
- data/lib/mongo/database/view.rb +18 -11
- data/lib/mongo/error.rb +2 -2
- data/lib/mongo/error/connection_check_out_timeout.rb +49 -0
- data/lib/mongo/error/operation_failure.rb +9 -9
- data/lib/mongo/error/parser.rb +25 -3
- data/lib/mongo/error/pool_closed_error.rb +43 -0
- data/lib/mongo/error/sdam_error_detection.rb +18 -0
- data/lib/mongo/grid/file/chunk.rb +0 -2
- data/lib/mongo/grid/fs_bucket.rb +26 -12
- data/lib/mongo/grid/stream/read.rb +36 -21
- data/lib/mongo/index/view.rb +11 -7
- data/lib/mongo/logger.rb +0 -2
- data/lib/mongo/monitoring.rb +31 -0
- data/lib/mongo/monitoring/cmap_log_subscriber.rb +53 -0
- data/lib/mongo/monitoring/event.rb +1 -0
- data/lib/mongo/monitoring/event/cmap.rb +25 -0
- data/lib/mongo/monitoring/event/cmap/base.rb +28 -0
- data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +78 -0
- data/lib/mongo/monitoring/event/cmap/connection_check_out_started.rb +56 -0
- data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +63 -0
- data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +64 -0
- data/lib/mongo/monitoring/event/cmap/connection_closed.rb +103 -0
- data/lib/mongo/monitoring/event/cmap/connection_created.rb +64 -0
- data/lib/mongo/monitoring/event/cmap/connection_ready.rb +64 -0
- data/lib/mongo/monitoring/event/cmap/pool_cleared.rb +57 -0
- data/lib/mongo/monitoring/event/cmap/pool_closed.rb +57 -0
- data/lib/mongo/monitoring/event/cmap/pool_created.rb +63 -0
- data/lib/mongo/monitoring/event/command_started.rb +12 -3
- data/lib/mongo/monitoring/publishable.rb +10 -2
- data/lib/mongo/operation.rb +0 -1
- data/lib/mongo/operation/find/legacy/result.rb +1 -0
- data/lib/mongo/operation/list_collections/result.rb +7 -1
- data/lib/mongo/operation/result.rb +10 -1
- data/lib/mongo/operation/shared/executable.rb +15 -0
- data/lib/mongo/operation/shared/result/use_legacy_error_parser.rb +29 -0
- data/lib/mongo/operation/shared/specifiable.rb +0 -16
- data/lib/mongo/operation/update/legacy/result.rb +1 -0
- data/lib/mongo/protocol/compressed.rb +0 -2
- data/lib/mongo/protocol/msg.rb +25 -2
- data/lib/mongo/retryable.rb +171 -33
- data/lib/mongo/server.rb +26 -7
- data/lib/mongo/server/app_metadata.rb +0 -2
- data/lib/mongo/server/connectable.rb +8 -2
- data/lib/mongo/server/connection.rb +83 -13
- data/lib/mongo/server/connection_base.rb +1 -1
- data/lib/mongo/server/connection_pool.rb +439 -43
- data/lib/mongo/server/monitor/connection.rb +4 -1
- data/lib/mongo/session.rb +37 -5
- data/lib/mongo/session/session_pool.rb +2 -2
- data/lib/mongo/socket.rb +0 -2
- data/lib/mongo/socket/ssl.rb +0 -2
- data/lib/mongo/uri.rb +127 -66
- data/lib/mongo/uri/srv_protocol.rb +35 -13
- data/lib/mongo/version.rb +1 -1
- data/spec/README.md +190 -63
- data/spec/integration/change_stream_spec.rb +64 -0
- data/spec/integration/command_spec.rb +0 -7
- data/spec/integration/error_detection_spec.rb +39 -0
- data/spec/integration/read_concern.rb +83 -0
- data/spec/integration/retryable_writes_spec.rb +6 -50
- data/spec/integration/sdam_error_handling_spec.rb +60 -7
- data/spec/integration/ssl_uri_options_spec.rb +24 -0
- data/spec/integration/step_down_spec.rb +197 -0
- data/spec/lite_spec_helper.rb +4 -0
- data/spec/mongo/client_construction_spec.rb +42 -17
- data/spec/mongo/client_spec.rb +32 -1
- data/spec/mongo/cluster/socket_reaper_spec.rb +2 -2
- data/spec/mongo/cluster_spec.rb +36 -2
- data/spec/mongo/collection/view/aggregation_spec.rb +2 -0
- data/spec/mongo/collection/view/change_stream_spec.rb +28 -28
- data/spec/mongo/collection/view/readable_spec.rb +1 -1
- data/spec/mongo/collection/view_spec.rb +3 -1
- data/spec/mongo/cursor_spec.rb +5 -5
- data/spec/mongo/error/parser_spec.rb +61 -1
- data/spec/mongo/grid/stream/read_spec.rb +2 -2
- data/spec/mongo/monitoring/event/cmap/connection_check_out_failed_spec.rb +23 -0
- data/spec/mongo/monitoring/event/cmap/connection_check_out_started_spec.rb +19 -0
- data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +23 -0
- data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +23 -0
- data/spec/mongo/monitoring/event/cmap/connection_closed_spec.rb +27 -0
- data/spec/mongo/monitoring/event/cmap/connection_created_spec.rb +24 -0
- data/spec/mongo/monitoring/event/cmap/connection_ready_spec.rb +24 -0
- data/spec/mongo/monitoring/event/cmap/pool_cleared_spec.rb +19 -0
- data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +19 -0
- data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +26 -0
- data/spec/mongo/operation/delete/bulk_spec.rb +1 -6
- data/spec/mongo/operation/delete/command_spec.rb +1 -1
- data/spec/mongo/operation/delete/op_msg_spec.rb +1 -1
- data/spec/mongo/operation/delete_spec.rb +4 -4
- data/spec/mongo/operation/insert/bulk_spec.rb +1 -1
- data/spec/mongo/operation/insert/command_spec.rb +1 -1
- data/spec/mongo/operation/insert/op_msg_spec.rb +1 -1
- data/spec/mongo/operation/update/bulk_spec.rb +1 -1
- data/spec/mongo/operation/update/command_spec.rb +2 -2
- data/spec/mongo/operation/update/op_msg_spec.rb +2 -2
- data/spec/mongo/protocol/msg_spec.rb +11 -0
- data/spec/mongo/retryable_spec.rb +78 -25
- data/spec/mongo/server/connection_pool_spec.rb +661 -126
- data/spec/mongo/server/connection_spec.rb +55 -7
- data/spec/mongo/server_spec.rb +5 -0
- data/spec/mongo/uri/srv_protocol_spec.rb +135 -2
- data/spec/mongo/uri_option_parsing_spec.rb +511 -0
- data/spec/mongo/uri_spec.rb +42 -6
- data/spec/spec_helper.rb +1 -84
- data/spec/spec_tests/cmap_spec.rb +50 -0
- data/spec/spec_tests/command_monitoring_spec.rb +7 -18
- data/spec/spec_tests/crud_spec.rb +3 -49
- data/spec/spec_tests/data/cmap/connection-must-have-id.yml +21 -0
- data/spec/spec_tests/data/cmap/connection-must-order-ids.yml +21 -0
- data/spec/spec_tests/data/cmap/pool-checkin-destroy-closed.yml +24 -0
- data/spec/spec_tests/data/cmap/pool-checkin-destroy-stale.yml +24 -0
- data/spec/spec_tests/data/cmap/pool-checkin-make-available.yml +21 -0
- data/spec/spec_tests/data/cmap/pool-checkin.yml +18 -0
- data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +13 -0
- data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +28 -0
- data/spec/spec_tests/data/cmap/pool-checkout-multiple.yml +34 -0
- data/spec/spec_tests/data/cmap/pool-checkout-no-idle.yml +31 -0
- data/spec/spec_tests/data/cmap/pool-checkout-no-stale.yml +29 -0
- data/spec/spec_tests/data/cmap/pool-close-destroy-conns.yml +26 -0
- data/spec/spec_tests/data/cmap/pool-close.yml +11 -0
- data/spec/spec_tests/data/cmap/pool-create-max-size.yml +56 -0
- data/spec/spec_tests/data/cmap/pool-create-min-size.yml +27 -0
- data/spec/spec_tests/data/cmap/pool-create-with-options.yml +20 -0
- data/spec/spec_tests/data/cmap/pool-create.yml +12 -0
- data/spec/spec_tests/data/cmap/wait-queue-fairness.yml +94 -0
- data/spec/spec_tests/data/cmap/wait-queue-timeout.yml +41 -0
- data/spec/spec_tests/data/retryable_reads/aggregate-serverErrors.yml +157 -0
- data/spec/spec_tests/data/retryable_reads/aggregate.yml +87 -0
- data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch-serverErrors.yml +149 -0
- data/spec/spec_tests/data/retryable_reads/changeStreams-client.watch.yml +61 -0
- data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch-serverErrors.yml +149 -0
- data/spec/spec_tests/data/retryable_reads/changeStreams-db.coll.watch.yml +65 -0
- data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch-serverErrors.yml +153 -0
- data/spec/spec_tests/data/retryable_reads/changeStreams-db.watch.yml +61 -0
- data/spec/spec_tests/data/retryable_reads/count-serverErrors.yml +150 -0
- data/spec/spec_tests/data/retryable_reads/count.yml +64 -0
- data/spec/spec_tests/data/retryable_reads/countDocuments-serverErrors.yml +150 -0
- data/spec/spec_tests/data/retryable_reads/countDocuments.yml +64 -0
- data/spec/spec_tests/data/retryable_reads/distinct-serverErrors.yml +156 -0
- data/spec/spec_tests/data/retryable_reads/distinct.yml +71 -0
- data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors.yml +148 -0
- data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount.yml +62 -0
- data/spec/spec_tests/data/retryable_reads/find-serverErrors.yml +160 -0
- data/spec/spec_tests/data/retryable_reads/find.yml +86 -0
- data/spec/spec_tests/data/retryable_reads/findOne-serverErrors.yml +154 -0
- data/spec/spec_tests/data/retryable_reads/findOne.yml +68 -0
- data/spec/spec_tests/data/retryable_reads/gridfs-download-serverErrors.yml +173 -0
- data/spec/spec_tests/data/retryable_reads/gridfs-download.yml +79 -0
- data/spec/spec_tests/data/retryable_reads/gridfs-downloadByName-serverErrors.yml +174 -0
- data/spec/spec_tests/data/retryable_reads/gridfs-downloadByName.yml +79 -0
- data/spec/spec_tests/data/retryable_reads/listCollectionNames-serverErrors.yml +143 -0
- data/spec/spec_tests/data/retryable_reads/listCollectionNames.yml +59 -0
- data/spec/spec_tests/data/retryable_reads/listCollectionObjects-serverErrors.yml +144 -0
- data/spec/spec_tests/data/retryable_reads/listCollectionObjects.yml +59 -0
- data/spec/spec_tests/data/retryable_reads/listCollections-serverErrors.yml +143 -0
- data/spec/spec_tests/data/retryable_reads/listCollections.yml +59 -0
- data/spec/spec_tests/data/retryable_reads/listDatabaseNames-serverErrors.yml +143 -0
- data/spec/spec_tests/data/retryable_reads/listDatabaseNames.yml +59 -0
- data/spec/spec_tests/data/retryable_reads/listDatabaseObjects-serverErrors.yml +144 -0
- data/spec/spec_tests/data/retryable_reads/listDatabaseObjects.yml +59 -0
- data/spec/spec_tests/data/retryable_reads/listDatabases-serverErrors.yml +144 -0
- data/spec/spec_tests/data/retryable_reads/listDatabases.yml +59 -0
- data/spec/spec_tests/data/retryable_reads/listIndexNames-serverErrors.yml +144 -0
- data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +60 -0
- data/spec/spec_tests/data/retryable_reads/listIndexes-serverErrors.yml +145 -0
- data/spec/spec_tests/data/retryable_reads/listIndexes.yml +60 -0
- data/spec/spec_tests/data/retryable_reads/mapReduce.yml +60 -0
- data/spec/spec_tests/data/retryable_writes/bulkWrite-serverErrors.yml +10 -7
- data/spec/spec_tests/data/retryable_writes/bulkWrite.yml +15 -22
- data/spec/spec_tests/data/retryable_writes/deleteMany.yml +22 -0
- data/spec/spec_tests/data/retryable_writes/deleteOne-serverErrors.yml +8 -7
- data/spec/spec_tests/data/retryable_writes/deleteOne.yml +5 -8
- data/spec/spec_tests/data/retryable_writes/findOneAndDelete-serverErrors.yml +8 -7
- data/spec/spec_tests/data/retryable_writes/findOneAndDelete.yml +5 -8
- data/spec/spec_tests/data/retryable_writes/findOneAndReplace-serverErrors.yml +8 -7
- data/spec/spec_tests/data/retryable_writes/findOneAndReplace.yml +5 -8
- data/spec/spec_tests/data/retryable_writes/findOneAndUpdate-serverErrors.yml +8 -7
- data/spec/spec_tests/data/retryable_writes/findOneAndUpdate.yml +5 -8
- data/spec/spec_tests/data/retryable_writes/insertMany-serverErrors.yml +8 -7
- data/spec/spec_tests/data/retryable_writes/insertMany.yml +5 -8
- data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +10 -45
- data/spec/spec_tests/data/retryable_writes/insertOne.yml +5 -8
- data/spec/spec_tests/data/retryable_writes/replaceOne-serverErrors.yml +8 -7
- data/spec/spec_tests/data/retryable_writes/replaceOne.yml +5 -8
- data/spec/spec_tests/data/retryable_writes/updateMany.yml +27 -0
- data/spec/spec_tests/data/retryable_writes/updateOne-serverErrors.yml +8 -7
- data/spec/spec_tests/data/retryable_writes/updateOne.yml +5 -14
- data/spec/spec_tests/data/transactions/abort.yml +7 -2
- data/spec/spec_tests/data/transactions/bulk.yml +7 -2
- data/spec/spec_tests/data/transactions/causal-consistency.yml +11 -4
- data/spec/spec_tests/data/transactions/commit.yml +11 -4
- data/spec/spec_tests/data/transactions/count.yml +64 -0
- data/spec/spec_tests/data/transactions/delete.yml +7 -2
- data/spec/spec_tests/data/transactions/error-labels.yml +8 -2
- data/spec/spec_tests/data/transactions/errors.yml +7 -2
- data/spec/spec_tests/data/transactions/findOneAndDelete.yml +7 -2
- data/spec/spec_tests/data/transactions/findOneAndReplace.yml +7 -2
- data/spec/spec_tests/data/transactions/findOneAndUpdate.yml +7 -2
- data/spec/spec_tests/data/transactions/insert.yml +9 -2
- data/spec/spec_tests/data/transactions/isolation.yml +7 -2
- data/spec/spec_tests/data/transactions/read-concern.yml +15 -6
- data/spec/spec_tests/data/transactions/read-pref.yml +7 -2
- data/spec/spec_tests/data/transactions/reads.yml +8 -48
- data/spec/spec_tests/data/transactions/retryable-abort.yml +7 -2
- data/spec/spec_tests/data/transactions/retryable-commit.yml +7 -2
- data/spec/spec_tests/data/transactions/retryable-writes.yml +7 -2
- data/spec/spec_tests/data/transactions/run-command.yml +7 -2
- data/spec/spec_tests/data/transactions/transaction-options.yml +7 -2
- data/spec/spec_tests/data/transactions/update.yml +7 -2
- data/spec/spec_tests/data/transactions/write-concern.yml +7 -2
- data/spec/spec_tests/data/transactions_api/callback-aborts.yml +6 -1
- data/spec/spec_tests/data/transactions_api/callback-commits.yml +6 -1
- data/spec/spec_tests/data/transactions_api/callback-retry.yml +6 -1
- data/spec/spec_tests/data/transactions_api/commit-retry.yml +6 -1
- data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror-4.2.yml +6 -3
- data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror.yml +6 -1
- data/spec/spec_tests/data/transactions_api/commit-writeconcernerror.yml +6 -1
- data/spec/spec_tests/data/transactions_api/commit.yml +6 -1
- data/spec/spec_tests/data/transactions_api/transaction-options.yml +6 -1
- data/spec/spec_tests/retryable_reads_spec.rb +11 -0
- data/spec/spec_tests/retryable_writes_spec.rb +4 -69
- data/spec/spec_tests/transactions_api_spec.rb +42 -37
- data/spec/spec_tests/transactions_spec.rb +42 -33
- data/spec/support/authorization.rb +12 -0
- data/spec/support/change_streams/operation.rb +1 -1
- data/spec/support/client_registry.rb +20 -0
- data/spec/support/cluster_config.rb +16 -15
- data/spec/support/cluster_tools.rb +346 -0
- data/spec/support/cmap.rb +367 -0
- data/spec/support/cmap/verifier.rb +46 -0
- data/spec/support/command_monitoring.rb +4 -6
- data/spec/support/common_shortcuts.rb +6 -0
- data/spec/support/connection_string.rb +2 -2
- data/spec/support/crud.rb +171 -184
- data/spec/support/crud/operation.rb +43 -0
- data/spec/support/crud/outcome.rb +53 -0
- data/spec/support/crud/read.rb +102 -12
- data/spec/support/crud/requirement.rb +69 -0
- data/spec/support/crud/spec.rb +68 -0
- data/spec/support/crud/test.rb +141 -0
- data/spec/support/crud/verifier.rb +96 -18
- data/spec/support/crud/write.rb +18 -3
- data/spec/support/event_subscriber.rb +15 -0
- data/spec/support/primary_socket.rb +2 -2
- data/spec/support/spec_config.rb +89 -20
- data/spec/support/transactions.rb +2 -306
- data/spec/support/transactions/operation.rb +7 -7
- data/spec/support/transactions/spec.rb +28 -0
- data/spec/support/transactions/test.rb +191 -0
- data/spec/support/utils.rb +123 -0
- metadata +202 -9
- metadata.gz.sig +0 -0
- data/lib/mongo/server/connection_pool/queue.rb +0 -359
- data/spec/mongo/server/connection_pool/queue_spec.rb +0 -353
- data/spec/support/transactions/verifier.rb +0 -97
data/lib/mongo/protocol/msg.rb
CHANGED
@@ -31,6 +31,12 @@ module Mongo
|
|
31
31
|
# @since 2.5.0
|
32
32
|
DATABASE_IDENTIFIER = '$db'.freeze
|
33
33
|
|
34
|
+
# Keys that the driver adds to commands. These are going to be
|
35
|
+
# moved to the end of the hash for better logging.
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
INTERNAL_KEYS = Set.new(%w($clusterTime lsid signature txnNumber)).freeze
|
39
|
+
|
34
40
|
# Creates a new OP_MSG protocol message
|
35
41
|
#
|
36
42
|
# @example Create a OP_MSG wire protocol message
|
@@ -82,10 +88,27 @@ module Mongo
|
|
82
88
|
#
|
83
89
|
# @since 2.5.0
|
84
90
|
def payload
|
91
|
+
# Reorder keys in global_args for better logging - see
|
92
|
+
# https://jira.mongodb.org/browse/RUBY-1591.
|
93
|
+
# Note that even without the reordering, the payload is not an exact
|
94
|
+
# match to what is sent over the wire because the command as used in
|
95
|
+
# the published eent combines keys from multiple sections of the
|
96
|
+
# payload sent over the wire.
|
97
|
+
ordered_command = {}
|
98
|
+
skipped_command = {}
|
99
|
+
command.each do |k, v|
|
100
|
+
if INTERNAL_KEYS.member?(k.to_s)
|
101
|
+
skipped_command[k] = v
|
102
|
+
else
|
103
|
+
ordered_command[k] = v
|
104
|
+
end
|
105
|
+
end
|
106
|
+
ordered_command.update(skipped_command)
|
107
|
+
|
85
108
|
BSON::Document.new(
|
86
|
-
command_name:
|
109
|
+
command_name: ordered_command.keys.first.to_s,
|
87
110
|
database_name: global_args[DATABASE_IDENTIFIER],
|
88
|
-
command:
|
111
|
+
command: ordered_command,
|
89
112
|
request_id: request_id,
|
90
113
|
reply: sections[0]
|
91
114
|
)
|
data/lib/mongo/retryable.rb
CHANGED
@@ -19,50 +19,115 @@ module Mongo
|
|
19
19
|
# @since 2.1.0
|
20
20
|
module Retryable
|
21
21
|
|
22
|
-
# Execute a read operation
|
22
|
+
# Execute a read operation returning a cursor with retrying.
|
23
|
+
#
|
24
|
+
# This method performs server selection for the specified server selector
|
25
|
+
# and yields to the provided block, which should execute the initial
|
26
|
+
# query operation and return its result. The block will be passed the
|
27
|
+
# server selected for the operation. If the block raises an exception,
|
28
|
+
# and this exception corresponds to a read retryable error, and read
|
29
|
+
# retries are enabled for the client, this method will perform server
|
30
|
+
# selection again and yield to the block again (with potentially a
|
31
|
+
# different server). If the block returns successfully, the result
|
32
|
+
# of the block (which should be a Mongo::Operation::Result) is used to
|
33
|
+
# construct a Mongo::Cursor object for the result set. The cursor
|
34
|
+
# is then returned.
|
35
|
+
#
|
36
|
+
# If modern retry reads are on (which is the default), the initial read
|
37
|
+
# operation will be retried once. If legacy retry reads are on, the
|
38
|
+
# initial read operation will be retried zero or more times depending
|
39
|
+
# on the :max_read_retries client setting, the default for which is 1.
|
40
|
+
# To disable read retries, turn off modern read retries by setting
|
41
|
+
# retry_reads: false and set :max_read_retries to 0 on the client.
|
23
42
|
#
|
24
43
|
# @api private
|
25
44
|
#
|
26
|
-
# @example Execute
|
27
|
-
#
|
45
|
+
# @example Execute a read returning a cursor.
|
46
|
+
# cursor = read_with_retry_cursor(session, server_selector, view) do |server|
|
47
|
+
# # return a Mongo::Operation::Result
|
28
48
|
# ...
|
29
49
|
# end
|
30
50
|
#
|
31
|
-
# @
|
51
|
+
# @param [ Mongo::Session ] session The session that the operation is being
|
52
|
+
# run on.
|
53
|
+
# @param [ Mongo::ServerSelector::Selectable ] server_selector Server
|
54
|
+
# selector for the operation.
|
55
|
+
# @param [ CollectionView ] view The +CollectionView+ defining the query.
|
56
|
+
# @param [ Proc ] block The block to execute.
|
57
|
+
#
|
58
|
+
# @return [ Cursor ] The cursor for the result set.
|
59
|
+
def read_with_retry_cursor(session, server_selector, view, &block)
|
60
|
+
read_with_retry(session, server_selector) do |server|
|
61
|
+
result = yield server
|
62
|
+
Cursor.new(view, result, server, session: session)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Execute a read operation with retrying.
|
67
|
+
#
|
68
|
+
# This method performs server selection for the specified server selector
|
69
|
+
# and yields to the provided block, which should execute the initial
|
70
|
+
# query operation and return its result. The block will be passed the
|
71
|
+
# server selected for the operation. If the block raises an exception,
|
72
|
+
# and this exception corresponds to a read retryable error, and read
|
73
|
+
# retries are enabled for the client, this method will perform server
|
74
|
+
# selection again and yield to the block again (with potentially a
|
75
|
+
# different server). If the block returns successfully, the result
|
76
|
+
# of the block is returned.
|
32
77
|
#
|
33
|
-
#
|
78
|
+
# If modern retry reads are on (which is the default), the initial read
|
79
|
+
# operation will be retried once. If legacy retry reads are on, the
|
80
|
+
# initial read operation will be retried zero or more times depending
|
81
|
+
# on the :max_read_retries client setting, the default for which is 1.
|
82
|
+
# To disable read retries, turn off modern read retries by setting
|
83
|
+
# retry_reads: false and set :max_read_retries to 0 on the client.
|
84
|
+
#
|
85
|
+
# @api private
|
86
|
+
#
|
87
|
+
# @example Execute the read.
|
88
|
+
# read_with_retry(session, server_selector) do |server|
|
89
|
+
# ...
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# @param [ Mongo::Session ] session The session that the operation is being
|
93
|
+
# run on.
|
94
|
+
# @param [ Mongo::ServerSelector::Selectable ] server_selector Server
|
95
|
+
# selector for the operation.
|
34
96
|
# @param [ Proc ] block The block to execute.
|
35
97
|
#
|
36
98
|
# @return [ Result ] The result of the operation.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
raise
|
47
|
-
end
|
48
|
-
log_retry(e)
|
49
|
-
cluster.scan!(false)
|
50
|
-
retry
|
51
|
-
rescue Error::OperationFailure => e
|
52
|
-
if cluster.sharded? && e.retryable? && !(session && session.in_transaction?)
|
53
|
-
if attempt > cluster.max_read_retries
|
54
|
-
raise
|
55
|
-
end
|
56
|
-
log_retry(e)
|
57
|
-
sleep(cluster.read_retry_interval)
|
58
|
-
retry
|
59
|
-
else
|
60
|
-
raise
|
99
|
+
def read_with_retry(session = nil, server_selector = nil, &block)
|
100
|
+
if session.nil? && server_selector.nil?
|
101
|
+
# Older versions of Mongoid call read_with_retry without arguments.
|
102
|
+
# This is already not correct in a MongoDB 3.6+ environment with
|
103
|
+
# sessions. For compatibility we emulate the legacy driver behavior
|
104
|
+
# here but upgrading Mongoid is strongly recommended.
|
105
|
+
unless $_mongo_read_with_retry_warned
|
106
|
+
$_mongo_read_with_retry_warned = true
|
107
|
+
Logger.logger.warn("Legacy read_with_retry invocation - please update the application and/or its dependencies")
|
61
108
|
end
|
109
|
+
# Since we don't have a session, we cannot use the modern read retries.
|
110
|
+
# And we need to select a server but we don't have a server selector.
|
111
|
+
# Use PrimaryPreferred which will work as long as there is a data
|
112
|
+
# bearing node in the cluster; the block may select a different server
|
113
|
+
# which is fine.
|
114
|
+
server_selector = ServerSelector.get(mode: :primary_preferred)
|
115
|
+
legacy_read_with_retry(nil, server_selector, &block)
|
116
|
+
elsif session && session.retry_reads?
|
117
|
+
modern_read_with_retry(session, server_selector, &block)
|
118
|
+
elsif client.max_read_retries > 0
|
119
|
+
legacy_read_with_retry(session, server_selector, &block)
|
120
|
+
else
|
121
|
+
server = select_server(cluster, server_selector)
|
122
|
+
yield server
|
62
123
|
end
|
63
124
|
end
|
64
125
|
|
65
|
-
# Execute a read operation with a single retry.
|
126
|
+
# Execute a read operation with a single retry on network errors.
|
127
|
+
#
|
128
|
+
# This method is used by the driver for some of the internal housekeeping
|
129
|
+
# operations. Application-requested reads should use read_with_retry
|
130
|
+
# rather than this method.
|
66
131
|
#
|
67
132
|
# @api private
|
68
133
|
#
|
@@ -159,6 +224,52 @@ module Mongo
|
|
159
224
|
|
160
225
|
private
|
161
226
|
|
227
|
+
def modern_read_with_retry(session, server_selector, &block)
|
228
|
+
attempt = 0
|
229
|
+
server = select_server(cluster, server_selector)
|
230
|
+
begin
|
231
|
+
yield server
|
232
|
+
rescue Error::SocketError, Error::SocketTimeoutError => e
|
233
|
+
if session.in_transaction?
|
234
|
+
raise
|
235
|
+
end
|
236
|
+
retry_read(e, server_selector, &block)
|
237
|
+
rescue Error::OperationFailure => e
|
238
|
+
if session.in_transaction? || !e.write_retryable?
|
239
|
+
raise
|
240
|
+
end
|
241
|
+
retry_read(e, server_selector, &block)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def legacy_read_with_retry(session, server_selector)
|
246
|
+
attempt = 0
|
247
|
+
server = select_server(cluster, server_selector)
|
248
|
+
begin
|
249
|
+
attempt += 1
|
250
|
+
yield server
|
251
|
+
rescue Error::SocketError, Error::SocketTimeoutError => e
|
252
|
+
if attempt > client.max_read_retries || (session && session.in_transaction?)
|
253
|
+
raise
|
254
|
+
end
|
255
|
+
log_retry(e, message: 'Legacy read retry')
|
256
|
+
server = select_server(cluster, server_selector)
|
257
|
+
retry
|
258
|
+
rescue Error::OperationFailure => e
|
259
|
+
if cluster.sharded? && e.retryable? && !(session && session.in_transaction?)
|
260
|
+
if attempt > client.max_read_retries
|
261
|
+
raise
|
262
|
+
end
|
263
|
+
log_retry(e, message: 'Legacy read retry')
|
264
|
+
sleep(client.read_retry_interval)
|
265
|
+
server = select_server(cluster, server_selector)
|
266
|
+
retry
|
267
|
+
else
|
268
|
+
raise
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
162
273
|
def retry_write_allowed?(session, write_concern)
|
163
274
|
unless session && session.retry_writes?
|
164
275
|
return false
|
@@ -174,6 +285,27 @@ module Mongo
|
|
174
285
|
end
|
175
286
|
end
|
176
287
|
|
288
|
+
def retry_read(original_error, server_selector, &block)
|
289
|
+
begin
|
290
|
+
server = select_server(cluster, server_selector)
|
291
|
+
rescue
|
292
|
+
raise original_error
|
293
|
+
end
|
294
|
+
|
295
|
+
log_retry(original_error, message: 'Read retry')
|
296
|
+
|
297
|
+
begin
|
298
|
+
yield server, true
|
299
|
+
rescue Error::SocketError, Error::SocketTimeoutError => e
|
300
|
+
raise e
|
301
|
+
rescue Error::OperationFailure => e
|
302
|
+
raise original_error unless e.write_retryable?
|
303
|
+
raise e
|
304
|
+
rescue
|
305
|
+
raise original_error
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
177
309
|
def retry_write(original_error, txn_num, &block)
|
178
310
|
# We do not request a scan of the cluster here, because error handling
|
179
311
|
# for the error which triggered the retry should have updated the
|
@@ -182,7 +314,7 @@ module Mongo
|
|
182
314
|
# server unknown). Here we just need to wait for server selection.
|
183
315
|
server = cluster.next_primary
|
184
316
|
raise original_error unless (server.retry_writes? && txn_num)
|
185
|
-
log_retry(original_error)
|
317
|
+
log_retry(original_error, message: 'Write retry')
|
186
318
|
yield(server, txn_num, true)
|
187
319
|
rescue Error::SocketError, Error::SocketTimeoutError => e
|
188
320
|
raise e
|
@@ -203,11 +335,11 @@ module Mongo
|
|
203
335
|
yield(server || cluster.next_primary)
|
204
336
|
rescue Error::OperationFailure => e
|
205
337
|
server = nil
|
206
|
-
if attempt >
|
338
|
+
if attempt > client.max_write_retries
|
207
339
|
raise
|
208
340
|
end
|
209
341
|
if e.write_retryable? && !(session && session.in_transaction?)
|
210
|
-
log_retry(e)
|
342
|
+
log_retry(e, message: 'Legacy write retry')
|
211
343
|
cluster.scan!(false)
|
212
344
|
retry
|
213
345
|
else
|
@@ -216,6 +348,12 @@ module Mongo
|
|
216
348
|
end
|
217
349
|
end
|
218
350
|
|
351
|
+
# This is a separate method to make it possible for the test suite to
|
352
|
+
# assert that server selection is performed during retry attempts.
|
353
|
+
def select_server(cluster, server_selector)
|
354
|
+
server_selector.select_server(cluster)
|
355
|
+
end
|
356
|
+
|
219
357
|
# Log a warning so that any application slow down is immediately obvious.
|
220
358
|
def log_retry(e, options = nil)
|
221
359
|
message = if options && options[:message]
|
data/lib/mongo/server.rb
CHANGED
@@ -61,6 +61,9 @@ module Mongo
|
|
61
61
|
monitor = options.delete(:monitor)
|
62
62
|
@options = options.freeze
|
63
63
|
@event_listeners = event_listeners
|
64
|
+
@connection_id_gen = Class.new do
|
65
|
+
include Id
|
66
|
+
end
|
64
67
|
@monitor = Monitor.new(address, event_listeners, monitoring,
|
65
68
|
options.merge(app_metadata: Monitor::AppMetadata.new(cluster.options)))
|
66
69
|
unless monitor == false
|
@@ -178,7 +181,13 @@ module Mongo
|
|
178
181
|
#
|
179
182
|
# @since 2.0.0
|
180
183
|
def disconnect!(wait=false)
|
181
|
-
|
184
|
+
begin
|
185
|
+
# For backwards compatibility we disconnect/clear the pool rather
|
186
|
+
# than close it here.
|
187
|
+
pool.disconnect!
|
188
|
+
rescue Error::PoolClosedError
|
189
|
+
# If the pool was already closed, we don't need to do anything here.
|
190
|
+
end
|
182
191
|
monitor.stop!(wait)
|
183
192
|
@connected = false
|
184
193
|
true
|
@@ -282,11 +291,7 @@ module Mongo
|
|
282
291
|
# @since 2.0.0
|
283
292
|
def pool
|
284
293
|
@pool_lock.synchronize do
|
285
|
-
@pool ||=
|
286
|
-
ConnectionPool.new(options) do |generation|
|
287
|
-
Connection.new(self, options.merge(generation: generation))
|
288
|
-
end
|
289
|
-
end
|
294
|
+
@pool ||= ConnectionPool.new(self, options)
|
290
295
|
end
|
291
296
|
end
|
292
297
|
|
@@ -315,7 +320,9 @@ module Mongo
|
|
315
320
|
#
|
316
321
|
# @since 2.1.0
|
317
322
|
def reconnect!
|
318
|
-
|
323
|
+
if options[:monitoring_io] != false
|
324
|
+
monitor.restart!
|
325
|
+
end
|
319
326
|
@connected = true
|
320
327
|
end
|
321
328
|
|
@@ -373,6 +380,13 @@ module Mongo
|
|
373
380
|
raise
|
374
381
|
end
|
375
382
|
|
383
|
+
# Whether the server supports modern read retries.
|
384
|
+
#
|
385
|
+
# @api private
|
386
|
+
def retry_reads?
|
387
|
+
!!(features.sessions_enabled? && logical_session_timeout)
|
388
|
+
end
|
389
|
+
|
376
390
|
# Will writes sent to this server be retried.
|
377
391
|
#
|
378
392
|
# @example Will writes be retried.
|
@@ -403,6 +417,11 @@ module Mongo
|
|
403
417
|
def update_description(description)
|
404
418
|
monitor.instance_variable_set('@description', description)
|
405
419
|
end
|
420
|
+
|
421
|
+
# @api private
|
422
|
+
def next_connection_id
|
423
|
+
@connection_id_gen.next_id
|
424
|
+
end
|
406
425
|
end
|
407
426
|
end
|
408
427
|
|
@@ -81,15 +81,21 @@ module Mongo
|
|
81
81
|
result
|
82
82
|
ensure
|
83
83
|
unless success
|
84
|
-
disconnect!
|
84
|
+
disconnect!(reason: :error)
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
89
|
def ensure_same_process!
|
90
90
|
if pid != Process.pid
|
91
|
-
|
91
|
+
# When we reconnect here, CMAP events won't be correctly sent
|
92
|
+
# since the CMAP spec does not permit a connection to be disconnected
|
93
|
+
# and then reconnected
|
94
|
+
log_warn("Detected PID change - Mongo client should have been reconnected (old pid #{pid}, new pid #{Process.pid}")
|
95
|
+
disconnect!(reason: :stale)
|
96
|
+
@closed = false
|
92
97
|
@pid = Process.pid
|
98
|
+
connect!
|
93
99
|
end
|
94
100
|
end
|
95
101
|
end
|
@@ -89,6 +89,7 @@ module Mongo
|
|
89
89
|
#
|
90
90
|
# @since 2.0.0
|
91
91
|
def initialize(server, options = {})
|
92
|
+
@id = server.next_connection_id
|
92
93
|
@monitoring = server.monitoring
|
93
94
|
@options = options.freeze
|
94
95
|
@server = server
|
@@ -97,13 +98,23 @@ module Mongo
|
|
97
98
|
@last_checkin = nil
|
98
99
|
@auth_mechanism = nil
|
99
100
|
@pid = Process.pid
|
101
|
+
|
102
|
+
publish_cmap_event(
|
103
|
+
Monitoring::Event::Cmap::ConnectionCreated.new(address, id)
|
104
|
+
)
|
100
105
|
end
|
101
106
|
|
102
|
-
# The last time the connection was checked back into a pool.
|
107
|
+
# @return [ Time ] The last time the connection was checked back into a pool.
|
103
108
|
#
|
104
109
|
# @since 2.5.0
|
105
110
|
attr_reader :last_checkin
|
106
111
|
|
112
|
+
# @return [ Integer ] The ID for the connection. This will be unique
|
113
|
+
# across connections to the same server object.
|
114
|
+
#
|
115
|
+
# @since 2.9.0
|
116
|
+
attr_reader :id
|
117
|
+
|
107
118
|
# Connection pool generation from which this connection was created.
|
108
119
|
# May be nil.
|
109
120
|
#
|
@@ -113,6 +124,18 @@ module Mongo
|
|
113
124
|
options[:generation]
|
114
125
|
end
|
115
126
|
|
127
|
+
# Whether the connection was closed.
|
128
|
+
#
|
129
|
+
# Closed connections should no longer be used. Instead obtain a new
|
130
|
+
# connection from the connection pool.
|
131
|
+
#
|
132
|
+
# @return [ true | false ] Whether connection was closed.
|
133
|
+
#
|
134
|
+
# @since 2.9.0
|
135
|
+
def closed?
|
136
|
+
!!@closed
|
137
|
+
end
|
138
|
+
|
116
139
|
# Establishes a network connection to the target address.
|
117
140
|
#
|
118
141
|
# If the connection is already established, this method does nothing.
|
@@ -120,44 +143,91 @@ module Mongo
|
|
120
143
|
# @example Connect to the host.
|
121
144
|
# connection.connect!
|
122
145
|
#
|
123
|
-
# @note This method mutates the connection
|
146
|
+
# @note This method mutates the connection object by setting a socket if
|
124
147
|
# one previously did not exist.
|
125
148
|
#
|
126
149
|
# @return [ true ] If the connection succeeded.
|
127
150
|
#
|
128
151
|
# @since 2.0.0
|
129
152
|
def connect!
|
153
|
+
if closed?
|
154
|
+
if Lint.enabled?
|
155
|
+
raise Error::LintError, "Reconnecting closed connections is no longer supported"
|
156
|
+
else
|
157
|
+
log_warn("Reconnecting closed connections is deprecated (for #{address})")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
130
161
|
unless @socket
|
131
|
-
socket = address.socket(socket_timeout, ssl_options,
|
132
|
-
connect_timeout: address.connect_timeout)
|
133
|
-
handshake!(socket)
|
134
|
-
pending_connection = PendingConnection.new(socket, @server, monitoring, options)
|
135
|
-
authenticate!(pending_connection)
|
136
162
|
# When @socket is assigned, the socket should have handshaken and
|
137
163
|
# authenticated and be usable.
|
138
|
-
@socket =
|
164
|
+
@socket = do_connect
|
165
|
+
|
166
|
+
publish_cmap_event(
|
167
|
+
Monitoring::Event::Cmap::ConnectionReady.new(address, id)
|
168
|
+
)
|
169
|
+
|
170
|
+
@close_event_published = false
|
139
171
|
end
|
140
172
|
true
|
141
173
|
end
|
142
174
|
|
175
|
+
# Separate method to permit easier mocking in the test suite.
|
176
|
+
def do_connect
|
177
|
+
socket = address.socket(socket_timeout, ssl_options,
|
178
|
+
connect_timeout: address.connect_timeout)
|
179
|
+
handshake!(socket)
|
180
|
+
pending_connection = PendingConnection.new(socket, @server, monitoring, options)
|
181
|
+
authenticate!(pending_connection)
|
182
|
+
socket
|
183
|
+
end
|
184
|
+
private :do_connect
|
185
|
+
|
143
186
|
# Disconnect the connection.
|
144
187
|
#
|
145
|
-
# @
|
146
|
-
# connection
|
188
|
+
# @note Once a connection is disconnected, it should no longer be used.
|
189
|
+
# A new connection should be obtained from the connection pool which
|
190
|
+
# will either return a ready connection or create a new connection.
|
191
|
+
# If linting is enabled, reusing a disconnected connection will raise
|
192
|
+
# Error::LintError. If linting is not enabled, a warning will be logged.
|
193
|
+
#
|
194
|
+
# @note This method mutates the connection object by setting the socket
|
195
|
+
# to nil if the closing succeeded.
|
147
196
|
#
|
148
|
-
# @
|
149
|
-
#
|
197
|
+
# @option options [ Symbol ] :reason The reason why the connection is
|
198
|
+
# being closed.
|
150
199
|
#
|
151
200
|
# @return [ true ] If the disconnect succeeded.
|
152
201
|
#
|
153
202
|
# @since 2.0.0
|
154
|
-
def disconnect!
|
203
|
+
def disconnect!(options = nil)
|
204
|
+
# Note: @closed may be true here but we also may have a socket.
|
205
|
+
# Check the socket and not @closed flag.
|
155
206
|
@auth_mechanism = nil
|
156
207
|
@last_checkin = nil
|
157
208
|
if socket
|
158
209
|
socket.close
|
159
210
|
@socket = nil
|
160
211
|
end
|
212
|
+
@closed = true
|
213
|
+
|
214
|
+
# To satisfy CMAP spec tests, publish close events even if the
|
215
|
+
# socket was never connected (and thus the ready event was never
|
216
|
+
# published). But track whether we published close event and do not
|
217
|
+
# publish it multiple times, unless the socket was reconnected -
|
218
|
+
# in that case publish the close event once per socket close.
|
219
|
+
unless @close_event_published
|
220
|
+
reason = options && options[:reason]
|
221
|
+
publish_cmap_event(
|
222
|
+
Monitoring::Event::Cmap::ConnectionClosed.new(
|
223
|
+
address,
|
224
|
+
id,
|
225
|
+
reason,
|
226
|
+
),
|
227
|
+
)
|
228
|
+
@close_event_published = true
|
229
|
+
end
|
230
|
+
|
161
231
|
true
|
162
232
|
end
|
163
233
|
|