Skip to content

Commit 13da54a

Browse files
committed
Don't allow static slave_ok opt on Server creation
1 parent 9b134b1 commit 13da54a

File tree

10 files changed

+68
-40
lines changed

10 files changed

+68
-40
lines changed

lib/mongo/client.rb

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ module Mongo
2121
class Client
2222
extend Forwardable
2323

24+
# The options that do not affect the behaviour of a cluster and its
25+
# subcomponents.
26+
#
27+
# @since 2.1.0
28+
CRUD_OPTIONS = [ :database, :read, :write ].freeze
29+
2430
# @return [ Mongo::Cluster ] cluster The cluster of servers for the client.
2531
attr_reader :cluster
2632

@@ -203,8 +209,9 @@ def with(new_options = {})
203209
clone.tap do |client|
204210
client.options.update(new_options)
205211
Database.create(client)
206-
# We can't use the same cluster if authentication details have changed.
207-
if new_options[:user] || new_options[:password]
212+
# We can't use the same cluster if some options that would affect it
213+
# have changed.
214+
if cluster_modifying?(new_options)
208215
Cluster.create(client)
209216
end
210217
end
@@ -244,9 +251,7 @@ def database_names
244251
#
245252
# @since 2.0.5
246253
def list_databases
247-
use(Database::ADMIN).command(
248-
listDatabases: 1
249-
).first['databases']
254+
use(Database::ADMIN).command(listDatabases: 1).first['databases']
250255
end
251256

252257
private
@@ -270,5 +275,14 @@ def initialize_copy(original)
270275
@read_preference = nil
271276
@write_concern = nil
272277
end
278+
279+
def cluster_modifying?(new_options)
280+
cluster_options = new_options.reject do |name|
281+
CRUD_OPTIONS.include?(name)
282+
end
283+
cluster_options.any? do |name, value|
284+
options[name] != value
285+
end
286+
end
273287
end
274288
end

lib/mongo/cluster.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ def add(host)
7070
if addition_allowed?(address)
7171
log_debug([ "Adding #{address.to_s} to the cluster." ])
7272
addresses.push(address)
73-
server = Server.new(address, event_listeners,
74-
options.merge(slave_ok: @slave_ok))
73+
server = Server.new(address, self, event_listeners, options)
7574
@servers.push(server)
7675
server
7776
end
@@ -93,7 +92,6 @@ def initialize(seeds, options = {})
9392
@event_listeners = Event::Listeners.new
9493
@options = options.freeze
9594
@topology = Topology.initial(seeds, options)
96-
@slave_ok = @topology.single? unless options[:read]
9795

9896
subscribe_to(Event::SERVER_ADDED, Event::ServerAdded.new(self))
9997
subscribe_to(Event::SERVER_REMOVED, Event::ServerRemoved.new(self))

lib/mongo/operation/read_preferrable.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def update_selector(context)
3737
end
3838

3939
def update_options(context)
40-
if context.slave_ok? || (!context.mongos? && read.slave_ok?)
40+
if context.cluster.single? || (!context.mongos? && read.slave_ok?)
4141
options.dup.tap do |opts|
4242
(opts[:flags] ||= []) << SLAVE_OK
4343
end

lib/mongo/server.rb

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class Server
3131
# @return [ String ] The configured address for the server.
3232
attr_reader :address
3333

34+
# @return [ Cluster ] cluster The server cluster.
35+
attr_reader :cluster
36+
3437
# @return [ Monitor ] monitor The server monitor.
3538
attr_reader :monitor
3639

