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.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +1 -1
  4. data/lib/mongo/auth/aws/request.rb +0 -1
  5. data/lib/mongo/client.rb +4 -0
  6. data/lib/mongo/collection/view/aggregation.rb +62 -17
  7. data/lib/mongo/collection/view/builder/aggregation.rb +11 -13
  8. data/lib/mongo/collection/view/builder/map_reduce.rb +5 -8
  9. data/lib/mongo/collection/view/change_stream.rb +7 -3
  10. data/lib/mongo/collection/view/iterable.rb +3 -20
  11. data/lib/mongo/collection/view/map_reduce.rb +3 -14
  12. data/lib/mongo/collection/view/readable.rb +24 -1
  13. data/lib/mongo/collection/view/writable.rb +23 -0
  14. data/lib/mongo/collection/view.rb +0 -1
  15. data/lib/mongo/collection.rb +21 -1
  16. data/lib/mongo/database/view.rb +4 -2
  17. data/lib/mongo/database.rb +6 -6
  18. data/lib/mongo/error/snapshot_session_invalid_server_version.rb +31 -0
  19. data/lib/mongo/error/snapshot_session_transaction_prohibited.rb +30 -0
  20. data/lib/mongo/error.rb +2 -0
  21. data/lib/mongo/operation/delete/op_msg.rb +2 -1
  22. data/lib/mongo/operation/find/builder/command.rb +1 -0
  23. data/lib/mongo/operation/result.rb +6 -0
  24. data/lib/mongo/operation/shared/executable.rb +4 -0
  25. data/lib/mongo/operation/shared/sessions_supported.rb +18 -2
  26. data/lib/mongo/operation/update/op_msg.rb +2 -1
  27. data/lib/mongo/query_cache.rb +2 -12
  28. data/lib/mongo/server/description/features.rb +3 -1
  29. data/lib/mongo/server/monitor/connection.rb +4 -10
  30. data/lib/mongo/server_selector/base.rb +26 -4
  31. data/lib/mongo/session.rb +19 -0
  32. data/lib/mongo/socket/ocsp_cache.rb +2 -3
  33. data/lib/mongo/socket.rb +1 -5
  34. data/lib/mongo/utils.rb +0 -6
  35. data/lib/mongo/version.rb +1 -1
  36. data/mongo.gemspec +1 -1
  37. data/spec/integration/query_cache_spec.rb +0 -159
  38. data/spec/integration/read_preference_spec.rb +16 -12
  39. data/spec/integration/sdam_events_spec.rb +0 -40
  40. data/spec/lite_spec_helper.rb +0 -7
  41. data/spec/mongo/collection/view/aggregation_spec.rb +71 -95
  42. data/spec/mongo/collection/view/change_stream_spec.rb +1 -1
  43. data/spec/mongo/collection/view/map_reduce_spec.rb +14 -17
  44. data/spec/mongo/collection/view/readable_spec.rb +0 -56
  45. data/spec/mongo/operation/read_preference_op_msg_spec.rb +24 -1
  46. data/spec/mongo/query_cache_spec.rb +0 -165
  47. data/spec/mongo/server_selector_spec.rb +136 -15
  48. data/spec/mongo/socket/ssl_spec.rb +26 -58
  49. data/spec/mongo/utils_spec.rb +0 -14
  50. data/spec/runners/auth.rb +1 -1
  51. data/spec/runners/change_streams/spec.rb +1 -1
  52. data/spec/runners/cmap.rb +1 -1
  53. data/spec/runners/command_monitoring.rb +1 -1
  54. data/spec/runners/connection_string.rb +1 -1
  55. data/spec/runners/crud/spec.rb +3 -1
  56. data/spec/runners/crud/verifier.rb +1 -2
  57. data/spec/runners/gridfs.rb +1 -1
  58. data/spec/runners/read_write_concern_document.rb +1 -1
  59. data/spec/runners/sdam.rb +1 -1
  60. data/spec/runners/server_selection.rb +1 -1
  61. data/spec/runners/server_selection_rtt.rb +1 -1
  62. data/spec/runners/unified/assertions.rb +3 -1
  63. data/spec/runners/unified/crud_operations.rb +77 -23
  64. data/spec/runners/unified/ddl_operations.rb +29 -1
  65. data/spec/runners/unified/entity_map.rb +3 -3
  66. data/spec/runners/unified/support_operations.rb +6 -1
  67. data/spec/runners/unified/test.rb +15 -3
  68. data/spec/runners/unified/test_group.rb +1 -1
  69. data/spec/shared/share/Dockerfile.erb +3 -3
  70. data/spec/shared/shlib/server.sh +1 -1
  71. data/spec/spec_tests/data/crud_unified/aggregate-let.yml +138 -0
  72. data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +155 -0
  73. data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +151 -0
  74. data/spec/spec_tests/data/crud_unified/deleteMany-let.yml +91 -0
  75. data/spec/spec_tests/data/crud_unified/deleteOne-let.yml +89 -0
  76. data/spec/spec_tests/data/crud_unified/find-let.yml +71 -0
  77. data/spec/spec_tests/data/crud_unified/findOneAndDelete-let.yml +88 -0
  78. data/spec/spec_tests/data/crud_unified/findOneAndReplace-let.yml +94 -0
  79. data/spec/spec_tests/data/crud_unified/findOneAndUpdate-let.yml +96 -0
  80. data/spec/spec_tests/data/crud_unified/updateMany-let.yml +103 -0
  81. data/spec/spec_tests/data/crud_unified/updateOne-let.yml +98 -0
  82. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +2 -2
  83. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +3 -3
  84. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest.yml +3 -3
  85. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +3 -3
  86. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +2 -2
  87. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +2 -2
  88. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/Secondary.yml +4 -4
  89. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +2 -2
  90. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +4 -4
  91. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/ZeroMaxStaleness.yml +2 -2
  92. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +2 -2
  93. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +3 -3
  94. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat.yml +2 -2
  95. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/LongHeartbeat2.yml +2 -2
  96. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +2 -2
  97. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +2 -2
  98. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest.yml +3 -3
  99. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +3 -3
  100. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +2 -2
  101. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +2 -2
  102. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +2 -2
  103. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +5 -5
  104. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +3 -3
  105. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +5 -5
  106. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +3 -3
  107. data/spec/spec_tests/data/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +2 -2
  108. data/spec/spec_tests/data/max_staleness/Sharded/SmallMaxStaleness.yml +2 -2
  109. data/spec/spec_tests/data/max_staleness/Single/SmallMaxStaleness.yml +1 -1
  110. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -1
  111. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-client-error.yml +69 -0
  112. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-not-supported-server-error.yml +102 -0
  113. data/spec/spec_tests/data/sessions_unified/snapshot-sessions-unsupported-ops.yml +258 -0
  114. data/spec/spec_tests/data/sessions_unified/snapshot-sessions.yml +482 -0
  115. data/spec/spec_tests/seed_list_discovery_spec.rb +1 -1
  116. data/spec/spec_tests/sessions_unified_spec.rb +13 -0
  117. data/spec/support/certificates/atlas-ocsp-ca.crt +47 -40
  118. data/spec/support/certificates/atlas-ocsp.crt +106 -101
  119. data/spec/support/utils.rb +0 -31
  120. data.tar.gz.sig +0 -0
  121. metadata +1084 -1058
  122. metadata.gz.sig +0 -0
  123. data/spec/integration/find_options_spec.rb +0 -227
