Skip to content
This repository was archived by the owner on Feb 1, 2022. It is now read-only.

Commit 66ac5b3

Browse files
committed
Merge pull request #856
2 parents ae4d94a + e6f687c commit 66ac5b3

5 files changed

Lines changed: 182 additions & 7 deletions

File tree

command_cursor.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ int php_mongocommandcursor_advance(mongo_command_cursor *cmd_cursor TSRMLS_DC)
223223
return FAILURE;
224224
}
225225
if (!php_mongo_get_more(cmd_cursor TSRMLS_CC)) {
226-
cmd_cursor->cursor_id = 0;
227226
return FAILURE;
228227
}
229228
}

cursor.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,15 +380,11 @@ int php_mongocursor_advance(mongo_cursor *cursor TSRMLS_DC)
380380
}
381381
/* Limit reached */
382382
if (cursor->limit != 0 && cursor->at >= cursor->limit) {
383-
mongo_deregister_callback_from_connection(cursor->connection, cursor);
384-
php_mongo_cursor_mark_dead(cursor);
383+
php_mongo_kill_cursor(cursor->connection, cursor->cursor_id TSRMLS_CC);
384+
cursor->cursor_id = 0;
385385
return FAILURE;
386386
}
387387
if (!php_mongo_get_more(cursor TSRMLS_CC)) {
388-
if (cursor->connection) {
389-
mongo_deregister_callback_from_connection(cursor->connection, cursor);
390-
}
391-
php_mongo_cursor_mark_dead(cursor);
392388
return FAILURE;
393389
}
394390
}

