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
@@ -34,6 +34,7 @@ module Mongo
|
|
34
34
|
#
|
35
35
|
# @since 2.0.0
|
36
36
|
def aggregate_write_errors(count)
|
37
|
+
return unless @replies
|
37
38
|
@replies.reduce(nil) do |errors, reply|
|
38
39
|
if write_errors = reply.documents.first[Error::WRITE_ERRORS]
|
39
40
|
wes = write_errors.collect do |we|
|
@@ -55,6 +56,7 @@ module Mongo
|
|
55
56
|
#
|
56
57
|
# @since 2.0.0
|
57
58
|
def aggregate_write_concern_errors(count)
|
59
|
+
return unless @replies
|
58
60
|
@replies.each_with_index.reduce(nil) do |errors, (reply, _)|
|
59
61
|
if write_concern_errors = reply.documents.first[Error::WRITE_CONCERN_ERRORS]
|
60
62
|
(errors || []) << write_concern_errors.reduce(nil) do |errs, wce|
|
@@ -33,6 +33,25 @@ module Mongo
|
|
33
33
|
include TakesWriteConcern
|
34
34
|
include UsesCommandOpMsg
|
35
35
|
|
36
|
+
# Execute the operation.
|
37
|
+
#
|
38
|
+
# @example Execute the operation.
|
39
|
+
# operation.execute(server)
|
40
|
+
#
|
41
|
+
# @param [ Mongo::Server ] server The server to send this operation to.
|
42
|
+
#
|
43
|
+
# @return [ Result ] The operation response, if there is one.
|
44
|
+
#
|
45
|
+
# @since 2.5.0
|
46
|
+
def execute(server)
|
47
|
+
result = Result.new(server.with_connection do |connection|
|
48
|
+
connection.dispatch([ message(server) ], operation_id)
|
49
|
+
end)
|
50
|
+
server.update_cluster_time(result)
|
51
|
+
session.process(result) if session
|
52
|
+
result.validate!
|
53
|
+
end
|
54
|
+
|
36
55
|
private
|
37
56
|
|
38
57
|
# The query selector for this ensure index command operation.
|
@@ -25,6 +25,25 @@ module Mongo
|
|
25
25
|
include Specifiable
|
26
26
|
include Writable
|
27
27
|
|
28
|
+
# Execute the operation.
|
29
|
+
#
|
30
|
+
# @example Execute the operation.
|
31
|
+
# operation.execute(server)
|
32
|
+
#
|
33
|
+
# @param [ Mongo::Server ] server The server to send this operation to.
|
34
|
+
#
|
35
|
+
# @return [ Result ] The operation response, if there is one.
|
36
|
+
#
|
37
|
+
# @since 2.5.0
|
38
|
+
def execute(server)
|
39
|
+
result = Result.new(server.with_connection do |connection|
|
40
|
+
connection.dispatch([ message(server) ], operation_id)
|
41
|
+
end)
|
42
|
+
server.update_cluster_time(result)
|
43
|
+
session.process(result) if session
|
44
|
+
result.validate!
|
45
|
+
end
|
46
|
+
|
28
47
|
private
|
29
48
|
|
30
49
|
# The query selector for this create user command operation.
|
@@ -52,8 +52,7 @@ module Mongo
|
|
52
52
|
global_args = { delete: coll_name,
|
53
53
|
Protocol::Msg::DATABASE_IDENTIFIER => db_name
|
54
54
|
}.merge!(command_options)
|
55
|
-
|
56
|
-
session.add_id!(global_args) if session
|
55
|
+
update_selector_for_session!(global_args, server)
|
57
56
|
|
58
57
|
section = { type: 1, payload: { identifier: IDENTIFIER, sequence: deletes } }
|
59
58
|
flags = unacknowledged_write? ? [:more_to_come] : [:none]
|
@@ -34,6 +34,25 @@ module Mongo
|
|
34
34
|
include TakesWriteConcern
|
35
35
|
include UsesCommandOpMsg
|
36
36
|
|
37
|
+
# Execute the operation.
|
38
|
+
#
|
39
|
+
# @example Execute the operation.
|
40
|
+
# operation.execute(server)
|
41
|
+
#
|
42
|
+
# @param [ Mongo::Server ] server The server to send this operation to.
|
43
|
+
#
|
44
|
+
# @return [ Result ] The operation response, if there is one.
|
45
|
+
#
|
46
|
+
# @since 2.5.0
|
47
|
+
def execute(server)
|
48
|
+
result = Result.new(server.with_connection do |connection|
|
49
|
+
connection.dispatch([ message(server) ], operation_id)
|
50
|
+
end)
|
51
|
+
server.update_cluster_time(result)
|
52
|
+
session.process(result) if session
|
53
|
+
result.validate!
|
54
|
+
end
|
55
|
+
|
37
56
|
private
|
38
57
|
|
39
58
|
# The query selector for this drop index command operation.
|
@@ -46,8 +46,7 @@ module Mongo
|
|
46
46
|
global_args = { insert: coll_name,
|
47
47
|
Protocol::Msg::DATABASE_IDENTIFIER => db_name
|
48
48
|
}.merge!(command_options)
|
49
|
-
|
50
|
-
session.add_id!(global_args) if session
|
49
|
+
update_selector_for_session!(global_args, server)
|
51
50
|
|
52
51
|
section = { type: 1, payload: { identifier: IDENTIFIER, sequence: documents } }
|
53
52
|
flags = unacknowledged_write? ? [:more_to_come] : [:none]
|
@@ -24,6 +24,25 @@ module Mongo
|
|
24
24
|
include Specifiable
|
25
25
|
include Writable
|
26
26
|
|
27
|
+
# Execute the operation.
|
28
|
+
#
|
29
|
+
# @example Execute the operation.
|
30
|
+
# operation.execute(server)
|
31
|
+
#
|
32
|
+
# @param [ Mongo::Server ] server The server to send this operation to.
|
33
|
+
#
|
34
|
+
# @return [ Result ] The operation response, if there is one.
|
35
|
+
#
|
36
|
+
# @since 2.5.0
|
37
|
+
def execute(server)
|
38
|
+
result = Result.new(server.with_connection do |connection|
|
39
|
+
connection.dispatch([ message(server) ], operation_id)
|
40
|
+
end)
|
41
|
+
server.update_cluster_time(result)
|
42
|
+
session.process(result) if session
|
43
|
+
result.validate!
|
44
|
+
end
|
45
|
+
|
27
46
|
private
|
28
47
|
|
29
48
|
# The query selector for this drop user command operation.
|
@@ -55,8 +55,7 @@ module Mongo
|
|
55
55
|
global_args = { update: coll_name,
|
56
56
|
Protocol::Msg::DATABASE_IDENTIFIER => db_name
|
57
57
|
}.merge!(command_options)
|
58
|
-
|
59
|
-
session.add_id!(global_args) if session
|
58
|
+
update_selector_for_session!(global_args, server)
|
60
59
|
|
61
60
|
section = { type: 1, payload: { identifier: IDENTIFIER, sequence: updates } }
|
62
61
|
flags = unacknowledged_write? ? [:more_to_come] : [:none]
|
@@ -25,6 +25,25 @@ module Mongo
|
|
25
25
|
include Specifiable
|
26
26
|
include Writable
|
27
27
|
|
28
|
+
# Execute the operation.
|
29
|
+
#
|
30
|
+
# @example Execute the operation.
|
31
|
+
# operation.execute(server)
|
32
|
+
#
|
33
|
+
# @param [ Mongo::Server ] server The server to send this operation to.
|
34
|
+
#
|
35
|
+
# @return [ Result ] The operation response, if there is one.
|
36
|
+
#
|
37
|
+
# @since 2.5.0
|
38
|
+
def execute(server)
|
39
|
+
result = Result.new(server.with_connection do |connection|
|
40
|
+
connection.dispatch([ message(server) ], operation_id)
|
41
|
+
end)
|
42
|
+
server.update_cluster_time(result)
|
43
|
+
session.process(result) if session
|
44
|
+
result.validate!
|
45
|
+
end
|
46
|
+
|
28
47
|
private
|
29
48
|
|
30
49
|
# The query selector for this update user command operation.
|
@@ -39,9 +39,7 @@ module Mongo
|
|
39
39
|
raise Error::UnsupportedArrayFilters.new(Error::UnsupportedArrayFilters::UNACKNOWLEDGED_WRITES_MESSAGE) if has_array_filters?
|
40
40
|
end
|
41
41
|
|
42
|
-
if
|
43
|
-
execute_message(server)
|
44
|
-
elsif server.features.op_msg_enabled? # version 3.6
|
42
|
+
if server.features.op_msg_enabled? # version 3.6
|
45
43
|
execute_write_command(server)
|
46
44
|
else # server version is 2.6 through 3.4
|
47
45
|
if unacknowledged_write?
|
@@ -48,7 +48,8 @@ module Mongo
|
|
48
48
|
#
|
49
49
|
# @param [ Mongo::Protocol::Message ] message The original message.
|
50
50
|
# @param [ String, Symbol ] compressor The compression algorithm to use.
|
51
|
-
# @param [ Integer ]
|
51
|
+
# @param [ Integer ] zlib_compression_level The zlib compression level to use.
|
52
|
+
# -1 and nil imply default.
|
52
53
|
#
|
53
54
|
# @since 2.5.0
|
54
55
|
def initialize(message, compressor, zlib_compression_level = nil)
|
@@ -355,9 +355,9 @@ module Mongo
|
|
355
355
|
|
356
356
|
# Writes a byte into the buffer.
|
357
357
|
#
|
358
|
-
# @param
|
359
|
-
# @param
|
360
|
-
# @param
|
358
|
+
# @param [ BSON::ByteBuffer ] buffer Buffer to receive the single byte.
|
359
|
+
# @param [ String ] value The byte to write to the buffer.
|
360
|
+
# @param [ true, false ] validating_keys Whether to validate keys.
|
361
361
|
#
|
362
362
|
# @return [ BSON::ByteBuffer ] Buffer with serialized value.
|
363
363
|
#
|
@@ -385,9 +385,9 @@ module Mongo
|
|
385
385
|
|
386
386
|
# Writes bytes into the buffer.
|
387
387
|
#
|
388
|
-
# @param
|
389
|
-
# @param
|
390
|
-
# @param
|
388
|
+
# @param [ BSON::ByteBuffer ] buffer Buffer to receive the bytes.
|
389
|
+
# @param [ String ] value The bytes to write to the buffer.
|
390
|
+
# @param [ true, false ] validating_keys Whether to validate keys.
|
391
391
|
#
|
392
392
|
# @return [ BSON::ByteBuffer ] Buffer with serialized value.
|
393
393
|
#
|
data/lib/mongo/retryable.rb
CHANGED
@@ -30,7 +30,6 @@ module Mongo
|
|
30
30
|
#
|
31
31
|
# @note This only retries read operations on socket errors.
|
32
32
|
#
|
33
|
-
# @param [ Integer ] attempt The retry attempt count - for internal use.
|
34
33
|
# @param [ Proc ] block The block to execute.
|
35
34
|
#
|
36
35
|
# @yieldparam [ Server ] server The server to which the write should be sent.
|
@@ -99,12 +98,58 @@ module Mongo
|
|
99
98
|
# @return [ Result ] The result of the operation.
|
100
99
|
#
|
101
100
|
# @since 2.1.0
|
102
|
-
def write_with_retry(session,
|
101
|
+
def write_with_retry(session, write_concern, &block)
|
102
|
+
unless retry_write_allowed?(session, write_concern)
|
103
|
+
return legacy_write_with_retry(&block)
|
104
|
+
end
|
105
|
+
|
106
|
+
server = cluster.next_primary
|
107
|
+
unless server.retry_writes?
|
108
|
+
return legacy_write_with_retry(server, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
begin
|
112
|
+
txn_num = session.next_txn_num
|
113
|
+
yield(server, txn_num)
|
114
|
+
rescue Error::SocketError, Error::SocketTimeoutError => e
|
115
|
+
retry_write(e, txn_num, &block)
|
116
|
+
rescue Error::OperationFailure => e
|
117
|
+
raise e unless e.write_retryable?
|
118
|
+
retry_write(e, txn_num, &block)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def retry_write_allowed?(session, write_concern)
|
125
|
+
session && session.retry_writes? &&
|
126
|
+
(write_concern.nil? || write_concern.acknowledged?)
|
127
|
+
end
|
128
|
+
|
129
|
+
def retry_write(original_error, txn_num, &block)
|
130
|
+
cluster.scan!
|
131
|
+
server = cluster.next_primary
|
132
|
+
raise original_error unless (server.retry_writes? && txn_num)
|
133
|
+
log_retry(original_error)
|
134
|
+
yield(server, txn_num)
|
135
|
+
rescue Error::SocketError, Error::SocketTimeoutError => e
|
136
|
+
cluster.scan!
|
137
|
+
raise e
|
138
|
+
rescue Error::OperationFailure => e
|
139
|
+
raise original_error unless e.write_retryable?
|
140
|
+
cluster.scan!
|
141
|
+
raise e
|
142
|
+
rescue
|
143
|
+
raise original_error
|
144
|
+
end
|
145
|
+
|
146
|
+
def legacy_write_with_retry(server = nil)
|
103
147
|
attempt = 0
|
104
148
|
begin
|
105
149
|
attempt += 1
|
106
|
-
yield(
|
150
|
+
yield(server || cluster.next_primary)
|
107
151
|
rescue Error::OperationFailure => e
|
152
|
+
server = nil
|
108
153
|
raise(e) if attempt > Cluster::MAX_WRITE_RETRIES
|
109
154
|
if e.write_retryable?
|
110
155
|
log_retry(e)
|
@@ -116,8 +161,6 @@ module Mongo
|
|
116
161
|
end
|
117
162
|
end
|
118
163
|
|
119
|
-
private
|
120
|
-
|
121
164
|
# Log a warning so that any application slow down is immediately obvious.
|
122
165
|
def log_retry(e)
|
123
166
|
Logger.logger.warn "Retry due to: #{e.class.name} #{e.message}"
|
data/lib/mongo/server.rb
CHANGED
@@ -268,5 +268,20 @@ module Mongo
|
|
268
268
|
unknown!
|
269
269
|
raise
|
270
270
|
end
|
271
|
+
|
272
|
+
# Will writes sent to this server be retried.
|
273
|
+
#
|
274
|
+
# @example Will writes be retried.
|
275
|
+
# server.retry_writes?
|
276
|
+
#
|
277
|
+
# @return [ true, false ] If writes will be retried.
|
278
|
+
#
|
279
|
+
# @note Retryable writes are only available on server versions 3.6+ and with
|
280
|
+
# sharded clusters or replica sets.
|
281
|
+
#
|
282
|
+
# @since 2.5.0
|
283
|
+
def retry_writes?
|
284
|
+
!!(features.sessions_enabled? && logical_session_timeout && !standalone?)
|
285
|
+
end
|
271
286
|
end
|
272
287
|
end
|
@@ -54,6 +54,11 @@ module Mongo
|
|
54
54
|
# @since 2.5.0
|
55
55
|
PING_OP_MSG_BYTES = PING_OP_MSG_MESSAGE.serialize.to_s.freeze
|
56
56
|
|
57
|
+
# The last time the connection was checked back into a pool.
|
58
|
+
#
|
59
|
+
# @since 2.5.0
|
60
|
+
attr_reader :last_checkin
|
61
|
+
|
57
62
|
def_delegators :@server,
|
58
63
|
:features,
|
59
64
|
:max_bson_object_size,
|
@@ -97,9 +102,10 @@ module Mongo
|
|
97
102
|
#
|
98
103
|
# @since 2.0.0
|
99
104
|
def disconnect!
|
105
|
+
@auth_mechanism = nil
|
106
|
+
@last_checkin = nil
|
100
107
|
if socket
|
101
108
|
socket.close
|
102
|
-
@auth_mechanism = nil
|
103
109
|
@socket = nil
|
104
110
|
end
|
105
111
|
true
|
@@ -151,6 +157,7 @@ module Mongo
|
|
151
157
|
@server = server
|
152
158
|
@ssl_options = options.reject { |k, v| !k.to_s.start_with?(SSL) }
|
153
159
|
@socket = nil
|
160
|
+
@last_checkin = nil
|
154
161
|
@auth_mechanism = nil
|
155
162
|
@pid = Process.pid
|
156
163
|
end
|
@@ -189,6 +196,19 @@ module Mongo
|
|
189
196
|
# @deprecated Please use :socket_timeout instead. Will be removed in 3.0.0
|
190
197
|
alias :timeout :socket_timeout
|
191
198
|
|
199
|
+
# Record the last checkin time.
|
200
|
+
#
|
201
|
+
# @example Record the checkin time on this connection.
|
202
|
+
# connection.record_checkin!
|
203
|
+
#
|
204
|
+
# @return [ self ]
|
205
|
+
#
|
206
|
+
# @since 2.5.0
|
207
|
+
def record_checkin!
|
208
|
+
@last_checkin = Time.now
|
209
|
+
self
|
210
|
+
end
|
211
|
+
|
192
212
|
private
|
193
213
|
|
194
214
|
def deliver(messages)
|
@@ -22,10 +22,13 @@ module Mongo
|
|
22
22
|
# @since 2.0.0
|
23
23
|
class ConnectionPool
|
24
24
|
include Loggable
|
25
|
+
extend Forwardable
|
25
26
|
|
26
27
|
# @return [ Hash ] options The pool options.
|
27
28
|
attr_reader :options
|
28
29
|
|
30
|
+
def_delegators :queue, :close_stale_sockets!
|
31
|
+
|
29
32
|
# Check a connection back into the pool. Will pull the connection from a
|
30
33
|
# thread local stack that should contain it after it was checked out.
|
31
34
|
#
|
@@ -16,9 +16,8 @@ module Mongo
|
|
16
16
|
class Server
|
17
17
|
class ConnectionPool
|
18
18
|
|
19
|
-
# A
|
20
|
-
# based on mperham's connection pool
|
21
|
-
# stack.
|
19
|
+
# A LIFO queue of connections to be used by the connection pool. This is
|
20
|
+
# based on mperham's connection pool.
|
22
21
|
#
|
23
22
|
# @since 2.0.0
|
24
23
|
class Queue
|
@@ -88,7 +87,7 @@ module Mongo
|
|
88
87
|
# @since 2.0.0
|
89
88
|
def enqueue(connection)
|
90
89
|
mutex.synchronize do
|
91
|
-
queue.unshift(connection)
|
90
|
+
queue.unshift(connection.record_checkin!)
|
92
91
|
resource.broadcast
|
93
92
|
end
|
94
93
|
end
|
@@ -165,12 +164,58 @@ module Mongo
|
|
165
164
|
@wait_timeout ||= options[:wait_queue_timeout] || WAIT_TIMEOUT
|
166
165
|
end
|
167
166
|
|
167
|
+
# The maximum seconds a socket can remain idle since it has been checked in to the pool.
|
168
|
+
#
|
169
|
+
# @example Get the max idle time.
|
170
|
+
# queue.max_idle_time
|
171
|
+
#
|
172
|
+
# @return [ Float ] The max socket idle time in seconds.
|
173
|
+
#
|
174
|
+
# @since 2.5.0
|
175
|
+
def max_idle_time
|
176
|
+
@max_idle_time ||= options[:max_idle_time]
|
177
|
+
end
|
178
|
+
|
179
|
+
# Close sockets that have been open for longer than the max idle time, if the
|
180
|
+
# option is set.
|
181
|
+
#
|
182
|
+
# @example Close the stale sockets
|
183
|
+
# queue.close_stale_sockets!
|
184
|
+
#
|
185
|
+
# @since 2.5.0
|
186
|
+
def close_stale_sockets!
|
187
|
+
return unless max_idle_time
|
188
|
+
|
189
|
+
to_refresh = []
|
190
|
+
queue.each do |connection|
|
191
|
+
if last_checkin = connection.last_checkin
|
192
|
+
if (Time.now - last_checkin) > max_idle_time
|
193
|
+
to_refresh << connection
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
mutex.synchronize do
|
199
|
+
num_checked_out = @connections - queue.size
|
200
|
+
min_size_delta = [(min_size - num_checked_out), 0].max
|
201
|
+
|
202
|
+
to_refresh.each do |connection|
|
203
|
+
if queue.include?(connection)
|
204
|
+
connection.disconnect!
|
205
|
+
if queue.index(connection) < min_size_delta
|
206
|
+
begin; connection.connect!; rescue; end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
168
213
|
private
|
169
214
|
|
170
215
|
def dequeue_connection
|
171
216
|
deadline = Time.now + wait_timeout
|
172
217
|
loop do
|
173
|
-
return queue.
|
218
|
+
return queue.shift unless queue.empty?
|
174
219
|
connection = create_connection
|
175
220
|
return connection if connection
|
176
221
|
wait_for_next!(deadline)
|