@@ -105,15 +108,17 @@ def disconnect!
105108
# subscribe to the appropriate events.
106109
#
107110
# @example Initialize the server.
108-
# Mongo::Server.new('127.0.0.1:27017', listeners)
111+
# Mongo::Server.new('127.0.0.1:27017', cluster, listeners)
109112
#
110113
# @param [ Address ] address The host:port address to connect to.
114+
# @param [ Cluster ] cluster The cluster the server belongs to.
111115
# @param [ Event::Listeners ] event_listeners The event listeners.
112116
# @param [ Hash ] options The server options.
113117
#
114118
# @since 2.0.0
115-
def initialize(address, event_listeners, options = {})
119+
def initialize(address, cluster, event_listeners, options = {})
116120
@address = address
121+
@cluster = cluster
117122
@options = options.freeze
118123
@monitor = Monitor.new(address, event_listeners, options)
119124
monitor.scan!
@@ -159,17 +164,5 @@ def matches_tag_set?(tag_set)
159164
tags[k] && tags[k] == tag_set[k]
160165
end
161166
end
162-
163-
# Whether the slaveOk bit must be set for all queries sent to the server.
164-
#
165-
# @example Does the slaveOk bit need to be set for all queries sent to the server.
166-
# server.slave_ok?
167-
#
168-
# @return [ true, false ] If the slaveOk bit needs to be set for all queries.
169-
#
170-
# @since 2.0.0
171-
def slave_ok?
172-
options[:slave_ok]
173-
end
174167
end
175168
end

lib/mongo/server/context.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ class Context
2727

2828
# Delegate state checks to the server.
2929
def_delegators :@server,
30+
:cluster,
3031
:features,
3132
:max_wire_version,
3233
:max_write_batch_size,
3334
:mongos?,
3435
:primary?,
3536
:secondary?,
36-
:standalone?,
37-
:slave_ok?
37+
:standalone?
3838

3939
# Instantiate a server context.
4040
#

spec/mongo/client_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,10 @@
412412
it 'returns the new client' do
413413
expect(client.send(:database).name).to eq('ruby-driver')
414414
end
415+
416+
it 'keeps the same cluster' do
417+
expect(database.cluster).to equal(client.cluster)
418+
end
415419
end
416420

417421
context 'when provided a string' do

spec/mongo/operation/read_preferrable_spec.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,14 @@
2828
end
2929
end
3030

31+
let(:cluster_double) do
32+
double('cluster')
33+
end
34+
3135
let(:context) do
3236
double('context').tap do |c|
33-
allow(c).to receive(:slave_ok?).and_return(slave_ok)
37+
allow(c).to receive(:cluster).and_return(cluster_double)
38+
allow(cluster_double).to receive(:single?).and_return(slave_ok)
3439
allow(c).to receive(:mongos?).and_return(mongos)
3540
end
3641
end

spec/mongo/server_discovery_and_monitoring_spec.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ class Mongo::Server
3434

3535
# The contructor keeps the same API, but does not instantiate a
3636
# monitor and run it.
37-
def initialize(address, event_listeners, options = {})
37+
def initialize(address, cluster, event_listeners, options = {})
3838
@address = address
39+
@cluster = cluster
3940
@options = options.freeze
4041
@monitor = Monitor.new(address, event_listeners, options)
4142
end
@@ -58,8 +59,9 @@ def disconnect!; true; end
5859
class Mongo::Server
5960

6061
# Returns the constructor to its original implementation.
61-
def initialize(address, event_listeners, options = {})
62+
def initialize(address, cluster, event_listeners, options = {})
6263
@address = address
64+
@cluster = cluster
6365
@options = options.freeze
6466
@monitor = Monitor.new(address, event_listeners, options)
6567
@monitor.scan!

spec/mongo/server_spec.rb

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
describe Mongo::Server do
44

5+
let(:cluster) do
6+
double('cluster')
7+
end
8+
59
let(:listeners) do
610
Mongo::Event::Listeners.new
711
end
@@ -13,7 +17,7 @@
1317
describe '#==' do
1418

1519
let(:server) do
16-
described_class.new(address, listeners, TEST_OPTIONS)
20+
described_class.new(address, cluster, listeners, TEST_OPTIONS)
1721
end
1822

1923
context 'when the other is not a server' do
@@ -32,7 +36,7 @@
3236
context 'when the addresses match' do
3337

3438
let(:other) do
35-
described_class.new(address, listeners, TEST_OPTIONS)
39+
described_class.new(address, cluster, listeners, TEST_OPTIONS)
3640
end
3741

3842
it 'returns true' do
@@ -47,7 +51,7 @@
4751
end
4852

