Skip to content

Commit d6ac6b0

Browse files
committed
Add testSessionFreed and fix cursorId check in ChangeStream::next()
1 parent 125c6d9 commit d6ac6b0

File tree

2 files changed

+31
-13
lines changed

2 files changed

+31
-13
lines changed

src/ChangeStream.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ public function next()
107107
* free any reference to Watch. This will also free the only
108108
* reference to an implicit session, since any such reference
109109
* belongs to Watch. */
110-
if ($this->getCursorId() === 0) {
111-
unset($this->resumeCallable);
110+
if ((string)$this->getCursorId() === '0') {
111+
$this->resumeCallable = null;
112112
}
113113
} catch (RuntimeException $e) {
114114
if (strpos($e->getMessage(), "not master") !== false) {
@@ -140,8 +140,8 @@ public function rewind()
140140
$this->resumeToken = $this->extractResumeToken($this->csIt->current());
141141
}
142142
// As with next(), free the callable once we know it will never be used.
143-
if ($this->getCursorId() === 0) {
144-
unset($this->resumeCallable);
143+
if ((string)$this->getCursorId() === '0') {
144+
$this->resumeCallable = null;
145145
}
146146
} catch (RuntimeException $e) {
147147
if (strpos($e->getMessage(), "not master") !== false) {

tests/Operation/WatchFunctionalTest.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
use MongoDB\Driver\Server;
99
use MongoDB\Driver\Exception\ConnectionTimeoutException;
1010
use MongoDB\Exception\ResumeTokenException;
11+
use MongoDB\Operation\CreateCollection;
1112
use MongoDB\Operation\DatabaseCommand;
13+
use MongoDB\Operation\DropCollection;
1214
use MongoDB\Operation\InsertOne;
1315
use MongoDB\Operation\Watch;
1416
use MongoDB\Tests\CommandObserver;
@@ -627,16 +629,10 @@ function ($changeStream) use (&$sessionAfterResume, &$commands) {
627629
);
628630

629631
$expectedCommands = [
630-
/* The initial aggregate command for change streams returns a cursor
631-
* envelope with an empty initial batch, since there are no changes
632-
* to report at the moment the change stream is created. Therefore,
633-
* we expect a getMore to be issued when we first advance the change
634-
* stream (with either rewind() or next()). */
632+
/* We expect a getMore to be issued because we are calling next(). */
635633
'getMore',
636-
/* Since socketTimeoutMS is less than maxAwaitTimeMS, the previous
637-
* getMore command encounters a client socket timeout and leaves the
638-
* cursor open on the server. ChangeStream should catch this error
639-
* and resume by issuing a new aggregate command. */
634+
/* Since we have killed the cursor, ChangeStream will resume by
635+
* issuing a new aggregate commmand. */
640636
'aggregate',
641637
/* When ChangeStream resumes, it overwrites its original cursor with
642638
* the new cursor resulting from the last aggregate command. This
@@ -653,7 +649,29 @@ function ($changeStream) use (&$sessionAfterResume, &$commands) {
653649
foreach ($sessionAfterResume as $session) {
654650
$this->assertEquals($session, $originalSession);
655651
}
652+
}
653+
654+
public function testSessionFreed()
655+
{
656+
$operation = new CreateCollection($this->getDatabaseName(), $this->getCollectionName());
657+
$operation->execute($this->getPrimaryServer());
658+
659+
$operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
660+
$changeStream = $operation->execute($this->getPrimaryServer());
661+
662+
$rc = new ReflectionClass($changeStream);
663+
$rp = $rc->getProperty('resumeCallable');
664+
$rp->setAccessible(true);
665+
666+
$this->assertNotNull($rp->getValue($changeStream));
667+
668+
// Invalidate the cursor to verify that resumeCallable is unset when the cursor is exhausted.
669+
$operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName());
670+
$operation->execute($this->getPrimaryServer());
671+
672+
$changeStream->next();
656673

674+
$this->assertNull($rp->getValue($changeStream));
657675
}
658676

659677
private function insertDocument($document)

0 commit comments

Comments
 (0)