mongo 2.10.5 → 2.11.0.rc0

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 (191) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/lib/mongo.rb +2 -0
  6. data/lib/mongo/address.rb +4 -0
  7. data/lib/mongo/address/validator.rb +99 -0
  8. data/lib/mongo/auth.rb +7 -2
  9. data/lib/mongo/auth/user.rb +1 -7
  10. data/lib/mongo/background_thread.rb +135 -0
  11. data/lib/mongo/bulk_write/transformable.rb +3 -3
  12. data/lib/mongo/client.rb +74 -16
  13. data/lib/mongo/cluster.rb +193 -41
  14. data/lib/mongo/cluster/periodic_executor.rb +31 -43
  15. data/lib/mongo/cluster/sdam_flow.rb +26 -3
  16. data/lib/mongo/cluster/srv_monitor.rb +127 -0
  17. data/lib/mongo/collection/view/readable.rb +3 -5
  18. data/lib/mongo/collection/view/writable.rb +3 -3
  19. data/lib/mongo/cursor/builder/get_more_command.rb +1 -4
  20. data/lib/mongo/cursor/builder/kill_cursors_command.rb +5 -23
  21. data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
  22. data/lib/mongo/cursor/builder/op_kill_cursors.rb +5 -24
  23. data/lib/mongo/error.rb +1 -0
  24. data/lib/mongo/error/auth_error.rb +1 -1
  25. data/lib/mongo/error/connection_check_out_timeout.rb +7 -8
  26. data/lib/mongo/error/invalid_address.rb +24 -0
  27. data/lib/mongo/error/notable.rb +2 -2
  28. data/lib/mongo/error/operation_failure.rb +3 -3
  29. data/lib/mongo/error/pool_closed_error.rb +11 -4
  30. data/lib/mongo/event.rb +1 -1
  31. data/lib/mongo/grid/file.rb +0 -5
  32. data/lib/mongo/grid/file/chunk.rb +0 -2
  33. data/lib/mongo/grid/fs_bucket.rb +13 -15
  34. data/lib/mongo/grid/stream/write.rb +3 -9
  35. data/lib/mongo/loggable.rb +5 -1
  36. data/lib/mongo/monitoring.rb +1 -0
  37. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +7 -0
  38. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +11 -3
  39. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +11 -3
  40. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +11 -3
  41. data/lib/mongo/monitoring/event/cmap/pool_created.rb +12 -3
  42. data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +62 -0
  43. data/lib/mongo/operation/shared/executable.rb +5 -10
  44. data/lib/mongo/operation/shared/sessions_supported.rb +1 -5
  45. data/lib/mongo/protocol/get_more.rb +1 -2
  46. data/lib/mongo/protocol/kill_cursors.rb +13 -6
  47. data/lib/mongo/protocol/serializers.rb +4 -20
  48. data/lib/mongo/retryable.rb +9 -34
  49. data/lib/mongo/semaphore.rb +1 -1
  50. data/lib/mongo/server.rb +113 -42
  51. data/lib/mongo/server/connection.rb +12 -5
  52. data/lib/mongo/server/connection_pool.rb +250 -40
  53. data/lib/mongo/server/connection_pool/populator.rb +58 -0
  54. data/lib/mongo/server/description.rb +9 -2
  55. data/lib/mongo/server/monitor.rb +68 -93
  56. data/lib/mongo/server/monitor/connection.rb +2 -0
  57. data/lib/mongo/server_selector/selectable.rb +13 -5
  58. data/lib/mongo/session.rb +0 -13
  59. data/lib/mongo/srv.rb +17 -0
  60. data/lib/mongo/srv/monitor.rb +96 -0
  61. data/lib/mongo/srv/resolver.rb +130 -0
  62. data/lib/mongo/srv/result.rb +126 -0
  63. data/lib/mongo/srv/warning_result.rb +35 -0
  64. data/lib/mongo/uri.rb +45 -55
  65. data/lib/mongo/uri/srv_protocol.rb +89 -42
  66. data/lib/mongo/version.rb +1 -1
  67. data/mongo.gemspec +3 -4
  68. data/spec/README.md +6 -1
  69. data/spec/enterprise_auth/kerberos_spec.rb +7 -6
  70. data/spec/integration/change_stream_examples_spec.rb +0 -4
  71. data/spec/integration/client_construction_spec.rb +14 -2
  72. data/spec/integration/connect_single_rs_name_spec.rb +2 -2
  73. data/spec/integration/connection_pool_populator_spec.rb +296 -0
  74. data/spec/integration/connection_spec.rb +31 -22
  75. data/spec/integration/cursor_reaping_spec.rb +1 -2
  76. data/spec/integration/docs_examples_spec.rb +0 -4
  77. data/spec/integration/heartbeat_events_spec.rb +17 -15
  78. data/spec/integration/reconnect_spec.rb +144 -1
  79. data/spec/integration/retryable_writes_errors_spec.rb +0 -4
  80. data/spec/integration/retryable_writes_spec.rb +36 -36
  81. data/spec/integration/sdam_error_handling_spec.rb +31 -25
  82. data/spec/integration/sdam_events_spec.rb +2 -6
  83. data/spec/integration/server_monitor_spec.rb +28 -0
  84. data/spec/integration/server_selector_spec.rb +7 -5
  85. data/spec/integration/srv_monitoring_spec.rb +360 -0
  86. data/spec/integration/step_down_spec.rb +4 -6
  87. data/spec/lite_spec_helper.rb +22 -0
  88. data/spec/mongo/address/validator_spec.rb +51 -0
  89. data/spec/mongo/auth/cr_spec.rb +1 -29
  90. data/spec/mongo/auth/ldap_spec.rb +1 -29
  91. data/spec/mongo/auth/scram/conversation_spec.rb +0 -2
  92. data/spec/mongo/auth/scram/negotiation_spec.rb +1 -1
  93. data/spec/mongo/auth/scram_spec.rb +1 -29
  94. data/spec/mongo/auth/user/view_spec.rb +1 -36
  95. data/spec/mongo/auth/user_spec.rb +0 -12
  96. data/spec/mongo/auth/x509_spec.rb +1 -29
  97. data/spec/mongo/bulk_write_spec.rb +2 -2
  98. data/spec/mongo/client_construction_spec.rb +56 -15
  99. data/spec/mongo/client_spec.rb +31 -27
  100. data/spec/mongo/cluster/periodic_executor_spec.rb +16 -0
  101. data/spec/mongo/cluster/srv_monitor_spec.rb +214 -0
  102. data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -11
  103. data/spec/mongo/cluster/topology/sharded_spec.rb +12 -9
  104. data/spec/mongo/cluster/topology/single_spec.rb +20 -11
  105. data/spec/mongo/cluster_spec.rb +45 -29
  106. data/spec/mongo/collection/view/map_reduce_spec.rb +14 -9
  107. data/spec/mongo/collection/view/readable_spec.rb +0 -16
  108. data/spec/mongo/collection_spec.rb +0 -44
  109. data/spec/mongo/cursor/builder/get_more_command_spec.rb +2 -4
  110. data/spec/mongo/cursor/builder/op_get_more_spec.rb +2 -4
  111. data/spec/mongo/cursor_spec.rb +27 -7
  112. data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +10 -3
  113. data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +10 -3
  114. data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +10 -3
  115. data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +10 -3
  116. data/spec/mongo/operation/delete/op_msg_spec.rb +17 -8
  117. data/spec/mongo/operation/insert/op_msg_spec.rb +50 -35
  118. data/spec/mongo/operation/update/op_msg_spec.rb +14 -7
  119. data/spec/mongo/retryable_spec.rb +52 -31
  120. data/spec/mongo/server/app_metadata_spec.rb +0 -8
  121. data/spec/mongo/server/connection_auth_spec.rb +5 -2
  122. data/spec/mongo/server/connection_pool/populator_spec.rb +101 -0
  123. data/spec/mongo/server/connection_pool_spec.rb +256 -107
  124. data/spec/mongo/server/connection_spec.rb +22 -33
  125. data/spec/mongo/server/description_spec.rb +42 -4
  126. data/spec/mongo/server/monitor/connection_spec.rb +22 -11
  127. data/spec/mongo/server/monitor_spec.rb +66 -107
  128. data/spec/mongo/server_spec.rb +82 -60
  129. data/spec/mongo/session/session_pool_spec.rb +1 -5
  130. data/spec/mongo/session_spec.rb +0 -4
  131. data/spec/mongo/socket/ssl_spec.rb +2 -2
  132. data/spec/mongo/srv/monitor_spec.rb +211 -0
  133. data/spec/mongo/srv/result_spec.rb +54 -0
  134. data/spec/mongo/uri/srv_protocol_spec.rb +30 -15
  135. data/spec/mongo/uri_spec.rb +125 -4
  136. data/spec/spec_helper.rb +6 -0
  137. data/spec/spec_tests/auth_spec.rb +39 -0
  138. data/spec/spec_tests/cmap_spec.rb +55 -8
  139. data/spec/spec_tests/connection_string_spec.rb +6 -31
  140. data/spec/spec_tests/data/auth/connection-string.yml +297 -0
  141. data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +4 -1
  142. data/spec/spec_tests/data/cmap/pool-create-with-options.yml +1 -0
  143. data/spec/spec_tests/data/command_monitoring/insertMany.yml +1 -1
  144. data/spec/spec_tests/data/connection_string/invalid-uris.yml +20 -0
  145. data/spec/spec_tests/data/connection_string/valid-auth.yml +16 -0
  146. data/spec/spec_tests/data/connection_string/valid-warnings.yml +26 -30
  147. data/spec/spec_tests/data/transactions/abort.yml +3 -3
  148. data/spec/spec_tests/data/transactions/error-labels.yml +3 -3
  149. data/spec/spec_tests/data/transactions_api/callback-retry.yml +3 -3
  150. data/spec/spec_tests/data/uri_options/auth-options.yml +1 -1
  151. data/spec/spec_tests/max_staleness_spec.rb +7 -2
  152. data/spec/spec_tests/retryable_reads_spec.rb +0 -31
  153. data/spec/spec_tests/sdam_monitoring_spec.rb +12 -12
  154. data/spec/spec_tests/sdam_spec.rb +4 -7
  155. data/spec/spec_tests/server_selection_spec.rb +6 -2
  156. data/spec/spec_tests/transactions_spec.rb +0 -2
  157. data/spec/spec_tests/uri_options_spec.rb +4 -2
  158. data/spec/stress/connection_pool_stress_spec.rb +203 -0
  159. data/spec/stress/connection_pool_timing_spec.rb +181 -0
  160. data/spec/support/auth.rb +113 -0
  161. data/spec/support/background_thread_registry.rb +63 -0
  162. data/spec/support/client_registry.rb +11 -2
  163. data/spec/support/cluster_config.rb +65 -46
  164. data/spec/support/cluster_tools.rb +2 -2
  165. data/spec/support/cmap.rb +13 -14
  166. data/spec/support/cmap/verifier.rb +4 -5
  167. data/spec/support/command_monitoring.rb +0 -5
  168. data/spec/support/common_shortcuts.rb +101 -1
  169. data/spec/support/constraints.rb +25 -0
  170. data/spec/support/dns.rb +13 -0
  171. data/spec/support/event_subscriber.rb +0 -7
  172. data/spec/support/json_ext_formatter.rb +5 -1
  173. data/spec/support/lite_constraints.rb +22 -6
  174. data/spec/support/local_resource_registry.rb +34 -0
  175. data/spec/support/sdam_monitoring.rb +115 -0
  176. data/spec/support/spec_config.rb +20 -6
  177. data/spec/support/spec_setup.rb +2 -2
  178. data/spec/support/transactions.rb +1 -1
  179. data/spec/support/transactions/test.rb +1 -1
  180. data/spec/support/utils.rb +1 -16
  181. metadata +685 -659
  182. metadata.gz.sig +0 -0
  183. data/lib/mongo/event/description_changed.rb +0 -52
  184. data/spec/integration/bson_symbol_spec.rb +0 -34
  185. data/spec/integration/crud_spec.rb +0 -45
  186. data/spec/integration/get_more_spec.rb +0 -32
  187. data/spec/integration/grid_fs_bucket_spec.rb +0 -48
  188. data/spec/integration/retryable_errors_spec.rb +0 -265
  189. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +0 -98
  190. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -56
  191. data/spec/runners/sdam/verifier.rb +0 -88
