mongo 2.16.4 → 2.17.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
- checksums.yaml.gz.sig +0 -0
- data/README.md +1 -1
- data/lib/mongo/auth/aws/request.rb +0 -1
- data/lib/mongo/client.rb +4 -0
- data/lib/mongo/collection/view/aggregation.rb +62 -17
- data/lib/mongo/collection/view/builder/aggregation.rb +11 -13
- data/lib/mongo/collection/view/builder/map_reduce.rb +5 -8
- data/lib/mongo/collection/view/change_stream.rb +7 -3
- data/lib/mongo/collection/view/iterable.rb +3 -20
- data/lib/mongo/collection/view/map_reduce.rb +3 -14
- data/lib/mongo/collection/view/readable.rb +24 -1
- data/lib/mongo/collection/view/writable.rb +23 -0
- data/lib/mongo/collection/view.rb +0 -1
- data/lib/mongo/collection.rb +21 -1
- data/lib/mongo/database/view.rb +4 -2
- data/lib/mongo/database.rb +6 -6
- data/lib/mongo/error/snapshot_session_invalid_server_version.rb +31 -0
- data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +30 -0
- data/lib/mongo/error.rb +2 -0
- data/lib/mongo/operation/delete/op_msg.rb +2 -1
- data/lib/mongo/operation/find/builder/command.rb +1 -0
- data/lib/mongo/operation/result.rb +6 -0
- data/lib/mongo/operation/shared/executable.rb +4 -0
- data/lib/mongo/operation/shared/sessions_supported.rb +18 -2
- data/lib/mongo/operation/update/op_msg.rb +2 -1
- data/lib/mongo/query_cache.rb +2 -12
- data/lib/mongo/server/description/features.rb +3 -1
- data/lib/mongo/server/monitor/connection.rb +4 -10
- data/lib/mongo/server_selector/base.rb +26 -4
- data/lib/mongo/session.rb +19 -0
- data/lib/mongo/socket/ocsp_cache.rb +2 -3
- data/lib/mongo/socket.rb +1 -5
- data/lib/mongo/utils.rb +0 -6
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +1 -1
- data/spec/integration/query_cache_spec.rb +0 -159
- data/spec/integration/read_preference_spec.rb +16 -12
- data/spec/integration/sdam_events_spec.rb +0 -40
- data/spec/lite_spec_helper.rb +0 -7
- data/spec/mongo/collection/view/aggregation_spec.rb +71 -95
- data/spec/mongo/collection/view/change_stream_spec.rb +1 -1
- data/spec/mongo/collection/view/map_reduce_spec.rb +14 -17
- data/spec/mongo/collection/view/readable_spec.rb +0 -56
- data/spec/mongo/operation/read_preference_op_msg_spec.rb +24 -1
- data/spec/mongo/query_cache_spec.rb +0 -165
- data/spec/mongo/server_selector_spec.rb +136 -15
- data/spec/mongo/socket/ssl_spec.rb +26 -58
- data/spec/mongo/utils_spec.rb +0 -14
- data/spec/runners/auth.rb +1 -1
- data/spec/runners/change_streams/spec.rb +1 -1
- data/spec/runners/cmap.rb +1 -1
- data/spec/runners/command_monitoring.rb +1 -1
- data/spec/runners/connection_string.rb +1 -1
- data/spec/runners/crud/spec.rb +3 -1
- data/spec/runners/crud/verifier.rb +1 -2
- data/spec/runners/gridfs.rb +1 -1
- data/spec/runners/read_write_concern_document.rb +1 -1
- data/spec/runners/sdam.rb +1 -1
- data/spec/runners/server_selection.rb +1 -1
- data/spec/runners/server_selection_rtt.rb +1 -1
- data/spec/runners/unified/assertions.rb +3 -1
- data/spec/runners/unified/crud_operations.rb +77 -23
- data/spec/runners/unified/ddl_operations.rb +29 -1
- data/spec/runners/unified/entity_map.rb +3 -3
- data/spec/runners/unified/support_operations.rb +6 -1
- data/spec/runners/unified/test.rb +15 -3
- data/spec/runners/unified/test_group.rb +1 -1
- data/spec/shared/share/Dockerfile.erb +3 -3
- data/spec/shared/shlib/server.sh +1 -1
- data/spec/spec_tests/data/crud_unified/aggregate-let.yml +138 -0
- data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +155 -0
- data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +151 -0
- data/spec/spec_tests/data/crud_unified/deleteMany-let.yml +91 -0
- data/spec/spec_tests/data/crud_unified/deleteOne-let.yml +89 -0
- data/spec/spec_tests/data/crud_unified/find-let.yml +71 -0
- data/spec/spec_tests/data/crud_unified/findOneAndDelete-let.yml +88 -0
- data/spec/spec_tests/data/crud_unified/findOneAndReplace-let.yml +94 -0
- data/spec/spec_tests/data/crud_unified/findOneAndUpdate-let.yml +96 -0
- data/spec/spec_tests/data/crud_unified/updateMany-let.yml +103 -0
- data/spec/spec_tests/data/crud_unified/updateOne-let.yml +98 -0
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Secondary.yml +4 -4
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +4 -4
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat2.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +2 -2
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +5 -5
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +5 -5
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
- data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/Sharded/SmallMaxStaleness.yml +2 -2
- data/spec/spec_tests/data/max_staleness/Single/SmallMaxStaleness.yml +1 -1
- data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -1
- data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-client-error.yml +69 -0
- data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-server-error.yml +102 -0
- data/spec/spec_tests/data/sessions_unified/snapshot-sessions-unsupported-ops.yml +258 -0
- data/spec/spec_tests/data/sessions_unified/snapshot-sessions.yml +482 -0
- data/spec/spec_tests/seed_list_discovery_spec.rb +1 -1
- data/spec/spec_tests/sessions_unified_spec.rb +13 -0
- data/spec/support/certificates/atlas-ocsp-ca.crt +47 -40
- data/spec/support/certificates/atlas-ocsp.crt +106 -101
- data/spec/support/utils.rb +0 -31
- data.tar.gz.sig +0 -0
- metadata +1084 -1058
- metadata.gz.sig +0 -0
- data/spec/integration/find_options_spec.rb +0 -227
data/lib/mongo/database.rb
CHANGED
@@ -253,12 +253,12 @@ module Mongo
|
|
253
253
|
|
254
254
|
client.send(:with_session, opts) do |session|
|
255
255
|
read_with_retry(session, preference) do |server|
|
256
|
-
Operation::Command.new(
|
257
|
-
:
|
258
|
-
:
|
259
|
-
:
|
260
|
-
:
|
261
|
-
|
256
|
+
Operation::Command.new(
|
257
|
+
selector: operation.dup,
|
258
|
+
db_name: name,
|
259
|
+
read: preference,
|
260
|
+
session: session,
|
261
|
+
).execute(server, context: Operation::Context.new(client: client, session: session))
|
262
262
|
end
|
263
263
|
end
|
264
264
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
# Copyright (C) 2021 MongoDB Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
module Mongo
|
19
|
+
class Error
|
20
|
+
|
21
|
+
# Exception raised if an operation using a snapshot session is
|
22
|
+
# directed to a pre-5.0 server.
|
23
|
+
class SnapshotSessionInvalidServerVersion < Error
|
24
|
+
|
25
|
+
# Instantiate the new exception.
|
26
|
+
def initialize
|
27
|
+
super("Snapshot reads require MongoDB 5.0 or later")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
# Copyright (C) 2021 MongoDB Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
module Mongo
|
19
|
+
class Error
|
20
|
+
|
21
|
+
# Exception raised if a transaction is attempted on a snapshot session.
|
22
|
+
class SnapshotSessionTransactionProhibited < Error
|
23
|
+
|
24
|
+
# Instantiate the new exception.
|
25
|
+
def initialize
|
26
|
+
super("Transactions are not supported in snapshot sessions")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/mongo/error.rb
CHANGED
@@ -223,6 +223,8 @@ require 'mongo/error/no_server_available'
|
|
223
223
|
require 'mongo/error/no_srv_records'
|
224
224
|
require 'mongo/error/session_ended'
|
225
225
|
require 'mongo/error/sessions_not_supported'
|
226
|
+
require 'mongo/error/snapshot_session_invalid_server_version'
|
227
|
+
require 'mongo/error/snapshot_session_transaction_prohibited'
|
226
228
|
require 'mongo/error/operation_failure'
|
227
229
|
require 'mongo/error/pool_closed_error'
|
228
230
|
require 'mongo/error/raise_original_error'
|
@@ -37,7 +37,8 @@ module Mongo
|
|
37
37
|
{ delete: coll_name,
|
38
38
|
Protocol::Msg::DATABASE_IDENTIFIER => db_name,
|
39
39
|
ordered: ordered?,
|
40
|
-
|
40
|
+
let: spec[:let],
|
41
|
+
}.compact.tap do |selector|
|
41
42
|
if hint = spec[:hint]
|
42
43
|
validate_hint_on_update(connection, selector)
|
43
44
|
selector[:hint] = hint
|
@@ -429,6 +429,12 @@ module Mongo
|
|
429
429
|
!!(first_document && first_document['writeConcernError'])
|
430
430
|
end
|
431
431
|
|
432
|
+
def snapshot_timestamp
|
433
|
+
if doc = reply.documents.first
|
434
|
+
doc['cursor']&.[]('atClusterTime') || doc['atClusterTime']
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
432
438
|
private
|
433
439
|
|
434
440
|
def aggregate_returned_count
|
@@ -199,8 +199,13 @@ module Mongo
|
|
199
199
|
read_doc
|
200
200
|
else
|
201
201
|
# In replica sets, read preference is passed to the server if one
|
202
|
-
# is specified by the application,
|
203
|
-
read&.to_doc
|
202
|
+
# is specified by the application, except for primary read preferences.
|
203
|
+
read_doc = BSON::Document.new(read&.to_doc || {})
|
204
|
+
if [nil, 'primary'].include?(read_doc['mode'])
|
205
|
+
nil
|
206
|
+
else
|
207
|
+
read_doc
|
208
|
+
end
|
204
209
|
end
|
205
210
|
|
206
211
|
if read_doc
|
@@ -224,6 +229,17 @@ module Mongo
|
|
224
229
|
then
|
225
230
|
sel[:recoveryToken] = session.recovery_token
|
226
231
|
end
|
232
|
+
|
233
|
+
if session.snapshot?
|
234
|
+
unless connection.description.server_version_gte?('5.0')
|
235
|
+
raise Error::SnapshotSessionInvalidServerVersion
|
236
|
+
end
|
237
|
+
|
238
|
+
sel[:readConcern] = {level: 'snapshot'}
|
239
|
+
if session.snapshot_timestamp
|
240
|
+
sel[:readConcern][:atClusterTime] = session.snapshot_timestamp
|
241
|
+
end
|
242
|
+
end
|
227
243
|
end
|
228
244
|
|
229
245
|
def build_message(connection, context)
|
data/lib/mongo/query_cache.rb
CHANGED
@@ -179,8 +179,7 @@ module Mongo
|
|
179
179
|
#
|
180
180
|
# @api private
|
181
181
|
def get(**opts)
|
182
|
-
limit =
|
183
|
-
|
182
|
+
limit = opts[:limit]
|
184
183
|
_namespace_key = namespace_key(**opts)
|
185
184
|
_cache_key = cache_key(**opts)
|
186
185
|
|
@@ -190,7 +189,7 @@ module Mongo
|
|
190
189
|
caching_cursor = namespace_hash[_cache_key]
|
191
190
|
return nil unless caching_cursor
|
192
191
|
|
193
|
-
caching_cursor_limit =
|
192
|
+
caching_cursor_limit = caching_cursor.view.limit
|
194
193
|
|
195
194
|
# There are two scenarios in which a caching cursor could fulfill the
|
196
195
|
# query:
|
@@ -200,7 +199,6 @@ module Mongo
|
|
200
199
|
#
|
201
200
|
# Otherwise, return nil because the stored cursor will not satisfy
|
202
201
|
# the query.
|
203
|
-
|
204
202
|
if limit && (caching_cursor_limit.nil? || caching_cursor_limit >= limit)
|
205
203
|
caching_cursor
|
206
204
|
elsif limit.nil? && caching_cursor_limit.nil?
|
@@ -210,14 +208,6 @@ module Mongo
|
|
210
208
|
end
|
211
209
|
end
|
212
210
|
|
213
|
-
def normalized_limit(limit)
|
214
|
-
return nil unless limit
|
215
|
-
# For the purposes of caching, a limit of 0 means no limit, as mongo treats it as such.
|
216
|
-
return nil if limit == 0
|
217
|
-
# For the purposes of caching, a negative limit is the same as as a positive limit.
|
218
|
-
limit.abs
|
219
|
-
end
|
220
|
-
|
221
211
|
private
|
222
212
|
|
223
213
|
def cache_key(**opts)
|
@@ -35,9 +35,11 @@ module Mongo
|
|
35
35
|
# - 8 => 4.2
|
36
36
|
# - 9 => 4.4
|
37
37
|
# - 13 => 5.0
|
38
|
+
# - 14 => 5.1
|
38
39
|
#
|
39
40
|
# @since 2.0.0
|
40
41
|
MAPPINGS = {
|
42
|
+
merge_out_on_secondary: 13,
|
41
43
|
retryable_write_error_label: 9,
|
42
44
|
commit_quorum: 9,
|
43
45
|
# Server versions older than 4.2 do not reliably validate options
|
@@ -78,7 +80,7 @@ module Mongo
|
|
78
80
|
# The wire protocol versions that this version of the driver supports.
|
79
81
|
#
|
80
82
|
# @since 2.0.0
|
81
|
-
DRIVER_WIRE_VERSIONS = (
|
83
|
+
DRIVER_WIRE_VERSIONS = (6..14).freeze
|
82
84
|
|
83
85
|
# Create the methods for each mapping to tell if they are supported.
|
84
86
|
#
|
@@ -227,21 +227,15 @@ module Mongo
|
|
227
227
|
# @api private
|
228
228
|
def check_document
|
229
229
|
server_api = @app_metadata.server_api || options[:server_api]
|
230
|
-
|
231
|
-
|
230
|
+
if hello_ok? || server_api
|
231
|
+
doc = HELLO_DOC
|
232
232
|
if server_api
|
233
|
-
|
233
|
+
doc = doc.merge(Utils.transform_server_api(server_api))
|
234
234
|
end
|
235
|
-
|
235
|
+
doc
|
236
236
|
else
|
237
237
|
LEGACY_HELLO_DOC
|
238
238
|
end
|
239
|
-
# compressors must be set to maintain correct compression status
|
240
|
-
# in the server description. See RUBY-2427
|
241
|
-
if compressors = options[:compressors]
|
242
|
-
doc = doc.merge(compression: compressors)
|
243
|
-
end
|
244
|
-
doc
|
245
239
|
end
|
246
240
|
|
247
241
|
private
|
@@ -162,6 +162,8 @@ module Mongo
|
|
162
162
|
# Deprecated and ignored.
|
163
163
|
# @param [ Session | nil ] session Optional session to take into account
|
164
164
|
# for mongos pinning. Added in version 2.10.0.
|
165
|
+
# @param [ true | false ] write_aggregation Whether we need a server that
|
166
|
+
# supports writing aggregations (e.g. with $merge/$out) on secondaries.
|
165
167
|
#
|
166
168
|
# @return [ Mongo::Server ] A server matching the server preference.
|
167
169
|
#
|
@@ -172,7 +174,7 @@ module Mongo
|
|
172
174
|
# lint mode is enabled.
|
173
175
|
#
|
174
176
|
# @since 2.0.0
|
175
|
-
def select_server(cluster, ping = nil, session = nil)
|
177
|
+
def select_server(cluster, ping = nil, session = nil, write_aggregation: false)
|
176
178
|
if cluster.topology.is_a?(Cluster::Topology::LoadBalanced)
|
177
179
|
return cluster.servers.first
|
178
180
|
end
|
@@ -243,7 +245,7 @@ module Mongo
|
|
243
245
|
=end
|
244
246
|
|
245
247
|
loop do
|
246
|
-
server = try_select_server(cluster)
|
248
|
+
server = try_select_server(cluster, write_aggregation: write_aggregation)
|
247
249
|
|
248
250
|
if server
|
249
251
|
unless cluster.topology.compatible?
|
@@ -294,11 +296,31 @@ module Mongo
|
|
294
296
|
# Tries to find a suitable server, returns the server if one is available
|
295
297
|
# or nil if there isn't a suitable server.
|
296
298
|
#
|
299
|
+
# @param [ Mongo::Cluster ] cluster The cluster from which to select
|
300
|
+
# an eligible server.
|
301
|
+
# @param [ true | false ] write_aggregation Whether we need a server that
|
302
|
+
# supports writing aggregations (e.g. with $merge/$out) on secondaries.
|
303
|
+
#
|
297
304
|
# @return [ Server | nil ] A suitable server, if one exists.
|
298
305
|
#
|
299
306
|
# @api private
|
300
|
-
def try_select_server(cluster)
|
301
|
-
servers =
|
307
|
+
def try_select_server(cluster, write_aggregation: false)
|
308
|
+
servers = if write_aggregation && cluster.replica_set?
|
309
|
+
# 1. Check if ALL servers in cluster support secondary writes.
|
310
|
+
is_write_supported = cluster.servers.reduce(true) do |res, server|
|
311
|
+
res && server.features.merge_out_on_secondary_enabled?
|
312
|
+
end
|
313
|
+
|
314
|
+
if is_write_supported
|
315
|
+
# 2. If all servers support secondary writes, we respect read preference.
|
316
|
+
suitable_servers(cluster)
|
317
|
+
else
|
318
|
+
# 3. Otherwise we fallback to primary for replica set.
|
319
|
+
[cluster.servers.detect(&:primary?)]
|
320
|
+
end
|
321
|
+
else
|
322
|
+
suitable_servers(cluster)
|
323
|
+
end
|
302
324
|
|
303
325
|
# This list of servers may be ordered in a specific way
|
304
326
|
# by the selector (e.g. for secondary preferred, the first
|
data/lib/mongo/session.rb
CHANGED
@@ -56,10 +56,16 @@ module Mongo
|
|
56
56
|
# - *:mode* -- the read preference as a string or symbol; valid values are
|
57
57
|
# *:primary*, *:primary_preferred*, *:secondary*, *:secondary_preferred*
|
58
58
|
# and *:nearest*.
|
59
|
+
# @option options [ true | false ] :snapshot Set up the session for
|
60
|
+
# snapshot reads.
|
59
61
|
#
|
60
62
|
# @since 2.5.0
|
61
63
|
# @api private
|
62
64
|
def initialize(server_session, client, options = {})
|
65
|
+
if options[:causal_consistency] && options[:snapshot]
|
66
|
+
raise ArgumentError, ':causal_consistency and :snapshot options cannot be both set on a session'
|
67
|
+
end
|
68
|
+
|
63
69
|
@server_session = server_session
|
64
70
|
options = options.dup
|
65
71
|
|
@@ -83,6 +89,12 @@ module Mongo
|
|
83
89
|
@client.cluster
|
84
90
|
end
|
85
91
|
|
92
|
+
# @return [ true | false ] Whether the session is configured for snapshot
|
93
|
+
# reads.
|
94
|
+
def snapshot?
|
95
|
+
!!options[:snapshot]
|
96
|
+
end
|
97
|
+
|
86
98
|
# @return [ BSON::Timestamp ] The latest seen operation time for this session.
|
87
99
|
#
|
88
100
|
# @since 2.5.0
|
@@ -506,6 +518,10 @@ module Mongo
|
|
506
518
|
=end
|
507
519
|
end
|
508
520
|
|
521
|
+
if snapshot?
|
522
|
+
raise Mongo::Error::SnapshotSessionTransactionProhibited
|
523
|
+
end
|
524
|
+
|
509
525
|
check_if_ended!
|
510
526
|
|
511
527
|
if within_states?(STARTING_TRANSACTION_STATE, TRANSACTION_IN_PROGRESS_STATE)
|
@@ -1024,6 +1040,9 @@ module Mongo
|
|
1024
1040
|
@server_session.txn_num
|
1025
1041
|
end
|
1026
1042
|
|
1043
|
+
# @api private
|
1044
|
+
attr_accessor :snapshot_timestamp
|
1045
|
+
|
1027
1046
|
private
|
1028
1047
|
|
1029
1048
|
# Get the read concern the session will use when starting a transaction.
|
@@ -21,8 +21,7 @@ module Mongo
|
|
21
21
|
# This module caches OCSP responses for their indicated validity time.
|
22
22
|
#
|
23
23
|
# The key is the CertificateId used for the OCSP request.
|
24
|
-
# The value is the SingleResponse
|
25
|
-
# emulation of it on Ruby 2.3.
|
24
|
+
# The value is the SingleResponse.
|
26
25
|
#
|
27
26
|
# @api private
|
28
27
|
module OcspCache
|
@@ -40,7 +39,7 @@ module Mongo
|
|
40
39
|
# expire by the time caller uses them. The caller should not perform
|
41
40
|
# update time checks on the returned response.
|
42
41
|
#
|
43
|
-
# @return [ OpenSSL::OCSP::SingleResponse
|
42
|
+
# @return [ OpenSSL::OCSP::SingleResponse ] The previously
|
44
43
|
# retrieved response.
|
45
44
|
module_function def get(cert_id)
|
46
45
|
resp = responses.detect do |resp|
|
data/lib/mongo/socket.rb
CHANGED
@@ -362,11 +362,7 @@ module Mongo
|
|
362
362
|
end
|
363
363
|
|
364
364
|
def allocate_string(capacity)
|
365
|
-
|
366
|
-
String.new('', :capacity => capacity, :encoding => 'BINARY')
|
367
|
-
else
|
368
|
-
('x'*capacity).force_encoding('BINARY')
|
369
|
-
end
|
365
|
+
String.new('', :capacity => capacity, :encoding => 'BINARY')
|
370
366
|
end
|
371
367
|
|
372
368
|
def read_buffer_size
|
data/lib/mongo/utils.rb
CHANGED
@@ -101,11 +101,5 @@ module Mongo
|
|
101
101
|
module_function def monotonic_time
|
102
102
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
103
103
|
end
|
104
|
-
|
105
|
-
# Hash#compact implementation for Ruby 2.3/2.4
|
106
|
-
# Implementation based on activesupport 5.2.3
|
107
|
-
module_function def slice_hash(hash, *keys)
|
108
|
-
keys.each_with_object({}) { |k, res| res[k] = hash[k] if hash.key?(k) }
|
109
|
-
end
|
110
104
|
end
|
111
105
|
end
|
data/lib/mongo/version.rb
CHANGED
data/mongo.gemspec
CHANGED
@@ -345,69 +345,18 @@ describe 'QueryCache' do
|
|
345
345
|
|
346
346
|
it 'uses the cache' do
|
347
347
|
results_limit_5 = authorized_collection.find.limit(5).to_a
|
348
|
-
results_limit_negative_5 = authorized_collection.find.limit(-5).to_a
|
349
348
|
results_limit_3 = authorized_collection.find.limit(3).to_a
|
350
|
-
results_limit_negative_3 = authorized_collection.find.limit(-3).to_a
|
351
349
|
results_no_limit = authorized_collection.find.to_a
|
352
|
-
results_limit_0 = authorized_collection.find.limit(0).to_a
|
353
|
-
|
354
|
-
|
355
|
-
expect(results_limit_5.length).to eq(5)
|
356
|
-
expect(results_limit_5.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4])
|
357
|
-
|
358
|
-
expect(results_limit_negative_5.length).to eq(5)
|
359
|
-
expect(results_limit_negative_5.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4])
|
360
|
-
|
361
|
-
expect(results_limit_3.length).to eq(3)
|
362
|
-
expect(results_limit_3.map { |r| r["test"] }).to eq([0, 1, 2])
|
363
|
-
|
364
|
-
expect(results_limit_negative_3.length).to eq(3)
|
365
|
-
expect(results_limit_negative_3.map { |r| r["test"] }).to eq([0, 1, 2])
|
366
|
-
|
367
|
-
expect(results_no_limit.length).to eq(10)
|
368
|
-
expect(results_no_limit.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
369
|
-
|
370
|
-
expect(results_limit_0.length).to eq(10)
|
371
|
-
expect(results_limit_0.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
372
|
-
|
373
|
-
expect(events.length).to eq(1)
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
context 'when the first query has a 0 limit' do
|
378
|
-
before do
|
379
|
-
authorized_collection.find.limit(0).to_a
|
380
|
-
end
|
381
|
-
|
382
|
-
it 'uses the cache' do
|
383
|
-
results_limit_5 = authorized_collection.find.limit(5).to_a
|
384
|
-
results_limit_negative_5 = authorized_collection.find.limit(-5).to_a
|
385
|
-
results_limit_3 = authorized_collection.find.limit(3).to_a
|
386
|
-
results_limit_negative_3 = authorized_collection.find.limit(-3).to_a
|
387
|
-
results_no_limit = authorized_collection.find.to_a
|
388
|
-
results_limit_0 = authorized_collection.find.limit(0).to_a
|
389
350
|
|
390
351
|
expect(results_limit_5.length).to eq(5)
|
391
352
|
expect(results_limit_5.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4])
|
392
353
|
|
393
|
-
expect(results_limit_negative_5.length).to eq(5)
|
394
|
-
expect(results_limit_negative_5.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4])
|
395
|
-
|
396
|
-
|
397
354
|
expect(results_limit_3.length).to eq(3)
|
398
355
|
expect(results_limit_3.map { |r| r["test"] }).to eq([0, 1, 2])
|
399
356
|
|
400
|
-
expect(results_limit_negative_3.length).to eq(3)
|
401
|
-
expect(results_limit_negative_3.map { |r| r["test"] }).to eq([0, 1, 2])
|
402
|
-
|
403
|
-
|
404
357
|
expect(results_no_limit.length).to eq(10)
|
405
358
|
expect(results_no_limit.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
406
359
|
|
407
|
-
|
408
|
-
expect(results_limit_0.length).to eq(10)
|
409
|
-
expect(results_limit_0.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
410
|
-
|
411
360
|
expect(events.length).to eq(1)
|
412
361
|
end
|
413
362
|
end
|
@@ -442,21 +391,6 @@ describe 'QueryCache' do
|
|
442
391
|
end
|
443
392
|
end
|
444
393
|
|
445
|
-
context 'and two queries are performed with a larger negative limit' do
|
446
|
-
it 'uses the query cache for the third query' do
|
447
|
-
results1 = authorized_collection.find.limit(-3).to_a
|
448
|
-
results2 = authorized_collection.find.limit(-3).to_a
|
449
|
-
|
450
|
-
expect(results1.length).to eq(3)
|
451
|
-
expect(results1.map { |r| r["test"] }).to eq([0, 1, 2])
|
452
|
-
|
453
|
-
expect(results2.length).to eq(3)
|
454
|
-
expect(results2.map { |r| r["test"] }).to eq([0, 1, 2])
|
455
|
-
|
456
|
-
expect(events.length).to eq(2)
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
394
|
context 'and the second query has a smaller limit' do
|
461
395
|
let(:results) { authorized_collection.find.limit(1).to_a }
|
462
396
|
|
@@ -467,99 +401,6 @@ describe 'QueryCache' do
|
|
467
401
|
end
|
468
402
|
end
|
469
403
|
|
470
|
-
context 'and the second query has a smaller negative limit' do
|
471
|
-
let(:results) { authorized_collection.find.limit(-1).to_a }
|
472
|
-
|
473
|
-
it 'uses the cached query' do
|
474
|
-
expect(results.count).to eq(1)
|
475
|
-
expect(results.first["test"]).to eq(0)
|
476
|
-
expect(events.length).to eq(1)
|
477
|
-
end
|
478
|
-
end
|
479
|
-
|
480
|
-
context 'and the second query has no limit' do
|
481
|
-
it 'queries again' do
|
482
|
-
expect(authorized_collection.find.to_a.count).to eq(10)
|
483
|
-
expect(events.length).to eq(2)
|
484
|
-
end
|
485
|
-
end
|
486
|
-
end
|
487
|
-
|
488
|
-
context 'when the first query has a negative limit' do
|
489
|
-
before do
|
490
|
-
authorized_collection.find.limit(-2).to_a
|
491
|
-
end
|
492
|
-
|
493
|
-
context 'and the second query has a larger limit' do
|
494
|
-
let(:results) { authorized_collection.find.limit(3).to_a }
|
495
|
-
|
496
|
-
it 'queries again' do
|
497
|
-
expect(results.length).to eq(3)
|
498
|
-
expect(results.map { |result| result["test"] }).to eq([0, 1, 2])
|
499
|
-
expect(events.length).to eq(2)
|
500
|
-
end
|
501
|
-
end
|
502
|
-
|
503
|
-
context 'and the second query has a larger negative limit' do
|
504
|
-
let(:results) { authorized_collection.find.limit(-3).to_a }
|
505
|
-
|
506
|
-
it 'queries again' do
|
507
|
-
expect(results.length).to eq(3)
|
508
|
-
expect(results.map { |result| result["test"] }).to eq([0, 1, 2])
|
509
|
-
expect(events.length).to eq(2)
|
510
|
-
end
|
511
|
-
end
|
512
|
-
|
513
|
-
context 'and two queries are performed with a larger limit' do
|
514
|
-
it 'uses the query cache for the third query' do
|
515
|
-
results1 = authorized_collection.find.limit(3).to_a
|
516
|
-
results2 = authorized_collection.find.limit(3).to_a
|
517
|
-
|
518
|
-
expect(results1.length).to eq(3)
|
519
|
-
expect(results1.map { |r| r["test"] }).to eq([0, 1, 2])
|
520
|
-
|
521
|
-
expect(results2.length).to eq(3)
|
522
|
-
expect(results2.map { |r| r["test"] }).to eq([0, 1, 2])
|
523
|
-
|
524
|
-
expect(events.length).to eq(2)
|
525
|
-
end
|
526
|
-
end
|
527
|
-
|
528
|
-
context 'and two queries are performed with a larger negative limit' do
|
529
|
-
it 'uses the query cache for the third query' do
|
530
|
-
results1 = authorized_collection.find.limit(-3).to_a
|
531
|
-
results2 = authorized_collection.find.limit(-3).to_a
|
532
|
-
|
533
|
-
expect(results1.length).to eq(3)
|
534
|
-
expect(results1.map { |r| r["test"] }).to eq([0, 1, 2])
|
535
|
-
|
536
|
-
expect(results2.length).to eq(3)
|
537
|
-
expect(results2.map { |r| r["test"] }).to eq([0, 1, 2])
|
538
|
-
|
539
|
-
expect(events.length).to eq(2)
|
540
|
-
end
|
541
|
-
end
|
542
|
-
|
543
|
-
context 'and the second query has a smaller limit' do
|
544
|
-
let(:results) { authorized_collection.find.limit(1).to_a }
|
545
|
-
|
546
|
-
it 'uses the cached query' do
|
547
|
-
expect(results.count).to eq(1)
|
548
|
-
expect(results.first["test"]).to eq(0)
|
549
|
-
expect(events.length).to eq(1)
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
context 'and the second query has a smaller negative limit' do
|
554
|
-
let(:results) { authorized_collection.find.limit(-1).to_a }
|
555
|
-
|
556
|
-
it 'uses the cached query' do
|
557
|
-
expect(results.count).to eq(1)
|
558
|
-
expect(results.first["test"]).to eq(0)
|
559
|
-
expect(events.length).to eq(1)
|
560
|
-
end
|
561
|
-
end
|
562
|
-
|
563
404
|
context 'and the second query has no limit' do
|
564
405
|
it 'queries again' do
|
565
406
|
expect(authorized_collection.find.to_a.count).to eq(10)
|