Skip to content

Commit db726e9

Browse files
authored
Set read_preference to primaryPreferred when topology single with replica set. (#266)
* Set read preference as primaryPreferred when topology is single and is replica. * Put missing replica? in ServerDescription.parse_hello_response/1 and add test. * update code format.
1 parent 9a71d4f commit db726e9

File tree

5 files changed

+92
-26
lines changed

5 files changed

+92
-26
lines changed

lib/mongo/read_preference.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,7 @@ defmodule Mongo.ReadPreference do
141141

142142
filter_nils(read_preference)
143143
end
144+
145+
def to_topology_single_type({_, %{replica?: true} = _server_description}), do: %{mode: :primaryPreferred}
146+
def to_topology_single_type(_), do: nil
144147
end

lib/mongo/server_description.ex

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ defmodule Mongo.ServerDescription do
4141
compression: [compressor_types],
4242
read_only: boolean(),
4343
logical_session_timeout: non_neg_integer,
44-
supports_retryable_writes: boolean()
44+
supports_retryable_writes: boolean(),
45+
replica?: boolean()
4546
}
4647

4748
@empty %{
@@ -69,7 +70,8 @@ defmodule Mongo.ServerDescription do
6970
compression: [],
7071
read_only: false,
7172
logical_session_timeout: 30,
72-
support_retryable_writes: false
73+
support_retryable_writes: false,
74+
replica?: false
7375
}
7476

7577
def new() do
@@ -115,7 +117,8 @@ defmodule Mongo.ServerDescription do
115117
compression: map_compressors(hello_response["compression"]),
116118
read_only: hello_response["readOnly"] || false,
117119
logical_session_timeout: hello_response["logicalSessionTimeoutMinutes"] || 30,
118-
supports_retryable_writes: supports_retryable_writes
120+
supports_retryable_writes: supports_retryable_writes,
121+
replica?: replica?(server_type)
119122
}
120123
end
121124

@@ -147,7 +150,8 @@ defmodule Mongo.ServerDescription do
147150
compression: map_compressors(hello_response["compression"]),
148151
read_only: hello_response["readOnly"] || false,
149152
logical_session_timeout: hello_response["logicalSessionTimeoutMinutes"] || 30,
150-
supports_retryable_writes: server_type != :standalone && max_wire_version >= @retryable_wire_version && hello_response["logicalSessionTimeoutMinutes"] != nil
153+
supports_retryable_writes: server_type != :standalone && max_wire_version >= @retryable_wire_version && hello_response["logicalSessionTimeoutMinutes"] != nil,
154+
replica?: replica?(server_type)
151155
}
152156
end
153157

@@ -187,4 +191,8 @@ defmodule Mongo.ServerDescription do
187191
[:zlib]
188192
end
189193
end
194+
195+
defp replica?(server_type) do
196+
server_type in [:rs_primary, :rs_secondary, :rs_arbiter, :rs_other, :rs_ghost]
197+
end
190198
end

lib/mongo/topology_description.ex

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,20 @@ defmodule Mongo.TopologyDescription do
123123
|> Keyword.get(:read_preference)
124124
|> ReadPreference.merge_defaults()
125125

126-
{servers, read_prefs} =
126+
{server, read_prefs} =
127127
case topology.type do
128128
:unknown ->
129-
{[], nil}
129+
{nil, nil}
130130

131131
:single ->
132-
{topology.servers, nil}
132+
server = pick_server(topology.servers)
133+
{server, ReadPreference.to_topology_single_type(server)}
133134

134135
:sharded ->
135-
{mongos_servers(topology), ReadPreference.to_mongos(read_preference)}
136+
{topology |> mongos_servers() |> pick_server(), ReadPreference.to_mongos(read_preference)}
136137

137138
_other ->
138-
{select_replica_set_server(topology, read_preference.mode, read_preference), ReadPreference.to_replica_set(read_preference)}
139+
{topology |> select_replica_set_server(read_preference.mode, read_preference) |> pick_server(), ReadPreference.to_replica_set(read_preference)}
139140
end
140141

141142
opts =
@@ -147,17 +148,12 @@ defmodule Mongo.TopologyDescription do
147148
Keyword.put(opts, :read_preference, prefs)
148149
end
149150

150-
server =
151-
servers
152-
|> Enum.take_random(1)
153-
|> Enum.map(fn {server, description} -> {server, description.compression} end)
154-
155151
case server do
156-
[] ->
152+
nil ->
157153
:empty
158154

159-
[{addr, compression}] ->
160-
{:ok, {addr, merge_compression(opts, compression)}}
155+
{addr, server_description} ->
156+
{:ok, {addr, merge_compression(opts, server_description.compression)}}
161157
end
162158
end
163159