4953
let(:other) do
50-
described_class.new(other_address, listeners, TEST_OPTIONS)
54+
described_class.new(other_address, cluster, listeners, TEST_OPTIONS)
5155
end
5256

5357
it 'returns false' do
@@ -60,7 +64,7 @@
6064
describe '#context' do
6165

6266
let(:server) do
63-
described_class.new(address, listeners, TEST_OPTIONS)
67+
described_class.new(address, cluster, listeners, TEST_OPTIONS)
6468
end
6569

6670
let(:context) do
@@ -75,7 +79,7 @@
7579
describe '#disconnect!' do
7680

7781
let(:server) do
78-
described_class.new(address, listeners, TEST_OPTIONS)
82+
described_class.new(address, cluster, listeners, TEST_OPTIONS)
7983
end
8084

8185
it 'stops the monitor instance' do
@@ -87,7 +91,7 @@
8791
describe '#initialize' do
8892

8993
let(:server) do
90-
described_class.new(address, listeners, TEST_OPTIONS.merge(:heartbeat_frequency => 5))
94+
described_class.new(address, cluster, listeners, TEST_OPTIONS.merge(:heartbeat_frequency => 5))
9195
end
9296

9397
it 'sets the address host' do
@@ -106,7 +110,7 @@
106110
describe '#pool' do
107111

108112
let(:server) do
109-
described_class.new(address, listeners, TEST_OPTIONS)
113+
described_class.new(address, cluster, listeners, TEST_OPTIONS)
110114
end
111115

112116
let(:pool) do
@@ -121,7 +125,7 @@
121125
describe '#scan!' do
122126

123127
let(:server) do
124-
described_class.new(address, listeners, TEST_OPTIONS)
128+
described_class.new(address, cluster, listeners, TEST_OPTIONS)
125129
end
126130

127131
it 'forces a scan on the monitor' do

spec/support/shared/operation.rb

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
let(:write_concern) { Mongo::WriteConcern.get(:w => 1) }
66
let(:options) { {} }
77

8+
let(:cluster_double) do
9+
double('cluster')
10+
end
11+
812
# Server doubles
913
let(:secondary_server) do
1014
double('secondary_server').tap do |s|
@@ -43,7 +47,8 @@
4347
allow(cxt).to receive(:primary?) { true }
4448
allow(cxt).to receive(:secondary?) { false }
4549
allow(cxt).to receive(:standalone?) { false }
46-
allow(cxt).to receive(:slave_ok?) { false }
50+
allow(cxt).to receive(:cluster) { cluster_double }
51+
allow(cluster_double).to receive(:single?) { false }
4752
end
4853
end
4954
let(:secondary_context) do
@@ -55,7 +60,8 @@
5560
allow(cxt).to receive(:secondary?) { true }
5661
allow(cxt).to receive(:primary?) { false }
5762
allow(cxt).to receive(:standalone?) { false }
58-
allow(cxt).to receive(:slave_ok?) { false }
63+
allow(cxt).to receive(:cluster) { cluster_double }
64+
allow(cluster_double).to receive(:single?) { false }
5965
end
6066
end
6167
let(:secondary_context_slave) do
@@ -67,7 +73,8 @@
6773
allow(cxt).to receive(:secondary?) { true }
6874
allow(cxt).to receive(:primary?) { false }
6975
allow(cxt).to receive(:standalone?) { false }
70-
allow(cxt).to receive(:slave_ok?) { true }
76+
allow(cxt).to receive(:cluster) { cluster_double }
77+
allow(cluster_double).to receive(:single?) { true }
7178
end
7279
end
7380
let(:primary_context_2_4_version) do
@@ -78,7 +85,8 @@
7885
allow(cxt).to receive(:primary?) { true }
7986
allow(cxt).to receive(:secondary?) { false }
8087
allow(cxt).to receive(:standalone?) { false }
81-
allow(cxt).to receive(:slave_ok?) { false }
88+
allow(cxt).to receive(:cluster) { cluster_double }
89+
allow(cluster_double).to receive(:single?) { false }
8290
allow(cxt).to receive(:features) { features_2_4 }
8391
end
8492
end

0 commit comments

Comments
 (0)