PYTHON-890 - Support localThresholdMS URI option.

This commit is contained in:
aherlihy 2015-06-03 16:02:28 -04:00 committed by Bernie Hackett
parent 313e21ab4f
commit 6e4608b9cd
10 changed files with 218 additions and 2 deletions

View File

@ -33,6 +33,7 @@
.. autoattribute:: read_preference
.. autoattribute:: tag_sets
.. autoattribute:: secondary_acceptable_latency_ms
.. autoattribute:: local_threshold_ms
.. autoattribute:: write_concern
.. autoattribute:: uuid_subtype
.. autoattribute:: is_locked

View File

@ -34,6 +34,7 @@
.. autoattribute:: read_preference
.. autoattribute:: tag_sets
.. autoattribute:: secondary_acceptable_latency_ms
.. autoattribute:: local_threshold_ms
.. autoattribute:: write_concern
.. autoattribute:: uuid_subtype
.. automethod:: database_names

View File

@ -328,6 +328,7 @@ VALIDATORS = {
'tag_sets': validate_tag_sets,
'secondaryacceptablelatencyms': validate_positive_float_or_zero,
'secondary_acceptable_latency_ms': validate_positive_float_or_zero,
'localthresholdms': validate_positive_float_or_zero,
'auto_start_request': validate_boolean,
'use_greenlets': validate_boolean,
'authmechanism': validate_auth_mechanism,

View File

@ -206,6 +206,14 @@ class MongoClient(common.BaseObject):
set, ``{}``, means "read from any member that matches the mode,
ignoring tags. Defaults to ``[{}]``, meaning "ignore members'
tags."
- `secondaryAcceptableLatencyMS`: (integer) Any replica-set member
whose ping time is within secondary_acceptable_latency_ms of the
nearest member may accept reads. Default 15 milliseconds.
**Ignored by mongos** and must be configured on the command line.
See the localThreshold_ option for more information.
- `localThresholdMS`: (integer) Alias for
secondaryAcceptableLatencyMS. Takes precedence over
secondaryAcceptableLatencyMS.
| **SSL configuration:**
@ -294,6 +302,11 @@ class MongoClient(common.BaseObject):
options[option] = value
options.update(opts)
# localthresholdms takes precedence over secondaryacceptablelatencyms.
if "localthresholdms" in options:
options["secondaryacceptablelatencyms"] = (
options["localthresholdms"])
common.validate_boolean('tz_aware', tz_aware)
uuid_representation = options.pop('uuidrepresentation', PYTHON_LEGACY)
options['codec_options'] = CodecOptions(
@ -688,6 +701,14 @@ class MongoClient(common.BaseObject):
return self.__member_property(
'max_write_batch_size', common.MAX_WRITE_BATCH_SIZE)
@property
def local_threshold_ms(self):
"""Alias for secondary_acceptable_latency_ms.
.. versionadded:: 2.9
"""
return self.secondary_acceptable_latency_ms
def __simple_command(self, sock_info, dbname, spec):
"""Send a command to the server. May raise AutoReconnect.
"""

View File

@ -550,11 +550,14 @@ class MongoReplicaSetClient(common.BaseObject):
ignoring tags." :class:`MongoReplicaSetClient` tries each set of
tags in turn until it finds a set of tags with at least one matching
member. Defaults to ``[{}]``, meaning "ignore members' tags."
- `secondary_acceptable_latency_ms`: (integer) Any replica-set member
whose ping time is within secondary_acceptable_latency_ms of the
- `secondaryAcceptableLatencyMS`: (integer) Any replica-set member
whose ping time is within secondaryAcceptableLatencyMS of the
nearest member may accept reads. Default 15 milliseconds.
**Ignored by mongos** and must be configured on the command line.
See the localThreshold_ option for more information.
- `localThresholdMS`: (integer) Alias for
secondaryAcceptableLatencyMS. Takes precedence over
secondaryAcceptableLatencyMS.
| **SSL configuration:**
@ -689,6 +692,11 @@ class MongoReplicaSetClient(common.BaseObject):
"2.6 you must install the ssl package "
"from PyPI.")
# localThresholdMS takes precedence over secondaryAcceptableLatencyMS
if "localthresholdms" in self.__opts:
self.__opts["secondaryacceptablelatencyms"] = (
self.__opts["localthresholdms"])
super(MongoReplicaSetClient, self).__init__(**self.__opts)
if self.slave_okay:
warnings.warn("slave_okay is deprecated. Please "
@ -1017,6 +1025,14 @@ class MongoReplicaSetClient(common.BaseObject):
"""**DEPRECATED** Is auto_start_request enabled?"""
return self.__auto_start_request
@property
def local_threshold_ms(self):
"""Alias for secondary_acceptable_latency_ms.
.. versionadded:: 2.9
"""
return self.secondary_acceptable_latency_ms
def __simple_command(self, sock_info, dbname, spec):
"""Send a command to the server.
Returns (response, ping_time in seconds).

View File

@ -331,6 +331,63 @@ class TestClient(unittest.TestCase, TestRequestMixin):
finally:
ctx.exit()
def test_backport_localthresholdms_uri(self):
uri = "mongodb://%s:%s" % (host, port)
lt_uri = "mongodb://%s:%d/?localThresholdMS=10" % (host, port)
sl_uri = ("mongodb://%s:%d/?secondaryAcceptableLatencyMS=10" %
(host, port))
lt_sl_uri = ("mongodb://%s:%d/?localThresholdMS=10;"
"secondaryAcceptableLatencyMS=8" % (host, port))
# Just localThresholdMS
client = MongoClient(uri)
self.assertEqual(client.secondary_acceptable_latency_ms, 15)
self.assertEqual(client.local_threshold_ms, 15)
client = MongoClient(uri, localThresholdMS=10)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(uri, localThresholdMS=10,
secondaryAcceptableLatencyMS=8)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
# URI options take precedence over kwargs but localThresholdMS takes
# precedence over secondaryAcceptableLatencyMS always. Test to make
# sure the precedence is correct between URI vs. kwargs.
client = MongoClient(lt_uri)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(lt_uri, localThresholdMS=8)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(lt_uri, secondaryAcceptableLatencyMS=8)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(lt_uri, localThresholdMS=8,
secondaryAcceptableLatencyMS=6)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(sl_uri, secondaryAcceptableLatencyMS=8)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(sl_uri, localThresholdMS=10)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(sl_uri, localThresholdMS=10,
secondaryAcceptableLatencyMS=6)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(lt_sl_uri)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(lt_sl_uri, localThresholdMS=8,
secondaryAcceptableLatencyMS=4)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
def test_get_default_database(self):
c = MongoClient("mongodb://%s:%d/foo" % (host, port), _connect=False)
self.assertEqual(Database(c, 'foo'), c.get_default_database())

View File

@ -154,6 +154,44 @@ class TestMongosHA(unittest.TestCase):
# No error
client.db.collection.find_one()
def test_backport_localthresholdms_kwarg(self):
# Test that localThresholdMS takes precedence over
# secondaryAcceptableLatencyMS.
client = MockClient(
standalones=[],
members=[],
mongoses=['a:1', 'b:2', 'c:3'],
host='a:1,b:2,c:3',
localThresholdMS=7,
secondaryAcceptableLatencyMS=0)
self.assertEqual(7, client.secondary_acceptable_latency_ms)
self.assertEqual(7, client.local_threshold_ms)
# No error
client.db.collection.find_one()
client = MockClient(
standalones=[],
members=[],
mongoses=['a:1', 'b:2', 'c:3'],
host='a:1,b:2,c:3',
localThresholdMS=0,
secondaryAcceptableLatencyMS=15)
self.assertEqual(0, client.secondary_acceptable_latency_ms)
self.assertEqual(0, client.local_threshold_ms)
# Test that using localThresholdMS works in the same way as using
# secondaryAcceptableLatencyMS.
client.db.collection.find_one()
# Our chosen mongos goes down.
client.kill_host('%s:%s' % (client.host, client.port))
try:
client.db.collection.find_one()
except:
pass
# No error
client.db.collection.find_one()
if __name__ == "__main__":
unittest.main()

View File

@ -166,6 +166,27 @@ class TestReadPreferences(TestReadPreferencesBase):
self._get_client,
secondaryacceptablelatencyms=-1)
def test_backport_latency_validation(self):
self.assertEqual(17, self._get_client(
localThresholdMS=17
).secondary_acceptable_latency_ms)
self.assertEqual(42, self._get_client(
secondaryAcceptableLatencyMS=42
).local_threshold_ms)
self.assertEqual(666, self._get_client(
localThresholdMS=666
).local_threshold_ms)
self.assertEqual(0, self._get_client(
localthresholdms=0
).local_threshold_ms)
self.assertRaises(ConfigurationError,
self._get_client,
localthresholdms=-1)
def test_primary(self):
self.assertReadsFrom('primary',
read_preference=ReadPreference.PRIMARY)

View File

@ -743,6 +743,64 @@ class TestReplicaSetClient(TestReplicaSetClientBase, TestRequestMixin):
self.assertTrue("pymongo_test_bernie" in dbs)
client.close()
def test_backport_repl_localthresholdms_uri(self):
uri = ("mongodb://%s/?replicaSet=%s" % (pair, self.name))
lt_uri = ("mongodb://%s/?replicaSet=%s;localThresholdMS=10"
% (pair, self.name))
sl_uri = ("mongodb://%s/?replicaSet=%s;secondaryAcceptableLatencyMS=10"
% (pair, self.name))
sl_lt_uri = ("mongodb://%s/?replicaSet=%s;localThresholdMS=10;"
"secondaryAcceptableLatencyMS=8" % (pair, self.name))
# Just localThresholdMS
client = MongoReplicaSetClient(uri)
self.assertEqual(client.secondary_acceptable_latency_ms, 15)
self.assertEqual(client.local_threshold_ms, 15)
client = MongoReplicaSetClient(uri, localThresholdMS=10)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(uri, localThresholdMS=10,
secondaryAcceptableLatencyMS=8)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
# URI options take precedence over kwargs but localThresholdMS takes
# precedence over secondaryAcceptableLatencyMS always. Test to make
# sure the precedence is correct between URI vs. kwargs.
client = MongoReplicaSetClient(lt_uri)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoReplicaSetClient(lt_uri, localThresholdMS=8)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(lt_uri, secondaryAcceptableLatencyMS=8)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(lt_uri, secondaryAcceptableLatencyMS=8,
localThresholdMS=6)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(sl_uri, secondaryAcceptableLatencyMS=8)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(sl_uri, localThresholdMS=10)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(sl_uri, localThresholdMS=10,
secondaryAcceptableLatencyMS=6)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(sl_lt_uri)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
client = MongoClient(sl_lt_uri, localThresholdMS=8,
secondaryAcceptableLatencyMS=4)
self.assertEqual(client.secondary_acceptable_latency_ms, 10)
self.assertEqual(client.local_threshold_ms, 10)
def _test_kill_cursor_explicit(self, read_pref):
c = self._get_client(read_preference=read_pref)
db = c.pymongo_test

View File

@ -138,6 +138,8 @@ class TestURI(unittest.TestCase):
self.assertEqual({'authsource': 'foobar'}, split_options('authSource=foobar'))
# maxPoolSize isn't yet a documented URI option.
self.assertRaises(ConfigurationError, split_options, 'maxpoolsize=50')
self.assertEqual({'localthresholdms': 300},
split_options('localThresholdMS=300'))
def test_parse_uri(self):
self.assertRaises(InvalidURI, parse_uri, "http://foobar.com")