Skip to content
This repository has been archived by the owner on Nov 11, 2020. It is now read-only.

Specify time limit operation on a mongodb cursor #227

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions lib/Doctrine/MongoDB/Cursor.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class Cursor implements CursorInterface
protected $sort;
protected $tailable;
protected $timeout;
protected $maxTimeMS;

/**
* Constructor.
Expand Down Expand Up @@ -508,6 +509,9 @@ public function recreate()
if ($this->timeout !== null) {
$this->mongoCursor->timeout($this->timeout);
}
if ($this->maxTimeMS !== null) {
$this->mongoCursor->maxTimeMS($this->maxTimeMS);
}
}

/**
Expand Down Expand Up @@ -664,6 +668,22 @@ public function timeout($ms)
return $this;
}

/**
* Wrapper method for MongoCursor::maxTimeMS().
*
* @see http://php.net/manual/en/mongocursor.maxtimems.php
* @param integer $ms
* @return self
*/
public function maxTimeMS($ms)
{
if (version_compare(phpversion('mongo'), '1.5.0', '>=')) {
$this->maxTimeMS = (integer)$ms;
$this->mongoCursor->maxTimeMS((integer)$ms);
}
return $this;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ne0h12: The most compatible solution would be to call MongoCursor::addOption('$maxTimeMS', $ms) here, as it doesn't depend on the driver's method at all.

}

/**
* Return the cursor's results as an array.
*
Expand Down
9 changes: 9 additions & 0 deletions lib/Doctrine/MongoDB/CursorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -253,4 +253,13 @@ public function tailable($tail = true);
* @return self
*/
public function timeout($ms);

/**
* Wrapper method for MongoCursor::maxTimeMS().
*
* @see http://php.net/manual/en/mongocursor.maxtimems.php
* @param integer $ms
* @return self
*/
public function maxTimeMS($ms);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alcaeus: We may have shot ourselves in the foot here, but AFAIK we cannot add a new method to the interface without bumping to a new major version. This has come up with the collection interfaces in Doctrine Common before.

/cc @Ocramius

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically speaking, yes. This is a BC break and thus would force us to go 2.0. I'm kicking myself now for not catching all methods that were added in the 1.5 driver.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ne0h12: Unfortunately, this needs to be removed. We cannot add new interface methods without bumping a major version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I removed it

}
11 changes: 11 additions & 0 deletions lib/Doctrine/MongoDB/EagerCursor.php
Original file line number Diff line number Diff line change
Expand Up @@ -440,4 +440,15 @@ public function timeout($ms)

return $this;
}


/**
* {@inheritdoc}
*/
public function maxTimeMS($ms)
{
$this->cursor->maxTimeMS($ms);

return $this;
}
}
13 changes: 13 additions & 0 deletions lib/Doctrine/MongoDB/LoggableCursor.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,17 @@ public function sort($fields)

return parent::sort($fields);
}

/**
* @see Cursor::maxTimeMS()
*/
public function maxTimeMS($ms)
{
$this->log(array(
'maxTimeMS' => true,
'maxTimeMSNum' => $ms,
));

return parent::maxTimeMS($ms);
}
}
12 changes: 12 additions & 0 deletions lib/Doctrine/MongoDB/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,18 @@ public function hint($index)
return $this;
}

/**
* Specifies a cumulative time limit in milliseconds for processing operations on a cursor.
*
* @param int $ms
* @return $this
*/
public function maxTimeMS($ms)
{
$this->query['maxTimeMS'] = $ms;
return $this;
}

/**
* Set the immortal cursor flag.
*
Expand Down
2 changes: 1 addition & 1 deletion lib/Doctrine/MongoDB/Query/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ protected function prepareCursor(Cursor $cursor)
$cursor->setReadPreference($this->query['readPreference'], $this->query['readPreferenceTags']);
}

foreach ($this->getQueryOptions('hint', 'immortal', 'limit', 'skip', 'slaveOkay', 'sort') as $key => $value) {
foreach ($this->getQueryOptions('hint', 'immortal', 'limit', 'skip', 'slaveOkay', 'sort', 'maxTimeMS') as $key => $value) {
$cursor->$key($value);
}

Expand Down
38 changes: 38 additions & 0 deletions tests/Doctrine/MongoDB/Tests/CursorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,44 @@ public function testRecreate()
$cursor->recreate();
}

public function testSetMaxTimeMSWhenRecreateCursor()
{
if (version_compare(phpversion('mongo'), '1.5.0', '<')) {
$this->markTestSkipped('This test is not applicable to driver versions < 1.5.0');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use addOption(), I think we can run this test on any driver version with appropriate mock changes.

}

$self = $this;

$setCursorExpectations = function($mongoCursor) use ($self) {
$mongoCursor->expects($self->once())
->method('maxTimeMS')
->with(30000);
};

$mongoCursor = $this->getMockMongoCursor();
$recreatedMongoCursor = $this->getMockMongoCursor();

$setCursorExpectations($mongoCursor);
$setCursorExpectations($recreatedMongoCursor);

$mongoCollection = $this->getMockCollection();
$mongoCollection->expects($this->once())
->method('find')
->with(array('x' => 9500), array())
->will($this->returnValue($recreatedMongoCursor));

$collection = $this->getMockCollection();
$collection->expects($this->once())
->method('getMongoCollection')
->will($this->returnValue($mongoCollection));

$cursor = $this->getTestCursor($collection, $mongoCursor, array('x' => 9500));

$cursor->maxTimeMS(30000);

$cursor->recreate();
}

private function getMockCollection()
{
return $this->getMockBuilder('Doctrine\MongoDB\Collection')
Expand Down
1 change: 1 addition & 0 deletions tests/Doctrine/MongoDB/Tests/LoggableCursorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public function provideLoggedMethods()
array('limit'),
array('hint', array()),
array('snapshot'),
array('maxTimeMS', array())
);
}
}
30 changes: 30 additions & 0 deletions tests/Doctrine/MongoDB/Tests/Query/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,36 @@ public function testUseIdentifierKeys()
$this->assertSame($cursor, $query->execute());
}

public function testSpecifyMaxTimeMSOnCursor()
{
if(version_compare(phpversion('mongo'), '1.5.0', '<')) {
$this->markTestSkipped('This test is not applicable to driver versions < 1.5.0');
}

$cursor = $this->getMockCursor();
$collection = $this->getMockCollection();

$collection->expects($this->once())
->method('find')
->with($this->equalTo(array('foo' => 'bar')))
->will($this->returnValue($cursor));

$cursor->expects($this->once())
->method('maxTimeMS')
->with($this->equalTo(30000))
->will($this->returnValue($cursor));

$queryArray = array(
'type' => Query::TYPE_FIND,
'query' => array('foo' => 'bar'),
'maxTimeMS' => 30000
);

$query = new Query($collection, $queryArray, array());

$this->assertSame($cursor, $query->execute());
}

/**
* @return \Doctrine\MongoDB\Collection
*/
Expand Down