mongo 2.8.0 → 2.9.0.rc0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/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
|
|