@@ -182,6 +178,13 @@ defmodule Mongo.TopologyDescription do
182178
end
183179
end
184180

181+
defp pick_server(servers) do
182+
case Enum.take_random(servers, 1) do
183+
[] -> nil
184+
[server] -> server
185+
end
186+
end
187+
185188
defp mongos_servers(%{:servers => servers}) do
186189
Enum.filter(servers, fn {_, server} -> server.type == :mongos end)
187190
end

test/mongo/topology_description_test.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,12 @@ defmodule Mongo.TopologyDescriptionTest do
137137

138138
assert :single = TopologyDescription.get_type(opts)
139139
end
140+
141+
test "Set read_preference to :primaryPreferred when topology is single and server is replica set" do
142+
assert {:ok, {_, opts}} = TopologyDescription.select_servers(single(), :read, [])
143+
assert nil == Keyword.get(opts, :read_preference)
144+
145+
assert {:ok, {_, opts}} = TopologyDescription.select_servers(single_with_repl_set(), :read, [])
146+
assert :primaryPreferred = Keyword.get(opts, :read_preference) |> Map.get(:mode)
147+
end
140148
end

test/support/topology_test_data.ex

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,43 @@ defmodule Mongo.TopologyTestData do
3030
set_version: nil,
3131
tag_set: %{},
3232
type: :standalone,
33-
compression: []
33+
compression: [],
34+
replica?: false
35+
}
36+
}
37+
}
38+
39+
def single_with_repl_set(),
40+
do: %{
41+
set_name: nil,
42+
type: :single,
43+
compatibility_error: nil,
44+
compatible: true,
45+
local_threshold_ms: 15,
46+
max_election_id: nil,
47+
max_set_version: nil,
48+
servers: %{
49+
"localhost:27017" => %{
50+
address: "localhost:27017",
51+
arbiters: [],
52+
election_id: nil,
53+
error: nil,
54+
hosts: [],
55+
last_update_time: nil,
56+
last_write_date: nil,
57+
max_wire_version: 4,
58+
me: nil,
59+
min_wire_version: 0,
60+
op_time: nil,
61+
passives: [],
62+
primary: nil,
63+
round_trip_time: 44,
64+
set_name: nil,
65+
set_version: nil,
66+
tag_set: %{},
67+
type: :standalone,
68+
compression: [],
69+
replica?: true
3470
}
3571
}
3672
}
@@ -64,7 +100,8 @@ defmodule Mongo.TopologyTestData do
64100
set_version: nil,
65101
tag_set: %{},
66102
type: :mongos,
67-
compression: []
103+
compression: [],
104+
replica?: false
68105
}
69106
}
70107
}
@@ -102,7 +139,8 @@ defmodule Mongo.TopologyTestData do
102139
"localhost:27018",
103140
"localhost:27019",
104141
"localhost:27020"
105-
]
142+
],
143+
replica?: true
106144
},
107145
"localhost:27019" => %{
108146
address: "localhost:27019",
@@ -127,7 +165,8 @@ defmodule Mongo.TopologyTestData do
127165
"localhost:27018",
128166
"localhost:27019",
129167
"localhost:27020"
130-
]
168+
],
169+
replica?: true
131170
},
132171
"localhost:27020" => %{
133172
address: "localhost:27020",
@@ -152,7 +191,8 @@ defmodule Mongo.TopologyTestData do
152191
"localhost:27018",
153192
"localhost:27019",
154193
"localhost:27020"
155-
]
194+
],
195+
replica?: true
156196
}
157197
}
158198
}
@@ -186,7 +226,8 @@ defmodule Mongo.TopologyTestData do
186226
tag_set: %{},
187227
type: :unknown,
188228
hosts: [],
189-
compression: []
229+
compression: [],
230+
replica?: true
190231
},
191232
"localhost:27019" => %{
192233
address: "localhost:27019",
@@ -211,7 +252,8 @@ defmodule Mongo.TopologyTestData do
211252
"localhost:27019",
212253
"localhost:27020"
213254
],
214-
compression: []
255+
compression: [],
256+
replica?: true
215257
},
216258
"localhost:27020" => %{
217259
address: "localhost:27020",
@@ -236,7 +278,8 @@ defmodule Mongo.TopologyTestData do
236278
"localhost:27019",
237279
"localhost:27020"
238280
],
239-
compression: []
281+
compression: [],
282+
replica?: true
240283
}
241284
}
242285
}
@@ -270,7 +313,8 @@ defmodule Mongo.TopologyTestData do
270313
tag_set: %{},
271314
type: :rs_primary,
272315
hosts: ["localhost:27018"],
273-
compression: []
316+
compression: [],
317+
replica?: true
274318
}
275319
}
276320
}

0 commit comments

Comments
 (0)