@@ -66,20 +66,15 @@ module Mongo
66
66
 
67
67
  if result.not_master? || result.node_recovering?
68
68
  if result.node_shutting_down?
69
- disconnect_pool = true
69
+ keep_pool = false
70
70
  else
71
- # Max wire version needs to be checked prior to marking the
72
- # server unknown
73
- disconnect_pool = !server.description.server_version_gte?('4.2')
71
+ # Max wire version needs to be examined while the server is known
72
+ keep_pool = server.description.server_version_gte?('4.2')
74
73
  end
75
74
 
76
- server.unknown!
75
+ server.unknown!(keep_connection_pool: keep_pool)
77
76
 
78
- if disconnect_pool
79
- server.pool.disconnect!
80
- end
81
-
82
- server.monitor.scan_semaphore.signal
77
+ server.scan_semaphore.signal
83
78
  end
84
79
 
85
80
  session.process(result) if session
@@ -95,10 +95,6 @@ module Mongo
95
95
  session.add_autocommit!(selector)
96
96
  end
97
97
 
98
- def apply_session_id!(selector)
99
- session.add_id!(selector)
100
- end
101
-
102
98
  def apply_start_transaction!(selector)
103
99
  session.add_start_transaction!(selector)
104
100
  end
@@ -146,7 +142,7 @@ module Mongo
146
142
  def apply_session_options(sel, server)
