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.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo/address.rb +1 -1
  5. data/lib/mongo/address/unix.rb +1 -1
  6. data/lib/mongo/auth/user.rb +0 -5
  7. data/lib/mongo/auth/user/view.rb +4 -4
  8. data/lib/mongo/bulk_write.rb +60 -32
  9. data/lib/mongo/client.rb +44 -8
  10. data/lib/mongo/cluster.rb +14 -12
  11. data/lib/mongo/cluster/periodic_executor.rb +106 -0
  12. data/lib/mongo/cluster/{cursor_reaper.rb → reapers/cursor_reaper.rb} +5 -37
  13. data/lib/mongo/cluster/reapers/socket_reaper.rb +59 -0
  14. data/lib/mongo/collection.rb +9 -6
  15. data/lib/mongo/collection/view.rb +2 -2
  16. data/lib/mongo/collection/view/builder/aggregation.rb +2 -1
  17. data/lib/mongo/collection/view/builder/find_command.rb +1 -1
  18. data/lib/mongo/collection/view/change_stream.rb +14 -1
  19. data/lib/mongo/collection/view/map_reduce.rb +30 -13
  20. data/lib/mongo/collection/view/readable.rb +5 -5
  21. data/lib/mongo/collection/view/writable.rb +98 -51
  22. data/lib/mongo/error.rb +3 -0
  23. data/lib/mongo/error/invalid_txt_record.rb +27 -0
  24. data/lib/mongo/error/invalid_uri.rb +7 -6
  25. data/lib/mongo/error/mismatched_domain.rb +27 -0
  26. data/lib/mongo/error/no_srv_records.rb +26 -0
  27. data/lib/mongo/error/unsupported_features.rb +0 -18
  28. data/lib/mongo/index/view.rb +2 -2
  29. data/lib/mongo/operation.rb +1 -0
  30. data/lib/mongo/operation/causally_consistent.rb +33 -0
  31. data/lib/mongo/operation/commands.rb +2 -1
  32. data/lib/mongo/operation/commands/aggregate.rb +2 -7
  33. data/lib/mongo/operation/commands/count.rb +27 -0
  34. data/lib/mongo/operation/commands/distinct.rb +27 -0
  35. data/lib/mongo/operation/commands/find.rb +3 -1
  36. data/lib/mongo/operation/commands/map_reduce.rb +1 -0
  37. data/lib/mongo/operation/commands/parallel_scan.rb +1 -0
  38. data/lib/mongo/operation/specifiable.rb +12 -0
  39. data/lib/mongo/operation/uses_command_op_msg.rb +36 -5
  40. data/lib/mongo/operation/write.rb +0 -5
  41. data/lib/mongo/operation/write/bulk/bulkable.rb +4 -8
  42. data/lib/mongo/operation/write/bulk/mergable.rb +2 -0
  43. data/lib/mongo/operation/write/command/create_index.rb +19 -0
  44. data/lib/mongo/operation/write/command/create_user.rb +19 -0
  45. data/lib/mongo/operation/write/command/delete.rb +1 -2
  46. data/lib/mongo/operation/write/command/drop_index.rb +19 -0
  47. data/lib/mongo/operation/write/command/insert.rb +1 -2
  48. data/lib/mongo/operation/write/command/remove_user.rb +19 -0
  49. data/lib/mongo/operation/write/command/update.rb +1 -2
  50. data/lib/mongo/operation/write/command/update_user.rb +19 -0
  51. data/lib/mongo/operation/write/write_command_enabled.rb +1 -3
  52. data/lib/mongo/protocol/compressed.rb +2 -1
  53. data/lib/mongo/protocol/serializers.rb +6 -6
  54. data/lib/mongo/retryable.rb +48 -5
  55. data/lib/mongo/server.rb +15 -0
  56. data/lib/mongo/server/connection.rb +21 -1
  57. data/lib/mongo/server/connection_pool.rb +3 -0
  58. data/lib/mongo/server/connection_pool/queue.rb +50 -5
  59. data/lib/mongo/server/description.rb +11 -3
  60. data/lib/mongo/server/description/features.rb +26 -7
  61. data/lib/mongo/session.rb +133 -6
  62. data/lib/mongo/session/server_session.rb +30 -0
  63. data/lib/mongo/session/session_pool.rb +20 -20
  64. data/lib/mongo/uri.rb +88 -44
  65. data/lib/mongo/uri/srv_protocol.rb +158 -0
  66. data/lib/mongo/version.rb +1 -1
  67. data/lib/mongo/write_concern/normalizable.rb +12 -0
  68. data/mongo.gemspec +1 -2
  69. data/spec/mongo/address_spec.rb +12 -0
  70. data/spec/mongo/auth/user/view_spec.rb +1 -5
  71. data/spec/mongo/bulk_write_spec.rb +232 -401
  72. data/spec/mongo/change_stream_examples_spec.rb +150 -0
  73. data/spec/mongo/client_spec.rb +142 -2
  74. data/spec/mongo/cluster/cursor_reaper_spec.rb +0 -70
  75. data/spec/mongo/cluster/socket_reaper_spec.rb +32 -0
  76. data/spec/mongo/cluster_spec.rb +11 -7
  77. data/spec/mongo/collection/view/aggregation_spec.rb +46 -1
  78. data/spec/mongo/collection/view/builder/find_command_spec.rb +15 -0
  79. data/spec/mongo/collection/view/change_stream_spec.rb +79 -12
  80. data/spec/mongo/collection/view/map_reduce_spec.rb +120 -4
  81. data/spec/mongo/collection/view/readable_spec.rb +23 -5
  82. data/spec/mongo/collection_spec.rb +292 -102
  83. data/spec/mongo/command_monitoring_spec.rb +26 -32
  84. data/spec/mongo/crud_spec.rb +1 -1
  85. data/spec/mongo/cursor_spec.rb +2 -3
  86. data/spec/mongo/database_spec.rb +30 -14
  87. data/spec/mongo/dns_seedlist_discovery_spec.rb +94 -0
  88. data/spec/mongo/grid/fs_bucket_spec.rb +1 -1
  89. data/spec/mongo/grid/stream/write_spec.rb +1 -1
  90. data/spec/mongo/index/view_spec.rb +8 -46
  91. data/spec/mongo/operation/write/bulk/delete_spec.rb +2 -2
  92. data/spec/mongo/operation/write/bulk/insert_spec.rb +2 -10
  93. data/spec/mongo/operation/write/{create_index_spec.rb → command/create_index_spec.rb} +2 -6
  94. data/spec/mongo/operation/write/command/delete_spec.rb +35 -7
  95. data/spec/mongo/operation/write/{drop_index_spec.rb → command/drop_index_spec.rb} +1 -1
  96. data/spec/mongo/operation/write/command/insert_spec.rb +37 -6
  97. data/spec/mongo/operation/write/{remove_user_spec.rb → command/remove_user_spec.rb} +2 -6
  98. data/spec/mongo/operation/write/command/update_spec.rb +34 -7
  99. data/spec/mongo/operation/write/{update_user_spec.rb → command/update_user_spec.rb} +1 -1
  100. data/spec/mongo/operation/write/create_user_spec.rb +1 -1
  101. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  102. data/spec/mongo/operation/write/insert_spec.rb +2 -10
  103. data/spec/mongo/operation/write/update_spec.rb +3 -15
  104. data/spec/mongo/retryable_spec.rb +1 -1
  105. data/spec/mongo/retryable_writes_spec.rb +815 -0
  106. data/spec/mongo/server/connection_pool/queue_spec.rb +35 -2
  107. data/spec/mongo/server/connection_pool_spec.rb +234 -1
  108. data/spec/mongo/server/connection_spec.rb +10 -6
  109. data/spec/mongo/server/description/features_spec.rb +51 -37
  110. data/spec/mongo/server/description_spec.rb +6 -3
  111. data/spec/mongo/server_spec.rb +87 -0
  112. data/spec/mongo/session/server_session_spec.rb +43 -0
  113. data/spec/mongo/session/session_pool_spec.rb +63 -27
  114. data/spec/mongo/session_spec.rb +247 -0
  115. data/spec/mongo/shell_examples_spec.rb +2 -2
  116. data/spec/mongo/uri/srv_protocol_spec.rb +933 -0
  117. data/spec/mongo/uri_spec.rb +42 -3
  118. data/spec/mongo/write_concern/acknowledged_spec.rb +11 -0
  119. data/spec/mongo/write_concern/unacknowledged_spec.rb +11 -0
  120. data/spec/spec_helper.rb +11 -25
  121. data/spec/support/authorization.rb +2 -1
  122. data/spec/support/connection_string.rb +8 -4
  123. data/spec/support/crud.rb +38 -24
  124. data/spec/support/crud/write.rb +30 -3
  125. data/spec/support/crud_tests/read/aggregate-out.yml +21 -0
  126. data/spec/support/crud_tests/write/bulkWrite-arrayFilters.yml +44 -0
  127. data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +1 -1
  128. data/spec/support/crud_tests/write/insertMany.yml +1 -3
  129. data/spec/support/crud_tests/write/replaceOne.yml +1 -1
  130. data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +1 -1
  131. data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +1 -1
  132. data/spec/support/dns_seedlist_discovery_tests/longer-parent-in-return.yml +11 -0
  133. data/spec/support/dns_seedlist_discovery_tests/misformatted-option.yml +5 -0
  134. data/spec/support/dns_seedlist_discovery_tests/no-results.yml +5 -0
  135. data/spec/support/dns_seedlist_discovery_tests/not-enough-parts.yml +5 -0
  136. data/spec/support/dns_seedlist_discovery_tests/one-result-default-port.yml +10 -0
  137. data/spec/support/dns_seedlist_discovery_tests/one-txt-record-multiple-strings.yml +10 -0
  138. data/spec/support/dns_seedlist_discovery_tests/one-txt-record.yml +11 -0
  139. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch1.yml +5 -0
  140. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch2.yml +5 -0
  141. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch3.yml +5 -0
  142. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch4.yml +5 -0
  143. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch5.yml +5 -0
  144. data/spec/support/dns_seedlist_discovery_tests/returned-parent-too-short.yml +5 -0
  145. data/spec/support/dns_seedlist_discovery_tests/returned-parent-wrong.yml +5 -0
  146. data/spec/support/dns_seedlist_discovery_tests/two-results-default-port.yml +11 -0
  147. data/spec/support/dns_seedlist_discovery_tests/two-results-nonstandard-port.yml +11 -0
  148. data/spec/support/dns_seedlist_discovery_tests/two-txt-records.yml +5 -0
  149. data/spec/support/dns_seedlist_discovery_tests/txt-record-not-allowed-option.yml +5 -0
  150. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-overridden-ssl-option.yml +11 -0
  151. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-overridden-uri-option.yml +11 -0
  152. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-unallowed-option.yml +5 -0
  153. data/spec/support/dns_seedlist_discovery_tests/uri-with-port.yml +5 -0
  154. data/spec/support/dns_seedlist_discovery_tests/uri-with-two-hosts.yml +5 -0
  155. data/spec/support/retryable_writes_tests/bulkWrite.yml +305 -0
  156. data/spec/support/retryable_writes_tests/deleteOne.yml +51 -0
  157. data/spec/support/retryable_writes_tests/findOneAndDelete.yml +52 -0
  158. data/spec/support/retryable_writes_tests/findOneAndReplace.yml +57 -0
  159. data/spec/support/retryable_writes_tests/findOneAndUpdate.yml +56 -0
  160. data/spec/support/retryable_writes_tests/insertMany.yml +72 -0
  161. data/spec/support/retryable_writes_tests/insertOne.yml +55 -0
  162. data/spec/support/retryable_writes_tests/replaceOne.yml +60 -0
  163. data/spec/support/retryable_writes_tests/updateOne.yml +120 -0
  164. data/spec/support/shared/session.rb +525 -24
  165. metadata +437 -350
  166. metadata.gz.sig +0 -0
  167. data/lib/mongo/operation/commands/user_query.rb +0 -72
  168. data/lib/mongo/operation/write/create_index.rb +0 -67
  169. data/lib/mongo/operation/write/create_user.rb +0 -50
  170. data/lib/mongo/operation/write/drop_index.rb +0 -63
  171. data/lib/mongo/operation/write/remove_user.rb +0 -48
  172. 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 ].freeze
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] && !replica_set_name.nil?
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 = (0..6).freeze
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
- def check_driver_support!
85
- if DRIVER_WIRE_VERSIONS.max < server_wire_versions.min ||
86
- DRIVER_WIRE_VERSIONS.min > server_wire_versions.max
87
- raise Error::UnsupportedFeatures.new(server_wire_versions)
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
- def_delegators :@server_session, :session_id
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
- MISTMATCHED_CLUSTER_ERROR_MSG = 'The client used to create this session does not match that of client ' +
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
- set_operation_time(result)
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(MISTMATCHED_CLUSTER_ERROR_MSG)
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
- result = yield(server_session)
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
- if @client
127
- ids = @queue.collect { |s| s.session_id }
128
-
129
- while !ids.empty?
130
- begin
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.server, uri.options)
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
- # Error details for an invalid scheme.
132
+ # Scheme delimiter.
105
133
  #
106
- # @since 2.1.0
107
- INVALID_SCHEME = "Invalid scheme. Scheme must be '#{SCHEME}'".freeze
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
- # Create the new uri from the provided string.
200
+ # Get either a URI object or a SRVProtocol URI object.
184
201
  #
185
- # @example Create the new URI.
186
- # URI.new('mongodb://localhost:27017')
202
+ # @example Get the uri object.
203
+ # URI.get(string)
187
204
  #
188
- # @param [ String ] string The uri string.
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.0.0
194
- def initialize(string, options = {})
195
- @string = string
196
- @options = options
197
- _, scheme, remaining = @string.partition(SCHEME)
198
- raise_invalid_error!(INVALID_SCHEME) unless scheme == SCHEME
199
- setup!(remaining)
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 setup!(remaining)
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'