mongo 2.14.1 → 2.15.0.alpha
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/README.md +4 -1
- data/Rakefile +8 -15
- data/lib/mongo/auth/aws/conversation.rb +1 -4
- data/lib/mongo/auth/base.rb +13 -7
- data/lib/mongo/auth/conversation_base.rb +32 -0
- data/lib/mongo/auth/cr/conversation.rb +6 -29
- data/lib/mongo/auth/gssapi/conversation.rb +4 -15
- data/lib/mongo/auth/ldap/conversation.rb +3 -14
- data/lib/mongo/auth/sasl_conversation_base.rb +1 -13
- data/lib/mongo/auth/scram_conversation_base.rb +7 -34
- data/lib/mongo/auth/user/view.rb +16 -9
- data/lib/mongo/auth/x509/conversation.rb +4 -25
- data/lib/mongo/bulk_write.rb +21 -18
- data/lib/mongo/client.rb +82 -6
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
- data/lib/mongo/cluster.rb +19 -2
- data/lib/mongo/collection/view/aggregation.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +1 -1
- data/lib/mongo/collection/view/iterable.rb +7 -17
- data/lib/mongo/collection/view/map_reduce.rb +2 -2
- data/lib/mongo/collection/view/readable.rb +42 -20
- data/lib/mongo/collection/view/writable.rb +14 -14
- data/lib/mongo/collection.rb +6 -6
- data/lib/mongo/cursor.rb +2 -12
- data/lib/mongo/database/view.rb +1 -1
- data/lib/mongo/database.rb +8 -3
- data/lib/mongo/error/bulk_write_error.rb +17 -3
- data/lib/mongo/error/internal_driver_error.rb +22 -0
- data/lib/mongo/error/operation_failure.rb +21 -2
- data/lib/mongo/error/parser.rb +65 -12
- data/lib/mongo/error/server_api_conflict.rb +23 -0
- data/lib/mongo/error/server_api_not_supported.rb +24 -0
- data/lib/mongo/error/unmet_dependency.rb +21 -0
- data/lib/mongo/error.rb +9 -1
- data/lib/mongo/index/view.rb +21 -11
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +27 -16
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +26 -15
- data/lib/mongo/monitoring.rb +13 -4
- data/lib/mongo/operation/collections_info/command.rb +2 -2
- data/lib/mongo/operation/collections_info.rb +18 -1
- data/lib/mongo/operation/context.rb +99 -0
- data/lib/mongo/operation/indexes.rb +15 -1
- data/lib/mongo/operation/insert/command.rb +2 -2
- data/lib/mongo/operation/insert/legacy.rb +2 -2
- data/lib/mongo/operation/insert/op_msg.rb +2 -2
- data/lib/mongo/operation/list_collections/result.rb +4 -1
- data/lib/mongo/operation/parallel_scan/command.rb +2 -1
- data/lib/mongo/operation/result.rb +2 -0
- data/lib/mongo/operation/shared/executable.rb +24 -14
- data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
- data/lib/mongo/operation/shared/op_msg_or_command.rb +1 -7
- data/lib/mongo/operation/shared/op_msg_or_find_command.rb +1 -7
- data/lib/mongo/operation/shared/polymorphic_operation.rb +39 -0
- data/lib/mongo/operation/shared/read_preference_supported.rb +36 -38
- data/lib/mongo/operation/shared/response_handling.rb +23 -23
- data/lib/mongo/operation/shared/sessions_supported.rb +15 -5
- data/lib/mongo/operation/shared/write.rb +8 -18
- data/lib/mongo/operation.rb +2 -2
- data/lib/mongo/protocol/compressed.rb +51 -5
- data/lib/mongo/protocol/message.rb +20 -2
- data/lib/mongo/protocol/msg.rb +38 -13
- data/lib/mongo/protocol/query.rb +11 -11
- data/lib/mongo/query_cache.rb +30 -0
- data/lib/mongo/retryable.rb +1 -1
- data/lib/mongo/server/app_metadata.rb +52 -18
- data/lib/mongo/server/connection.rb +5 -0
- data/lib/mongo/server/connection_base.rb +13 -10
- data/lib/mongo/server/connection_pool.rb +6 -2
- data/lib/mongo/server/description/features.rb +9 -8
- data/lib/mongo/server/description.rb +4 -0
- data/lib/mongo/server/monitor/app_metadata.rb +1 -1
- data/lib/mongo/server/monitor/connection.rb +9 -10
- data/lib/mongo/server/monitor.rb +20 -1
- data/lib/mongo/server/pending_connection.rb +24 -6
- data/lib/mongo/server/push_monitor.rb +11 -1
- data/lib/mongo/server.rb +7 -1
- data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
- data/lib/mongo/session/session_pool.rb +4 -2
- data/lib/mongo/session.rb +2 -2
- data/lib/mongo/socket/ssl.rb +8 -0
- data/lib/mongo/socket.rb +29 -4
- data/lib/mongo/uri/options_mapper.rb +38 -0
- data/lib/mongo/utils.rb +15 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo.rb +23 -0
- data/spec/README.md +24 -1
- data/spec/integration/auth_spec.rb +25 -15
- data/spec/integration/bulk_write_error_message_spec.rb +41 -0
- data/spec/integration/change_stream_spec.rb +4 -4
- data/spec/integration/command_monitoring_spec.rb +2 -2
- data/spec/integration/connection_spec.rb +2 -0
- data/spec/integration/docs_examples_spec.rb +8 -1
- data/spec/integration/fork_reconnect_spec.rb +4 -1
- data/spec/integration/ocsp_verifier_spec.rb +13 -7
- data/spec/integration/operation_failure_code_spec.rb +1 -1
- data/spec/integration/operation_failure_message_spec.rb +90 -0
- data/spec/integration/query_cache_spec.rb +0 -45
- data/spec/integration/reconnect_spec.rb +1 -1
- data/spec/integration/snappy_compression_spec.rb +25 -0
- data/spec/integration/srv_monitoring_spec.rb +1 -1
- data/spec/integration/transactions_examples_spec.rb +6 -0
- data/spec/integration/zlib_compression_spec.rb +1 -1
- data/spec/integration/zstd_compression_spec.rb +26 -0
- data/spec/lite_spec_helper.rb +7 -1
- data/spec/mongo/address_spec.rb +15 -11
- data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
- data/spec/mongo/auth/ldap_spec.rb +5 -1
- data/spec/mongo/auth/scram_negotiation_spec.rb +1 -1
- data/spec/mongo/auth/scram_spec.rb +1 -1
- data/spec/mongo/auth/x509/conversation_spec.rb +3 -3
- data/spec/mongo/client_construction_spec.rb +207 -33
- data/spec/mongo/client_spec.rb +17 -0
- data/spec/mongo/cluster_spec.rb +1 -0
- data/spec/mongo/collection/view/explainable_spec.rb +1 -1
- data/spec/mongo/collection/view/readable_spec.rb +33 -19
- data/spec/mongo/collection_crud_spec.rb +4357 -0
- data/spec/mongo/collection_ddl_spec.rb +534 -0
- data/spec/mongo/collection_spec.rb +5 -4859
- data/spec/mongo/database_spec.rb +66 -4
- data/spec/mongo/error/bulk_write_error_spec.rb +3 -3
- data/spec/mongo/error/parser_spec.rb +37 -6
- data/spec/mongo/index/view_spec.rb +4 -0
- data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +1 -1
- data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +1 -1
- data/spec/mongo/operation/aggregate_spec.rb +2 -1
- data/spec/mongo/operation/collections_info_spec.rb +4 -1
- data/spec/mongo/operation/command_spec.rb +6 -3
- data/spec/mongo/operation/create_index_spec.rb +6 -3
- data/spec/mongo/operation/create_user_spec.rb +6 -3
- data/spec/mongo/operation/delete/bulk_spec.rb +9 -6
- data/spec/mongo/operation/delete_spec.rb +11 -7
- data/spec/mongo/operation/drop_index_spec.rb +6 -2
- data/spec/mongo/operation/find/legacy_spec.rb +3 -1
- data/spec/mongo/operation/get_more_spec.rb +3 -1
- data/spec/mongo/operation/indexes_spec.rb +5 -1
- data/spec/mongo/operation/insert/bulk_spec.rb +10 -7
- data/spec/mongo/operation/insert_spec.rb +15 -12
- data/spec/mongo/operation/map_reduce_spec.rb +5 -2
- data/spec/mongo/operation/read_preference_legacy_spec.rb +19 -9
- data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
- data/spec/mongo/operation/remove_user_spec.rb +6 -3
- data/spec/mongo/operation/result_spec.rb +1 -1
- data/spec/mongo/operation/update/bulk_spec.rb +9 -6
- data/spec/mongo/operation/update_spec.rb +10 -7
- data/spec/mongo/operation/update_user_spec.rb +4 -1
- data/spec/mongo/protocol/compressed_spec.rb +26 -12
- data/spec/mongo/query_cache_middleware_spec.rb +55 -0
- data/spec/mongo/retryable_spec.rb +3 -2
- data/spec/mongo/server/app_metadata_shared.rb +7 -33
- data/spec/mongo/server/app_metadata_spec.rb +2 -0
- data/spec/mongo/server/connection_pool/populator_spec.rb +3 -1
- data/spec/mongo/server/connection_pool_spec.rb +1 -1
- data/spec/mongo/server/connection_spec.rb +24 -17
- data/spec/mongo/server/monitor/connection_spec.rb +17 -7
- data/spec/mongo/server/monitor_spec.rb +9 -1
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
- data/spec/mongo/server_spec.rb +15 -2
- data/spec/mongo/socket/ssl_spec.rb +40 -0
- data/spec/mongo/socket_spec.rb +2 -2
- data/spec/mongo/tls_context_hooks_spec.rb +37 -0
- data/spec/runners/connection_string.rb +0 -4
- data/spec/runners/crud/requirement.rb +40 -3
- data/spec/runners/crud/verifier.rb +8 -0
- data/spec/runners/transactions/operation.rb +1 -1
- data/spec/runners/transactions/test.rb +1 -0
- data/spec/runners/unified/assertions.rb +249 -0
- data/spec/runners/unified/change_stream_operations.rb +26 -0
- data/spec/runners/unified/crud_operations.rb +199 -0
- data/spec/runners/unified/ddl_operations.rb +96 -0
- data/spec/runners/unified/entity_map.rb +39 -0
- data/spec/runners/unified/error.rb +25 -0
- data/spec/runners/unified/event_subscriber.rb +91 -0
- data/spec/runners/unified/exceptions.rb +21 -0
- data/spec/runners/unified/grid_fs_operations.rb +55 -0
- data/spec/runners/unified/support_operations.rb +250 -0
- data/spec/runners/unified/test.rb +393 -0
- data/spec/runners/unified/test_group.rb +28 -0
- data/spec/runners/unified/using_hash.rb +31 -0
- data/spec/runners/unified.rb +96 -0
- data/spec/shared/lib/mrss/cluster_config.rb +0 -3
- data/spec/shared/lib/mrss/docker_runner.rb +0 -3
- data/spec/shared/lib/mrss/lite_constraints.rb +0 -16
- data/spec/shared/lib/mrss/server_version_registry.rb +0 -3
- data/spec/shared/lib/mrss/spec_organizer.rb +0 -3
- data/spec/shared/shlib/server.sh +1 -1
- data/spec/spec_helper.rb +4 -1
- data/spec/spec_tests/crud_unified_spec.rb +10 -0
- data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
- data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +267 -0
- data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-4.9.yml +60 -0
- data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → estimatedDocumentCount-pre4.9.yml} +2 -0
- data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors-4.9.yml +146 -0
- data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → estimatedDocumentCount-serverErrors-pre4.9.yml} +2 -0
- data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +1 -1
- data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +220 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +170 -0
- data/spec/spec_tests/data/uri_options/compression-options.yml +1 -1
- data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +416 -0
- data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +409 -0
- data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +67 -0
- data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
- data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +44 -0
- data/spec/spec_tests/data/versioned_api/transaction-handling.yml +180 -0
- data/spec/spec_tests/unified_spec.rb +15 -0
- data/spec/spec_tests/uri_options_spec.rb +16 -0
- data/spec/spec_tests/versioned_api_spec.rb +10 -0
- data/spec/support/client_registry.rb +4 -8
- data/spec/support/client_registry_macros.rb +4 -4
- data/spec/support/common_shortcuts.rb +15 -1
- data/spec/support/shared/session.rb +2 -2
- data/spec/support/spec_config.rb +42 -11
- data/spec/support/utils.rb +64 -3
- data.tar.gz.sig +0 -0
- metadata +1005 -915
- metadata.gz.sig +0 -0
- data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +0 -58
- data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -47
- data/spec/integration/secondary_reads_spec.rb +0 -102
- data/spec/support/cluster_config.rb +0 -207
@@ -0,0 +1,99 @@
|
|
1
|
+
# Copyright (C) 2021 MongoDB Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
module Operation
|
17
|
+
|
18
|
+
# Context for operations.
|
19
|
+
#
|
20
|
+
# Holds various objects needed to make decisions about operation execution
|
21
|
+
# in a single container, and provides facade methods for the contained
|
22
|
+
# objects.
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
class Context
|
26
|
+
def initialize(client: nil, session: nil, options: nil)
|
27
|
+
if options
|
28
|
+
if client
|
29
|
+
raise ArgumentError, 'Client and options cannot both be specified'
|
30
|
+
end
|
31
|
+
|
32
|
+
if session
|
33
|
+
raise ArgumentError, 'Session and options cannot both be specified'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@client = client
|
38
|
+
@session = session
|
39
|
+
@options = options
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :client
|
43
|
+
attr_reader :session
|
44
|
+
attr_reader :options
|
45
|
+
|
46
|
+
def in_transaction?
|
47
|
+
session&.in_transaction? || false
|
48
|
+
end
|
49
|
+
|
50
|
+
def starting_transaction?
|
51
|
+
session&.starting_transaction? || false
|
52
|
+
end
|
53
|
+
|
54
|
+
def committing_transaction?
|
55
|
+
in_transaction? && session.committing_transaction?
|
56
|
+
end
|
57
|
+
|
58
|
+
def aborting_transaction?
|
59
|
+
in_transaction? && session.aborting_transaction?
|
60
|
+
end
|
61
|
+
|
62
|
+
def modern_retry_writes?
|
63
|
+
client && client.options[:retry_writes]
|
64
|
+
end
|
65
|
+
|
66
|
+
def legacy_retry_writes?
|
67
|
+
client && !client.options[:retry_writes] && client.max_write_retries > 0
|
68
|
+
end
|
69
|
+
|
70
|
+
def any_retry_writes?
|
71
|
+
modern_retry_writes? || legacy_retry_writes?
|
72
|
+
end
|
73
|
+
|
74
|
+
def server_api
|
75
|
+
if client
|
76
|
+
client.options[:server_api]
|
77
|
+
elsif options
|
78
|
+
options[:server_api]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def encrypt?
|
83
|
+
client&.encrypter&.encrypt? || false
|
84
|
+
end
|
85
|
+
|
86
|
+
def decrypt?
|
87
|
+
!!client&.encrypter
|
88
|
+
end
|
89
|
+
|
90
|
+
def encrypter
|
91
|
+
if client&.encrypter
|
92
|
+
client.encrypter
|
93
|
+
else
|
94
|
+
raise Error::InternalDriverError, 'Encrypter should only be accessed when encryption is to be performed'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -27,7 +27,21 @@ module Mongo
|
|
27
27
|
# @since 2.0.0
|
28
28
|
class Indexes
|
29
29
|
include Specifiable
|
30
|
-
include
|
30
|
+
include PolymorphicOperation
|
31
|
+
include PolymorphicLookup
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def final_operation(connection)
|
36
|
+
cls = if connection.features.op_msg_enabled?
|
37
|
+
polymorphic_class(self.class.name, :OpMsg)
|
38
|
+
elsif connection.features.list_indexes_enabled?
|
39
|
+
polymorphic_class(self.class.name, :Command)
|
40
|
+
else
|
41
|
+
polymorphic_class(self.class.name, :Legacy)
|
42
|
+
end
|
43
|
+
cls.new(spec)
|
44
|
+
end
|
31
45
|
end
|
32
46
|
end
|
33
47
|
end
|
@@ -32,9 +32,9 @@ module Mongo
|
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
-
def get_result(connection,
|
35
|
+
def get_result(connection, context, options = {})
|
36
36
|
# This is a Mongo::Operation::Insert::Result
|
37
|
-
Result.new(*dispatch_message(connection,
|
37
|
+
Result.new(*dispatch_message(connection, context), @ids)
|
38
38
|
end
|
39
39
|
|
40
40
|
def selector(connection)
|
@@ -30,9 +30,9 @@ module Mongo
|
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
|
-
def get_result(connection,
|
33
|
+
def get_result(connection, context, options = {})
|
34
34
|
# This is a Mongo::Operation::Insert::Result
|
35
|
-
Result.new(*dispatch_message(connection,
|
35
|
+
Result.new(*dispatch_message(connection, context), @ids)
|
36
36
|
end
|
37
37
|
|
38
38
|
def selector
|
@@ -30,9 +30,9 @@ module Mongo
|
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
|
-
def get_result(connection,
|
33
|
+
def get_result(connection, context, options = {})
|
34
34
|
# This is a Mongo::Operation::Insert::Result
|
35
|
-
Result.new(*dispatch_message(connection,
|
35
|
+
Result.new(*dispatch_message(connection, context), @ids)
|
36
36
|
end
|
37
37
|
|
38
38
|
def selector(connection)
|
@@ -23,11 +23,11 @@ module Mongo
|
|
23
23
|
|
24
24
|
include ResponseHandling
|
25
25
|
|
26
|
-
def do_execute(connection,
|
26
|
+
def do_execute(connection, context, options = {})
|
27
27
|
unpin_maybe(session) do
|
28
|
-
add_error_labels(
|
28
|
+
add_error_labels(connection, context) do
|
29
29
|
add_server_diagnostics(connection) do
|
30
|
-
get_result(connection,
|
30
|
+
get_result(connection, context, options).tap do |result|
|
31
31
|
process_result(result, connection)
|
32
32
|
end
|
33
33
|
end
|
@@ -35,15 +35,15 @@ module Mongo
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def execute(connection,
|
38
|
+
def execute(connection, context:, options: {})
|
39
39
|
if Lint.enabled?
|
40
40
|
unless connection.is_a?(Mongo::Server::Connection)
|
41
41
|
raise Error::LintError, "Connection argument is of wrong type: #{connection}"
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
do_execute(connection,
|
46
|
-
validate_result(result,
|
45
|
+
do_execute(connection, context, options).tap do |result|
|
46
|
+
validate_result(result, connection, context)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -53,20 +53,30 @@ module Mongo
|
|
53
53
|
Result
|
54
54
|
end
|
55
55
|
|
56
|
-
def get_result(connection,
|
57
|
-
result_class.new(*dispatch_message(connection,
|
56
|
+
def get_result(connection, context, options = {})
|
57
|
+
result_class.new(*dispatch_message(connection, context, options))
|
58
58
|
end
|
59
59
|
|
60
60
|
# Returns a Protocol::Message or nil as reply.
|
61
|
-
def dispatch_message(connection,
|
62
|
-
message = build_message(connection)
|
63
|
-
message = message.maybe_encrypt(connection,
|
64
|
-
reply = connection.dispatch([ message ],
|
61
|
+
def dispatch_message(connection, context, options = {})
|
62
|
+
message = build_message(connection, context)
|
63
|
+
message = message.maybe_encrypt(connection, context)
|
64
|
+
reply = connection.dispatch([ message ], context, options)
|
65
65
|
[reply, connection.description]
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
# @param [ Mongo::Server::Connection ] connection The connection on which
|
69
|
+
# the operation is performed.
|
70
|
+
# @param [ Mongo::Operation::Context ] context The operation context.
|
71
|
+
def build_message(connection, context)
|
72
|
+
msg = message(connection)
|
73
|
+
if (server_api = context.server_api) &&
|
74
|
+
# Commands in a transaction do not allow API parameters.
|
75
|
+
!(context.in_transaction? && !context.starting_transaction?)
|
76
|
+
then
|
77
|
+
msg = msg.maybe_add_server_api(server_api)
|
78
|
+
end
|
79
|
+
msg
|
70
80
|
end
|
71
81
|
|
72
82
|
def process_result(result, connection)
|
@@ -20,15 +20,9 @@ module Mongo
|
|
20
20
|
#
|
21
21
|
# @api private
|
22
22
|
module OpMsgOrCommand
|
23
|
+
include PolymorphicOperation
|
23
24
|
include PolymorphicLookup
|
24
25
|
|
25
|
-
def execute(server, client:, options: {})
|
26
|
-
server.with_connection do |connection|
|
27
|
-
operation = final_operation(connection)
|
28
|
-
operation.execute(connection, client: client, options: options)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
26
|
private
|
33
27
|
|
34
28
|
def final_operation(connection)
|
@@ -21,15 +21,9 @@ module Mongo
|
|
21
21
|
#
|
22
22
|
# @api private
|
23
23
|
module OpMsgOrFindCommand
|
24
|
+
include PolymorphicOperation
|
24
25
|
include PolymorphicLookup
|
25
26
|
|
26
|
-
def execute(server, client:)
|
27
|
-
server.with_connection do |connection|
|
28
|
-
operation = final_operation(connection)
|
29
|
-
operation.execute(connection, client: client)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
27
|
private
|
34
28
|
|
35
29
|
def final_operation(connection)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# Copyright (C) 2021 MongoDB Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
module Operation
|
17
|
+
|
18
|
+
# Shared behavior of implementing an operation differently based on
|
19
|
+
# the server that will be executing the operation.
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
module PolymorphicOperation
|
23
|
+
|
24
|
+
# Execute the operation.
|
25
|
+
#
|
26
|
+
# @param [ Mongo::Server ] server The server to send the operation to.
|
27
|
+
# @param [ Operation::Context ] context The operation context.
|
28
|
+
# @param [ Hash ] options Operation execution options.
|
29
|
+
#
|
30
|
+
# @return [ Mongo::Operation::Result ] The operation result.
|
31
|
+
def execute(server, context:, options: {})
|
32
|
+
server.with_connection do |connection|
|
33
|
+
operation = final_operation(connection)
|
34
|
+
operation.execute(connection, context: context, options: options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -36,44 +36,47 @@ module Mongo
|
|
36
36
|
#
|
37
37
|
# @since 2.0.0
|
38
38
|
def options(connection)
|
39
|
-
|
40
|
-
if add_slave_ok_flag?(connection)
|
41
|
-
flags = options[:flags]&.dup || []
|
42
|
-
flags << :slave_ok
|
43
|
-
options = options.merge(flags: flags)
|
44
|
-
end
|
45
|
-
options
|
39
|
+
add_slave_ok_flag_maybe(super, connection)
|
46
40
|
end
|
47
41
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
42
|
+
# Adds :slave_ok flag to options based on the read preference specified
|
43
|
+
# in the operation or implied by the topology that the connection's
|
44
|
+
# server is a part of.
|
51
45
|
#
|
46
|
+
# @param [ Hash ] options The options calculated so far.
|
52
47
|
# @param [ Server::Connection ] connection The connection that the
|
53
48
|
# operation will be executed on.
|
54
49
|
#
|
55
|
-
# @return [
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
50
|
+
# @return [ Hash ] The new options.
|
51
|
+
def add_slave_ok_flag_maybe(options, connection)
|
52
|
+
add_flag =
|
53
|
+
# https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection.rst#topology-type-single
|
54
|
+
if connection.description.standalone?
|
55
|
+
# Read preference is never sent to standalones.
|
56
|
+
false
|
57
|
+
elsif connection.server.cluster.single?
|
58
|
+
# In Single topology the driver forces primaryPreferred read
|
59
|
+
# preference mode (via the slave_ok flag, in case of old servers)
|
60
|
+
# so that the query is satisfied.
|
61
|
+
true
|
62
|
+
else
|
63
|
+
# In replica sets and sharded clusters, read preference is passed
|
64
|
+
# to the server if one is specified by the application, and there
|
65
|
+
# is no default.
|
66
|
+
read && read.slave_ok?
|
67
|
+
end
|
68
|
+
|
69
|
+
if add_flag
|
70
|
+
options= options.dup
|
71
|
+
(options[:flags] ||= []) << :slave_ok
|
71
72
|
end
|
73
|
+
|
74
|
+
options
|
72
75
|
end
|
73
76
|
|
74
77
|
def command(connection)
|
75
78
|
sel = super
|
76
|
-
|
79
|
+
update_selector_for_read_pref(sel, connection)
|
77
80
|
end
|
78
81
|
|
79
82
|
# Adds $readPreference field to the command document.
|
@@ -92,19 +95,14 @@ module Mongo
|
|
92
95
|
# operation will be executed on.
|
93
96
|
#
|
94
97
|
# @return [ Hash ] New command document to send to the server.
|
95
|
-
def
|
98
|
+
def update_selector_for_read_pref(sel, connection)
|
96
99
|
if read && connection.description.mongos? && read_pref = read.to_mongos
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
Mongo::Lint.validate_camel_case_read_preference(read_pref)
|
103
|
-
sel = sel[:$query] ? sel : {:$query => sel}
|
104
|
-
sel = sel.merge(:$readPreference => read_pref)
|
105
|
-
end
|
100
|
+
Mongo::Lint.validate_camel_case_read_preference(read_pref)
|
101
|
+
sel = sel[:$query] ? sel : {:$query => sel}
|
102
|
+
sel = sel.merge(:$readPreference => read_pref)
|
103
|
+
else
|
104
|
+
sel
|
106
105
|
end
|
107
|
-
sel
|
108
106
|
end
|
109
107
|
end
|
110
108
|
end
|
@@ -22,9 +22,13 @@ module Mongo
|
|
22
22
|
|
23
23
|
private
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
# @param [ Mongo::Operation::Result ] result The operation result.
|
26
|
+
# @param [ Mongo::Server::Connection ] connection The connection on which
|
27
|
+
# the operation is performed.
|
28
|
+
# @param [ Mongo::Operation::Context ] context The operation context.
|
29
|
+
def validate_result(result, connection, context)
|
30
|
+
unpin_maybe(context.session) do
|
31
|
+
add_error_labels(connection, context) do
|
28
32
|
add_server_diagnostics(connection) do
|
29
33
|
result.validate!
|
30
34
|
end
|
@@ -38,25 +42,29 @@ module Mongo
|
|
38
42
|
# and server-side errors (Error::OperationFailure); it does not
|
39
43
|
# handle server selection errors (Error::NoServerAvailable), for which
|
40
44
|
# labels are added in the server selection code.
|
41
|
-
|
45
|
+
#
|
46
|
+
# @param [ Mongo::Server::Connection ] connection The connection on which
|
47
|
+
# the operation is performed.
|
48
|
+
# @param [ Mongo::Operation::Context ] context The operation context.
|
49
|
+
def add_error_labels(connection, context)
|
42
50
|
begin
|
43
51
|
yield
|
44
52
|
rescue Mongo::Error::SocketError => e
|
45
|
-
if
|
53
|
+
if context.in_transaction? && !context.committing_transaction?
|
46
54
|
e.add_label('TransientTransactionError')
|
47
55
|
end
|
48
|
-
if
|
56
|
+
if context.committing_transaction?
|
49
57
|
e.add_label('UnknownTransactionCommitResult')
|
50
58
|
end
|
51
59
|
|
52
|
-
maybe_add_retryable_write_error_label!(e, connection,
|
60
|
+
maybe_add_retryable_write_error_label!(e, connection, context)
|
53
61
|
|
54
62
|
raise e
|
55
63
|
rescue Mongo::Error::SocketTimeoutError => e
|
56
|
-
maybe_add_retryable_write_error_label!(e, connection,
|
64
|
+
maybe_add_retryable_write_error_label!(e, connection, context)
|
57
65
|
raise e
|
58
66
|
rescue Mongo::Error::OperationFailure => e
|
59
|
-
if
|
67
|
+
if context.committing_transaction?
|
60
68
|
if e.write_retryable? || e.wtimeout? || (e.write_concern_error? &&
|
61
69
|
!Session::UNLABELED_WRITE_CONCERN_CODES.include?(e.write_concern_error_code)
|
62
70
|
) || e.max_time_ms_expired?
|
@@ -64,7 +72,7 @@ module Mongo
|
|
64
72
|
end
|
65
73
|
end
|
66
74
|
|
67
|
-
maybe_add_retryable_write_error_label!(e, connection,
|
75
|
+
maybe_add_retryable_write_error_label!(e, connection, context)
|
68
76
|
|
69
77
|
raise e
|
70
78
|
end
|
@@ -125,21 +133,12 @@ module Mongo
|
|
125
133
|
# @param [ Mongo::Error ] error The error to which to add the label.
|
126
134
|
# @param [ Mongo::Server::Connection ] connection The connection on which
|
127
135
|
# the operation is performed.
|
128
|
-
# @param [ Mongo::
|
129
|
-
# the operation.
|
130
|
-
# @param [ Mongo::Session ] session The operation's session.
|
136
|
+
# @param [ Mongo::Operation::Context ] context The operation context.
|
131
137
|
#
|
132
138
|
# @note The client argument is optional because some operations, such as
|
133
139
|
# end_session, do not pass the client as an argument to the execute
|
134
140
|
# method.
|
135
|
-
def maybe_add_retryable_write_error_label!(error, connection,
|
136
|
-
in_transaction = session && session.in_transaction?
|
137
|
-
committing_transaction = in_transaction && session.committing_transaction?
|
138
|
-
aborting_transaction = in_transaction && session.aborting_transaction?
|
139
|
-
modern_retry_writes = client && client.options[:retry_writes]
|
140
|
-
legacy_retry_writes = client && !client.options[:retry_writes] &&
|
141
|
-
client.max_write_retries > 0
|
142
|
-
|
141
|
+
def maybe_add_retryable_write_error_label!(error, connection, context)
|
143
142
|
# An operation is retryable if it meets one of the following criteria:
|
144
143
|
# - It is a commitTransaction or abortTransaction
|
145
144
|
# - It does not occur during a transaction and the client has enabled
|
@@ -147,8 +146,9 @@ module Mongo
|
|
147
146
|
#
|
148
147
|
# Note: any write operation within a transaction (excepting commit and
|
149
148
|
# abort is NOT a retryable operation)
|
150
|
-
retryable_operation = committing_transaction ||
|
151
|
-
|
149
|
+
retryable_operation = context.committing_transaction? ||
|
150
|
+
context.aborting_transaction? ||
|
151
|
+
!context.in_transaction? && context.any_retry_writes?
|
152
152
|
|
153
153
|
# An operation should add the RetryableWriteError label if one of the
|
154
154
|
# following conditions is met:
|
@@ -171,10 +171,9 @@ module Mongo
|
|
171
171
|
elsif connection.description.mongos?
|
172
172
|
# When server is a mongos:
|
173
173
|
# - $readPreference is never sent when mode is 'primary'
|
174
|
+
# - When mode is 'secondaryPreferred' $readPreference is only sent
|
175
|
+
# when a non-mode field (i.e. tag_sets) is present
|
174
176
|
# - Otherwise $readPreference is sent
|
175
|
-
# When mode is 'secondaryPreferred' $readPreference is currently
|
176
|
-
# required to only be sent when a non-mode field (i.e. tag_sets)
|
177
|
-
# is present, but this causes wrong behavior (DRIVERS-1642).
|
178
177
|
if read
|
179
178
|
doc = read.to_mongos
|
180
179
|
if doc
|
@@ -223,9 +222,20 @@ module Mongo
|
|
223
222
|
end
|
224
223
|
end
|
225
224
|
|
226
|
-
def build_message(connection)
|
225
|
+
def build_message(connection, context)
|
226
|
+
if self.session != context.session
|
227
|
+
if self.session
|
228
|
+
raise Error::InternalDriverError, "Operation session #{self.session.inspect} does not match context session #{context.session.inspect}"
|
229
|
+
else
|
230
|
+
# Some operations are not constructed with sessions but are
|
231
|
+
# executed in a context where a session is available.
|
232
|
+
# This could be OK or a driver issue.
|
233
|
+
# TODO investigate.
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
227
237
|
super.tap do |message|
|
228
|
-
if session
|
238
|
+
if session = context.session
|
229
239
|
# Serialize the message to detect client-side problems,
|
230
240
|
# such as invalid BSON keys. The message will be serialized again
|
231
241
|
# later prior to being sent to the connection.
|
@@ -25,18 +25,13 @@ module Mongo
|
|
25
25
|
|
26
26
|
# Execute the operation.
|
27
27
|
#
|
28
|
-
# @example
|
29
|
-
# operation.execute(server, client: nil)
|
30
|
-
#
|
31
28
|
# @param [ Mongo::Server ] server The server to send the operation to.
|
32
|
-
# @param [
|
33
|
-
# perform auto-encryption if it is necessary to encrypt the command
|
34
|
-
# being executed (optional).
|
29
|
+
# @param [ Operation::Context ] context The operation context.
|
35
30
|
#
|
36
31
|
# @return [ Mongo::Operation::Result ] The operation result.
|
37
32
|
#
|
38
33
|
# @since 2.5.2
|
39
|
-
def execute(server,
|
34
|
+
def execute(server, context:)
|
40
35
|
server.with_connection do |connection|
|
41
36
|
validate!(connection)
|
42
37
|
op = if connection.features.op_msg_enabled?
|
@@ -47,34 +42,29 @@ module Mongo
|
|
47
42
|
self.class::Command.new(spec)
|
48
43
|
end
|
49
44
|
|
50
|
-
result = op.execute(connection,
|
51
|
-
validate_result(result,
|
45
|
+
result = op.execute(connection, context: context)
|
46
|
+
validate_result(result, connection, context)
|
52
47
|
end
|
53
48
|
end
|
54
49
|
|
55
50
|
# Execute the bulk write operation.
|
56
51
|
#
|
57
|
-
# @example
|
58
|
-
# operation.bulk_execute(connection, client: nil)
|
59
|
-
#
|
60
52
|
# @param [ Mongo::Server::Connection ] connection The connection over
|
61
53
|
# which to send the operation.
|
62
|
-
# @param [
|
63
|
-
# perform auto-encryption if it is necessary to encrypt the command
|
64
|
-
# being executed (optional).
|
54
|
+
# @param [ Operation::Context ] context The operation context.
|
65
55
|
#
|
66
56
|
# @return [ Mongo::Operation::Delete::BulkResult,
|
67
57
|
# Mongo::Operation::Insert::BulkResult,
|
68
58
|
# Mongo::Operation::Update::BulkResult ] The bulk result.
|
69
59
|
#
|
70
60
|
# @since 2.5.2
|
71
|
-
def bulk_execute(connection,
|
61
|
+
def bulk_execute(connection, context:)
|
72
62
|
Lint.assert_type(connection, Server::Connection)
|
73
63
|
|
74
64
|
if connection.features.op_msg_enabled?
|
75
|
-
self.class::OpMsg.new(spec).execute(connection,
|
65
|
+
self.class::OpMsg.new(spec).execute(connection, context: context).bulk_result
|
76
66
|
else
|
77
|
-
self.class::Command.new(spec).execute(connection,
|
67
|
+
self.class::Command.new(spec).execute(connection, context: context).bulk_result
|
78
68
|
end
|
79
69
|
end
|
80
70
|
|