147
143
  apply_cluster_time!(sel, server)
148
144
  sel[:txnNumber] = BSON::Int64.new(txn_num) if txn_num
149
- apply_session_id!(sel)
145
+ sel.merge!(lsid: session.session_id)
150
146
  apply_start_transaction!(sel)
151
147
  apply_causal_consistency!(sel, server)
152
148
  apply_autocommit!(sel)
@@ -110,7 +110,6 @@ module Mongo
110
110
  # The get more constant.
111
111
  #
112
112
  # @since 2.2.0
113
- # @deprecated
114
113
  GET_MORE = 'getMore'.freeze
115
114
 
116
115
  # @return [ String ] collection The name of the collection.
@@ -149,7 +148,7 @@ module Mongo
149
148
  # @since 2.1.0
150
149
  def command
151
150
  document = BSON::Document.new
152
- document.store('getMore', BSON::Int64.new(cursor_id))
151
+ document.store(GET_MORE, cursor_id)
153
152
  document.store(Message::BATCH_SIZE, number_to_return)
154
153
  document.store(Message::COLLECTION, collection)
155
154
  document
@@ -52,7 +52,7 @@ module Mongo
52
52
  command_name: 'killCursors',
53
53
  database_name: @database,
54
54
  command: upconverter.command,
55
- request_id: request_id,
55
+ request_id: request_id
56
56
  )
