mongo 2.3.1 → 2.4.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -3
- data/lib/mongo/bulk_write.rb +8 -7
- data/lib/mongo/bulk_write/combineable.rb +4 -0
- data/lib/mongo/bulk_write/transformable.rb +17 -5
- data/lib/mongo/bulk_write/validatable.rb +1 -0
- data/lib/mongo/client.rb +3 -0
- data/lib/mongo/cluster.rb +8 -0
- data/lib/mongo/cluster/app_metadata.rb +135 -0
- data/lib/mongo/collection.rb +42 -10
- data/lib/mongo/collection/view.rb +15 -1
- data/lib/mongo/collection/view/aggregation.rb +5 -0
- data/lib/mongo/collection/view/builder/aggregation.rb +13 -3
- data/lib/mongo/collection/view/builder/find_command.rb +7 -21
- data/lib/mongo/collection/view/builder/map_reduce.rb +22 -5
- data/lib/mongo/collection/view/iterable.rb +1 -0
- data/lib/mongo/collection/view/map_reduce.rb +5 -0
- data/lib/mongo/collection/view/readable.rb +35 -14
- data/lib/mongo/collection/view/writable.rb +54 -23
- data/lib/mongo/cursor/builder/get_more_command.rb +2 -3
- data/lib/mongo/database.rb +10 -2
- data/lib/mongo/error.rb +2 -0
- data/lib/mongo/error/invalid_application_name.rb +38 -0
- data/lib/mongo/error/invalid_server_preference.rb +24 -3
- data/lib/mongo/error/unsupported_collation.rb +51 -0
- data/lib/mongo/index/view.rb +28 -15
- data/lib/mongo/operation.rb +6 -0
- data/lib/mongo/operation/commands.rb +3 -0
- data/lib/mongo/operation/commands/aggregate.rb +10 -10
- data/lib/mongo/operation/commands/create.rb +45 -0
- data/lib/mongo/operation/commands/drop.rb +45 -0
- data/lib/mongo/operation/commands/drop_database.rb +45 -0
- data/lib/mongo/operation/commands/map_reduce.rb +12 -1
- data/lib/mongo/operation/commands/parallel_scan.rb +1 -0
- data/lib/mongo/operation/read_preference.rb +9 -9
- data/lib/mongo/operation/specifiable.rb +34 -0
- data/lib/mongo/operation/takes_write_concern.rb +35 -0
- data/lib/mongo/operation/write/bulk/bulkable.rb +1 -1
- data/lib/mongo/operation/write/command/create_index.rb +6 -0
- data/lib/mongo/operation/write/command/drop_index.rb +6 -0
- data/lib/mongo/operation/write/command/insert.rb +1 -1
- data/lib/mongo/operation/write/command/update.rb +1 -0
- data/lib/mongo/operation/write/command/writable.rb +2 -2
- data/lib/mongo/operation/write/create_index.rb +2 -2
- data/lib/mongo/operation/write/create_user.rb +1 -1
- data/lib/mongo/operation/write/delete.rb +5 -1
- data/lib/mongo/operation/write/gle.rb +1 -1
- data/lib/mongo/operation/write/insert.rb +2 -2
- data/lib/mongo/operation/write/remove_user.rb +1 -1
- data/lib/mongo/operation/write/update.rb +5 -1
- data/lib/mongo/operation/write/update_user.rb +1 -1
- data/lib/mongo/operation/write/write_command_enabled.rb +10 -2
- data/lib/mongo/protocol/insert.rb +1 -2
- data/lib/mongo/protocol/query.rb +3 -7
- data/lib/mongo/server.rb +8 -3
- data/lib/mongo/server/connection.rb +17 -11
- data/lib/mongo/server/description.rb +22 -0
- data/lib/mongo/server/description/features.rb +2 -0
- data/lib/mongo/server/monitor.rb +5 -0
- data/lib/mongo/server/monitor/connection.rb +11 -0
- data/lib/mongo/server_selector/nearest.rb +9 -6
- data/lib/mongo/server_selector/primary.rb +4 -0
- data/lib/mongo/server_selector/primary_preferred.rb +7 -1
- data/lib/mongo/server_selector/secondary.rb +5 -0
- data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
- data/lib/mongo/server_selector/selectable.rb +57 -10
- data/lib/mongo/socket/ssl.rb +1 -0
- data/lib/mongo/uri.rb +4 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo/write_concern.rb +1 -0
- data/mongo.gemspec +1 -1
- data/spec/mongo/auth/cr_spec.rb +7 -1
- data/spec/mongo/auth/ldap_spec.rb +7 -1
- data/spec/mongo/auth/scram_spec.rb +7 -1
- data/spec/mongo/auth/x509_spec.rb +7 -1
- data/spec/mongo/bulk_write_spec.rb +598 -5
- data/spec/mongo/client_spec.rb +47 -1
- data/spec/mongo/cluster/app_metadata_spec.rb +104 -0
- data/spec/mongo/cluster/topology/replica_set_spec.rb +14 -8
- data/spec/mongo/cluster/topology/sharded_spec.rb +9 -3
- data/spec/mongo/cluster/topology/single_spec.rb +10 -4
- data/spec/mongo/cluster_spec.rb +29 -0
- data/spec/mongo/collection/view/aggregation_spec.rb +139 -0
- data/spec/mongo/collection/view/builder/find_command_spec.rb +6 -243
- data/spec/mongo/collection/view/map_reduce_spec.rb +104 -0
- data/spec/mongo/collection/view/readable_spec.rb +83 -0
- data/spec/mongo/collection/view/writable_spec.rb +447 -1
- data/spec/mongo/collection/view_spec.rb +57 -0
- data/spec/mongo/collection_spec.rb +926 -101
- data/spec/mongo/crud_spec.rb +4 -5
- data/spec/mongo/database_spec.rb +99 -1
- data/spec/mongo/index/view_spec.rb +360 -31
- data/spec/mongo/max_staleness_spec.rb +108 -0
- data/spec/mongo/operation/read_preference_spec.rb +8 -8
- data/spec/mongo/operation/write/command/delete_spec.rb +1 -1
- data/spec/mongo/operation/write/command/insert_spec.rb +1 -1
- data/spec/mongo/operation/write/command/update_spec.rb +1 -1
- data/spec/mongo/server/connection_pool_spec.rb +3 -1
- data/spec/mongo/server/connection_spec.rb +17 -7
- data/spec/mongo/server/description/features_spec.rb +50 -0
- data/spec/mongo/server/description_spec.rb +9 -3
- data/spec/mongo/server_selection_spec.rb +5 -3
- data/spec/mongo/server_selector/nearest_spec.rb +73 -0
- data/spec/mongo/server_selector/primary_preferred_spec.rb +73 -0
- data/spec/mongo/server_selector/primary_spec.rb +36 -0
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +73 -0
- data/spec/mongo/server_selector/secondary_spec.rb +73 -0
- data/spec/mongo/server_selector_spec.rb +53 -0
- data/spec/mongo/server_spec.rb +3 -1
- data/spec/mongo/uri_spec.rb +54 -0
- data/spec/mongo/write_concern_spec.rb +18 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/support/authorization.rb +8 -1
- data/spec/support/crud.rb +15 -0
- data/spec/support/crud/read.rb +27 -19
- data/spec/support/crud/write.rb +28 -3
- data/spec/support/crud_tests/read/aggregate.yml +15 -3
- data/spec/support/crud_tests/read/count.yml +14 -3
- data/spec/support/crud_tests/read/distinct.yml +13 -1
- data/spec/support/crud_tests/read/find.yml +12 -2
- data/spec/support/crud_tests/write/deleteMany.yml +22 -1
- data/spec/support/crud_tests/write/deleteOne.yml +20 -1
- data/spec/support/crud_tests/write/findOneAndDelete.yml +27 -2
- data/spec/support/crud_tests/write/findOneAndReplace.yml +43 -14
- data/spec/support/crud_tests/write/findOneAndUpdate.yml +50 -8
- data/spec/support/crud_tests/write/replaceOne.yml +34 -10
- data/spec/support/crud_tests/write/updateMany.yml +42 -11
- data/spec/support/crud_tests/write/updateOne.yml +32 -7
- data/spec/support/max_staleness/ReplicaSetNoPrimary/DefaultNoMaxStaleness.yml +26 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/Incompatible.yml +25 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/LastUpdateTime.yml +33 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest.yml +33 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/Nearest2.yml +33 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred.yml +27 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/PrimaryPreferred_tags.yml +36 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/Secondary.yml +51 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred.yml +26 -0
- data/spec/support/max_staleness/ReplicaSetNoPrimary/SecondaryPreferred_tags.yml +51 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/DefaultNoMaxStaleness.yml +26 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/Incompatible.yml +25 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/LastUpdateTime.yml +35 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessTooSmall.yml +25 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/MaxStalenessWithModePrimary.yml +23 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest.yml +33 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest2.yml +33 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/Nearest_tags.yml +36 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred.yml +27 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/PrimaryPreferred_incompatible.yml +27 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred.yml +26 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags.yml +59 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/SecondaryPreferred_tags2.yml +43 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags.yml +59 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/Secondary_tags2.yml +43 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/ShortHeartbeartShortMaxStaleness.yml +29 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/ShortHeartbeartShortMaxStaleness2.yml +29 -0
- data/spec/support/max_staleness/ReplicaSetWithPrimary/ZeroMaxStaleness.yml +27 -0
- data/spec/support/max_staleness/Sharded/Incompatible.yml +25 -0
- data/spec/support/max_staleness/Sharded/SmallMaxStaleness.yml +20 -0
- data/spec/support/max_staleness/Single/Incompatible.yml +18 -0
- data/spec/support/max_staleness/Single/SmallMaxStaleness.yml +20 -0
- data/spec/support/server_selection.rb +25 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest_multiple.yml +27 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_multi_tags.yml +31 -0
- data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_multi_tags2.yml +31 -0
- data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest_multiple.yml +34 -0
- data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/SecondaryPreferred_tags.yml +28 -0
- data/spec/support/shared/server_selector.rb +4 -3
- metadata +91 -6
- metadata.gz.sig +0 -0
@@ -43,7 +43,8 @@ module Mongo
|
|
43
43
|
:features,
|
44
44
|
:max_bson_object_size,
|
45
45
|
:max_message_size,
|
46
|
-
:mongos
|
46
|
+
:mongos?,
|
47
|
+
:app_metadata
|
47
48
|
|
48
49
|
# Tell the underlying socket to establish a connection to the host.
|
49
50
|
#
|
@@ -60,6 +61,7 @@ module Mongo
|
|
60
61
|
unless socket && socket.connectable?
|
61
62
|
@socket = address.socket(timeout, ssl_options)
|
62
63
|
socket.connect!
|
64
|
+
handshake!
|
63
65
|
authenticate!
|
64
66
|
end
|
65
67
|
true
|
@@ -79,6 +81,7 @@ module Mongo
|
|
79
81
|
def disconnect!
|
80
82
|
if socket
|
81
83
|
socket.close
|
84
|
+
@auth_mechanism = nil
|
82
85
|
@socket = nil
|
83
86
|
end
|
84
87
|
true
|
@@ -130,6 +133,7 @@ module Mongo
|
|
130
133
|
@server = server
|
131
134
|
@ssl_options = options.reject { |k, v| !k.to_s.start_with?(SSL) }
|
132
135
|
@socket = nil
|
136
|
+
@auth_mechanism = nil
|
133
137
|
@pid = Process.pid
|
134
138
|
end
|
135
139
|
|
@@ -159,6 +163,17 @@ module Mongo
|
|
159
163
|
messages.last.replyable? ? read(messages.last.request_id) : nil
|
160
164
|
end
|
161
165
|
|
166
|
+
def handshake!
|
167
|
+
if socket && socket.connectable?
|
168
|
+
socket.write(app_metadata.ismaster_bytes)
|
169
|
+
response = Protocol::Reply.deserialize(socket, max_message_size).documents[0]
|
170
|
+
min_wire_version = response[Description::MIN_WIRE_VERSION] || Description::LEGACY_WIRE_VERSION
|
171
|
+
max_wire_version = response[Description::MAX_WIRE_VERSION] || Description::LEGACY_WIRE_VERSION
|
172
|
+
features = Description::Features.new(min_wire_version..max_wire_version)
|
173
|
+
@auth_mechanism = (features.scram_sha_1_enabled? || @server.features.scram_sha_1_enabled?) ? :scram : :mongodb_cr
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
162
177
|
def authenticate!
|
163
178
|
if options[:user]
|
164
179
|
user = Auth::User.new(Options::Redacted.new(:auth_mech => default_mechanism).merge(options))
|
@@ -169,16 +184,7 @@ module Mongo
|
|
169
184
|
end
|
170
185
|
|
171
186
|
def default_mechanism
|
172
|
-
|
173
|
-
socket.write(Monitor::Connection::ISMASTER_BYTES)
|
174
|
-
ismaster = Protocol::Reply.deserialize(socket, max_message_size).documents[0]
|
175
|
-
min_wire_version = ismaster[Description::MIN_WIRE_VERSION] || Description::LEGACY_WIRE_VERSION
|
176
|
-
max_wire_version = ismaster[Description::MAX_WIRE_VERSION] || Description::LEGACY_WIRE_VERSION
|
177
|
-
features = Description::Features.new(min_wire_version..max_wire_version)
|
178
|
-
(features.scram_sha_1_enabled? || @server.features.scram_sha_1_enabled?) ? :scram : :mongodb_cr
|
179
|
-
else
|
180
|
-
@server.features.scram_sha_1_enabled? ? :scram : :mongodb_cr
|
181
|
-
end
|
187
|
+
@auth_mechanism || (@server.features.scram_sha_1_enabled? ? :scram : :mongodb_cr)
|
182
188
|
end
|
183
189
|
|
184
190
|
def write(messages, buffer = BSON::ByteBuffer.new)
|
@@ -84,6 +84,16 @@ module Mongo
|
|
84
84
|
# @since 2.0.0
|
85
85
|
MAX_WRITE_BATCH_SIZE = 'maxWriteBatchSize'.freeze
|
86
86
|
|
87
|
+
# Constant for the lastWrite subdocument.
|
88
|
+
#
|
89
|
+
# @since 2.4.0
|
90
|
+
LAST_WRITE = 'lastWrite'.freeze
|
91
|
+
|
92
|
+
# Constant for the lastWriteDate field in the lastWrite subdocument.
|
93
|
+
#
|
94
|
+
# @since 2.4.0
|
95
|
+
LAST_WRITE_DATE = 'lastWriteDate'.freeze
|
96
|
+
|
87
97
|
# Constant for reading the me field.
|
88
98
|
#
|
89
99
|
# @since 2.1.0
|
@@ -360,6 +370,18 @@ module Mongo
|
|
360
370
|
config[SET_VERSION]
|
361
371
|
end
|
362
372
|
|
373
|
+
# Get the lastWriteDate from the lastWrite subdocument in the config.
|
374
|
+
#
|
375
|
+
# @example Get the lastWriteDate value.
|
376
|
+
# description.last_write_date
|
377
|
+
#
|
378
|
+
# @return [ Time ] The last write date.
|
379
|
+
#
|
380
|
+
# @since 2.4.0
|
381
|
+
def last_write_date
|
382
|
+
config[LAST_WRITE][LAST_WRITE_DATE] if config[LAST_WRITE]
|
383
|
+
end
|
384
|
+
|
363
385
|
# Is the server a mongos?
|
364
386
|
#
|
365
387
|
# @example Is the server a mongos?
|
data/lib/mongo/server/monitor.rb
CHANGED
@@ -53,6 +53,11 @@ module Mongo
|
|
53
53
|
# @return [ Hash ] options The server options.
|
54
54
|
attr_reader :options
|
55
55
|
|
56
|
+
# @return [ Time ] last_scan The time of the last server scan.
|
57
|
+
#
|
58
|
+
# @since 2.4.0
|
59
|
+
attr_reader :last_scan
|
60
|
+
|
56
61
|
# Force the monitor to immediately do a check of its server.
|
57
62
|
#
|
58
63
|
# @example Force a scan.
|
@@ -75,6 +75,7 @@ module Mongo
|
|
75
75
|
unless socket && socket.connectable?
|
76
76
|
@socket = address.socket(timeout, ssl_options)
|
77
77
|
socket.connect!
|
78
|
+
handshake!
|
78
79
|
end
|
79
80
|
true
|
80
81
|
end
|
@@ -115,6 +116,7 @@ module Mongo
|
|
115
116
|
def initialize(address, options = {})
|
116
117
|
@address = address
|
117
118
|
@options = options.freeze
|
119
|
+
@app_metadata = options[:app_metadata]
|
118
120
|
@ssl_options = options.reject { |k, v| !k.to_s.start_with?(SSL) }
|
119
121
|
@socket = nil
|
120
122
|
@pid = Process.pid
|
@@ -131,6 +133,15 @@ module Mongo
|
|
131
133
|
def timeout
|
132
134
|
@timeout ||= options[:connect_timeout] || CONNECT_TIMEOUT
|
133
135
|
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def handshake!
|
140
|
+
if @app_metadata
|
141
|
+
socket.write(@app_metadata.ismaster_bytes)
|
142
|
+
Protocol::Reply.deserialize(socket, Mongo::Protocol::Message::MAX_MESSAGE_SIZE).documents[0]
|
143
|
+
end
|
144
|
+
end
|
134
145
|
end
|
135
146
|
end
|
136
147
|
end
|
@@ -67,6 +67,7 @@ module Mongo
|
|
67
67
|
def to_mongos
|
68
68
|
preference = { :mode => 'nearest' }
|
69
69
|
preference.merge!({ :tags => tag_sets }) unless tag_sets.empty?
|
70
|
+
preference.merge!({ maxStalenessMS: max_staleness * 1000 }) if max_staleness
|
70
71
|
preference
|
71
72
|
end
|
72
73
|
|
@@ -76,18 +77,20 @@ module Mongo
|
|
76
77
|
# local threshold between the nearest server and other servers.
|
77
78
|
#
|
78
79
|
# @example Select nearest servers given a list of candidates.
|
79
|
-
# preference = Mongo::
|
80
|
+
# preference = Mongo::ServerSelector::Nearest.new
|
80
81
|
# preference.select_server(cluster)
|
81
82
|
#
|
82
83
|
# @return [ Array ] The nearest servers from the list of candidates.
|
83
84
|
#
|
84
85
|
# @since 2.0.0
|
85
86
|
def select(candidates)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
matching_servers = filter_stale_servers(candidates, primary(candidates).first)
|
88
|
+
matching_servers = match_tag_sets(matching_servers) unless tag_sets.empty?
|
89
|
+
near_servers(matching_servers)
|
90
|
+
end
|
91
|
+
|
92
|
+
def max_staleness_allowed?
|
93
|
+
true
|
91
94
|
end
|
92
95
|
end
|
93
96
|
end
|
@@ -68,6 +68,7 @@ module Mongo
|
|
68
68
|
def to_mongos
|
69
69
|
preference = { :mode => 'primaryPreferred' }
|
70
70
|
preference.merge!({ :tags => tag_sets }) unless tag_sets.empty?
|
71
|
+
preference.merge!({ maxStalenessMS: max_staleness * 1000 }) if max_staleness
|
71
72
|
preference
|
72
73
|
end
|
73
74
|
|
@@ -87,7 +88,12 @@ module Mongo
|
|
87
88
|
# @since 2.0.0
|
88
89
|
def select(candidates)
|
89
90
|
primary = primary(candidates)
|
90
|
-
|
91
|
+
secondaries = near_servers(secondaries(candidates))
|
92
|
+
primary.first ? primary : secondaries
|
93
|
+
end
|
94
|
+
|
95
|
+
def max_staleness_allowed?
|
96
|
+
true
|
91
97
|
end
|
92
98
|
end
|
93
99
|
end
|
@@ -68,6 +68,7 @@ module Mongo
|
|
68
68
|
def to_mongos
|
69
69
|
preference = { :mode => 'secondary' }
|
70
70
|
preference.merge!({ :tags => tag_sets }) unless tag_sets.empty?
|
71
|
+
preference.merge!({ maxStalenessMS: max_staleness * 1000 }) if max_staleness
|
71
72
|
preference
|
72
73
|
end
|
73
74
|
|
@@ -86,6 +87,10 @@ module Mongo
|
|
86
87
|
def select(candidates)
|
87
88
|
near_servers(secondaries(candidates))
|
88
89
|
end
|
90
|
+
|
91
|
+
def max_staleness_allowed?
|
92
|
+
true
|
93
|
+
end
|
89
94
|
end
|
90
95
|
end
|
91
96
|
end
|
@@ -68,9 +68,10 @@ module Mongo
|
|
68
68
|
#
|
69
69
|
# @since 2.0.0
|
70
70
|
def to_mongos
|
71
|
-
return nil if tag_sets.empty?
|
71
|
+
return nil if tag_sets.empty? && max_staleness.nil?
|
72
72
|
preference = { mode: 'secondaryPreferred' }
|
73
|
-
preference.merge!({ tags: tag_sets })
|
73
|
+
preference.merge!({ tags: tag_sets }) unless tag_sets.empty?
|
74
|
+
preference.merge!({ maxStalenessMS: max_staleness * 1000 }) if max_staleness
|
74
75
|
preference
|
75
76
|
end
|
76
77
|
|
@@ -91,6 +92,10 @@ module Mongo
|
|
91
92
|
def select(candidates)
|
92
93
|
near_servers(secondaries(candidates)) + primary(candidates)
|
93
94
|
end
|
95
|
+
|
96
|
+
def max_staleness_allowed?
|
97
|
+
true
|
98
|
+
end
|
94
99
|
end
|
95
100
|
end
|
96
101
|
end
|
@@ -26,6 +26,12 @@ module Mongo
|
|
26
26
|
# @return [ Array ] tag_sets The tag sets used to select servers.
|
27
27
|
attr_reader :tag_sets
|
28
28
|
|
29
|
+
# @return [ Float ] max_staleness The maximum replication lag, in seconds, that a
|
30
|
+
# secondary can suffer and still be eligible for a read.
|
31
|
+
#
|
32
|
+
# @since 2.4.0
|
33
|
+
attr_reader :max_staleness
|
34
|
+
|
29
35
|
# Check equality of two server selector.
|
30
36
|
#
|
31
37
|
# @example Check server selector equality.
|
@@ -38,7 +44,8 @@ module Mongo
|
|
38
44
|
# @since 2.0.0
|
39
45
|
def ==(other)
|
40
46
|
name == other.name &&
|
41
|
-
tag_sets == other.tag_sets
|
47
|
+
tag_sets == other.tag_sets &&
|
48
|
+
max_staleness == other.max_staleness
|
42
49
|
end
|
43
50
|
|
44
51
|
# Initialize the server selector.
|
@@ -60,9 +67,9 @@ module Mongo
|
|
60
67
|
# @since 2.0.0
|
61
68
|
def initialize(options = {})
|
62
69
|
@options = (options || {}).freeze
|
63
|
-
tag_sets = options[:tag_sets] || []
|
64
|
-
|
65
|
-
|
70
|
+
@tag_sets = (options[:tag_sets] || []).freeze
|
71
|
+
@max_staleness = options[:max_staleness] if options[:max_staleness] && options[:max_staleness] > 0
|
72
|
+
validate!
|
66
73
|
end
|
67
74
|
|
68
75
|
# Inspect the server selector.
|
@@ -74,7 +81,7 @@ module Mongo
|
|
74
81
|
#
|
75
82
|
# @since 2.2.0
|
76
83
|
def inspect
|
77
|
-
"#<#{self.class.name}:0x#{object_id} tag_sets=#{tag_sets.inspect}>"
|
84
|
+
"#<#{self.class.name}:0x#{object_id} tag_sets=#{tag_sets.inspect} max_staleness=#{max_staleness.inspect}>"
|
78
85
|
end
|
79
86
|
|
80
87
|
# Select a server from eligible candidates.
|
@@ -143,10 +150,11 @@ module Mongo
|
|
143
150
|
|
144
151
|
def candidates(cluster)
|
145
152
|
if cluster.single?
|
146
|
-
cluster.servers
|
153
|
+
cluster.servers.each { |server| validate_max_staleness_support!(server) }
|
147
154
|
elsif cluster.sharded?
|
148
|
-
near_servers(cluster.servers)
|
155
|
+
near_servers(cluster.servers).each { |server| validate_max_staleness_support!(server) }
|
149
156
|
else
|
157
|
+
validate_max_staleness_value!(cluster)
|
150
158
|
select(cluster.servers)
|
151
159
|
end
|
152
160
|
end
|
@@ -175,6 +183,7 @@ module Mongo
|
|
175
183
|
# @since 2.0.0
|
176
184
|
def secondaries(candidates)
|
177
185
|
matching_servers = candidates.select(&:secondary?)
|
186
|
+
matching_servers = filter_stale_servers(matching_servers, primary(candidates).first)
|
178
187
|
matching_servers = match_tag_sets(matching_servers) unless tag_sets.empty?
|
179
188
|
matching_servers
|
180
189
|
end
|
@@ -212,9 +221,47 @@ module Mongo
|
|
212
221
|
matches || []
|
213
222
|
end
|
214
223
|
|
215
|
-
def
|
216
|
-
|
217
|
-
|
224
|
+
def filter_stale_servers(candidates, primary = nil)
|
225
|
+
return candidates unless @max_staleness
|
226
|
+
max_staleness_ms = @max_staleness * 1000
|
227
|
+
|
228
|
+
if primary
|
229
|
+
candidates.select do |server|
|
230
|
+
validate_max_staleness_support!(server)
|
231
|
+
staleness = (server.last_scan - server.last_write_date) -
|
232
|
+
(primary.last_scan - primary.last_write_date) +
|
233
|
+
(server.heartbeat_frequency * 1000)
|
234
|
+
staleness <= max_staleness_ms
|
235
|
+
end
|
236
|
+
else
|
237
|
+
max_write_date = candidates.collect(&:last_write_date).max
|
238
|
+
candidates.select do |server|
|
239
|
+
validate_max_staleness_support!(server)
|
240
|
+
staleness = max_write_date - server.last_write_date + (server.heartbeat_frequency * 1000)
|
241
|
+
staleness <= max_staleness_ms
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def validate!
|
247
|
+
if !@tag_sets.all? { |set| set.empty? } && !tags_allowed?
|
248
|
+
raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::NO_TAG_SUPPORT)
|
249
|
+
elsif @max_staleness && !max_staleness_allowed?
|
250
|
+
raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::NO_MAX_STALENESS_SUPPORT)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def validate_max_staleness_support!(server)
|
255
|
+
if @max_staleness && !server.features.max_staleness_enabled?
|
256
|
+
raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::NO_MAX_STALENESS_WITH_LEGACY_SERVER)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def validate_max_staleness_value!(cluster)
|
261
|
+
return unless @max_staleness
|
262
|
+
heartbeat_frequency = cluster.options[:heartbeat_frequency] || Server::Monitor::HEARTBEAT_FREQUENCY
|
263
|
+
if @max_staleness < heartbeat_frequency * 2
|
264
|
+
raise Error::InvalidServerPreference.new(Error::InvalidServerPreference::INVALID_MAX_STALENESS)
|
218
265
|
end
|
219
266
|
end
|
220
267
|
end
|
data/lib/mongo/socket/ssl.rb
CHANGED
@@ -56,6 +56,7 @@ module Mongo
|
|
56
56
|
Timeout.timeout(timeout, Error::SocketTimeoutError) do
|
57
57
|
handle_errors { @tcp_socket.connect(::Socket.pack_sockaddr_in(port, host)) }
|
58
58
|
@socket = OpenSSL::SSL::SSLSocket.new(@tcp_socket, context)
|
59
|
+
@socket.hostname = @host_name unless BSON::Environment.jruby?
|
59
60
|
@socket.sync_close = true
|
60
61
|
handle_errors { @socket.connect }
|
61
62
|
verify_certificate!(@socket)
|
data/lib/mongo/uri.rb
CHANGED
@@ -374,6 +374,7 @@ module Mongo
|
|
374
374
|
# Read Options
|
375
375
|
uri_option 'readpreference', :mode, :group => :read, :type => :read_mode
|
376
376
|
uri_option 'readpreferencetags', :tag_sets, :group => :read, :type => :read_tags
|
377
|
+
uri_option 'maxstalenessms', :max_staleness, :group => :read, :type => :ms_convert
|
377
378
|
|
378
379
|
# Pool options
|
379
380
|
uri_option 'minpoolsize', :min_pool_size
|
@@ -391,6 +392,9 @@ module Mongo
|
|
391
392
|
uri_option 'authmechanism', :auth_mech, :type => :auth_mech
|
392
393
|
uri_option 'authmechanismproperties', :auth_mech_properties, :type => :auth_mech_props
|
393
394
|
|
395
|
+
# Client Options
|
396
|
+
uri_option 'appname', :app_name
|
397
|
+
|
394
398
|
# Casts option values that do not have a specifically provided
|
395
399
|
# transformation to the appropriate type.
|
396
400
|
#
|
data/lib/mongo/version.rb
CHANGED
data/lib/mongo/write_concern.rb
CHANGED
data/mongo.gemspec
CHANGED
data/spec/mongo/auth/cr_spec.rb
CHANGED
@@ -14,8 +14,14 @@ describe Mongo::Auth::CR do
|
|
14
14
|
Mongo::Event::Listeners.new
|
15
15
|
end
|
16
16
|
|
17
|
+
let(:cluster) do
|
18
|
+
double('cluster').tap do |cl|
|
19
|
+
allow(cl).to receive(:app_metadata).and_return(app_metadata)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
17
23
|
let(:server) do
|
18
|
-
Mongo::Server.new(address,
|
24
|
+
Mongo::Server.new(address, cluster, monitoring, listeners, TEST_OPTIONS)
|
19
25
|
end
|
20
26
|
|
21
27
|
let(:connection) do
|