@@ -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
- :selector => operation.dup,
258
- :db_name => name,
259
- :read => preference,
260
- :session => session
261
- }).execute(server, context: Operation::Context.new(client: client, session: session))
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
- }.tap do |selector|
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
@@ -35,6 +35,7 @@ module Mongo
35
35
  comment: 'comment',
36
36
  filter: 'filter',
37
37
  hint: 'hint',
38
+ let: 'let',
38
39
  limit: 'limit',
39
40
  max_scan: 'maxScan',
40
41
  max_time_ms: 'maxTimeMS',
@@ -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
@@ -43,6 +43,10 @@ module Mongo
43
43
  session.pin_to_service(connection.service_id)
44
44
  end
45
45
  end
46
+
47
+ if session.snapshot? && !session.snapshot_timestamp
48
+ session.snapshot_timestamp = result.snapshot_timestamp
49
+ end
46
50
  end
47
51
  process_result(result, connection)
48
52
  end
@@ -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, and there is no default.
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)
@@ -37,7 +37,8 @@ module Mongo
37
37
  {
38
38
  update: coll_name,
39
39
  ordered: ordered?,
40
- }
40
+ let: spec[:let]
41
+ }.compact
41
42
  end
42
43
 
43
44
  def message(connection)
@@ -179,8 +179,7 @@ module Mongo
179
179
  #
180
180
  # @api private
181
181
  def get(**opts)
182
- limit = normalized_limit(opts[: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 = normalized_limit(caching_cursor.view.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 = (2..13).freeze
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
- doc = if hello_ok? || server_api
231
- _doc = HELLO_DOC
230
+ if hello_ok? || server_api
231
+ doc = HELLO_DOC
232
232
  if server_api
233
- _doc = _doc.merge(Utils.transform_server_api(server_api))
233
+ doc = doc.merge(Utils.transform_server_api(server_api))
234
234
  end
235
- _doc
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 = suitable_servers(cluster)
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 on Ruby 2.4+, or the OpenStruct
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 | OpenStruct ] The previously
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
- if RUBY_VERSION >= '2.4.0'
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
@@ -20,5 +20,5 @@ module Mongo
20
20
  # The current version of the driver.
21
21
  #
22
22
  # @since 2.0.0
23
- VERSION = '2.16.4'.freeze
23
+ VERSION = '2.17.0'.freeze
24
24
  end
data/mongo.gemspec CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |s|
36
36
  s.require_paths = ['lib']
37
37
  s.bindir = 'bin'
38
38
 
39
- s.required_ruby_version = ">= 2.4"
39
+ s.required_ruby_version = ">= 2.5"
40
40
 
41
41
  s.add_dependency 'bson', '>=4.8.2', '<5.0.0'
42
42
  end
@@ -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)