mongo 2.20.1 → 2.21.0
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
- data/README.md +3 -0
- data/Rakefile +2 -2
- data/lib/mongo/address.rb +22 -3
- data/lib/mongo/auth/aws/credentials_retriever.rb +70 -17
- data/lib/mongo/auth/base.rb +1 -1
- data/lib/mongo/bulk_write.rb +35 -2
- data/lib/mongo/client.rb +38 -6
- data/lib/mongo/client_encryption.rb +6 -3
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -1
- data/lib/mongo/cluster/sdam_flow.rb +20 -7
- data/lib/mongo/cluster.rb +14 -4
- data/lib/mongo/collection/helpers.rb +1 -1
- data/lib/mongo/collection/view/aggregation/behavior.rb +131 -0
- data/lib/mongo/collection/view/aggregation.rb +33 -99
- data/lib/mongo/collection/view/builder/aggregation.rb +1 -7
- data/lib/mongo/collection/view/change_stream.rb +80 -27
- data/lib/mongo/collection/view/iterable.rb +76 -60
- data/lib/mongo/collection/view/map_reduce.rb +25 -8
- data/lib/mongo/collection/view/readable.rb +79 -30
- data/lib/mongo/collection/view/writable.rb +109 -48
- data/lib/mongo/collection/view.rb +43 -3
- data/lib/mongo/collection.rb +158 -23
- data/lib/mongo/crypt/auto_encrypter.rb +4 -6
- data/lib/mongo/crypt/binding.rb +4 -4
- data/lib/mongo/crypt/context.rb +20 -14
- data/lib/mongo/crypt/encryption_io.rb +56 -26
- data/lib/mongo/crypt/explicit_encrypter.rb +49 -20
- data/lib/mongo/crypt/explicit_encryption_context.rb +17 -11
- data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +22 -6
- data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +29 -4
- data/lib/mongo/csot_timeout_holder.rb +119 -0
- data/lib/mongo/cursor/kill_spec.rb +5 -2
- data/lib/mongo/cursor/nontailable.rb +27 -0
- data/lib/mongo/cursor.rb +86 -24
- data/lib/mongo/cursor_host.rb +82 -0
- data/lib/mongo/database/view.rb +81 -14
- data/lib/mongo/database.rb +88 -18
- data/lib/mongo/error/operation_failure.rb +209 -204
- data/lib/mongo/error/server_timeout_error.rb +12 -0
- data/lib/mongo/error/socket_timeout_error.rb +3 -1
- data/lib/mongo/error/timeout_error.rb +23 -0
- data/lib/mongo/error.rb +2 -0
- data/lib/mongo/grid/fs_bucket.rb +45 -12
- data/lib/mongo/grid/stream/read.rb +15 -1
- data/lib/mongo/grid/stream/write.rb +21 -4
- data/lib/mongo/index/view.rb +77 -16
- data/lib/mongo/operation/context.rb +40 -2
- data/lib/mongo/operation/create_search_indexes/op_msg.rb +2 -2
- data/lib/mongo/operation/delete/op_msg.rb +2 -1
- data/lib/mongo/operation/drop_search_index/op_msg.rb +2 -2
- data/lib/mongo/operation/find/op_msg.rb +45 -0
- data/lib/mongo/operation/get_more/op_msg.rb +33 -0
- data/lib/mongo/operation/insert/op_msg.rb +3 -2
- data/lib/mongo/operation/insert/result.rb +4 -2
- data/lib/mongo/operation/list_collections/result.rb +1 -1
- data/lib/mongo/operation/map_reduce/result.rb +1 -1
- data/lib/mongo/operation/op_msg_base.rb +3 -1
- data/lib/mongo/operation/result.rb +26 -5
- data/lib/mongo/operation/shared/executable.rb +12 -1
- data/lib/mongo/operation/shared/op_msg_executable.rb +4 -1
- data/lib/mongo/operation/shared/response_handling.rb +3 -3
- data/lib/mongo/operation/shared/sessions_supported.rb +1 -1
- data/lib/mongo/operation/shared/timed.rb +52 -0
- data/lib/mongo/operation/shared/write.rb +4 -1
- data/lib/mongo/operation/update/op_msg.rb +2 -1
- data/lib/mongo/operation/update_search_index/op_msg.rb +2 -2
- data/lib/mongo/operation.rb +1 -0
- data/lib/mongo/protocol/message.rb +1 -4
- data/lib/mongo/protocol/msg.rb +2 -2
- data/lib/mongo/retryable/read_worker.rb +69 -29
- data/lib/mongo/retryable/write_worker.rb +49 -18
- data/lib/mongo/retryable.rb +8 -2
- data/lib/mongo/server/connection.rb +11 -5
- data/lib/mongo/server/connection_base.rb +22 -2
- data/lib/mongo/server/connection_pool.rb +32 -14
- data/lib/mongo/server/description/features.rb +1 -1
- data/lib/mongo/server/description.rb +18 -5
- data/lib/mongo/server/monitor.rb +7 -4
- data/lib/mongo/server/pending_connection.rb +7 -3
- data/lib/mongo/server/{round_trip_time_averager.rb → round_trip_time_calculator.rb} +25 -7
- data/lib/mongo/server.rb +11 -6
- data/lib/mongo/server_selector/base.rb +25 -9
- data/lib/mongo/session.rb +78 -9
- data/lib/mongo/socket/ssl.rb +109 -17
- data/lib/mongo/socket/tcp.rb +40 -6
- data/lib/mongo/socket.rb +154 -25
- data/lib/mongo/uri/options_mapper.rb +1 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo.rb +1 -0
- data/spec/atlas/atlas_connectivity_spec.rb +4 -0
- data/spec/atlas/operations_spec.rb +4 -0
- data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +2 -1
- data/spec/integration/client_side_encryption/auto_encryption_spec.rb +494 -487
- data/spec/integration/client_side_encryption/on_demand_aws_credentials_spec.rb +1 -1
- data/spec/integration/client_side_encryption/range_explicit_encryption_prose_spec.rb +66 -22
- data/spec/integration/client_side_operations_timeout/encryption_prose_spec.rb +131 -0
- data/spec/integration/connection_pool_populator_spec.rb +2 -0
- data/spec/integration/cursor_pinning_spec.rb +15 -60
- data/spec/integration/cursor_reaping_spec.rb +1 -1
- data/spec/integration/docs_examples_spec.rb +1 -1
- data/spec/integration/operation_failure_code_spec.rb +1 -1
- data/spec/integration/operation_failure_message_spec.rb +3 -3
- data/spec/integration/retryable_errors_spec.rb +2 -2
- data/spec/integration/sdam_error_handling_spec.rb +2 -1
- data/spec/integration/search_indexes_prose_spec.rb +4 -0
- data/spec/integration/server_spec.rb +4 -3
- data/spec/integration/transactions_api_examples_spec.rb +2 -0
- data/spec/kerberos/kerberos_spec.rb +4 -0
- data/spec/lite_spec_helper.rb +3 -1
- data/spec/mongo/auth/user/view_spec.rb +1 -1
- data/spec/mongo/caching_cursor_spec.rb +1 -1
- data/spec/mongo/client_encryption_spec.rb +1 -0
- data/spec/mongo/client_spec.rb +158 -4
- data/spec/mongo/collection/view/aggregation_spec.rb +14 -39
- data/spec/mongo/collection/view/change_stream_spec.rb +3 -3
- data/spec/mongo/collection_spec.rb +5 -6
- data/spec/mongo/crypt/auto_encrypter_spec.rb +14 -12
- data/spec/mongo/crypt/data_key_context_spec.rb +3 -1
- data/spec/mongo/crypt/explicit_encryption_context_spec.rb +2 -2
- data/spec/mongo/crypt/handle_spec.rb +1 -1
- data/spec/mongo/cursor_spec.rb +26 -9
- data/spec/mongo/error/operation_failure_heavy_spec.rb +2 -2
- data/spec/mongo/operation/context_spec.rb +79 -0
- data/spec/mongo/operation/create/op_msg_spec.rb +106 -110
- data/spec/mongo/operation/delete/op_msg_spec.rb +6 -5
- data/spec/mongo/operation/find/op_msg_spec.rb +66 -0
- data/spec/mongo/operation/get_more/op_msg_spec.rb +65 -0
- data/spec/mongo/operation/insert/op_msg_spec.rb +128 -131
- data/spec/mongo/operation/shared/csot/examples.rb +113 -0
- data/spec/mongo/query_cache_spec.rb +243 -225
- data/spec/mongo/retryable_spec.rb +1 -0
- data/spec/mongo/server/round_trip_time_calculator_spec.rb +120 -0
- data/spec/mongo/socket/ssl_spec.rb +0 -10
- data/spec/runners/change_streams/test.rb +2 -2
- data/spec/runners/crud/operation.rb +1 -1
- data/spec/runners/crud/verifier.rb +3 -1
- data/spec/runners/transactions/operation.rb +4 -6
- data/spec/runners/unified/ambiguous_operations.rb +13 -0
- data/spec/runners/unified/assertions.rb +4 -0
- data/spec/runners/unified/change_stream_operations.rb +14 -24
- data/spec/runners/unified/crud_operations.rb +82 -59
- data/spec/runners/unified/ddl_operations.rb +38 -7
- data/spec/runners/unified/grid_fs_operations.rb +37 -2
- data/spec/runners/unified/support_operations.rb +43 -4
- data/spec/runners/unified/test.rb +22 -10
- data/spec/runners/unified.rb +1 -1
- data/spec/solo/clean_exit_spec.rb +2 -0
- data/spec/spec_tests/client_side_operations_timeout_spec.rb +15 -0
- data/spec/spec_tests/data/change_streams_unified/change-streams-clusterTime.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-disambiguatedPaths.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-errors.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-pre_and_post_images.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-resume-allowlist.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +1 -1
- data/spec/spec_tests/data/client_side_encryption/badQueries.yml +2 -1
- data/spec/spec_tests/data/client_side_encryption/timeoutMS.yml +67 -0
- data/spec/spec_tests/data/client_side_operations_timeout/bulkWrite.yml +87 -0
- data/spec/spec_tests/data/client_side_operations_timeout/change-streams.yml +358 -0
- data/spec/spec_tests/data/client_side_operations_timeout/close-cursors.yml +129 -0
- data/spec/spec_tests/data/client_side_operations_timeout/command-execution.yml +250 -0
- data/spec/spec_tests/data/client_side_operations_timeout/convenient-transactions.yml +113 -0
- data/spec/spec_tests/data/client_side_operations_timeout/cursors.yml +70 -0
- data/spec/spec_tests/data/client_side_operations_timeout/deprecated-options.yml +3982 -0
- data/spec/spec_tests/data/client_side_operations_timeout/error-transformations.yml +96 -0
- data/spec/spec_tests/data/client_side_operations_timeout/global-timeoutMS.yml +3236 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-advanced.yml +207 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-delete.yml +152 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-download.yml +182 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-find.yml +100 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-upload.yml +249 -0
- data/spec/spec_tests/data/client_side_operations_timeout/legacy-timeouts.yml +204 -0
- data/spec/spec_tests/data/client_side_operations_timeout/non-tailable-cursors.yml +307 -0
- data/spec/spec_tests/data/client_side_operations_timeout/override-collection-timeoutMS.yml +1877 -0
- data/spec/spec_tests/data/client_side_operations_timeout/override-operation-timeoutMS.yml +1918 -0
- data/spec/spec_tests/data/client_side_operations_timeout/retryability-legacy-timeouts.yml +1676 -0
- data/spec/spec_tests/data/client_side_operations_timeout/retryability-timeoutMS.yml +2824 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-inherit-timeoutMS.yml +168 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-operation-timeoutMS.yml +171 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-timeoutMS.yml +168 -0
- data/spec/spec_tests/data/client_side_operations_timeout/tailable-awaitData.yml +247 -0
- data/spec/spec_tests/data/client_side_operations_timeout/tailable-non-awaitData.yml +181 -0
- data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +4 -0
- data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +4 -0
- data/spec/spec_tests/data/crud_unified/find-test-all-options.yml +29 -0
- data/spec/spec_tests/server_selection_rtt_spec.rb +6 -6
- data/spec/support/certificates/atlas-ocsp-ca.crt +81 -83
- data/spec/support/certificates/atlas-ocsp.crt +107 -107
- data/spec/support/cluster_tools.rb +3 -3
- data/spec/support/common_shortcuts.rb +2 -2
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Date.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalNoPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoubleNoPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoublePrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Int.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Long.json +1 -1
- data/spec/support/shared/session.rb +2 -2
- data/spec/support/spec_setup.rb +2 -2
- data/spec/support/utils.rb +3 -1
- metadata +78 -91
- data/spec/mongo/server/round_trip_time_averager_spec.rb +0 -48
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Correctness.yml +0 -423
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Update.yml +0 -253
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Aggregate.yml +0 -1688
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Correctness.yml +0 -294
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Delete.yml +0 -906
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-FindOneAndUpdate.yml +0 -1685
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-InsertFind.yml +0 -1681
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Update.yml +0 -1698
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Aggregate.yml +0 -330
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Correctness.yml +0 -425
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Delete.yml +0 -227
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.yml +0 -328
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-InsertFind.yml +0 -320
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Update.yml +0 -337
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Aggregate.yml +0 -914
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Correctness.yml +0 -293
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Delete.yml +0 -519
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-FindOneAndUpdate.yml +0 -912
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-InsertFind.yml +0 -908
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Update.yml +0 -925
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Aggregate.yml +0 -326
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Correctness.yml +0 -425
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Delete.yml +0 -225
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-FindOneAndUpdate.yml +0 -324
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-InsertFind.yml +0 -320
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Update.yml +0 -339
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Correctness.yml +0 -424
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Update.yml +0 -255
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Correctness.yml +0 -423
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Update.yml +0 -255
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-WrongType.yml +0 -44
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mongo
|
4
|
+
class Collection
|
5
|
+
class View
|
6
|
+
class Aggregation
|
7
|
+
# Distills the behavior common to aggregator classes, like
|
8
|
+
# View::Aggregator and View::ChangeStream.
|
9
|
+
module Behavior
|
10
|
+
extend Forwardable
|
11
|
+
include Enumerable
|
12
|
+
include Immutable
|
13
|
+
include Iterable
|
14
|
+
include Explainable
|
15
|
+
include Loggable
|
16
|
+
include Retryable
|
17
|
+
|
18
|
+
# @return [ View ] view The collection view.
|
19
|
+
attr_reader :view
|
20
|
+
|
21
|
+
# Delegate necessary operations to the view.
|
22
|
+
def_delegators :view, :collection, :read, :cluster, :cursor_type, :limit, :batch_size
|
23
|
+
|
24
|
+
# Delegate necessary operations to the collection.
|
25
|
+
def_delegators :collection, :database, :client
|
26
|
+
|
27
|
+
# Set to true if disk usage is allowed during the aggregation.
|
28
|
+
#
|
29
|
+
# @example Set disk usage flag.
|
30
|
+
# aggregation.allow_disk_use(true)
|
31
|
+
#
|
32
|
+
# @param [ true, false ] value The flag value.
|
33
|
+
#
|
34
|
+
# @return [ true, false, Aggregation ] The aggregation if a value was
|
35
|
+
# set or the value if used as a getter.
|
36
|
+
#
|
37
|
+
# @since 2.0.0
|
38
|
+
def allow_disk_use(value = nil)
|
39
|
+
configure(:allow_disk_use, value)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get the explain plan for the aggregation.
|
43
|
+
#
|
44
|
+
# @example Get the explain plan for the aggregation.
|
45
|
+
# aggregation.explain
|
46
|
+
#
|
47
|
+
# @return [ Hash ] The explain plan.
|
48
|
+
#
|
49
|
+
# @since 2.0.0
|
50
|
+
def explain
|
51
|
+
self.class.new(view, pipeline, options.merge(explain: true)).first
|
52
|
+
end
|
53
|
+
|
54
|
+
# Whether this aggregation will write its result to a database collection.
|
55
|
+
#
|
56
|
+
# @return [ Boolean ] Whether the aggregation will write its result
|
57
|
+
# to a collection.
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
def write?
|
61
|
+
pipeline.any? { |op| op.key?('$out') || op.key?(:$out) || op.key?('$merge') || op.key?(:$merge) }
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [ Integer | nil ] the timeout_ms value that was passed as
|
65
|
+
# an option to this object, or which was inherited from the view.
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
def timeout_ms
|
69
|
+
@timeout_ms || view.timeout_ms
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Common setup for all classes that include this behavior; the
|
75
|
+
# constructor should invoke this method.
|
76
|
+
def perform_setup(view, options, forbid: [])
|
77
|
+
@view = view
|
78
|
+
|
79
|
+
@timeout_ms = options.delete(:timeout_ms)
|
80
|
+
@options = BSON::Document.new(options).freeze
|
81
|
+
|
82
|
+
yield
|
83
|
+
|
84
|
+
validate_timeout_mode!(options, forbid: forbid)
|
85
|
+
end
|
86
|
+
|
87
|
+
def server_selector
|
88
|
+
@view.send(:server_selector)
|
89
|
+
end
|
90
|
+
|
91
|
+
def aggregate_spec(session, read_preference)
|
92
|
+
Builder::Aggregation.new(
|
93
|
+
pipeline,
|
94
|
+
view,
|
95
|
+
options.merge(session: session, read_preference: read_preference)
|
96
|
+
).specification
|
97
|
+
end
|
98
|
+
|
99
|
+
# Skip, sort, limit, projection are specified as pipeline stages
|
100
|
+
# rather than as options.
|
101
|
+
def cache_options
|
102
|
+
{
|
103
|
+
namespace: collection.namespace,
|
104
|
+
selector: pipeline,
|
105
|
+
read_concern: view.read_concern,
|
106
|
+
read_preference: view.read_preference,
|
107
|
+
collation: options[:collation],
|
108
|
+
# Aggregations can read documents from more than one collection,
|
109
|
+
# so they will be cleared on every write operation.
|
110
|
+
multi_collection: true,
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
# @return [ Hash ] timeout_ms value set on the operation level (if any),
|
115
|
+
# and/or timeout_ms that is set on collection/database/client level (if any).
|
116
|
+
#
|
117
|
+
# @api private
|
118
|
+
def operation_timeouts(opts = {})
|
119
|
+
{}.tap do |result|
|
120
|
+
if opts[:timeout_ms] || @timeout_ms
|
121
|
+
result[:operation_timeout_ms] = opts.delete(:timeout_ms) || @timeout_ms
|
122
|
+
else
|
123
|
+
result[:inherited_timeout_ms] = view.timeout_ms
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -15,6 +15,8 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
|
+
require 'mongo/collection/view/aggregation/behavior'
|
19
|
+
|
18
20
|
module Mongo
|
19
21
|
class Collection
|
20
22
|
class View
|
@@ -23,46 +25,11 @@ module Mongo
|
|
23
25
|
#
|
24
26
|
# @since 2.0.0
|
25
27
|
class Aggregation
|
26
|
-
|
27
|
-
include Enumerable
|
28
|
-
include Immutable
|
29
|
-
include Iterable
|
30
|
-
include Explainable
|
31
|
-
include Loggable
|
32
|
-
include Retryable
|
28
|
+
include Behavior
|
33
29
|
|
34
|
-
# @return [ View ] view The collection view.
|
35
|
-
attr_reader :view
|
36
30
|
# @return [ Array<Hash> ] pipeline The aggregation pipeline.
|
37
31
|
attr_reader :pipeline
|
38
32
|
|
39
|
-
# Delegate necessary operations to the view.
|
40
|
-
def_delegators :view, :collection, :read, :cluster
|
41
|
-
|
42
|
-
# Delegate necessary operations to the collection.
|
43
|
-
def_delegators :collection, :database, :client
|
44
|
-
|
45
|
-
# The reroute message.
|
46
|
-
#
|
47
|
-
# @since 2.1.0
|
48
|
-
# @deprecated
|
49
|
-
REROUTE = 'Rerouting the Aggregation operation to the primary server.'.freeze
|
50
|
-
|
51
|
-
# Set to true if disk usage is allowed during the aggregation.
|
52
|
-
#
|
53
|
-
# @example Set disk usage flag.
|
54
|
-
# aggregation.allow_disk_use(true)
|
55
|
-
#
|
56
|
-
# @param [ true, false ] value The flag value.
|
57
|
-
#
|
58
|
-
# @return [ true, false, Aggregation ] The aggregation if a value was
|
59
|
-
# set or the value if used as a getter.
|
60
|
-
#
|
61
|
-
# @since 2.0.0
|
62
|
-
def allow_disk_use(value = nil)
|
63
|
-
configure(:allow_disk_use, value)
|
64
|
-
end
|
65
|
-
|
66
33
|
# Initialize the aggregation for the provided collection view, pipeline
|
67
34
|
# and options.
|
68
35
|
#
|
@@ -86,59 +53,29 @@ module Mongo
|
|
86
53
|
# @option options [ Hash ] :let Mapping of variables to use in the pipeline.
|
87
54
|
# See the server documentation for details.
|
88
55
|
# @option options [ Integer ] :max_time_ms The maximum amount of time in
|
89
|
-
# milliseconds to allow the aggregation to run.
|
90
|
-
#
|
91
|
-
# will request that the server provide results using a cursor. Note that
|
92
|
-
# as of server version 3.6, aggregations always provide results using a
|
93
|
-
# cursor and this option is therefore not valid.
|
56
|
+
# milliseconds to allow the aggregation to run. This option is deprecated, use
|
57
|
+
# :timeout_ms instead.
|
94
58
|
# @option options [ Session ] :session The session to use.
|
59
|
+
# @option options [ :cursor_lifetime | :iteration ] :timeout_mode How to interpret
|
60
|
+
# :timeout_ms (whether it applies to the lifetime of the cursor, or per
|
61
|
+
# iteration).
|
62
|
+
# @option options [ Integer ] :timeout_ms The operation timeout in milliseconds.
|
63
|
+
# Must be a non-negative integer. An explicit value of 0 means infinite.
|
64
|
+
# The default value is unset which means the value is inherited from
|
65
|
+
# the collection or the database or the client.
|
95
66
|
#
|
96
67
|
# @since 2.0.0
|
97
68
|
def initialize(view, pipeline, options = {})
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
69
|
+
perform_setup(view, options) do
|
70
|
+
@pipeline = pipeline.dup
|
71
|
+
unless Mongo.broken_view_aggregate || view.filter.empty?
|
72
|
+
@pipeline.unshift(:$match => view.filter)
|
73
|
+
end
|
102
74
|
end
|
103
|
-
@options = BSON::Document.new(options).freeze
|
104
|
-
end
|
105
|
-
|
106
|
-
# Get the explain plan for the aggregation.
|
107
|
-
#
|
108
|
-
# @example Get the explain plan for the aggregation.
|
109
|
-
# aggregation.explain
|
110
|
-
#
|
111
|
-
# @return [ Hash ] The explain plan.
|
112
|
-
#
|
113
|
-
# @since 2.0.0
|
114
|
-
def explain
|
115
|
-
self.class.new(view, pipeline, options.merge(explain: true)).first
|
116
|
-
end
|
117
|
-
|
118
|
-
# Whether this aggregation will write its result to a database collection.
|
119
|
-
#
|
120
|
-
# @return [ Boolean ] Whether the aggregation will write its result
|
121
|
-
# to a collection.
|
122
|
-
#
|
123
|
-
# @api private
|
124
|
-
def write?
|
125
|
-
pipeline.any? { |op| op.key?('$out') || op.key?(:$out) || op.key?('$merge') || op.key?(:$merge) }
|
126
75
|
end
|
127
76
|
|
128
77
|
private
|
129
78
|
|
130
|
-
def server_selector
|
131
|
-
@view.send(:server_selector)
|
132
|
-
end
|
133
|
-
|
134
|
-
def aggregate_spec(session, read_preference)
|
135
|
-
Builder::Aggregation.new(
|
136
|
-
pipeline,
|
137
|
-
view,
|
138
|
-
options.merge(session: session, read_preference: read_preference)
|
139
|
-
).specification
|
140
|
-
end
|
141
|
-
|
142
79
|
def new(options)
|
143
80
|
Aggregation.new(view, pipeline, options)
|
144
81
|
end
|
@@ -180,32 +117,29 @@ module Mongo
|
|
180
117
|
|
181
118
|
end
|
182
119
|
|
183
|
-
def send_initial_query(server,
|
184
|
-
server.
|
120
|
+
def send_initial_query(server, context)
|
121
|
+
if server.load_balancer?
|
122
|
+
# Connection will be checked in when cursor is drained.
|
123
|
+
connection = server.pool.check_out(context: context)
|
185
124
|
initial_query_op(
|
186
|
-
session,
|
125
|
+
context.session,
|
187
126
|
effective_read_preference(connection)
|
188
127
|
).execute_with_connection(
|
189
128
|
connection,
|
190
|
-
context:
|
129
|
+
context: context
|
191
130
|
)
|
131
|
+
else
|
132
|
+
server.with_connection do |connection|
|
133
|
+
initial_query_op(
|
134
|
+
context.session,
|
135
|
+
effective_read_preference(connection)
|
136
|
+
).execute_with_connection(
|
137
|
+
connection,
|
138
|
+
context: context
|
139
|
+
)
|
140
|
+
end
|
192
141
|
end
|
193
142
|
end
|
194
|
-
|
195
|
-
# Skip, sort, limit, projection are specified as pipeline stages
|
196
|
-
# rather than as options.
|
197
|
-
def cache_options
|
198
|
-
{
|
199
|
-
namespace: collection.namespace,
|
200
|
-
selector: pipeline,
|
201
|
-
read_concern: view.read_concern,
|
202
|
-
read_preference: view.read_preference,
|
203
|
-
collation: options[:collation],
|
204
|
-
# Aggregations can read documents from more than one collection,
|
205
|
-
# so they will be cleared on every write operation.
|
206
|
-
multi_collection: true,
|
207
|
-
}
|
208
|
-
end
|
209
143
|
end
|
210
144
|
end
|
211
145
|
end
|
@@ -113,17 +113,11 @@ module Mongo
|
|
113
113
|
command[:readConcern] = Options::Mapper.transform_values_to_strings(
|
114
114
|
read_concern)
|
115
115
|
end
|
116
|
-
command[:cursor] =
|
116
|
+
command[:cursor] = batch_size_doc
|
117
117
|
command.merge!(Options::Mapper.transform_documents(options, MAPPINGS))
|
118
118
|
command
|
119
119
|
end
|
120
120
|
|
121
|
-
def cursor
|
122
|
-
if options[:use_cursor] == true || options[:use_cursor].nil?
|
123
|
-
batch_size_doc
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
121
|
def batch_size_doc
|
128
122
|
value = options[:batch_size] || view.batch_size
|
129
123
|
if value == 0 && write?
|
@@ -15,6 +15,7 @@
|
|
15
15
|
# See the License for the specific language governing permissions and
|
16
16
|
# limitations under the License.
|
17
17
|
|
18
|
+
require 'mongo/collection/view/aggregation/behavior'
|
18
19
|
require 'mongo/collection/view/change_stream/retryable'
|
19
20
|
|
20
21
|
module Mongo
|
@@ -35,7 +36,8 @@ module Mongo
|
|
35
36
|
#
|
36
37
|
#
|
37
38
|
# @since 2.5.0
|
38
|
-
class ChangeStream
|
39
|
+
class ChangeStream
|
40
|
+
include Aggregation::Behavior
|
39
41
|
include Retryable
|
40
42
|
|
41
43
|
# @return [ String ] The fullDocument option default value.
|
@@ -60,6 +62,10 @@ module Mongo
|
|
60
62
|
# @since 2.5.0
|
61
63
|
attr_reader :options
|
62
64
|
|
65
|
+
# @return [ Cursor ] the underlying cursor for this operation
|
66
|
+
# @api private
|
67
|
+
attr_reader :cursor
|
68
|
+
|
63
69
|
# Initialize the change stream for the provided collection view, pipeline
|
64
70
|
# and options.
|
65
71
|
#
|
@@ -125,11 +131,13 @@ module Mongo
|
|
125
131
|
#
|
126
132
|
# @since 2.5.0
|
127
133
|
def initialize(view, pipeline, changes_for, options = {})
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
134
|
+
# change stream cursors can only be :iterable, so we don't allow
|
135
|
+
# timeout_mode to be specified.
|
136
|
+
perform_setup(view, options, forbid: %i[ timeout_mode ]) do
|
137
|
+
@changes_for = changes_for
|
138
|
+
@change_stream_filters = pipeline && pipeline.dup
|
139
|
+
@start_after = @options[:start_after]
|
140
|
+
end
|
133
141
|
|
134
142
|
# The resume token tracked by the change stream, used only
|
135
143
|
# when there is no cursor, or no cursor resume token
|
@@ -181,24 +189,30 @@ module Mongo
|
|
181
189
|
# @return [ BSON::Document | nil ] A change stream document.
|
182
190
|
# @since 2.6.0
|
183
191
|
def try_next
|
192
|
+
recreate_cursor! if @timed_out
|
193
|
+
|
184
194
|
raise StopIteration.new if closed?
|
195
|
+
|
185
196
|
begin
|
186
197
|
doc = @cursor.try_next
|
187
198
|
rescue Mongo::Error => e
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
199
|
+
# "If a next call fails with a timeout error, drivers MUST NOT
|
200
|
+
# invalidate the change stream. The subsequent next call MUST
|
201
|
+
# perform a resume attempt to establish a new change stream on the
|
202
|
+
# server..."
|
203
|
+
#
|
204
|
+
# However, SocketTimeoutErrors are TimeoutErrors, but are also
|
205
|
+
# change-stream-resumable. To preserve existing (specified) behavior,
|
206
|
+
# We only count timeouts when the error is not also
|
207
|
+
# change-stream-resumable.
|
208
|
+
@timed_out = e.is_a?(Mongo::Error::TimeoutError) && !e.change_stream_resumable?
|
209
|
+
|
210
|
+
raise unless @timed_out || e.change_stream_resumable?
|
195
211
|
|
196
|
-
# Save cursor's resume token so we can use it
|
197
|
-
# to create a new cursor
|
198
212
|
@resume_token = @cursor.resume_token
|
213
|
+
raise e if @timed_out
|
199
214
|
|
200
|
-
|
201
|
-
create_cursor!
|
215
|
+
recreate_cursor!(@cursor.context)
|
202
216
|
retry
|
203
217
|
end
|
204
218
|
|
@@ -231,14 +245,17 @@ module Mongo
|
|
231
245
|
# This method ignores any errors that occur when closing the
|
232
246
|
# server-side cursor.
|
233
247
|
#
|
248
|
+
# @params [ Hash ] opts Options to be passed to the cursor close
|
249
|
+
# command.
|
250
|
+
#
|
234
251
|
# @return [ nil ] Always nil.
|
235
252
|
#
|
236
253
|
# @since 2.5.0
|
237
|
-
def close
|
254
|
+
def close(opts = {})
|
238
255
|
unless closed?
|
239
256
|
begin
|
240
|
-
@cursor.close
|
241
|
-
rescue Error::OperationFailure, Error::SocketError, Error::SocketTimeoutError, Error::MissingConnection
|
257
|
+
@cursor.close(opts)
|
258
|
+
rescue Error::OperationFailure::Family, Error::SocketError, Error::SocketTimeoutError, Error::MissingConnection
|
242
259
|
# ignore
|
243
260
|
end
|
244
261
|
@cursor = nil
|
@@ -284,6 +301,28 @@ module Mongo
|
|
284
301
|
cursor_resume_token || @resume_token
|
285
302
|
end
|
286
303
|
|
304
|
+
# "change streams are an abstraction around tailable-awaitData cursors..."
|
305
|
+
#
|
306
|
+
# @return :tailable_await
|
307
|
+
def cursor_type
|
308
|
+
:tailable_await
|
309
|
+
end
|
310
|
+
|
311
|
+
# "change streams...implicitly use ITERATION mode"
|
312
|
+
#
|
313
|
+
# @return :iteration
|
314
|
+
def timeout_mode
|
315
|
+
:iteration
|
316
|
+
end
|
317
|
+
|
318
|
+
# Returns the value of the max_await_time_ms option that was
|
319
|
+
# passed to this change stream.
|
320
|
+
#
|
321
|
+
# @return [ Integer | nil ] the max_await_time_ms value
|
322
|
+
def max_await_time_ms
|
323
|
+
options[:max_await_time_ms]
|
324
|
+
end
|
325
|
+
|
287
326
|
private
|
288
327
|
|
289
328
|
def for_cluster?
|
@@ -298,19 +337,23 @@ module Mongo
|
|
298
337
|
!for_cluster? && !for_database?
|
299
338
|
end
|
300
339
|
|
301
|
-
def create_cursor!
|
340
|
+
def create_cursor!(timeout_ms = nil)
|
302
341
|
# clear the cache because we may get a newer or an older server
|
303
342
|
# (rolling upgrades)
|
304
343
|
@start_at_operation_time_supported = nil
|
305
344
|
|
306
|
-
session = client.
|
345
|
+
session = client.get_session(@options)
|
346
|
+
context = Operation::Context.new(client: client, session: session, view: self, operation_timeouts: timeout_ms ? { operation_timeout_ms: timeout_ms } : operation_timeouts)
|
347
|
+
|
307
348
|
start_at_operation_time = nil
|
308
349
|
start_at_operation_time_supported = nil
|
309
|
-
|
350
|
+
|
351
|
+
@cursor = read_with_retry_cursor(session, server_selector, self, context: context) do |server|
|
310
352
|
server.with_connection do |connection|
|
311
353
|
start_at_operation_time_supported = connection.description.server_version_gte?('4.0')
|
312
354
|
|
313
|
-
result = send_initial_query(connection,
|
355
|
+
result = send_initial_query(connection, context)
|
356
|
+
|
314
357
|
if doc = result.replies.first && result.replies.first.documents.first
|
315
358
|
start_at_operation_time = doc['operationTime']
|
316
359
|
else
|
@@ -324,6 +367,7 @@ module Mongo
|
|
324
367
|
result
|
325
368
|
end
|
326
369
|
end
|
370
|
+
|
327
371
|
@start_at_operation_time = start_at_operation_time
|
328
372
|
@start_at_operation_time_supported = start_at_operation_time_supported
|
329
373
|
end
|
@@ -390,11 +434,11 @@ module Mongo
|
|
390
434
|
end
|
391
435
|
end
|
392
436
|
|
393
|
-
def send_initial_query(connection,
|
394
|
-
initial_query_op(session, view.read_preference)
|
437
|
+
def send_initial_query(connection, context)
|
438
|
+
initial_query_op(context.session, view.read_preference)
|
395
439
|
.execute_with_connection(
|
396
440
|
connection,
|
397
|
-
context:
|
441
|
+
context: context,
|
398
442
|
)
|
399
443
|
end
|
400
444
|
|
@@ -412,6 +456,15 @@ module Mongo
|
|
412
456
|
def resuming?
|
413
457
|
!!@resuming
|
414
458
|
end
|
459
|
+
|
460
|
+
# Recreates the current cursor (typically as a consequence of attempting
|
461
|
+
# to resume the change stream)
|
462
|
+
def recreate_cursor!(context = nil)
|
463
|
+
@timed_out = false
|
464
|
+
|
465
|
+
close
|
466
|
+
create_cursor!(context&.remaining_timeout_ms)
|
467
|
+
end
|
415
468
|
end
|
416
469
|
end
|
417
470
|
end
|