Skip to content

Commit e5ddb13

Browse files
committed
Use slaves for group, distinct, count PYTHON-256
Or secondaries with ReplicaSetConnection.
1 parent 4fa59c2 commit e5ddb13

5 files changed

Lines changed: 51 additions & 13 deletions

File tree

pymongo/collection.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,13 @@ def group(self, key, condition, initial, reduce, finalize=None,
887887
containing a JavaScript function to be applied to each
888888
document, returning the key to group by.
889889
890+
With :class:`~pymongo.replica_set_connection.ReplicaSetConnection`
891+
or :class:`~pymongo.master_slave_connection.MasterSlaveConnection`,
892+
if the `read_preference` attribute of this instance is not set to
893+
:attr:`pymongo.ReadPreference.PRIMARY` or the (deprecated)
894+
`slave_okay` attribute of this instance is set to `True` the group
895+
command will be sent to a secondary or slave.
896+
890897
:Parameters:
891898
- `key`: fields to group by (see above description)
892899
- `condition`: specification of rows to be
@@ -921,7 +928,10 @@ def group(self, key, condition, initial, reduce, finalize=None,
921928
if finalize is not None:
922929
group["finalize"] = Code(finalize)
923930

924-
return self.__database.command("group", group)["retval"]
931+
use_master = not self.slave_okay and not self.read_preference
932+
933+
return self.__database.command("group", group,
934+
_use_master=use_master)["retval"]
925935

926936
def rename(self, new_name, **kwargs):
927937
"""Rename this collection.

pymongo/cursor.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,12 @@ def count(self, with_limit_and_skip=False):
449449
`with_limit_and_skip` to ``True`` if that is the desired behavior.
450450
Raises :class:`~pymongo.errors.OperationFailure` on a database error.
451451
452+
With :class:`~pymongo.replica_set_connection.ReplicaSetConnection`
453+
or :class:`~pymongo.master_slave_connection.MasterSlaveConnection`,
454+
if `read_preference` is not :attr:`pymongo.ReadPreference.PRIMARY` or
455+
(deprecated) `slave_okay` is `True` the count command will be sent to
456+
a secondary or slave.
457+
452458
:Parameters:
453459
- `with_limit_and_skip` (optional): take any :meth:`limit` or
454460
:meth:`skip` that has been applied to this cursor into account when
@@ -464,6 +470,9 @@ def count(self, with_limit_and_skip=False):
464470
"""
465471
command = {"query": self.__spec, "fields": self.__fields}
466472

473+
use_master = not self.__slave_okay and not self.__read_preference
474+
command['_use_master'] = use_master
475+
467476
if with_limit_and_skip:
468477
if self.__limit:
469478
command["limit"] = self.__limit
@@ -484,6 +493,12 @@ def distinct(self, key):
484493
Raises :class:`TypeError` if `key` is not an instance of
485494
:class:`basestring`.
486495
496+
With :class:`~pymongo.replica_set_connection.ReplicaSetConnection`
497+
or :class:`~pymongo.master_slave_connection.MasterSlaveConnection`,
498+
if `read_preference` is not :attr:`pymongo.ReadPreference.PRIMARY` or
499+
(deprecated) `slave_okay` is `True` the distinct command will be sent
500+
to a secondary or slave.
501+
487502
:Parameters:
488503
- `key`: name of key for which we want to get the distinct values
489504
@@ -500,6 +515,9 @@ def distinct(self, key):
500515
if self.__spec:
501516
options["query"] = self.__spec
502517

518+
use_master = not self.__slave_okay and not self.__read_preference
519+
options['_use_master'] = use_master
520+
503521
return self.__collection.database.command("distinct",
504522
self.__collection.name,
505523
**options)["values"]

pymongo/database.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,14 +326,16 @@ def command(self, command, value=1,
326326
if isinstance(command, basestring):
327327
command = SON([(command, value)])
328328

329+
use_master = kwargs.pop('_use_master', True)
330+
329331
fields = kwargs.get('fields')
330332
if fields is not None and not isinstance(fields, dict):
331333
kwargs['fields'] = helpers._fields_list_to_dict(fields)
332334

333335
command.update(kwargs)
334336

335337
result = self["$cmd"].find_one(command,
336-
_must_use_master=True,
338+
_must_use_master=use_master,
337339
_is_command=True)
338340

339341
if check:

pymongo/master_slave_connection.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ def __init__(self, master, slaves=[], tz_aware=False):
6666
slave)
6767

6868
super(MasterSlaveConnection,
69-
self).__init__(slave_okay=True,
70-
read_preference=ReadPreference.SECONDARY,
69+
self).__init__(read_preference=ReadPreference.SECONDARY,
7170
safe=master.safe,
7271
**(master.get_lasterror_options()))
7372

test/test_master_slave_connection.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -318,36 +318,44 @@ def cursor_count():
318318

319319
def test_base_object(self):
320320
c = self.connection
321-
self.assertTrue(c.slave_okay)
321+
self.assertFalse(c.slave_okay)
322+
self.assertTrue(bool(c.read_preference))
322323
self.assertFalse(c.safe)
323324
self.assertEqual({}, c.get_lasterror_options())
324325
db = c.test
325-
self.assertTrue(db.slave_okay)
326+
self.assertFalse(db.slave_okay)
327+
self.assertTrue(bool(c.read_preference))
326328
self.assertFalse(db.safe)
327329
self.assertEqual({}, db.get_lasterror_options())
328330
coll = db.test
329-
self.assertTrue(coll.slave_okay)
331+
self.assertFalse(coll.slave_okay)
332+
self.assertTrue(bool(c.read_preference))
330333
self.assertFalse(coll.safe)
331334
self.assertEqual({}, coll.get_lasterror_options())
332335
cursor = coll.find()
333-
self.assertTrue(cursor._Cursor__slave_okay)
336+
self.assertFalse(cursor._Cursor__slave_okay)
337+
self.assertTrue(bool(cursor._Cursor__read_preference))
334338

335339
c.safe = True
336340
c.set_lasterror_options(w=2, wtimeout=100)
337-
self.assertTrue(c.slave_okay)
341+
self.assertFalse(c.slave_okay)
342+
self.assertTrue(bool(c.read_preference))
338343
self.assertTrue(c.safe)
339344
self.assertEqual({'w': 2, 'wtimeout': 100}, c.get_lasterror_options())
340345
db = c.test
341-
self.assertTrue(db.slave_okay)
346+
self.assertFalse(db.slave_okay)
347+
self.assertTrue(bool(c.read_preference))
342348
self.assertTrue(db.safe)
343349
self.assertEqual({'w': 2, 'wtimeout': 100}, db.get_lasterror_options())
344350
coll = db.test
345-
self.assertTrue(coll.slave_okay)
351+
self.assertFalse(coll.slave_okay)
352+
self.assertTrue(bool(c.read_preference))
346353
self.assertTrue(coll.safe)
347354
self.assertEqual({'w': 2, 'wtimeout': 100},
348355
coll.get_lasterror_options())
349356
cursor = coll.find()
350-
self.assertTrue(cursor._Cursor__slave_okay)
357+
self.assertFalse(cursor._Cursor__slave_okay)
358+
self.assertTrue(bool(cursor._Cursor__read_preference))
351359

352360
coll.insert({'foo': 'bar'})
353361
self.assertEquals(1, coll.find({'foo': 'bar'}).count())
@@ -358,7 +366,8 @@ def test_base_object(self):
358366
# Set self.connection back to defaults
359367
c.safe = False
360368
c.unset_lasterror_options()
361-
self.assertTrue(self.connection.slave_okay)
369+
self.assertFalse(self.connection.slave_okay)
370+
self.assertTrue(bool(self.connection.read_preference))
362371
self.assertFalse(self.connection.safe)
363372
self.assertEqual({}, self.connection.get_lasterror_options())
364373

0 commit comments

Comments
 (0)