cursor_shared.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ int php_mongo_cursor_failed(mongo_cursor *cursor TSRMLS_DC)
629629
{
630630
mongo_manager_connection_deregister(MonGlo(manager), cursor->connection);
631631
cursor->dead = 1;
632+
cursor->cursor_id = 0;
632633
cursor->connection = NULL;
633634

634635
return FAILURE;

tests/generic/bug01460-001.phpt

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
--TEST--
2+
Test for PHP-1460: Query with limit leaves open cursors on server (foreach iteration)
3+
--SKIPIF--
4+
<?php require_once "tests/utils/standalone.inc" ?>
5+
--FILE--
6+
<?php
7+
require_once "tests/utils/server.inc";
8+
9+
function getNumOpenCursors(MongoClient $mc) {
10+
$result = $mc->admin->command(array('serverStatus' => 1));
11+
12+
if (isset($result['metrics']['cursor']['open']['total'])) {
13+
return (integer) $result['metrics']['cursor']['open']['total'];
14+
}
15+
16+
if (isset($result['cursors']['totalOpen'])) {
17+
return (integer) $result['cursors']['totalOpen'];
18+
}
19+
20+
throw new RuntimeException('serverStatus did not return cursor metrics');
21+
}
22+
23+
function log_killcursor($server, $info) {
24+
printf("Killing cursor: %d\n", $info['cursor_id']);
25+
}
26+
27+
function log_getmore($server, $info) {
28+
printf("Getmore on cursor: %d\n", $info['cursor_id']);
29+
}
30+
31+
$ctx = stream_context_create(array(
32+
'mongodb' => array(
33+
'log_getmore' => 'log_getmore',
34+
'log_killcursor' => 'log_killcursor',
35+
),
36+
));
37+
38+
$host = MongoShellServer::getStandaloneInfo();
39+
$mc = new MongoClient($host, array(), array('context' => $ctx));
40+
41+
$c = $mc->selectCollection(dbname(), collname(__FILE__));
42+
$c->drop();
43+
44+
for ($i = 0; $i < 15; $i++) {
45+
$c->insert(array('_id' => $i));
46+
}
47+
48+
$numOpenCursorsBeforeQuery = getNumOpenCursors($mc);
49+
printf("Number of open cursors before query: %d\n", $numOpenCursorsBeforeQuery);
50+
51+
$cursor = $c->find()->limit(10)->batchSize(5);
52+
printf("Cursor is dead: %s\n", $cursor->dead() ? 'true' : 'false');
53+
54+
foreach ($cursor as $document) {
55+
printf("Found document: %d\n", $document['_id']);
56+
if ($document['_id'] === 4 || $document['_id'] === 9) {
57+
printf("Cursor is dead: %s\n", $cursor->dead() ? 'true' : 'false');
58+
}
59+
}
60+
61+
printf("Cursor is dead: %s\n", $cursor->dead() ? 'true' : 'false');
62+
63+
$numOpenCursorsAfterQuery = getNumOpenCursors($mc);
64+
printf("Number of open cursors after query: %d\n", $numOpenCursorsAfterQuery);
65+
printf("Same number of cursors open before and after query: %s\n", $numOpenCursorsBeforeQuery === $numOpenCursorsAfterQuery ? 'true' : 'false');
66+
67+
?>
68+
===DONE===
69+
--EXPECTF--
70+
Number of open cursors before query: %d
71+
Cursor is dead: false
72+
Found document: 0
73+
Found document: 1
74+
Found document: 2
75+
Found document: 3
76+
Found document: 4
77+
Cursor is dead: false
78+
Getmore on cursor: %d
79+
Found document: 5
80+
Found document: 6
81+
Found document: 7
82+
Found document: 8
83+
Found document: 9
84+
Cursor is dead: false
85+
Killing cursor: %d
86+
Cursor is dead: true
87+
Number of open cursors after query: %d
88+
Same number of cursors open before and after query: true
89+
===DONE===

tests/generic/bug01460-002.phpt

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
--TEST--
2+
Test for PHP-1460: Query with limit leaves open cursors on server (getNext/hasNext iteration)
3+
--SKIPIF--
4+
<?php require_once "tests/utils/standalone.inc" ?>
5+
--FILE--
6+
<?php
7+
require_once "tests/utils/server.inc";
8+
9+
function getNumOpenCursors(MongoClient $mc) {
10+
$result = $mc->admin->command(array('serverStatus' => 1));
11+
12+
if (isset($result['metrics']['cursor']['open']['total'])) {
13+
return (integer) $result['metrics']['cursor']['open']['total'];
14+
}
15+
16+
if (isset($result['cursors']['totalOpen'])) {
17+
return (integer) $result['cursors']['totalOpen'];
18+
}
19+
20+
throw new RuntimeException('serverStatus did not return cursor metrics');
21+
}
22+
23+
function log_killcursor($server, $info) {
24+
printf("Killing cursor: %d\n", $info['cursor_id']);
25+
}
26+
27+
function log_getmore($server, $info) {
28+
printf("Getmore on cursor: %d\n", $info['cursor_id']);
29+
}
30+
31+
$ctx = stream_context_create(array(
32+
'mongodb' => array(
33+
'log_getmore' => 'log_getmore',
34+
'log_killcursor' => 'log_killcursor',
35+
),
36+
));
37+
38+
$host = MongoShellServer::getStandaloneInfo();
39+
$mc = new MongoClient($host, array(), array('context' => $ctx));
40+
41+
$c = $mc->selectCollection(dbname(), collname(__FILE__));
42+
$c->drop();
43+
44+
for ($i = 0; $i < 15; $i++) {
45+
$c->insert(array('_id' => $i));
46+
}
47+
48+
$numOpenCursorsBeforeQuery = getNumOpenCursors($mc);
49+
printf("Number of open cursors before query: %d\n", $numOpenCursorsBeforeQuery);
50+
51+
$cursor = $c->find()->limit(10)->batchSize(5);
52+
printf("Cursor is dead: %s\n", $cursor->dead() ? 'true' : 'false');
53+
54+
while ($cursor->hasNext()) {
55+
$document = $cursor->getNext();
56+
printf("Found document: %d\n", $document['_id']);
57+
if ($document['_id'] === 4 || $document['_id'] === 9) {
58+
printf("Cursor is dead: %s\n", $cursor->dead() ? 'true' : 'false');
59+
}
60+
}
61+
62+
printf("Cursor is dead: %s\n", $cursor->dead() ? 'true' : 'false');
63+
64+
$numOpenCursorsAfterQuery = getNumOpenCursors($mc);
65+
printf("Number of open cursors after query: %d\n", $numOpenCursorsAfterQuery);
66+
printf("Same number of cursors open before and after query: %s\n", $numOpenCursorsBeforeQuery === $numOpenCursorsAfterQuery ? 'true' : 'false');
67+
68+
?>
69+
===DONE===
70+
--EXPECTF--
71+
Number of open cursors before query: %d
72+
Cursor is dead: false
73+
Found document: 0
74+
Found document: 1
75+
Found document: 2
76+
Found document: 3
77+
Found document: 4
78+
Cursor is dead: false
79+
Getmore on cursor: %d
80+
Found document: 5
81+
Found document: 6
82+
Found document: 7
83+
Found document: 8
84+
Found document: 9
85+
Cursor is dead: false
86+
Killing cursor: %d
87+
Cursor is dead: true
88+
Number of open cursors after query: %d
89+
Same number of cursors open before and after query: true
90+
===DONE===

0 commit comments

Comments
 (0)