Skip to content

Commit f282bab

Browse files
committed
PYTHON-926 - ReadPreference.NEAREST shouldn't pick arbiters.
1 parent c31d480 commit f282bab

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

pymongo/server_selectors.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def any_server_selector(server_descriptions):
2121
return server_descriptions
2222

2323

24+
def readable_server_selector(server_descriptions):
25+
return [s for s in server_descriptions if s.is_readable]
26+
27+
2428
def writable_server_selector(server_descriptions):
2529
return [s for s in server_descriptions if s.is_writable]
2630

@@ -49,6 +53,11 @@ def single_tag_set_server_selector(tag_set, server_descriptions):
4953
A server tagged {'a': '1', 'b': '2'} matches the tag set {'a': '1'}.
5054
5155
The empty tag set {} matches any server.
56+
57+
The `server_descriptions` passed to this function should have
58+
non-readable servers (e.g. RSGhost, RSArbiter, Unknown) filtered
59+
out (e.g. by readable_server_selector or secondary_server_selector)
60+
first.
5261
"""
5362
def tags_match(server_tags):
5463
for key, value in tag_set.items():
@@ -68,6 +77,11 @@ def tag_sets_server_selector(tag_sets, server_descriptions):
6877
[{'a': 'value'}, {}] expresses a preference for servers tagged
6978
{'a': 'value'}, but accepts any server if none matches the first
7079
preference.
80+
81+
The `server_descriptions` passed to this function should have
82+
non-readable servers (e.g. RSGhost, RSArbiter, Unknown) filtered
83+
out (e.g. by readable_server_selector or secondary_server_selector)
84+
first.
7185
"""
7286
for tag_set in tag_sets:
7387
selected = single_tag_set_server_selector(tag_set, server_descriptions)
@@ -81,6 +95,11 @@ def apply_local_threshold(latency_ms, server_descriptions):
8195
"""All servers with round trip times within latency_ms of the fastest one.
8296
8397
No ServerDescription's round_trip_time can be None.
98+
99+
The `server_descriptions` passed to this function should have
100+
non-readable servers (e.g. RSGhost, RSArbiter, Unknown) filtered
101+
out (e.g. by readable_server_selector or secondary_server_selector)
102+
first.
84103
"""
85104
if not server_descriptions:
86105
# Avoid ValueError from min() with empty sequence.
@@ -104,4 +123,5 @@ def secondary_with_tags_server_selector(tag_sets, server_descriptions):
104123

105124
def member_with_tags_server_selector(tag_sets, server_descriptions):
106125
"""All near-enough members matching the tag sets."""
107-
return tag_sets_server_selector(tag_sets, server_descriptions)
126+
return tag_sets_server_selector(
127+
tag_sets, readable_server_selector(server_descriptions))

test/__init__.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,13 @@ def __init__(self):
127127
self.rs_client = pymongo.MongoClient(
128128
pair, replicaSet=self.replica_set_name)
129129

130-
self.nodes = set([partition_node(node)
131-
for node in self.ismaster.get('hosts', [])])
130+
nodes = [partition_node(node)
131+
for node in self.ismaster.get('hosts', [])]
132+
nodes.extend([partition_node(node)
133+
for node in self.ismaster.get('passives', [])])
134+
nodes.extend([partition_node(node)
135+
for node in self.ismaster.get('arbiters', [])])
136+
self.nodes = set(nodes)
132137

133138
self.rs_or_standalone_client = self.rs_client or self.client
134139

test/test_read_preferences.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
Primary, PrimaryPreferred,
3232
Secondary, SecondaryPreferred,
3333
Nearest, _ServerMode)
34-
from pymongo.server_selectors import any_server_selector
34+
from pymongo.server_selectors import readable_server_selector
3535
from pymongo.server_type import SERVER_TYPE
3636
from pymongo.write_concern import WriteConcern
3737

@@ -97,7 +97,7 @@ def read_from_which_kind(self, client):
9797
def assertReadsFrom(self, expected, **kwargs):
9898
c = rs_client(**kwargs)
9999
wait_until(
100-
lambda: len(c.nodes) == self.w,
100+
lambda: len(c.nodes - c.arbiters) == self.w,
101101
"discovered all nodes")
102102

103103
used = self.read_from_which_kind(c)
@@ -249,7 +249,8 @@ def test_nearest(self):
249249
latencies = ', '.join(
250250
'%s: %dms' % (server.description.address,
251251
server.description.round_trip_time)
252-
for server in c._get_topology().select_servers(any_server_selector))
252+
for server in c._get_topology().select_servers(
253+
readable_server_selector))
253254

254255
self.assertFalse(
255256
not_used,

0 commit comments

Comments
 (0)