57
57
  end
58
58
 
@@ -85,6 +85,16 @@ module Mongo
85
85
  # @since 2.1.0
86
86
  class Upconverter
87
87
 
88
+ # The kill cursors constant.
89
+ #
90
+ # @since 2.2.0
91
+ KILL_CURSORS = 'killCursors'.freeze
92
+
93
+ # The cursors constant.
94
+ #
95
+ # @since 2.2.0
96
+ CURSORS = 'cursors'.freeze
97
+
88
98
  # @return [ String ] collection The name of the collection.
89
99
  attr_reader :collection
90
100
 
@@ -115,11 +125,8 @@ module Mongo
115
125
  # @since 2.1.0
116
126
  def command
117
127
  document = BSON::Document.new
118
- document.store('killCursors', collection)
119
- store_ids = cursor_ids.map do |cursor_id|
120
- BSON::Int64.new(cursor_id)
121
- end
122
- document.store('cursors', store_ids)
128
+ document.store(KILL_CURSORS, collection)
129
+ document.store(CURSORS, cursor_ids)
123
130
  document
124
131
  end
125
132
  end
@@ -102,21 +102,13 @@ module Mongo
102
102
  # Serializes and de-serializes one 32-bit integer.
103
103
  module Int32
104
104
 
105
- # Serializes a number to a 32-bit integer
105
+ # Serializes a fixnum to a 4-byte 32-bit integer
106
106
  #
107
107
  # @param buffer [ String ] Buffer to receive the serialized Int32.
108
- # @param value [ Integer | BSON::Int32 ] 32-bit integer to be serialized.
108
+ # @param value [ Fixnum ] 32-bit integer to be serialized.
109
109
  #
110
110
  # @return [String] Buffer with serialized value.
111
111
  def self.serialize(buffer, value, validating_keys = BSON::Config.validating_keys?)
