mongo 2.14.0 → 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.tar.gz.sig +0 -0
- data/README.md +4 -1
- data/Rakefile +8 -15
- data/lib/mongo.rb +23 -0
- 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/background_thread.rb +11 -0
- data/lib/mongo/bulk_write.rb +21 -18
- data/lib/mongo/client.rb +82 -6
- data/lib/mongo/cluster.rb +19 -28
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
- data/lib/mongo/cluster/sdam_flow.rb +14 -0
- data/lib/mongo/collection.rb +8 -6
- 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 +1 -1
- 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/cursor.rb +2 -2
- data/lib/mongo/database.rb +22 -5
- data/lib/mongo/database/view.rb +1 -1
- data/lib/mongo/error.rb +9 -1
- 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/grid/fs_bucket.rb +37 -37
- data/lib/mongo/index/view.rb +21 -11
- data/lib/mongo/monitoring.rb +13 -4
- 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/operation.rb +2 -2
- data/lib/mongo/operation/collections_info.rb +18 -1
- data/lib/mongo/operation/collections_info/command.rb +2 -2
- 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/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/response_handling.rb +23 -23
- data/lib/mongo/operation/shared/sessions_supported.rb +13 -2
- data/lib/mongo/operation/shared/write.rb +8 -18
- data/lib/mongo/protocol/compressed.rb +51 -5
- data/lib/mongo/protocol/message.rb +20 -2
- data/lib/mongo/protocol/msg.rb +36 -11
- data/lib/mongo/query_cache.rb +30 -0
- data/lib/mongo/retryable.rb +1 -1
- data/lib/mongo/server.rb +7 -15
- 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 -4
- data/lib/mongo/server/description.rb +4 -0
- data/lib/mongo/server/description/features.rb +9 -8
- data/lib/mongo/server/monitor.rb +20 -1
- data/lib/mongo/server/monitor/app_metadata.rb +1 -1
- data/lib/mongo/server/monitor/connection.rb +9 -10
- data/lib/mongo/server/pending_connection.rb +24 -6
- data/lib/mongo/server/push_monitor.rb +11 -1
- data/lib/mongo/session.rb +2 -2
- data/lib/mongo/session/session_pool.rb +4 -2
- data/lib/mongo/socket.rb +29 -4
- data/lib/mongo/socket/ssl.rb +8 -0
- data/lib/mongo/srv/monitor.rb +0 -11
- data/lib/mongo/uri/options_mapper.rb +38 -0
- data/lib/mongo/utils.rb +15 -0
- data/lib/mongo/version.rb +1 -1
- 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/reconnect_spec.rb +1 -1
- data/spec/integration/sdam_error_handling_spec.rb +1 -1
- data/spec/integration/sdam_events_spec.rb +3 -5
- 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 +3 -18
- 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 +8 -2
- 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/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_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_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 +13 -2
- data/spec/runners/transactions/test.rb +1 -0
- data/spec/runners/unified.rb +96 -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/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/lib/mrss/cluster_config.rb +218 -0
- data/spec/shared/lib/mrss/constraints.rb +43 -0
- data/spec/shared/lib/mrss/docker_runner.rb +262 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +112 -0
- data/spec/shared/lib/mrss/utils.rb +15 -0
- data/spec/shared/share/Dockerfile.erb +231 -0
- data/spec/shared/shlib/distro.sh +73 -0
- data/spec/shared/shlib/server.sh +290 -0
- data/spec/shared/shlib/set_env.sh +128 -0
- data/spec/solo/clean_exit_spec.rb +21 -0
- 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/common_shortcuts.rb +15 -1
- data/spec/support/shared/session.rb +2 -2
- data/spec/support/spec_config.rb +46 -3
- data/spec/support/spec_setup.rb +48 -38
- data/spec/support/utils.rb +64 -3
- metadata +1104 -992
- 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/support/cluster_config.rb +0 -207
@@ -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
|
@@ -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:
|
@@ -222,9 +222,20 @@ module Mongo
|
|
222
222
|
end
|
223
223
|
end
|
224
224
|
|
225
|
-
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
|
+
|
226
237
|
super.tap do |message|
|
227
|
-
if session
|
238
|
+
if session = context.session
|
228
239
|
# Serialize the message to detect client-side problems,
|
229
240
|
# such as invalid BSON keys. The message will be serialized again
|
230
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
|
|
@@ -18,12 +18,25 @@ module Mongo
|
|
18
18
|
# MongoDB Wire protocol Compressed message.
|
19
19
|
#
|
20
20
|
# This is a bi-directional message that compresses another opcode.
|
21
|
+
# See https://github.com/mongodb/specifications/blob/master/source/compression/OP_COMPRESSED.rst
|
21
22
|
#
|
22
23
|
# @api semipublic
|
23
24
|
#
|
24
25
|
# @since 2.5.0
|
25
26
|
class Compressed < Message
|
26
27
|
|
28
|
+
# The noop compressor identifier.
|
29
|
+
NOOP = 'noop'.freeze
|
30
|
+
|
31
|
+
# The byte signaling that the message has not been compressed (test mode).
|
32
|
+
NOOP_BYTE = 0.chr.force_encoding(BSON::BINARY).freeze
|
33
|
+
|
34
|
+
# The snappy compressor identifier.
|
35
|
+
SNAPPY = 'snappy'.freeze
|
36
|
+
|
37
|
+
# The byte signaling that the message has been compressed with snappy.
|
38
|
+
SNAPPY_BYTE = 1.chr.force_encoding(BSON::BINARY).freeze
|
39
|
+
|
27
40
|
# The byte signaling that the message has been compressed with Zlib.
|
28
41
|
#
|
29
42
|
# @since 2.5.0
|
@@ -34,10 +47,20 @@ module Mongo
|
|
34
47
|
# @since 2.5.0
|
35
48
|
ZLIB = 'zlib'.freeze
|
36
49
|
|
50
|
+
# The zstd compressor identifier.
|
51
|
+
ZSTD = 'zstd'.freeze
|
52
|
+
|
53
|
+
# The byte signaling that the message has been compressed with zstd.
|
54
|
+
ZSTD_BYTE = 3.chr.force_encoding(BSON::BINARY).freeze
|
55
|
+
|
37
56
|
# The compressor identifier to byte map.
|
38
57
|
#
|
39
58
|
# @since 2.5.0
|
40
|
-
COMPRESSOR_ID_MAP = {
|
59
|
+
COMPRESSOR_ID_MAP = {
|
60
|
+
SNAPPY => SNAPPY_BYTE,
|
61
|
+
ZSTD => ZSTD_BYTE,
|
62
|
+
ZLIB => ZLIB_BYTE
|
63
|
+
}.freeze
|
41
64
|
|
42
65
|
# Creates a new OP_COMPRESSED message.
|
43
66
|
#
|
@@ -68,9 +91,7 @@ module Mongo
|
|
68
91
|
# @api private
|
69
92
|
def maybe_inflate
|
70
93
|
message = Registry.get(@original_op_code).allocate
|
71
|
-
|
72
|
-
|
73
|
-
buf = BSON::ByteBuffer.new(uncompressed_message)
|
94
|
+
buf = decompress(@compressed_message)
|
74
95
|
|
75
96
|
message.send(:fields).each do |field|
|
76
97
|
if field[:multi]
|
@@ -125,10 +146,35 @@ module Mongo
|
|
125
146
|
buf = BSON::ByteBuffer.new
|
126
147
|
@original_message.send(:serialize_fields, buf, max_bson_size)
|
127
148
|
@uncompressed_size = buf.length
|
128
|
-
@compressed_message =
|
149
|
+
@compressed_message = compress(buf)
|
129
150
|
super
|
130
151
|
end
|
131
152
|
|
153
|
+
def compress(buffer)
|
154
|
+
if @compressor_id == NOOP_BYTE
|
155
|
+
buffer.to_s.force_encoding(BSON::BINARY)
|
156
|
+
elsif @compressor_id == ZLIB_BYTE
|
157
|
+
Zlib::Deflate.deflate(buffer.to_s, @zlib_compression_level).force_encoding(BSON::BINARY)
|
158
|
+
elsif @compressor_id == SNAPPY_BYTE
|
159
|
+
Snappy.deflate(buffer.to_s).force_encoding(BSON::BINARY)
|
160
|
+
elsif @compressor_id == ZSTD_BYTE
|
161
|
+
# DRIVERS-600 will allow this to be configurable in the future
|
162
|
+
Zstd.compress(buffer.to_s).force_encoding(BSON::BINARY)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def decompress(compressed_message)
|
167
|
+
if @compressor_id == NOOP_BYTE
|
168
|
+
BSON::ByteBuffer.new(compressed_message)
|
169
|
+
elsif @compressor_id == ZLIB_BYTE
|
170
|
+
BSON::ByteBuffer.new(Zlib::Inflate.inflate(compressed_message))
|
171
|
+
elsif @compressor_id == SNAPPY_BYTE
|
172
|
+
BSON::ByteBuffer.new(Snappy.inflate(compressed_message))
|
173
|
+
elsif @compressor_id == ZSTD_BYTE
|
174
|
+
BSON::ByteBuffer.new(Zstd.decompress(compressed_message))
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
132
178
|
Registry.register(OP_CODE, self)
|
133
179
|
end
|
134
180
|
end
|
@@ -140,7 +140,13 @@ module Mongo
|
|
140
140
|
self
|
141
141
|
end
|
142
142
|
|
143
|
-
|
143
|
+
# Possibly decrypt this message with libmongocrypt.
|
144
|
+
#
|
145
|
+
# @param [ Mongo::Operation::Context ] context The operation context.
|
146
|
+
#
|
147
|
+
# @return [ Mongo::Protocol::Msg ] The decrypted message, or the original
|
148
|
+
# message if decryption was not possible or necessary.
|
149
|
+
def maybe_decrypt(context)
|
144
150
|
# TODO determine if we should be decrypting data coming from pre-4.2
|
145
151
|
# servers, potentially using legacy wire protocols. If so we need
|
146
152
|
# to implement decryption for those wire protocols as our current
|
@@ -148,11 +154,23 @@ module Mongo
|
|
148
154
|
self
|
149
155
|
end
|
150
156
|
|
151
|
-
|
157
|
+
# Possibly encrypt this message with libmongocrypt.
|
158
|
+
#
|
159
|
+
# @param [ Mongo::Server::Connection ] connection The connection on which
|
160
|
+
# the operation is performed.
|
161
|
+
# @param [ Mongo::Operation::Context ] context The operation context.
|
162
|
+
#
|
163
|
+
# @return [ Mongo::Protocol::Msg ] The encrypted message, or the original
|
164
|
+
# message if encryption was not possible or necessary.
|
165
|
+
def maybe_encrypt(connection, context)
|
152
166
|
# Do nothing if the Message subclass has not implemented this method
|
153
167
|
self
|
154
168
|
end
|
155
169
|
|
170
|
+
def maybe_add_server_api(server_api)
|
171
|
+
raise Error::ServerApiNotSupported, "Server API parameters cannot be sent to pre-3.6 MongoDB servers. Please remove the :server_api parameter from Client options or use MongoDB 3.6 or newer"
|
172
|
+
end
|
173
|
+
|
156
174
|
private def merge_sections
|
157
175
|
cmd = if @sections.length > 1
|
158
176
|
cmd = @sections.detect { |section| section[:type] == 0 }[:payload]
|
data/lib/mongo/protocol/msg.rb
CHANGED
@@ -199,15 +199,16 @@ module Mongo
|
|
199
199
|
# represents one of the command types whitelisted by libmongocrypt and it
|
200
200
|
# contains data that is required to be encrypted by a local or remote json schema.
|
201
201
|
#
|
202
|
-
# @param [ Mongo::
|
203
|
-
#
|
202
|
+
# @param [ Mongo::Server::Connection ] connection The connection on which
|
203
|
+
# the operation is performed.
|
204
|
+
# @param [ Mongo::Operation::Context ] context The operation context.
|
204
205
|
#
|
205
206
|
# @return [ Mongo::Protocol::Msg ] The encrypted message, or the original
|
206
207
|
# message if encryption was not possible or necessary.
|
207
|
-
def maybe_encrypt(connection,
|
208
|
+
def maybe_encrypt(connection, context)
|
208
209
|
# TODO verify compression happens later, i.e. when this method runs
|
209
210
|
# the message is not compressed.
|
210
|
-
if
|
211
|
+
if context.encrypt?
|
211
212
|
if connection.description.max_wire_version < 8
|
212
213
|
raise Error::CryptError.new(
|
213
214
|
"Cannot perform encryption against a MongoDB server older than " +
|
@@ -219,7 +220,7 @@ module Mongo
|
|
219
220
|
|
220
221
|
db_name = @main_document[DATABASE_IDENTIFIER]
|
221
222
|
cmd = merge_sections
|
222
|
-
enc_cmd =
|
223
|
+
enc_cmd = context.encrypter.encrypt(db_name, cmd)
|
223
224
|
if cmd.key?('$db') && !enc_cmd.key?('$db')
|
224
225
|
enc_cmd['$db'] = cmd['$db']
|
225
226
|
end
|
@@ -237,15 +238,14 @@ module Mongo
|
|
237
238
|
# types whitelisted by libmongocrypt and it contains data that is required
|
238
239
|
# to be encrypted by a local or remote json schema.
|
239
240
|
#
|
240
|
-
# @param [ Mongo::
|
241
|
-
# command. This client may have auto-encryption options specified.
|
241
|
+
# @param [ Mongo::Operation::Context ] context The operation context.
|
242
242
|
#
|
243
|
-
# @return [ Mongo::Protocol::Msg ] The
|
243
|
+
# @return [ Mongo::Protocol::Msg ] The decrypted message, or the original
|
244
244
|
# message if decryption was not possible or necessary.
|
245
|
-
def maybe_decrypt(
|
246
|
-
if
|
245
|
+
def maybe_decrypt(context)
|
246
|
+
if context.decrypt?
|
247
247
|
cmd = merge_sections
|
248
|
-
enc_cmd =
|
248
|
+
enc_cmd = context.encrypter.decrypt(cmd)
|
249
249
|
Msg.new(@flags, @options, enc_cmd)
|
250
250
|
else
|
251
251
|
self
|
@@ -275,6 +275,31 @@ module Mongo
|
|
275
275
|
num_inserts > 1 || num_updates > 1 || num_deletes > 1
|
276
276
|
end
|
277
277
|
|
278
|
+
def maybe_add_server_api(server_api)
|
279
|
+
if @main_document[:getMore]
|
280
|
+
# getMore does not allow API parameters.
|
281
|
+
return self
|
282
|
+
end
|
283
|
+
|
284
|
+
conflicts = {}
|
285
|
+
%i(apiVersion apiStrict apiDeprecationErrors).each do |key|
|
286
|
+
if @main_document.key?(key)
|
287
|
+
conflicts[key] = @main_document[key]
|
288
|
+
end
|
289
|
+
if @main_document.key?(key.to_s)
|
290
|
+
conflicts[key] = @main_document[key.to_s]
|
291
|
+
end
|
292
|
+
end
|
293
|
+
unless conflicts.empty?
|
294
|
+
raise Error::ServerApiConflict, "The Client is configured with :server_api option but the operation provided the following conflicting parameters: #{conflicts.inspect}"
|
295
|
+
end
|
296
|
+
|
297
|
+
main_document = @main_document.merge(
|
298
|
+
Utils.transform_server_api(server_api)
|
299
|
+
)
|
300
|
+
Msg.new(@flags, @options, main_document, *@sequences)
|
301
|
+
end
|
302
|
+
|
278
303
|
private
|
279
304
|
|
280
305
|
# Validate that the documents in this message are all smaller than the
|