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
data/lib/mongo/operation.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'mongo/operation/context'
|
1
2
|
require 'mongo/operation/result'
|
2
3
|
|
3
4
|
require 'mongo/operation/shared/response_handling'
|
@@ -5,6 +6,7 @@ require 'mongo/operation/shared/executable'
|
|
5
6
|
require 'mongo/operation/shared/executable_no_validate'
|
6
7
|
require 'mongo/operation/shared/executable_transaction_label'
|
7
8
|
require 'mongo/operation/shared/polymorphic_lookup'
|
9
|
+
require 'mongo/operation/shared/polymorphic_operation'
|
8
10
|
require 'mongo/operation/shared/polymorphic_result'
|
9
11
|
require 'mongo/operation/shared/read_preference_supported'
|
10
12
|
require 'mongo/operation/shared/bypass_document_validation'
|
@@ -18,8 +20,6 @@ require 'mongo/operation/shared/specifiable'
|
|
18
20
|
require 'mongo/operation/shared/object_id_generator'
|
19
21
|
require 'mongo/operation/shared/op_msg_or_command'
|
20
22
|
require 'mongo/operation/shared/op_msg_or_find_command'
|
21
|
-
require 'mongo/operation/shared/op_msg_or_list_indexes_command'
|
22
|
-
require 'mongo/operation/shared/collections_info_or_list_collections'
|
23
23
|
|
24
24
|
require 'mongo/operation/op_msg_base'
|
25
25
|
require 'mongo/operation/command'
|
@@ -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
@@ -43,8 +43,8 @@ module Mongo
|
|
43
43
|
# Msg.new([:more_to_come], {}, { ismaster: 1 },
|
44
44
|
# { type: 1, payload: { identifier: 'documents', sequence: [..] } })
|
45
45
|
#
|
46
|
-
# @param [ Array<Symbol> ] flags The flag bits.
|
47
|
-
#
|
46
|
+
# @param [ Array<Symbol> ] flags The flag bits. Current supported values
|
47
|
+
# are :more_to_come and :checksum_present.
|
48
48
|
# @param [ Hash ] options The options.
|
49
49
|
# @param [ BSON::Document, Hash ] main_document The document that will
|
50
50
|
# become the payload type 0 section. Can contain global args as they
|
@@ -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
|
data/lib/mongo/protocol/query.rb
CHANGED
@@ -46,18 +46,18 @@ module Mongo
|
|
46
46
|
# @example Find all user ids.
|
47
47
|
# Query.new('xgen', 'users', {}, :fields => {:id => 1})
|
48
48
|
#
|
49
|
-
# @param [
|
50
|
-
# @param [
|
51
|
-
# @param [
|
52
|
-
# @param [
|
49
|
+
# @param database [String, Symbol] The database to query.
|
50
|
+
# @param collection [String, Symbol] The collection to query.
|
51
|
+
# @param selector [Hash] The query selector.
|
52
|
+
# @param options [Hash] The additional query options.
|
53
53
|
#
|
54
|
-
# @option options [
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
54
|
+
# @option options :project [Hash] The projection.
|
55
|
+
# @option options :skip [Integer] The number of documents to skip.
|
56
|
+
# @option options :limit [Integer] The number of documents to return.
|
57
|
+
# @option options :flags [Array] The flags for the query message.
|
58
|
+
#
|
59
|
+
# Supported flags: +:tailable_cursor+, +:slave_ok+, +:oplog_replay+,
|
60
|
+
# +:no_cursor_timeout+, +:await_data+, +:exhaust+, +:partial+
|
61
61
|
def initialize(database, collection, selector, options = {})
|
62
62
|
@database = database
|
63
63
|
@namespace = "#{database}.#{collection}"
|
data/lib/mongo/query_cache.rb
CHANGED
@@ -238,5 +238,35 @@ module Mongo
|
|
238
238
|
end
|
239
239
|
end
|
240
240
|
end
|
241
|
+
|
242
|
+
# Rack middleware that activates the query cache for each request.
|
243
|
+
class Middleware
|
244
|
+
|
245
|
+
# Instantiate the middleware.
|
246
|
+
#
|
247
|
+
# @example Create the new middleware.
|
248
|
+
# Middleware.new(app)
|
249
|
+
#
|
250
|
+
# @param [ Object ] app The rack application stack.
|
251
|
+
def initialize(app)
|
252
|
+
@app = app
|
253
|
+
end
|
254
|
+
|
255
|
+
# Enable query cache and execute the request.
|
256
|
+
#
|
257
|
+
# @example Execute the request.
|
258
|
+
# middleware.call(env)
|
259
|
+
#
|
260
|
+
# @param [ Object ] env The environment.
|
261
|
+
#
|
262
|
+
# @return [ Object ] The result of the call.
|
263
|
+
def call(env)
|
264
|
+
QueryCache.cache do
|
265
|
+
@app.call(env)
|
266
|
+
end
|
267
|
+
ensure
|
268
|
+
QueryCache.clear
|
269
|
+
end
|
270
|
+
end
|
241
271
|
end
|
242
272
|
end
|
data/lib/mongo/retryable.rb
CHANGED
@@ -477,7 +477,7 @@ module Mongo
|
|
477
477
|
else
|
478
478
|
"Retry"
|
479
479
|
end
|
480
|
-
Logger.logger.warn "#{message} due to: #{e.class.name} #{e.message}"
|
480
|
+
Logger.logger.warn "#{message} due to: #{e.class.name}: #{e.message}"
|
481
481
|
end
|
482
482
|
|
483
483
|
# Retry writes on MMAPv1 should raise an actionable error; append actionable
|
@@ -43,6 +43,11 @@ module Mongo
|
|
43
43
|
# @api private
|
44
44
|
AUTH_OPTION_KEYS = [:user, :auth_source, :auth_mech].freeze
|
45
45
|
|
46
|
+
# Possible connection purposes.
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
PURPOSES = %i(application monitor push_monitor).freeze
|
50
|
+
|
46
51
|
# Instantiate the new AppMetadata object.
|
47
52
|
#
|
48
53
|
# @api private
|
@@ -60,10 +65,16 @@ module Mongo
|
|
60
65
|
# @option options [ Array<String> ] :compressors A list of potential
|
61
66
|
# compressors to use, in order of preference. The driver chooses the
|
62
67
|
# first compressor that is also supported by the server. Currently the
|
63
|
-
# driver only supports 'zlib'.
|
68
|
+
# driver only supports 'zstd', 'snappy' and 'zlib'.
|
64
69
|
# @option options [ String ] :platform Platform information to include in
|
65
70
|
# the metadata printed to the mongod logs upon establishing a connection
|
66
71
|
# in server versions >= 3.4.
|
72
|
+
# @option options [ Symbol ] :purpose The purpose of this connection.
|
73
|
+
# @option options [ Hash ] :server_api The requested server API version.
|
74
|
+
# This hash can have the following items:
|
75
|
+
# - *:version* -- string
|
76
|
+
# - *:strict* -- boolean
|
77
|
+
# - *:deprecation_errors* -- boolean
|
67
78
|
# @option options [ String ] :user The user name.
|
68
79
|
# @option options [ Array<Hash> ] :wrapping_libraries Information about
|
69
80
|
# libraries such as ODMs that are wrapping the driver. Specify the
|
@@ -71,11 +82,17 @@ module Mongo
|
|
71
82
|
# :platform.
|
72
83
|
#
|
73
84
|
# @since 2.4.0
|
74
|
-
def initialize(options)
|
85
|
+
def initialize(options = {})
|
75
86
|
@app_name = options[:app_name].to_s if options[:app_name]
|
76
87
|
@platform = options[:platform]
|
88
|
+
if @purpose = options[:purpose]
|
89
|
+
unless PURPOSES.include?(@purpose)
|
90
|
+
raise ArgumentError, "Invalid purpose: #{@purpose}"
|
91
|
+
end
|
92
|
+
end
|
77
93
|
@compressors = options[:compressors] || []
|
78
94
|
@wrapping_libraries = options[:wrapping_libraries]
|
95
|
+
@server_api = options[:server_api]
|
79
96
|
|
80
97
|
if options[:user] && !options[:auth_mech]
|
81
98
|
auth_db = options[:auth_source] || 'admin'
|
@@ -83,6 +100,12 @@ module Mongo
|
|
83
100
|
end
|
84
101
|
end
|
85
102
|
|
103
|
+
# @return [ Symbol ] The purpose of the connection for which this
|
104
|
+
# app metadata is created.
|
105
|
+
#
|
106
|
+
# @api private
|
107
|
+
attr_reader :purpose
|
108
|
+
|
86
109
|
# @return [ Array<Hash> | nil ] Information about libraries wrapping
|
87
110
|
# the driver.
|
88
111
|
attr_reader :wrapping_libraries
|
@@ -130,22 +153,29 @@ module Mongo
|
|
130
153
|
end
|
131
154
|
|
132
155
|
def document
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
client_document[:os]
|
137
|
-
|
138
|
-
|
139
|
-
client_document
|
140
|
-
|
141
|
-
|
156
|
+
@document ||= begin
|
157
|
+
client_document = full_client_document
|
158
|
+
while client_document.to_bson.to_s.size > MAX_DOCUMENT_SIZE do
|
159
|
+
if client_document[:os][:name] || client_document[:os][:architecture]
|
160
|
+
client_document[:os].delete(:name)
|
161
|
+
client_document[:os].delete(:architecture)
|
162
|
+
elsif client_document[:platform]
|
163
|
+
client_document.delete(:platform)
|
164
|
+
else
|
165
|
+
client_document = nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
document = Server::Monitor::Connection::ISMASTER
|
169
|
+
document = document.merge(compression: @compressors)
|
170
|
+
document[:client] = client_document
|
171
|
+
document[:saslSupportedMechs] = @request_auth_mech if @request_auth_mech
|
172
|
+
if @server_api
|
173
|
+
document.update(
|
174
|
+
Utils.transform_server_api(@server_api)
|
175
|
+
)
|
142
176
|
end
|
177
|
+
document
|
143
178
|
end
|
144
|
-
document = Server::Monitor::Connection::ISMASTER
|
145
|
-
document = document.merge(compression: @compressors)
|
146
|
-
document[:client] = client_document
|
147
|
-
document[:saslSupportedMechs] = @request_auth_mech if @request_auth_mech
|
148
|
-
document
|
149
179
|
end
|
150
180
|
|
151
181
|
def driver_doc
|
@@ -192,12 +222,16 @@ module Mongo
|
|
192
222
|
ruby_versions = ["Ruby #{RUBY_VERSION}"]
|
193
223
|
platforms = [RUBY_PLATFORM]
|
194
224
|
end
|
195
|
-
|
225
|
+
platforms = [
|
196
226
|
@platform,
|
197
227
|
*ruby_versions,
|
198
228
|
*platforms,
|
199
229
|
RbConfig::CONFIG['build'],
|
200
|
-
]
|
230
|
+
]
|
231
|
+
if @purpose
|
232
|
+
platforms << @purpose.to_s[0].upcase
|
233
|
+
end
|
234
|
+
platform = platforms.compact.join(', ')
|
201
235
|
platforms = [platform]
|
202
236
|
if wrapping_libraries
|
203
237
|
wrapping_libraries.each do |library|
|
@@ -85,6 +85,11 @@ module Mongo
|
|
85
85
|
#
|
86
86
|
# @option options [ Integer ] :generation Connection pool's generation
|
87
87
|
# for this connection.
|
88
|
+
# @option options [ Hash ] :server_api The requested server API version.
|
89
|
+
# This hash can have the following items:
|
90
|
+
# - *:version* -- string
|
91
|
+
# - *:strict* -- boolean
|
92
|
+
# - *:deprecation_errors* -- boolean
|
88
93
|
#
|
89
94
|
# @since 2.0.0
|
90
95
|
def initialize(server, options = {})
|
@@ -105,7 +105,7 @@ module Mongo
|
|
105
105
|
if same
|
106
106
|
@server.app_metadata
|
107
107
|
else
|
108
|
-
AppMetadata.new(options)
|
108
|
+
AppMetadata.new(options.merge(purpose: @server.app_metadata.purpose))
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
@@ -124,7 +124,7 @@ module Mongo
|
|
124
124
|
#
|
125
125
|
# @param [ Array<Message> ] messages A one-element array containing
|
126
126
|
# the message to dispatch.
|
127
|
-
# @param [
|
127
|
+
# @param [ Operation::Context ] context The operation context.
|
128
128
|
# @param [ Hash ] options
|
129
129
|
#
|
130
130
|
# @option options [ Boolean ] :deserialize_as_bson Whether to deserialize
|
@@ -134,24 +134,27 @@ module Mongo
|
|
134
134
|
# @return [ Protocol::Message | nil ] The reply if needed.
|
135
135
|
#
|
136
136
|
# @since 2.0.0
|
137
|
-
def dispatch(messages,
|
137
|
+
def dispatch(messages, context, options = {})
|
138
138
|
# The monitoring code does not correctly handle multiple messages,
|
139
139
|
# and the driver internally does not send more than one message at
|
140
140
|
# a time ever. Thus prohibit multiple message use for now.
|
141
141
|
if messages.length != 1
|
142
142
|
raise ArgumentError, 'Can only dispatch one message at a time'
|
143
143
|
end
|
144
|
+
if description.unknown?
|
145
|
+
raise Error::InternalDriverError, "Cannot dispatch a message on a connection with unknown description: #{description.inspect}"
|
146
|
+
end
|
144
147
|
message = messages.first
|
145
|
-
deliver(message,
|
148
|
+
deliver(message, context, options)
|
146
149
|
end
|
147
150
|
|
148
151
|
private
|
149
152
|
|
150
|
-
def deliver(message,
|
153
|
+
def deliver(message, context, options = {})
|
151
154
|
if Lint.enabled? && !@socket
|
152
155
|
raise Error::LintError, "Trying to deliver a message over a disconnected connection (to #{address})"
|
153
156
|
end
|
154
|
-
buffer = serialize(message,
|
157
|
+
buffer = serialize(message, context)
|
155
158
|
ensure_connected do |socket|
|
156
159
|
operation_id = Monitoring.next_operation_id
|
157
160
|
command_started(address, operation_id, message.payload,
|
@@ -178,14 +181,14 @@ module Mongo
|
|
178
181
|
total_duration = Time.now - start
|
179
182
|
command_completed(result, address, operation_id, message.payload, total_duration)
|
180
183
|
end
|
181
|
-
if
|
182
|
-
result = result.maybe_decrypt(
|
184
|
+
if result && context.decrypt?
|
185
|
+
result = result.maybe_decrypt(context)
|
183
186
|
end
|
184
187
|
result
|
185
188
|
end
|
186
189
|
end
|
187
190
|
|
188
|
-
def serialize(message,
|
191
|
+
def serialize(message, context, buffer = BSON::ByteBuffer.new)
|
189
192
|
# Driver specifications only mandate the fixed 16MiB limit for
|
190
193
|
# serialized BSON documents. However, the server returns its
|
191
194
|
# active serialized BSON document size limit in the ismaster response,
|
@@ -194,7 +197,7 @@ module Mongo
|
|
194
197
|
# only as the default if the server's ismaster did not contain
|
195
198
|
# maxBsonObjectSize.
|
196
199
|
max_bson_size = max_bson_object_size || DEFAULT_MAX_BSON_OBJECT_SIZE
|
197
|
-
if
|
200
|
+
if context.encrypt?
|
198
201
|
# The client-side encryption specification requires bulk writes to
|
199
202
|
# be split at a reduced maxBsonObjectSize. If this message is a bulk
|
200
203
|
# write and its size exceeds the reduced size limit, the serializer
|
@@ -703,8 +703,12 @@ module Mongo
|
|
703
703
|
private
|
704
704
|
|
705
705
|
def create_connection
|
706
|
-
connection = Connection.new(@server, options.merge(
|
707
|
-
|
706
|
+
connection = Connection.new(@server, options.merge(
|
707
|
+
generation: generation,
|
708
|
+
connection_pool: self,
|
709
|
+
# Do not pass app metadata - this will be retrieved by the connection
|
710
|
+
# based on the auth needs.
|
711
|
+
))
|
708
712
|
end
|
709
713
|
|
710
714
|
# Create a connection, connect it, and add it to the pool.
|
@@ -23,14 +23,15 @@ module Mongo
|
|
23
23
|
# List of features and the wire protocol version they appear in.
|
24
24
|
#
|
25
25
|
# Wire protocol versions map to server releases as follows:
|
26
|
-
# -
|
27
|
-
# -
|
28
|
-
# -
|
29
|
-
# -
|
30
|
-
# -
|
31
|
-
# -
|
32
|
-
# -
|
33
|
-
# -
|
26
|
+
# - 2 => 2.6
|
27
|
+
# - 3 => 3.0
|
28
|
+
# - 4 => 3.2
|
29
|
+
# - 5 => 3.4
|
30
|
+
# - 6 => 3.6
|
31
|
+
# - 7 => 4.0
|
32
|
+
# - 8 => 4.2
|
33
|
+
# - 9 => 4.4
|
34
|
+
# - 12 => 5.0
|
34
35
|
#
|
35
36
|
# @since 2.0.0
|
36
37
|
MAPPINGS = {
|
@@ -44,7 +44,7 @@ module Mongo
|
|
44
44
|
# The constant for the ismaster command.
|
45
45
|
#
|
46
46
|
# @since 2.2.0
|
47
|
-
ISMASTER_MESSAGE = Protocol::Query.new(Database::ADMIN, Database::COMMAND, ISMASTER, :
|
47
|
+
ISMASTER_MESSAGE = Protocol::Query.new(Database::ADMIN, Database::COMMAND, ISMASTER, limit: -1)
|
48
48
|
|
49
49
|
# The constant for the ismaster command as an OP_MSG (server versions >= 3.6).
|
50
50
|
#
|
@@ -83,7 +83,7 @@ module Mongo
|
|
83
83
|
# @option options [ Array<String> ] :compressors A list of potential
|
84
84
|
# compressors to use, in order of preference. The driver chooses the
|
85
85
|
# first compressor that is also supported by the server. Currently the
|
86
|
-
# driver only supports 'zlib'.
|
86
|
+
# driver only supports 'zstd', 'snappy' and 'zlib'.
|
87
87
|
# @option options [ Float ] :connect_timeout The timeout, in seconds,
|
88
88
|
# to use for network operations. This timeout is used for all
|
89
89
|
# socket operations rather than connect calls only, contrary to
|
@@ -93,7 +93,9 @@ module Mongo
|
|
93
93
|
def initialize(address, options = {})
|
94
94
|
@address = address
|
95
95
|
@options = options.dup.freeze
|
96
|
-
@app_metadata = options[:app_metadata]
|
96
|
+
unless @app_metadata = options[:app_metadata]
|
97
|
+
raise ArgumentError, 'App metadata is required'
|
98
|
+
end
|
97
99
|
@socket = nil
|
98
100
|
@pid = Process.pid
|
99
101
|
@compressor = nil
|
@@ -221,14 +223,11 @@ module Mongo
|
|
221
223
|
end
|
222
224
|
|
223
225
|
def handshake!
|
224
|
-
payload =
|
225
|
-
@app_metadata.ismaster_bytes
|
226
|
-
else
|
227
|
-
log_warn("No app metadata provided for handshake with #{address}")
|
228
|
-
ISMASTER_BYTES
|
229
|
-
end
|
226
|
+
payload = @app_metadata.ismaster_bytes
|
230
227
|
message = dispatch_bytes(payload)
|
231
|
-
|
228
|
+
result = Operation::Result.new(message)
|
229
|
+
result.validate!
|
230
|
+
reply = result.documents.first
|
232
231
|
set_compressor!(reply)
|
233
232
|
@server_connection_id = reply['connectionId']
|
234
233
|
reply
|