112
- if value.is_a?(BSON::Int32)
113
- if value.respond_to?(:value)
114
- # bson-ruby >= 4.6.0
115
- value = value.value
116
- else
117
- value = value.instance_variable_get('@integer')
118
- end
119
- end
120
112
  buffer.put_int32(value)
121
113
  end
122
114
 
@@ -135,21 +127,13 @@ module Mongo
135
127
  # Serializes and de-serializes one 64-bit integer.
136
128
  module Int64
137
129
 
138
- # Serializes a number to a 64-bit integer
130
+ # Serializes a fixnum to an 8-byte 64-bit integer
139
131
  #
140
132
  # @param buffer [ String ] Buffer to receive the serialized Int64.
141
- # @param value [ Integer | BSON::Int64 ] 64-bit integer to be serialized.
133
+ # @param value [ Fixnum ] 64-bit integer to be serialized.
142
134
  #
143
135
  # @return [ String ] Buffer with serialized value.
144
136
  def self.serialize(buffer, value, validating_keys = BSON::Config.validating_keys?)
145
- if value.is_a?(BSON::Int64)
146
- if value.respond_to?(:value)
147
- # bson-ruby >= 4.6.0
148
- value = value.value
149
- else
150
- value = value.instance_variable_get('@integer')
151
- end
152
- end
153
137
  buffer.put_int64(value)
154
138
  end
155
139
 
@@ -119,12 +119,7 @@ module Mongo
119
119
  legacy_read_with_retry(session, server_selector, &block)
120
120
  else
121
121
  server = select_server(cluster, server_selector, session)
122
- begin
123
- yield server
124
- rescue Error::SocketError, Error::SocketTimeoutError, Error::OperationFailure => e
125
- e.add_note('retries disabled')
126
- raise e
127
- end
122
+ yield server
128
123
  end
129
124
  end
130
125
 
@@ -219,14 +214,12 @@ module Mongo
219
214
  begin
220
215
  yield(server, txn_num, false)
221
216
  rescue Error::SocketError, Error::SocketTimeoutError => e
222
- e.add_note('modern retry')
223
217
  e.add_note("attempt 1")
224
218
  if session.in_transaction? && !ending_transaction
225
219
  raise e
226
220
  end
227
221
  retry_write(e, session, txn_num, &block)
228
222
  rescue Error::OperationFailure => e
229
- e.add_note('modern retry')
230
223
  e.add_note("attempt 1")
231
224
  if e.unsupported_retryable_write?
232
225
  raise_unsupported_error(e)
@@ -257,12 +250,7 @@ module Mongo
257
250
  def nro_write_with_retry(session, write_concern, &block)
258
251
  if session && session.client.options[:retry_writes]
259
252
  server = select_server(cluster, ServerSelector.primary, session)
260
- begin
261
- yield server
262
- rescue Error::SocketError, Error::SocketTimeoutError, Error::OperationFailure => e
263
- e.add_note('retries disabled')
264
- raise e
265
- end
253
+ yield server
266
254
  else
267
255
  legacy_write_with_retry(nil, session, &block)
268
256
  end
@@ -292,8 +280,7 @@ module Mongo
292
280
  server ||= select_server(cluster, ServerSelector.primary, session)
293
281
  yield server
294
282
  rescue Error::OperationFailure => e
295
- e.add_note('legacy retry')
296
- e.add_note("attempt #{attempt}")
283
+ e.add_note("attempt #{attempt + 1}")
297
284
  server = nil
298
285
  if attempt > client.max_write_retries
299
286
  raise e
@@ -311,19 +298,18 @@ module Mongo
311
298
  private
312
299
 
313
300
  def modern_read_with_retry(session, server_selector, &block)
301
+ attempt = 0
314
302
  server = select_server(cluster, server_selector, session)
315
303
  begin
316
304
  yield server
317
305
  rescue Error::SocketError, Error::SocketTimeoutError => e
318
- e.add_note('modern retry')
319
- e.add_note("attempt 1")
306
+ e.add_note("attempt #{attempt + 1}")
320
307
  if session.in_transaction?
321
308
  raise e
322
309
  end
323
310
  retry_read(e, server_selector, session, &block)
324
311
  rescue Error::OperationFailure => e
325
- e.add_note('modern retry')
326
- e.add_note("attempt 1")
312
+ e.add_note("attempt #{attempt + 1}")
327
313
  if session.in_transaction? || !e.write_retryable?
