PYTHON-920, PYTHON-921 - Fix metadata helpers with direct connection.
With this change metadata helpers (database_names, collection_names, options, and index_information) no longer require a non-primary read preference or the slave_okay option to run them against a directly connected secondary or slave. This was the easiest way to make the driver behave consistently across MongoDB versions and helpers. This is also consistent with the server selection spec, though we are not implementing that spec for PyMongo 2.x.
This commit is contained in:
parent
4897c51090
commit
9bf46d2bb1
@ -1270,10 +1270,12 @@ class Collection(common.BaseObject):
|
||||
client = self.database.connection
|
||||
client._ensure_connected(True)
|
||||
|
||||
slave_okay = not client._rs_client and not client.is_mongos
|
||||
if client.max_wire_version > 2:
|
||||
res, addr = self.__database._command(
|
||||
"listIndexes", self.__name, as_class=SON,
|
||||
cursor={}, read_preference=ReadPreference.PRIMARY)
|
||||
cursor={}, slave_okay=slave_okay,
|
||||
read_preference=ReadPreference.PRIMARY)
|
||||
# MongoDB 2.8rc2
|
||||
if "indexes" in res:
|
||||
raw = res["indexes"]
|
||||
@ -1283,6 +1285,7 @@ class Collection(common.BaseObject):
|
||||
else:
|
||||
raw = self.__database.system.indexes.find({"ns": self.__full_name},
|
||||
{"ns": 0}, as_class=SON,
|
||||
slave_okay=slave_okay,
|
||||
_must_use_master=True)
|
||||
info = {}
|
||||
for index in raw:
|
||||
@ -1303,12 +1306,14 @@ class Collection(common.BaseObject):
|
||||
client._ensure_connected(True)
|
||||
|
||||
result = None
|
||||
slave_okay = not client._rs_client and not client.is_mongos
|
||||
if client.max_wire_version > 2:
|
||||
res, addr = self.__database._command(
|
||||
"listCollections",
|
||||
cursor={},
|
||||
filter={"name": self.__name},
|
||||
read_preference=ReadPreference.PRIMARY)
|
||||
read_preference=ReadPreference.PRIMARY,
|
||||
slave_okay=slave_okay)
|
||||
# MongoDB 2.8rc2
|
||||
if "collections" in res:
|
||||
results = res["collections"]
|
||||
@ -1320,7 +1325,9 @@ class Collection(common.BaseObject):
|
||||
break
|
||||
else:
|
||||
result = self.__database.system.namespaces.find_one(
|
||||
{"name": self.__full_name}, _must_use_master=True)
|
||||
{"name": self.__full_name},
|
||||
slave_okay=slave_okay,
|
||||
_must_use_master=True)
|
||||
|
||||
if not result:
|
||||
return {}
|
||||
|
||||
@ -448,10 +448,12 @@ class Database(common.BaseObject):
|
||||
client = self.connection
|
||||
client._ensure_connected(True)
|
||||
|
||||
slave_okay = not client._rs_client and not client.is_mongos
|
||||
if client.max_wire_version > 2:
|
||||
res, addr = self._command("listCollections",
|
||||
cursor={},
|
||||
read_preference=ReadPreference.PRIMARY)
|
||||
read_preference=ReadPreference.PRIMARY,
|
||||
slave_okay=slave_okay)
|
||||
# MongoDB 2.8rc2
|
||||
if "collections" in res:
|
||||
results = res["collections"]
|
||||
@ -461,7 +463,9 @@ class Database(common.BaseObject):
|
||||
names = [result["name"] for result in results]
|
||||
else:
|
||||
names = [result["name"] for result
|
||||
in self["system.namespaces"].find(_must_use_master=True)]
|
||||
in self["system.namespaces"].find(
|
||||
slave_okay=slave_okay,
|
||||
_must_use_master=True)]
|
||||
names = [n[len(self.__name) + 1:] for n in names
|
||||
if n.startswith(self.__name + ".") and "$" not in n]
|
||||
|
||||
|
||||
@ -1373,9 +1373,14 @@ class MongoClient(common.BaseObject):
|
||||
def database_names(self):
|
||||
"""Get a list of the names of all databases on the connected server.
|
||||
"""
|
||||
# SERVER-15994 changed listDatabases to require slaveOk when run
|
||||
# against a secondary / slave. Passing slave_okay=True makes things
|
||||
# consistent across server versions.
|
||||
return [db["name"] for db in
|
||||
self.admin.command("listDatabases",
|
||||
read_preference=ReadPreference.PRIMARY)["databases"]]
|
||||
self.admin.command(
|
||||
"listDatabases",
|
||||
read_preference=ReadPreference.PRIMARY,
|
||||
slave_okay=not self.is_mongos)["databases"]]
|
||||
|
||||
def drop_database(self, name_or_database):
|
||||
"""Drop a database.
|
||||
|
||||
@ -82,6 +82,24 @@ class TestReadPreferencesBase(TestReplicaSetClientBase):
|
||||
expected, used))
|
||||
|
||||
|
||||
class TestSlaveOkayMetadataCommands(TestReadPreferencesBase):
|
||||
|
||||
def test_slave_okay_metadata_commands(self):
|
||||
|
||||
secondaries = iter(self._get_client().secondaries)
|
||||
host, port = secondaries.next()
|
||||
# Direct connection to a secondary.
|
||||
client = MongoClient(host, port)
|
||||
self.assertFalse(client.is_primary)
|
||||
self.assertEqual(client.read_preference, ReadPreference.PRIMARY)
|
||||
|
||||
# No error.
|
||||
client.database_names()
|
||||
client.pymongo_test.collection_names()
|
||||
client.pymongo_test.test.options()
|
||||
client.pymongo_test.test.index_information()
|
||||
|
||||
|
||||
class TestReadPreferences(TestReadPreferencesBase):
|
||||
def test_mode_validation(self):
|
||||
# 'modes' are imported from read_preferences.py
|
||||
|
||||
Loading…
Reference in New Issue
Block a user