mongo 2.5.0.beta → 2.5.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.tar.gz.sig +0 -0
- data/lib/mongo/address.rb +1 -1
- data/lib/mongo/address/unix.rb +1 -1
- data/lib/mongo/auth/user.rb +0 -5
- data/lib/mongo/auth/user/view.rb +4 -4
- data/lib/mongo/bulk_write.rb +60 -32
- data/lib/mongo/client.rb +44 -8
- data/lib/mongo/cluster.rb +14 -12
- data/lib/mongo/cluster/periodic_executor.rb +106 -0
- data/lib/mongo/cluster/{cursor_reaper.rb → reapers/cursor_reaper.rb} +5 -37
- data/lib/mongo/cluster/reapers/socket_reaper.rb +59 -0
- data/lib/mongo/collection.rb +9 -6
- data/lib/mongo/collection/view.rb +2 -2
- data/lib/mongo/collection/view/builder/aggregation.rb +2 -1
- data/lib/mongo/collection/view/builder/find_command.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +14 -1
- data/lib/mongo/collection/view/map_reduce.rb +30 -13
- data/lib/mongo/collection/view/readable.rb +5 -5
- data/lib/mongo/collection/view/writable.rb +98 -51
- data/lib/mongo/error.rb +3 -0
- data/lib/mongo/error/invalid_txt_record.rb +27 -0
- data/lib/mongo/error/invalid_uri.rb +7 -6
- data/lib/mongo/error/mismatched_domain.rb +27 -0
- data/lib/mongo/error/no_srv_records.rb +26 -0
- data/lib/mongo/error/unsupported_features.rb +0 -18
- data/lib/mongo/index/view.rb +2 -2
- data/lib/mongo/operation.rb +1 -0
- data/lib/mongo/operation/causally_consistent.rb +33 -0
- data/lib/mongo/operation/commands.rb +2 -1
- data/lib/mongo/operation/commands/aggregate.rb +2 -7
- data/lib/mongo/operation/commands/count.rb +27 -0
- data/lib/mongo/operation/commands/distinct.rb +27 -0
- data/lib/mongo/operation/commands/find.rb +3 -1
- data/lib/mongo/operation/commands/map_reduce.rb +1 -0
- data/lib/mongo/operation/commands/parallel_scan.rb +1 -0
- data/lib/mongo/operation/specifiable.rb +12 -0
- data/lib/mongo/operation/uses_command_op_msg.rb +36 -5
- data/lib/mongo/operation/write.rb +0 -5
- data/lib/mongo/operation/write/bulk/bulkable.rb +4 -8
- data/lib/mongo/operation/write/bulk/mergable.rb +2 -0
- data/lib/mongo/operation/write/command/create_index.rb +19 -0
- data/lib/mongo/operation/write/command/create_user.rb +19 -0
- data/lib/mongo/operation/write/command/delete.rb +1 -2
- data/lib/mongo/operation/write/command/drop_index.rb +19 -0
- data/lib/mongo/operation/write/command/insert.rb +1 -2
- data/lib/mongo/operation/write/command/remove_user.rb +19 -0
- data/lib/mongo/operation/write/command/update.rb +1 -2
- data/lib/mongo/operation/write/command/update_user.rb +19 -0
- data/lib/mongo/operation/write/write_command_enabled.rb +1 -3
- data/lib/mongo/protocol/compressed.rb +2 -1
- data/lib/mongo/protocol/serializers.rb +6 -6
- data/lib/mongo/retryable.rb +48 -5
- data/lib/mongo/server.rb +15 -0
- data/lib/mongo/server/connection.rb +21 -1
- data/lib/mongo/server/connection_pool.rb +3 -0
- data/lib/mongo/server/connection_pool/queue.rb +50 -5
- data/lib/mongo/server/description.rb +11 -3
- data/lib/mongo/server/description/features.rb +26 -7
- data/lib/mongo/session.rb +133 -6
- data/lib/mongo/session/server_session.rb +30 -0
- data/lib/mongo/session/session_pool.rb +20 -20
- data/lib/mongo/uri.rb +88 -44
- data/lib/mongo/uri/srv_protocol.rb +158 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo/write_concern/normalizable.rb +12 -0
- data/mongo.gemspec +1 -2
- data/spec/mongo/address_spec.rb +12 -0
- data/spec/mongo/auth/user/view_spec.rb +1 -5
- data/spec/mongo/bulk_write_spec.rb +232 -401
- data/spec/mongo/change_stream_examples_spec.rb +150 -0
- data/spec/mongo/client_spec.rb +142 -2
- data/spec/mongo/cluster/cursor_reaper_spec.rb +0 -70
- data/spec/mongo/cluster/socket_reaper_spec.rb +32 -0
- data/spec/mongo/cluster_spec.rb +11 -7
- data/spec/mongo/collection/view/aggregation_spec.rb +46 -1
- data/spec/mongo/collection/view/builder/find_command_spec.rb +15 -0
- data/spec/mongo/collection/view/change_stream_spec.rb +79 -12
- data/spec/mongo/collection/view/map_reduce_spec.rb +120 -4
- data/spec/mongo/collection/view/readable_spec.rb +23 -5
- data/spec/mongo/collection_spec.rb +292 -102
- data/spec/mongo/command_monitoring_spec.rb +26 -32
- data/spec/mongo/crud_spec.rb +1 -1
- data/spec/mongo/cursor_spec.rb +2 -3
- data/spec/mongo/database_spec.rb +30 -14
- data/spec/mongo/dns_seedlist_discovery_spec.rb +94 -0
- data/spec/mongo/grid/fs_bucket_spec.rb +1 -1
- data/spec/mongo/grid/stream/write_spec.rb +1 -1
- data/spec/mongo/index/view_spec.rb +8 -46
- data/spec/mongo/operation/write/bulk/delete_spec.rb +2 -2
- data/spec/mongo/operation/write/bulk/insert_spec.rb +2 -10
- data/spec/mongo/operation/write/{create_index_spec.rb → command/create_index_spec.rb} +2 -6
- data/spec/mongo/operation/write/command/delete_spec.rb +35 -7
- data/spec/mongo/operation/write/{drop_index_spec.rb → command/drop_index_spec.rb} +1 -1
- data/spec/mongo/operation/write/command/insert_spec.rb +37 -6
- data/spec/mongo/operation/write/{remove_user_spec.rb → command/remove_user_spec.rb} +2 -6
- data/spec/mongo/operation/write/command/update_spec.rb +34 -7
- data/spec/mongo/operation/write/{update_user_spec.rb → command/update_user_spec.rb} +1 -1
- data/spec/mongo/operation/write/create_user_spec.rb +1 -1
- data/spec/mongo/operation/write/delete_spec.rb +1 -1
- data/spec/mongo/operation/write/insert_spec.rb +2 -10
- data/spec/mongo/operation/write/update_spec.rb +3 -15
- data/spec/mongo/retryable_spec.rb +1 -1
- data/spec/mongo/retryable_writes_spec.rb +815 -0
- data/spec/mongo/server/connection_pool/queue_spec.rb +35 -2
- data/spec/mongo/server/connection_pool_spec.rb +234 -1
- data/spec/mongo/server/connection_spec.rb +10 -6
- data/spec/mongo/server/description/features_spec.rb +51 -37
- data/spec/mongo/server/description_spec.rb +6 -3
- data/spec/mongo/server_spec.rb +87 -0
- data/spec/mongo/session/server_session_spec.rb +43 -0
- data/spec/mongo/session/session_pool_spec.rb +63 -27
- data/spec/mongo/session_spec.rb +247 -0
- data/spec/mongo/shell_examples_spec.rb +2 -2
- data/spec/mongo/uri/srv_protocol_spec.rb +933 -0
- data/spec/mongo/uri_spec.rb +42 -3
- data/spec/mongo/write_concern/acknowledged_spec.rb +11 -0
- data/spec/mongo/write_concern/unacknowledged_spec.rb +11 -0
- data/spec/spec_helper.rb +11 -25
- data/spec/support/authorization.rb +2 -1
- data/spec/support/connection_string.rb +8 -4
- data/spec/support/crud.rb +38 -24
- data/spec/support/crud/write.rb +30 -3
- data/spec/support/crud_tests/read/aggregate-out.yml +21 -0
- data/spec/support/crud_tests/write/bulkWrite-arrayFilters.yml +44 -0
- data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +1 -1
- data/spec/support/crud_tests/write/insertMany.yml +1 -3
- data/spec/support/crud_tests/write/replaceOne.yml +1 -1
- data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +1 -1
- data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +1 -1
- data/spec/support/dns_seedlist_discovery_tests/longer-parent-in-return.yml +11 -0
- data/spec/support/dns_seedlist_discovery_tests/misformatted-option.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/no-results.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/not-enough-parts.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/one-result-default-port.yml +10 -0
- data/spec/support/dns_seedlist_discovery_tests/one-txt-record-multiple-strings.yml +10 -0
- data/spec/support/dns_seedlist_discovery_tests/one-txt-record.yml +11 -0
- data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch1.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch2.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch3.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch4.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch5.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/returned-parent-too-short.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/returned-parent-wrong.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/two-results-default-port.yml +11 -0
- data/spec/support/dns_seedlist_discovery_tests/two-results-nonstandard-port.yml +11 -0
- data/spec/support/dns_seedlist_discovery_tests/two-txt-records.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/txt-record-not-allowed-option.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/txt-record-with-overridden-ssl-option.yml +11 -0
- data/spec/support/dns_seedlist_discovery_tests/txt-record-with-overridden-uri-option.yml +11 -0
- data/spec/support/dns_seedlist_discovery_tests/txt-record-with-unallowed-option.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/uri-with-port.yml +5 -0
- data/spec/support/dns_seedlist_discovery_tests/uri-with-two-hosts.yml +5 -0
- data/spec/support/retryable_writes_tests/bulkWrite.yml +305 -0
- data/spec/support/retryable_writes_tests/deleteOne.yml +51 -0
- data/spec/support/retryable_writes_tests/findOneAndDelete.yml +52 -0
- data/spec/support/retryable_writes_tests/findOneAndReplace.yml +57 -0
- data/spec/support/retryable_writes_tests/findOneAndUpdate.yml +56 -0
- data/spec/support/retryable_writes_tests/insertMany.yml +72 -0
- data/spec/support/retryable_writes_tests/insertOne.yml +55 -0
- data/spec/support/retryable_writes_tests/replaceOne.yml +60 -0
- data/spec/support/retryable_writes_tests/updateOne.yml +120 -0
- data/spec/support/shared/session.rb +525 -24
- metadata +437 -350
- metadata.gz.sig +0 -0
- data/lib/mongo/operation/commands/user_query.rb +0 -72
- data/lib/mongo/operation/write/create_index.rb +0 -67
- data/lib/mongo/operation/write/create_user.rb +0 -50
- data/lib/mongo/operation/write/drop_index.rb +0 -63
- data/lib/mongo/operation/write/remove_user.rb +0 -48
- data/lib/mongo/operation/write/update_user.rb +0 -50
@@ -124,6 +124,11 @@ module Mongo
|
|
124
124
|
# @since 2.0.0
|
125
125
|
PRIMARY = 'ismaster'.freeze
|
126
126
|
|
127
|
+
# Constant for reading primary host field from config.
|
128
|
+
#
|
129
|
+
# @since 2.5.0
|
130
|
+
PRIMARY_HOST = 'primary'.freeze
|
131
|
+
|
127
132
|
# Constant for reading secondary info from config.
|
128
133
|
#
|
129
134
|
# @since 2.0.0
|
@@ -169,7 +174,8 @@ module Mongo
|
|
169
174
|
# @since 2.0.6
|
170
175
|
EXCLUDE_FOR_COMPARISON = [ LOCAL_TIME,
|
171
176
|
LAST_WRITE,
|
172
|
-
OPERATION_TIME
|
177
|
+
OPERATION_TIME,
|
178
|
+
Operation::CLUSTER_TIME ].freeze
|
173
179
|
|
174
180
|
# @return [ Address ] address The server's address.
|
175
181
|
attr_reader :address
|
@@ -258,7 +264,7 @@ module Mongo
|
|
258
264
|
def initialize(address, config = {}, average_round_trip_time = 0)
|
259
265
|
@address = address
|
260
266
|
@config = config
|
261
|
-
@features = Features.new(wire_versions)
|
267
|
+
@features = Features.new(wire_versions, me)
|
262
268
|
@average_round_trip_time = average_round_trip_time
|
263
269
|
end
|
264
270
|
|
@@ -464,7 +470,9 @@ module Mongo
|
|
464
470
|
#
|
465
471
|
# @since 2.0.0
|
466
472
|
def primary?
|
467
|
-
!!config[PRIMARY] &&
|
473
|
+
!!config[PRIMARY] &&
|
474
|
+
(config[PRIMARY_HOST].nil? || config[PRIMARY_HOST] == address.to_s) &&
|
475
|
+
!replica_set_name.nil?
|
468
476
|
end
|
469
477
|
|
470
478
|
# Get the name of the replica set the server belongs to, returns nil if
|
@@ -38,10 +38,22 @@ module Mongo
|
|
38
38
|
:users_info => 2
|
39
39
|
}.freeze
|
40
40
|
|
41
|
+
# Error message if the server is too old for this version of the driver.
|
42
|
+
#
|
43
|
+
# @since 2.5.0
|
44
|
+
SERVER_TOO_OLD = "Server at (%s) reports wire version (%s), but this version of the Ruby driver " +
|
45
|
+
"requires at least (%s)."
|
46
|
+
|
47
|
+
# Error message if the driver is too old for the version of the server.
|
48
|
+
#
|
49
|
+
# @since 2.5.0
|
50
|
+
DRIVER_TOO_OLD = "Server at (%s) requires wire version (%s), but this version of the Ruby driver " +
|
51
|
+
"only supports up to (%s)."
|
52
|
+
|
41
53
|
# The wire protocol versions that this version of the driver supports.
|
42
54
|
#
|
43
55
|
# @since 2.0.0
|
44
|
-
DRIVER_WIRE_VERSIONS = (
|
56
|
+
DRIVER_WIRE_VERSIONS = (2..6).freeze
|
45
57
|
|
46
58
|
# Create the methods for each mapping to tell if they are supported.
|
47
59
|
#
|
@@ -74,17 +86,24 @@ module Mongo
|
|
74
86
|
# versions.
|
75
87
|
#
|
76
88
|
# @since 2.0.0
|
77
|
-
def initialize(server_wire_versions)
|
89
|
+
def initialize(server_wire_versions, address = nil)
|
78
90
|
@server_wire_versions = server_wire_versions
|
79
|
-
check_driver_support!
|
91
|
+
check_driver_support!(address) unless server_wire_versions == ZERO_RANGE
|
80
92
|
end
|
81
93
|
|
82
94
|
private
|
83
95
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
96
|
+
ZERO_RANGE = (0..0).freeze
|
97
|
+
|
98
|
+
def check_driver_support!(address)
|
99
|
+
if DRIVER_WIRE_VERSIONS.min > server_wire_versions.max
|
100
|
+
raise Error::UnsupportedFeatures.new(SERVER_TOO_OLD % [address,
|
101
|
+
server_wire_versions.max,
|
102
|
+
DRIVER_WIRE_VERSIONS.min])
|
103
|
+
elsif DRIVER_WIRE_VERSIONS.max < server_wire_versions.min
|
104
|
+
raise Error::UnsupportedFeatures.new(DRIVER_TOO_OLD % [address,
|
105
|
+
server_wire_versions.min,
|
106
|
+
DRIVER_WIRE_VERSIONS.max])
|
88
107
|
end
|
89
108
|
end
|
90
109
|
end
|
data/lib/mongo/session.rb
CHANGED
@@ -34,13 +34,23 @@ module Mongo
|
|
34
34
|
# @since 2.5.0
|
35
35
|
attr_reader :client
|
36
36
|
|
37
|
-
|
37
|
+
# The cluster time for this session.
|
38
|
+
#
|
39
|
+
# @since 2.5.0
|
40
|
+
attr_reader :cluster_time
|
41
|
+
|
42
|
+
# The latest seen operation time for this session.
|
43
|
+
#
|
44
|
+
# @since 2.5.0
|
45
|
+
attr_reader :operation_time
|
46
|
+
|
47
|
+
def_delegators :client, :cluster
|
38
48
|
|
39
49
|
# Error message describing that the session was attempted to be used by a client different from the
|
40
50
|
# one it was originally associated with.
|
41
51
|
#
|
42
52
|
# @since 2.5.0
|
43
|
-
|
53
|
+
MISMATCHED_CLUSTER_ERROR_MSG = 'The client used to create this session does not match that of client ' +
|
44
54
|
'initiating this operation. Please only use this session for operations through its parent client.'.freeze
|
45
55
|
|
46
56
|
# Error message describing that the session cannot be used because it has already been ended.
|
@@ -66,7 +76,20 @@ module Mongo
|
|
66
76
|
def initialize(server_session, client, options = {})
|
67
77
|
@server_session = server_session
|
68
78
|
@client = client
|
69
|
-
@options = options
|
79
|
+
@options = options.dup.freeze
|
80
|
+
@cluster_time = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
# Get a formatted string for use in inspection.
|
84
|
+
#
|
85
|
+
# @example Inspect the session object.
|
86
|
+
# session.inspect
|
87
|
+
#
|
88
|
+
# @return [ String ] The session inspection.
|
89
|
+
#
|
90
|
+
# @since 2.5.0
|
91
|
+
def inspect
|
92
|
+
"#<Mongo::Session:0x#{object_id} session_id=#{session_id} options=#{@options}>"
|
70
93
|
end
|
71
94
|
|
72
95
|
# End this session.
|
@@ -144,19 +167,113 @@ module Mongo
|
|
144
167
|
# @example Process a response from the server.
|
145
168
|
# session.process(result)
|
146
169
|
#
|
147
|
-
# @param [ Operation::Result ] The result from the operation.
|
170
|
+
# @param [ Operation::Result ] result The result from the operation.
|
148
171
|
#
|
149
172
|
# @return [ Operation::Result ] The result.
|
150
173
|
#
|
151
174
|
# @since 2.5.0
|
152
175
|
def process(result)
|
153
|
-
|
176
|
+
unless implicit_session?
|
177
|
+
set_operation_time(result)
|
178
|
+
set_cluster_time(result)
|
179
|
+
end
|
154
180
|
@server_session.set_last_use!
|
155
181
|
result
|
156
182
|
end
|
157
183
|
|
184
|
+
# Advance the cached cluster time document for this session.
|
185
|
+
#
|
186
|
+
# @example Advance the cluster time.
|
187
|
+
# session.advance_cluster_time(doc)
|
188
|
+
#
|
189
|
+
# @param [ BSON::Document, Hash ] new_cluster_time The new cluster time.
|
190
|
+
#
|
191
|
+
# @return [ BSON::Document, Hash ] The new cluster time.
|
192
|
+
#
|
193
|
+
# @since 2.5.0
|
194
|
+
def advance_cluster_time(new_cluster_time)
|
195
|
+
if @cluster_time
|
196
|
+
@cluster_time = [ @cluster_time, new_cluster_time ].max_by { |doc| doc[Cluster::CLUSTER_TIME] }
|
197
|
+
else
|
198
|
+
@cluster_time = new_cluster_time
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Advance the cached operation time for this session.
|
203
|
+
#
|
204
|
+
# @example Advance the operation time.
|
205
|
+
# session.advance_operation_time(timestamp)
|
206
|
+
#
|
207
|
+
# @param [ BSON::Timestamp ] new_operation_time The new operation time.
|
208
|
+
#
|
209
|
+
# @return [ BSON::Timestamp ] The max operation time, considering the current and new times.
|
210
|
+
#
|
211
|
+
# @since 2.5.0
|
212
|
+
def advance_operation_time(new_operation_time)
|
213
|
+
if @operation_time
|
214
|
+
@operation_time = [ @operation_time, new_operation_time ].max
|
215
|
+
else
|
216
|
+
@operation_time = new_operation_time
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Will writes executed with this session be retried.
|
221
|
+
#
|
222
|
+
# @example Will writes be retried.
|
223
|
+
# session.retry_writes?
|
224
|
+
#
|
225
|
+
# @return [ true, false ] If writes will be retried.
|
226
|
+
#
|
227
|
+
# @note Retryable writes are only available on server versions at least 3.6 and with
|
228
|
+
# sharded clusters or replica sets.
|
229
|
+
#
|
230
|
+
# @since 2.5.0
|
231
|
+
def retry_writes?
|
232
|
+
!!client.options[:retry_writes] && (cluster.replica_set? || cluster.sharded?)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Get the session id.
|
236
|
+
#
|
237
|
+
# @example Get the session id.
|
238
|
+
# session.session_id
|
239
|
+
#
|
240
|
+
# @return [ BSON::Document ] The session id.
|
241
|
+
#
|
242
|
+
# @since 2.5.0
|
243
|
+
def session_id
|
244
|
+
@server_session.session_id if @server_session
|
245
|
+
end
|
246
|
+
|
247
|
+
# Increment and return the next transaction number.
|
248
|
+
#
|
249
|
+
# @example Get the next transaction number.
|
250
|
+
# server_session.next_txn_num
|
251
|
+
#
|
252
|
+
# @return [ Integer ] The next transaction number.
|
253
|
+
#
|
254
|
+
# @since 2.5.0
|
255
|
+
def next_txn_num
|
256
|
+
@server_session.next_txn_num if @server_session
|
257
|
+
end
|
258
|
+
|
158
259
|
private
|
159
260
|
|
261
|
+
def causal_consistency_doc(read_concern)
|
262
|
+
if operation_time && causal_consistency?
|
263
|
+
(read_concern || {}).merge(:afterClusterTime => operation_time)
|
264
|
+
else
|
265
|
+
read_concern
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def causal_consistency?
|
270
|
+
@causal_consistency ||= (if @options.key?(:causal_consistency)
|
271
|
+
@options[:causal_consistency] == true
|
272
|
+
else
|
273
|
+
true
|
274
|
+
end)
|
275
|
+
end
|
276
|
+
|
160
277
|
def implicit_session?
|
161
278
|
@implicit_session ||= !!(@options.key?(:implicit) && @options[:implicit] == true)
|
162
279
|
end
|
@@ -167,13 +284,23 @@ module Mongo
|
|
167
284
|
end
|
168
285
|
end
|
169
286
|
|
287
|
+
def set_cluster_time(result)
|
288
|
+
if cluster_time_doc = result.cluster_time
|
289
|
+
if @cluster_time.nil?
|
290
|
+
@cluster_time = cluster_time_doc
|
291
|
+
elsif cluster_time_doc[Cluster::CLUSTER_TIME] > @cluster_time[Cluster::CLUSTER_TIME]
|
292
|
+
@cluster_time = cluster_time_doc
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
170
297
|
def check_if_ended!
|
171
298
|
raise Mongo::Error::InvalidSession.new(SESSION_ENDED_ERROR_MSG) if ended?
|
172
299
|
end
|
173
300
|
|
174
301
|
def check_matching_client!(client)
|
175
302
|
if @client != client
|
176
|
-
raise Mongo::Error::InvalidSession.new(
|
303
|
+
raise Mongo::Error::InvalidSession.new(MISMATCHED_CLUSTER_ERROR_MSG)
|
177
304
|
end
|
178
305
|
end
|
179
306
|
end
|
@@ -46,6 +46,8 @@ module Mongo
|
|
46
46
|
# @since 2.5.0
|
47
47
|
def initialize
|
48
48
|
set_last_use!
|
49
|
+
session_id
|
50
|
+
@txn_num = -1
|
49
51
|
end
|
50
52
|
|
51
53
|
# Update the last_use attribute of the server session to now.
|
@@ -53,6 +55,8 @@ module Mongo
|
|
53
55
|
# @example Set the last use field to now.
|
54
56
|
# server_session.set_last_use!
|
55
57
|
#
|
58
|
+
# @return [ Time ] The last time the session was used.
|
59
|
+
#
|
56
60
|
# @since 2.5.0
|
57
61
|
def set_last_use!
|
58
62
|
@last_use = Time.now
|
@@ -63,11 +67,37 @@ module Mongo
|
|
63
67
|
# @example Get the session id.
|
64
68
|
# server_session.session_id
|
65
69
|
#
|
70
|
+
# @return [ BSON::Document ] The session id.
|
71
|
+
#
|
66
72
|
# @since 2.5.0
|
67
73
|
def session_id
|
68
74
|
@session_id ||= (bytes = [SecureRandom.uuid.gsub(DASH_REGEX, '')].pack(UUID_PACK)
|
69
75
|
BSON::Document.new(id: BSON::Binary.new(bytes, :uuid)))
|
70
76
|
end
|
77
|
+
|
78
|
+
# Increment and return the next transaction number.
|
79
|
+
#
|
80
|
+
# @example Get the next transaction number.
|
81
|
+
# server_session.next_txn_num
|
82
|
+
#
|
83
|
+
# @return [ Integer ] The next transaction number.
|
84
|
+
#
|
85
|
+
# @since 2.5.0
|
86
|
+
def next_txn_num
|
87
|
+
@txn_num += 1
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get a formatted string for use in inspection.
|
91
|
+
#
|
92
|
+
# @example Inspect the session object.
|
93
|
+
# session.inspect
|
94
|
+
#
|
95
|
+
# @return [ String ] The session inspection.
|
96
|
+
#
|
97
|
+
# @since 2.5.0
|
98
|
+
def inspect
|
99
|
+
"#<Mongo::Session::ServerSession:0x#{object_id} session_id=#{session_id} last_use=#{@last_use}>"
|
100
|
+
end
|
71
101
|
end
|
72
102
|
end
|
73
103
|
end
|
@@ -23,11 +23,6 @@ module Mongo
|
|
23
23
|
# @since 2.5.0
|
24
24
|
class SessionPool
|
25
25
|
|
26
|
-
# The command sent to the server to end a session.
|
27
|
-
#
|
28
|
-
# @since 2.5.0
|
29
|
-
END_SESSION = { :endSessions => 1 }.freeze
|
30
|
-
|
31
26
|
# Create a SessionPool.
|
32
27
|
#
|
33
28
|
# @example
|
@@ -57,6 +52,18 @@ module Mongo
|
|
57
52
|
@client = client
|
58
53
|
end
|
59
54
|
|
55
|
+
# Get a formatted string for use in inspection.
|
56
|
+
#
|
57
|
+
# @example Inspect the session pool object.
|
58
|
+
# session_pool.inspect
|
59
|
+
#
|
60
|
+
# @return [ String ] The session pool inspection.
|
61
|
+
#
|
62
|
+
# @since 2.5.0
|
63
|
+
def inspect
|
64
|
+
"#<Mongo::Session::SessionPool:0x#{object_id} current_size=#{@queue.size}>"
|
65
|
+
end
|
66
|
+
|
60
67
|
# Checkout a session to be used in the context of a block and return the session back to
|
61
68
|
# the pool after the block completes.
|
62
69
|
#
|
@@ -70,8 +77,7 @@ module Mongo
|
|
70
77
|
# @since 2.5.0
|
71
78
|
def with_session
|
72
79
|
server_session = checkout
|
73
|
-
|
74
|
-
result
|
80
|
+
yield(server_session)
|
75
81
|
ensure
|
76
82
|
begin; checkin(server_session) if server_session; rescue; end
|
77
83
|
end
|
@@ -104,7 +110,7 @@ module Mongo
|
|
104
110
|
# @example Checkin a session.
|
105
111
|
# pool.checkin(session)
|
106
112
|
#
|
107
|
-
# @param [ Session::ServerSession ] The session to checkin.
|
113
|
+
# @param [ Session::ServerSession ] session The session to checkin.
|
108
114
|
#
|
109
115
|
# @since 2.5.0
|
110
116
|
def checkin(session)
|
@@ -123,19 +129,13 @@ module Mongo
|
|
123
129
|
#
|
124
130
|
# @since 2.5.0
|
125
131
|
def end_sessions
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
Operation::Commands::Command.new({
|
132
|
-
:selector => END_SESSION.merge(ids: ids.shift(10_000)),
|
133
|
-
:db_name => Database::ADMIN
|
134
|
-
}).execute(@client.cluster.next_primary)
|
135
|
-
rescue
|
136
|
-
end
|
137
|
-
end
|
132
|
+
while !@queue.empty?
|
133
|
+
server = ServerSelector.get(mode: :primary_preferred).select_server(@client.cluster)
|
134
|
+
Operation::Commands::Command.new(
|
135
|
+
:selector => {endSessions: @queue.shift(10_000).collect { |s| s.session_id }},
|
136
|
+
:db_name => Database::ADMIN).execute(server)
|
138
137
|
end
|
138
|
+
rescue
|
139
139
|
end
|
140
140
|
|
141
141
|
private
|
data/lib/mongo/uri.rb
CHANGED
@@ -22,8 +22,8 @@ module Mongo
|
|
22
22
|
# http://docs.mongodb.org/manual/reference/connection-string/
|
23
23
|
#
|
24
24
|
# @example Use the uri string to make a client connection.
|
25
|
-
# uri = URI.new('mongodb://localhost:27017')
|
26
|
-
# client = Client.new(uri.
|
25
|
+
# uri = Mongo::URI.new('mongodb://localhost:27017')
|
26
|
+
# client = Mongo::Client.new(uri.servers, uri.options)
|
27
27
|
# client.login(uri.credentials)
|
28
28
|
# client[uri.database]
|
29
29
|
#
|
@@ -46,6 +46,39 @@ module Mongo
|
|
46
46
|
# @since 2.0.0
|
47
47
|
attr_reader :servers
|
48
48
|
|
49
|
+
# The mongodb connection string scheme.
|
50
|
+
#
|
51
|
+
# @deprecated Will be removed in 3.0.
|
52
|
+
#
|
53
|
+
# @since 2.0.0
|
54
|
+
SCHEME = 'mongodb://'.freeze
|
55
|
+
|
56
|
+
# The mongodb connection string scheme root.
|
57
|
+
#
|
58
|
+
# @since 2.5.0
|
59
|
+
MONGODB_SCHEME = 'mongodb'.freeze
|
60
|
+
|
61
|
+
# The mongodb srv protocol connection string scheme root.
|
62
|
+
#
|
63
|
+
# @since 2.5.0
|
64
|
+
MONGODB_SRV_SCHEME = 'mongodb+srv'.freeze
|
65
|
+
|
66
|
+
# Error details for an invalid scheme.
|
67
|
+
#
|
68
|
+
# @since 2.1.0
|
69
|
+
INVALID_SCHEME = "Invalid scheme. Scheme must be '#{MONGODB_SCHEME}' or '#{MONGODB_SRV_SCHEME}'".freeze
|
70
|
+
|
71
|
+
# MongoDB URI format specification.
|
72
|
+
#
|
73
|
+
# @since 2.0.0
|
74
|
+
FORMAT = 'mongodb://[username:password@]host1[:port1][,host2[:port2]' +
|
75
|
+
',...[,hostN[:portN]]][/[database][?options]]'.freeze
|
76
|
+
|
77
|
+
# MongoDB URI (connection string) documentation url
|
78
|
+
#
|
79
|
+
# @since 2.0.0
|
80
|
+
HELP = 'http://docs.mongodb.org/manual/reference/connection-string/'.freeze
|
81
|
+
|
49
82
|
# Unsafe characters that must be urlencoded.
|
50
83
|
#
|
51
84
|
# @since 2.1.0
|
@@ -56,11 +89,6 @@ module Mongo
|
|
56
89
|
# @since 2.1.0
|
57
90
|
UNIX_SOCKET = /.sock/
|
58
91
|
|
59
|
-
# The mongodb connection string scheme.
|
60
|
-
#
|
61
|
-
# @since 2.0.0
|
62
|
-
SCHEME = 'mongodb://'.freeze
|
63
|
-
|
64
92
|
# The character delimiting hosts.
|
65
93
|
#
|
66
94
|
# @since 2.1.0
|
@@ -101,10 +129,10 @@ module Mongo
|
|
101
129
|
# @since 2.1.0
|
102
130
|
AUTH_DELIM = '@'.freeze
|
103
131
|
|
104
|
-
#
|
132
|
+
# Scheme delimiter.
|
105
133
|
#
|
106
|
-
# @since 2.
|
107
|
-
|
134
|
+
# @since 2.5.0
|
135
|
+
SCHEME_DELIM = '://'.freeze
|
108
136
|
|
109
137
|
# Error details for an invalid options format.
|
110
138
|
#
|
@@ -142,17 +170,6 @@ module Mongo
|
|
142
170
|
# @since 2.1.0
|
143
171
|
INVALID_PORT = "Invalid port. Port must be an integer greater than 0 and less than 65536".freeze
|
144
172
|
|
145
|
-
# MongoDB URI format specification.
|
146
|
-
#
|
147
|
-
# @since 2.0.0
|
148
|
-
FORMAT = 'mongodb://[username:password@]host1[:port1][,host2[:port2]' +
|
149
|
-
',...[,hostN[:portN]]][/[database][?options]]'.freeze
|
150
|
-
|
151
|
-
# MongoDB URI (connection string) documentation url
|
152
|
-
#
|
153
|
-
# @since 2.0.0
|
154
|
-
HELP = 'http://docs.mongodb.org/manual/reference/connection-string/'.freeze
|
155
|
-
|
156
173
|
# Map of URI read preference modes to ruby driver read preference modes
|
157
174
|
#
|
158
175
|
# @since 2.0.0
|
@@ -180,23 +197,24 @@ module Mongo
|
|
180
197
|
# @since 2.1.0
|
181
198
|
REPEATABLE_OPTIONS = [ :tag_sets ]
|
182
199
|
|
183
|
-
#
|
200
|
+
# Get either a URI object or a SRVProtocol URI object.
|
184
201
|
#
|
185
|
-
# @example
|
186
|
-
# URI.
|
202
|
+
# @example Get the uri object.
|
203
|
+
# URI.get(string)
|
187
204
|
#
|
188
|
-
# @
|
189
|
-
# @param [ Hash ] options The options.
|
190
|
-
#
|
191
|
-
# @raise [ Error::InvalidURI ] If the uri does not match the spec.
|
205
|
+
# @return [URI, URI::SRVProtocol] The uri object.
|
192
206
|
#
|
193
|
-
# @since 2.
|
194
|
-
def
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
207
|
+
# @since 2.5.0
|
208
|
+
def self.get(string, opts = {})
|
209
|
+
scheme, _, remaining = string.partition(SCHEME_DELIM)
|
210
|
+
case scheme
|
211
|
+
when MONGODB_SCHEME
|
212
|
+
URI.new(string, opts)
|
213
|
+
when MONGODB_SRV_SCHEME
|
214
|
+
SRVProtocol.new(string, opts)
|
215
|
+
else
|
216
|
+
raise Error::InvalidURI.new(string, INVALID_SCHEME)
|
217
|
+
end
|
200
218
|
end
|
201
219
|
|
202
220
|
# Gets the options hash that needs to be passed to a Mongo::Client on
|
@@ -214,6 +232,25 @@ module Mongo
|
|
214
232
|
@user ? opts.merge(credentials) : opts
|
215
233
|
end
|
216
234
|
|
235
|
+
# Create the new uri from the provided string.
|
236
|
+
#
|
237
|
+
# @example Create the new URI.
|
238
|
+
# URI.new('mongodb://localhost:27017')
|
239
|
+
#
|
240
|
+
# @param [ String ] string The uri string.
|
241
|
+
# @param [ Hash ] options The options.
|
242
|
+
#
|
243
|
+
# @raise [ Error::InvalidURI ] If the uri does not match the spec.
|
244
|
+
#
|
245
|
+
# @since 2.0.0
|
246
|
+
def initialize(string, options = {})
|
247
|
+
@string = string
|
248
|
+
@options = options
|
249
|
+
parsed_scheme, _, remaining = string.partition(SCHEME_DELIM)
|
250
|
+
raise_invalid_error!(INVALID_SCHEME) unless parsed_scheme == scheme
|
251
|
+
parse!(remaining)
|
252
|
+
end
|
253
|
+
|
217
254
|
# Get the credentials provided in the URI.
|
218
255
|
#
|
219
256
|
# @example Get the credentials.
|
@@ -242,7 +279,18 @@ module Mongo
|
|
242
279
|
|
243
280
|
private
|
244
281
|
|
245
|
-
def
|
282
|
+
def scheme
|
283
|
+
MONGODB_SCHEME
|
284
|
+
end
|
285
|
+
|
286
|
+
def parse_creds_hosts!(string)
|
287
|
+
hosts, creds = split_creds_hosts(string)
|
288
|
+
@servers = parse_servers!(hosts)
|
289
|
+
@user = parse_user!(creds)
|
290
|
+
@password = parse_password!(creds)
|
291
|
+
end
|
292
|
+
|
293
|
+
def parse!(remaining)
|
246
294
|
creds_hosts, db_opts = extract_db_opts!(remaining)
|
247
295
|
parse_creds_hosts!(creds_hosts)
|
248
296
|
parse_db_opts!(db_opts)
|
@@ -257,13 +305,6 @@ module Mongo
|
|
257
305
|
[ creds_hosts, db_opts ].map { |s| s.reverse }
|
258
306
|
end
|
259
307
|
|
260
|
-
def parse_creds_hosts!(string)
|
261
|
-
hosts, creds = split_creds_hosts(string)
|
262
|
-
@servers = parse_servers!(hosts)
|
263
|
-
@user = parse_user!(creds)
|
264
|
-
@password = parse_password!(creds)
|
265
|
-
end
|
266
|
-
|
267
308
|
def split_creds_hosts(string)
|
268
309
|
hosts, _, creds = string.reverse.partition(AUTH_DELIM)
|
269
310
|
hosts, creds = creds, hosts if hosts.empty?
|
@@ -330,13 +371,14 @@ module Mongo
|
|
330
371
|
validate_port_string!(p)
|
331
372
|
elsif host =~ UNIX_SOCKET
|
332
373
|
raise_invalid_error!(UNESCAPED_UNIX_SOCKET) if host =~ UNSAFE
|
374
|
+
host = decode(host)
|
333
375
|
end
|
334
376
|
servers << host
|
335
377
|
end
|
336
378
|
end
|
337
379
|
|
338
380
|
def raise_invalid_error!(details)
|
339
|
-
raise Error::InvalidURI.new(@string, details)
|
381
|
+
raise Error::InvalidURI.new(@string, details, FORMAT)
|
340
382
|
end
|
341
383
|
|
342
384
|
def decode(value)
|
@@ -585,3 +627,5 @@ module Mongo
|
|
585
627
|
end
|
586
628
|
end
|
587
629
|
end
|
630
|
+
|
631
|
+
require 'mongo/uri/srv_protocol'
|