328
314
  raise e
329
315
  end
@@ -338,8 +324,7 @@ module Mongo
338
324
  attempt += 1
339
325
  yield server
340
326
  rescue Error::SocketError, Error::SocketTimeoutError => e
341
- e.add_note('legacy retry')
342
- e.add_note("attempt #{attempt}")
327
+ e.add_note("attempt #{attempt + 1}")
343
328
  if attempt > client.max_read_retries || (session && session.in_transaction?)
344
329
  raise e
345
330
  end
@@ -347,9 +332,8 @@ module Mongo
347
332
  server = select_server(cluster, server_selector, session)
348
333
  retry
349
334
  rescue Error::OperationFailure => e
350
- e.add_note('legacy retry')
351
- e.add_note("attempt #{attempt}")
352
- if e.retryable? && !(session && session.in_transaction?)
335
+ e.add_note("attempt #{attempt + 1}")
336
+ if cluster.sharded? && e.retryable? && !(session && session.in_transaction?)
353
337
  if attempt > client.max_read_retries
354
338
  raise e
355
339
  end
@@ -391,11 +375,9 @@ module Mongo
391
375
  begin
392
376
  yield server, true
393
377
  rescue Error::SocketError, Error::SocketTimeoutError => e
394
- e.add_note('modern retry')
395
378
  e.add_note("attempt 2")
396
379
  raise e
397
380
  rescue Error::OperationFailure => e
398
- e.add_note('modern retry')
399
381
  unless e.write_retryable?
400
382
  original_error.add_note("later retry failed: #{e.class}: #{e}")
401
383
  raise original_error
@@ -403,7 +385,6 @@ module Mongo
403
385
  e.add_note("attempt 2")
404
386
  raise e
405
387
  rescue => e
406
- e.add_note('modern retry')
407
388
  original_error.add_note("later retry failed: #{e.class}: #{e}")
408
389
  raise original_error
409
390
  end
@@ -417,19 +398,15 @@ module Mongo
417
398
  # server unknown). Here we just need to wait for server selection.
418
399
  server = select_server(cluster, ServerSelector.primary, session)
419
400
  unless server.retry_writes?
420
- # Do not need to add "modern retry" here, it should already be on
421
- # the first exception.
422
401
  original_error.add_note('did not retry because server selected for retry does not supoprt retryable writes')
423
402
  raise original_error
424
403
  end
425
404
  log_retry(original_error, message: 'Write retry')
426
405
  yield(server, txn_num, true)
427
406
  rescue Error::SocketError, Error::SocketTimeoutError => e
428
- e.add_note('modern retry')
429
407
  e.add_note('attempt 2')
430
408
  raise e
431
409
  rescue Error::OperationFailure => e
432
- e.add_note('modern retry')
433
410
  if e.write_retryable?
434
411
  e.add_note('attempt 2')
435
412
  raise e
@@ -438,8 +415,6 @@ module Mongo
438
415
  raise original_error
439
416
  end
440
417
  rescue => e
441
- # Do not need to add "modern retry" here, it should already be on
442
- # the first exception.
443
418
  original_error.add_note("later retry failed: #{e.class}: #{e}")
444
419
  raise original_error
445
420
  end
@@ -25,7 +25,7 @@ module Mongo
25
25
 
26
26
  # Waits for the semaphore to be signaled up to timeout seconds.
27
27
  # If semaphore is not signaled, returns after timeout seconds.
28
- def wait(timeout)
28
+ def wait(timeout = nil)
29
29
  @lock.synchronize do
30
30
  @cv.wait(@lock, timeout)
31
31
  end
data/lib/mongo/server.rb CHANGED
@@ -58,16 +58,24 @@ module Mongo
58
58
  @cluster = cluster
59
59
  @monitoring = monitoring
60
60
  options = options.dup
61
- monitor = options.delete(:monitor)
61
+ _monitor = options.delete(:monitor)
62
62
  @options = options.freeze
63
63
  @event_listeners = event_listeners
64
64
  @connection_id_gen = Class.new do
65
65
  include Id
66
66
  end
67
- @monitor = Monitor.new(address, event_listeners, monitoring,
68
- options.merge(app_metadata: Monitor::AppMetadata.new(cluster.options)))
69
- unless monitor == false
70
- start_monitoring
67
+ @scan_semaphore = Semaphore.new
68
+ @round_trip_time_averager = RoundTripTimeAverager.new
69
+ @description = Description.new(address, {})
70
+ @last_scan = nil
71
+ unless options[:monitoring_io] == false
72
+ @monitor = Monitor.new(self, event_listeners, monitoring,
73
+ options.merge(
74
+ app_metadata: Monitor::AppMetadata.new(cluster.options),
75
+ ))
76
+ unless _monitor == false
77
+ start_monitoring
78
+ end
71
79
  end
72
80
  @connected = true
73
81
  @pool_lock = Mutex.new
@@ -79,7 +87,8 @@ module Mongo
79
87
  # @return [ Cluster ] cluster The server cluster.
80
88
  attr_reader :cluster
81
89
 
82
- # @return [ Monitor ] monitor The server monitor.
90
+ # @return [ nil | Monitor ] monitor The server monitor. nil if the servenr
91
+ # was created with monitoring_io: false option.
83
92
  attr_reader :monitor
84
93
 
85
94
  # @return [ Hash ] The options hash.
@@ -88,15 +97,46 @@ module Mongo
88
97
  # @return [ Monitoring ] monitoring The monitoring.
89
98
  attr_reader :monitoring
90
99
 
91
- # Get the description from the monitor and scan on monitor.
92
- def_delegators :monitor,
93
- :description,
94
- :scan!,
95
- :heartbeat_frequency,
96
- :last_scan,
97
- :compressor
100
+ # @return [ Server::Description ] description The server
101
+ # description the monitor refreshes.
102
+ attr_reader :description
103
+
104
+ # @return [ Time | nil ] last_scan The time when the last server scan
105
+ # completed, or nil if the server has not been scanned yet.
106
+ #
107
+ # @since 2.4.0
108
+ def last_scan
109
+ if description && !description.config.empty?
110
+ description.last_update_time
111
+ else
112
+ @last_scan
113
+ end
114
+ end
115
+
116
+ # @deprecated
117
+ def heartbeat_frequency
118
+ cluster.heartbeat_interval
119
+ end
120
+
121
+ # @deprecated
98
122
  alias :heartbeat_frequency_seconds :heartbeat_frequency
99
123
 
124
+ # @deprecated
125
+ def_delegators :monitor, :scan!
126
+
127
+ # The last compressor discovered by the server monitor.
128
+ #
129
+ # The compressor state should be determined for each individual
130
+ # connection rather than kept per server. A future version of the
131
+ # driver will change how compressors are tracked and used.
132
+ def compressor
133
+ if monitor
134
+ monitor.compressor
135
+ else
136
+ nil
137
+ end
138
+ end
139
+
100
140
  # Delegate convenience methods to the monitor description.
101
141
  def_delegators :description,
102
142
  :arbiter?,
@@ -127,6 +167,16 @@ module Mongo
127
167
  def_delegators :features,
128
168
  :check_driver_support!
129
169
 
170
+ # @return [ Semaphore ] Semaphore to signal to request an immediate scan
171
+ # of this server by its monitor, if one is running.
172
+ #
173
+ # @api private
174
+ attr_reader :scan_semaphore
175
+
176
+ # @return [ RoundTripTimeAverager ] Round trip time averager object.
177
+ # @api private
178
+ attr_reader :round_trip_time_averager
179
+
130
180
  # Is this server equal to another?
131
181
  #
132
182
  # @example Is the server equal to the other?
@@ -169,26 +219,37 @@ module Mongo
169
219
  # @deprecated No longer necessary with Server Selection specification.
170
220
  def connectable?; end
171
221
 
172
- # Disconnect the server from the connection.
173
- #
174
- # @example Disconnect the server.
175
- # server.disconnect!
222
+ # Disconnect the driver from this server.
176
223
  #
177
- # @param [ Boolean ] wait Whether to wait for background threads to
178
- # finish running.
224
+ # Disconnects all idle connections to this server in its connection pool,
225
+ # if any exist. Stops the populator of the connection pool, if it is
226
+ # running. Does not immediately close connections which are presently
227
+ # checked out (i.e. in use) - such connections will be closed when they
228
+ # are returned to their respective connection pools. Stop the server's
229
+ # background monitor.
179
230
  #
180
- # @return [ true ] Always true with no exception.
231
+ # @return [ true ] Always true.
181
232
  #
182
233
  # @since 2.0.0
183
- def disconnect!(wait=false)
184
- begin
234
+ def disconnect!
235
+ if monitor
236
+ monitor.stop!
237
+ end
238
+ _pool = @pool_lock.synchronize do
239
+ @pool
240
+ end
241
+ if _pool
185
242
  # For backwards compatibility we disconnect/clear the pool rather
186
- # than close it here.
187
- pool.disconnect!
188
- rescue Error::PoolClosedError
189
- # If the pool was already closed, we don't need to do anything here.
243
+ # than close it here. We also stop the populator which allows the
244
+ # the pool to continue providing connections but stops it from
245
+ # connecting in background on clients/servers that are in fact
246
+ # intended to be closed and no longer used.
247
+ begin
248
+ _pool.disconnect!(stop_populator: true)
249
+ rescue Error::PoolClosedError
250
+ # If the pool was already closed, we don't need to do anything here.
251
+ end
190
252
  end
191
- monitor.stop!(wait)
192
253
  @connected = false
193
254
  true
194
255
  end
@@ -228,8 +289,8 @@ module Mongo
228
289
  Monitoring::Event::ServerOpening.new(address, cluster.topology)
229
290
  )
230
291
  if options[:monitoring_io] != false
231
- monitor.run!
232
292
  ObjectSpace.define_finalizer(self, self.class.finalize(monitor))
293
+ monitor.run!
233
294
  end
234
295
  end
235
296
 
@@ -275,11 +336,17 @@ module Mongo
275
336
  if replica_set_name
276
337
  status += " replica_set=#{replica_set_name}"
277
338
  end
339
+
340
+ if @pool
341
+ status += " pool=#{@pool.summary}"
342
+ end
343
+
278
344
  address_bit = if address
279
345
  "#{address.host}:#{address.port}"
280
346
  else
281
347
  'nil'
282
348
  end
349
+
283
350
  "#<Server address=#{address_bit} #{status}>"
284
351
  end
285
352
 
@@ -374,7 +441,6 @@ module Mongo
374
441
  rescue Mongo::Error::SocketError
375
442
  # non-timeout network error
376
443
  unknown!
377
- pool.disconnect!
378
444
  raise
379
445
  rescue Auth::Unauthorized
380
446
  # auth error, keep server description and topology as they are
@@ -407,24 +473,24 @@ module Mongo
407
473
  # Marks server unknown and publishes the associated SDAM event
408
474
  # (server description changed).
409
475
  #
476
+ # @param [ Hash ] options Options.
477
+ #
478
+ # @option options [ true | false ] :keep_connection_pool Usually when the
479
+ # new server description is unknown, the connection pool on the
480
+ # respective server is cleared. Set this option to true to keep the
481
+ # existing connection pool (required when handling not master errors
482
+ # on 4.2+ servers).
483
+ #
410
484
  # @since 2.4.0, SDAM events are sent as of version 2.7.0
411
- def unknown!
412
- # Just dispatch the description changed event here, SDAM flow
413
- # will update description on the server without in-place mutations
414
- # and invoke SDAM transitions as needed.
415
- publish(Event::DESCRIPTION_CHANGED, description, Description.new(address))
485
+ def unknown!(options = {})
486
+ # SDAM flow will update description on the server without in-place
487
+ # mutations and invoke SDAM transitions as needed.
488
+ cluster.run_sdam_flow(description, Description.new(address), options)
416
489
  end
417
490
 
418
491
  # @api private
419
492
  def update_description(description)
420
- prev_description = monitor.instance_variable_get('@description')
421
- monitor.instance_variable_set('@description', description)
422
- if description.unknown? && !prev_description.unknown?
423
- # This clears redundantly sometimes and also clears the pool on
424
- # 4.2+ servers after not master errors which should not be done.
425
- # Driver version 2.11+ has the correct implementation.
426
- clear_connection_pool
427
- end
493
+ @description = description
428
494
  end
429
495
 
430
496
  # @api private
@@ -440,6 +506,11 @@ module Mongo
440
506
  def next_connection_id
441
507
  @connection_id_gen.next_id
442
508
  end
509
+
510
+ # @api private
511
+ def update_last_scan
512
+ @last_scan = Time.now
513
+ end
443
514
  end
444
515
  end
445
516