From cb3e96d961617176ce1d68801a0eece07ad8ba02 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 14 Apr 2015 15:07:20 -0400 Subject: [PATCH 1/5] PHPC-240: Regression tests for command cursor getmore --- tests/standalone/cursor-getmore-001.phpt | 37 +++++++++++++++++++ tests/standalone/cursor-getmore-002.phpt | 36 +++++++++++++++++++ tests/standalone/cursor-getmore-003.phpt | 45 ++++++++++++++++++++++++ tests/standalone/cursor-getmore-004.phpt | 44 +++++++++++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 tests/standalone/cursor-getmore-001.phpt create mode 100644 tests/standalone/cursor-getmore-002.phpt create mode 100644 tests/standalone/cursor-getmore-003.phpt create mode 100644 tests/standalone/cursor-getmore-004.phpt diff --git a/tests/standalone/cursor-getmore-001.phpt b/tests/standalone/cursor-getmore-001.phpt new file mode 100644 index 000000000..92b63ed5c --- /dev/null +++ b/tests/standalone/cursor-getmore-001.phpt @@ -0,0 +1,37 @@ +--TEST-- +MongoDB\Driver\Cursor query result iteration with batchSize requiring getmore with full batches +--SKIPIF-- + +--FILE-- +insert(array('_id' => $i)); +} + +$writeResult = $manager->executeBulkWrite(NS, $bulkWrite); +printf("Inserted: %d\n", $writeResult->getInsertedCount()); + +$cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array(), array('batchSize' => 2))); + +foreach ($cursor as $i => $document) { + printf("%d => {_id: %d}\n", $i, $document['_id']); +} + +?> +===DONE=== + +--EXPECT-- +Inserted: 6 +0 => {_id: 0} +1 => {_id: 1} +2 => {_id: 2} +3 => {_id: 3} +4 => {_id: 4} +5 => {_id: 5} +===DONE=== diff --git a/tests/standalone/cursor-getmore-002.phpt b/tests/standalone/cursor-getmore-002.phpt new file mode 100644 index 000000000..db8a505ca --- /dev/null +++ b/tests/standalone/cursor-getmore-002.phpt @@ -0,0 +1,36 @@ +--TEST-- +MongoDB\Driver\Cursor query result iteration with batchSize requiring getmore with non-full batches +--SKIPIF-- + +--FILE-- +insert(array('_id' => $i)); +} + +$writeResult = $manager->executeBulkWrite(NS, $bulkWrite); +printf("Inserted: %d\n", $writeResult->getInsertedCount()); + +$cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array(), array('batchSize' => 2))); + +foreach ($cursor as $i => $document) { + printf("%d => {_id: %d}\n", $i, $document['_id']); +} + +?> +===DONE=== + +--EXPECT-- +Inserted: 5 +0 => {_id: 0} +1 => {_id: 1} +2 => {_id: 2} +3 => {_id: 3} +4 => {_id: 4} +===DONE=== diff --git a/tests/standalone/cursor-getmore-003.phpt b/tests/standalone/cursor-getmore-003.phpt new file mode 100644 index 000000000..4e345fb21 --- /dev/null +++ b/tests/standalone/cursor-getmore-003.phpt @@ -0,0 +1,45 @@ +--TEST-- +MongoDB\Driver\Cursor command result iteration with batchSize requiring getmore with full batches +--SKIPIF-- + +--FILE-- +insert(array('_id' => $i)); +} + +$writeResult = $manager->executeBulkWrite(NS, $bulkWrite); +printf("Inserted: %d\n", $writeResult->getInsertedCount()); + +$command = new MongoDB\Driver\Command(array( + 'aggregate' => COLLECTION_NAME, + 'pipeline' => array( + array('$match' => new stdClass), + ), + 'cursor' => array('batchSize' => 2), +)); + +$cursor = $manager->executeCommand(DATABASE_NAME, $command); + +foreach ($cursor as $i => $document) { + printf("%d => {_id: %d}\n", $i, $document['_id']); +} + +?> +===DONE=== + +--EXPECT-- +Inserted: 6 +0 => {_id: 0} +1 => {_id: 1} +2 => {_id: 2} +3 => {_id: 3} +4 => {_id: 4} +5 => {_id: 5} +===DONE=== diff --git a/tests/standalone/cursor-getmore-004.phpt b/tests/standalone/cursor-getmore-004.phpt new file mode 100644 index 000000000..7697fad66 --- /dev/null +++ b/tests/standalone/cursor-getmore-004.phpt @@ -0,0 +1,44 @@ +--TEST-- +MongoDB\Driver\Cursor command result iteration with batchSize requiring getmore with non-full batches +--SKIPIF-- + +--FILE-- +insert(array('_id' => $i)); +} + +$writeResult = $manager->executeBulkWrite(NS, $bulkWrite); +printf("Inserted: %d\n", $writeResult->getInsertedCount()); + +$command = new MongoDB\Driver\Command(array( + 'aggregate' => COLLECTION_NAME, + 'pipeline' => array( + array('$match' => new stdClass), + ), + 'cursor' => array('batchSize' => 2), +)); + +$cursor = $manager->executeCommand(DATABASE_NAME, $command); + +foreach ($cursor as $i => $document) { + printf("%d => {_id: %d}\n", $i, $document['_id']); +} + +?> +===DONE=== + +--EXPECT-- +Inserted: 5 +0 => {_id: 0} +1 => {_id: 1} +2 => {_id: 2} +3 => {_id: 3} +4 => {_id: 4} +===DONE=== From c7b78916977fb5dbc62fce79f8b8ace350727da5 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 15 Apr 2015 16:43:09 -0400 Subject: [PATCH 2/5] PHPC-240: Rely on libmongoc for command cursor iteration libmongoc already provides a mechanism to upgrade a cursor with a single command result document into a command cursor, which will seamlessly iterate through the first batch and documents returned by successive getmore ops. This allows us to remove our own "first batch" handling and simplify the move_forward and rewind iteration handlers. --- php_phongo.c | 117 ++++++------------ php_phongo_classes.h | 3 - tests/readPreference/002.phpt | 20 --- .../manager-executeCommand-001.phpt | 7 -- .../standalone/manager-executeQuery-001.phpt | 9 -- .../standalone/server-executeCommand-001.phpt | 7 -- 6 files changed, 39 insertions(+), 124 deletions(-) diff --git a/php_phongo.c b/php_phongo.c index 6277c0193..c2e13e376 100644 --- a/php_phongo.c +++ b/php_phongo.c @@ -235,7 +235,7 @@ static void php_phongo_log(mongoc_log_level_t log_level, const char *log_domain, /* }}} */ /* {{{ Init objects */ -void phongo_cursor_init(zval *return_value, mongoc_cursor_t *cursor, const bson_t *bson, mongoc_client_t *client, zend_bool is_command_cursor TSRMLS_DC) /* {{{ */ +void phongo_cursor_init(zval *return_value, mongoc_cursor_t *cursor, mongoc_client_t *client TSRMLS_DC) /* {{{ */ { php_phongo_cursor_t *intern; @@ -245,8 +245,6 @@ void phongo_cursor_init(zval *return_value, mongoc_cursor_t *cursor, const bson_ intern->cursor = cursor; intern->server_id = mongoc_cursor_get_hint(cursor); intern->client = client; - intern->is_command_cursor = is_command_cursor; - intern->firstBatch = bson ? bson_copy(bson) : NULL; } /* }}} */ void phongo_server_init(zval *return_value, mongoc_client_t *client, int server_id TSRMLS_DC) /* {{{ */ @@ -589,7 +587,7 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, const p return true; } - phongo_cursor_init(return_value, cursor, doc, client, 0 TSRMLS_CC); + phongo_cursor_init(return_value, cursor, client TSRMLS_CC); return true; } /* }}} */ @@ -619,36 +617,43 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, const bson_t return true; } - /* Detect if its an command cursor */ - if (bson_iter_init_find (&iter, doc, "cursor") && BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) { - while (bson_iter_next (&child)) { - if (BSON_ITER_IS_KEY (&child, "id")) { - cursor->rpc.reply.cursor_id = bson_iter_as_int64 (&child); - } else if (BSON_ITER_IS_KEY (&child, "ns")) { + /* This code is adapated from _mongoc_cursor_cursorid_prime(), but we avoid + * advancing the cursor, since we are already positioned at the first result + * after the error checking above. */ + if (bson_iter_init_find(&iter, doc, "cursor") && BSON_ITER_HOLDS_DOCUMENT(&iter) && bson_iter_recurse(&iter, &child)) { + mongoc_cursor_cursorid_t *cid; + + _mongoc_cursor_cursorid_init(cursor); + cursor->limit = 0; + + cid = cursor->iface_data; + cid->has_cursor = true; + + while (bson_iter_next(&child)) { + if (BSON_ITER_IS_KEY(&child, "id")) { + cursor->rpc.reply.cursor_id = bson_iter_as_int64(&child); + } else if (BSON_ITER_IS_KEY(&child, "ns")) { const char *ns; - ns = bson_iter_utf8 (&child, &cursor->nslen); - bson_strncpy (cursor->ns, ns, sizeof cursor->ns); - } else if (BSON_ITER_IS_KEY (&child, "firstBatch")) { - if (BSON_ITER_HOLDS_ARRAY (&child)) { - const uint8_t *data = NULL; - uint32_t data_len = 0; - bson_t first_batch; - - bson_iter_array (&child, &data_len, &data); - if (bson_init_static (&first_batch, data, data_len)) { - _mongoc_cursor_cursorid_init(cursor); - cursor->limit = 0; - cursor->is_command = false; - phongo_cursor_init(return_value, cursor, &first_batch, client, 1 TSRMLS_CC); - return true; - } + ns = bson_iter_utf8(&child, &cursor->nslen); + bson_strncpy(cursor->ns, ns, sizeof cursor->ns); + } else if (BSON_ITER_IS_KEY(&child, "firstBatch")) { + if (BSON_ITER_HOLDS_ARRAY(&child) && bson_iter_recurse(&child, &cid->first_batch_iter)) { + cid->in_first_batch = true; } } } + + cursor->is_command = false; + + /* The cursor's current element is the command's response document. + * Advance once so that the cursor is positioned at the first document + * within the command cursor's result set. + */ + mongoc_cursor_next(cursor, &doc); } - phongo_cursor_init(return_value, cursor, doc, client, 0 TSRMLS_CC); + phongo_cursor_init(return_value, cursor, client TSRMLS_CC); return true; } /* }}} */ @@ -1291,17 +1296,7 @@ void php_phongo_cursor_to_zval(zval *retval, php_phongo_cursor_t *cursor) /* {{{ add_assoc_null_ex(retval, ZEND_STRS("cursor")); } - if (cursor->firstBatch) { - php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER; - - MAKE_STD_ZVAL(state.zchild); - bson_to_zval(bson_get_data(cursor->firstBatch), cursor->firstBatch->len, &state); - add_assoc_zval_ex(retval, ZEND_STRS("firstBatch"), state.zchild); - } else { - add_assoc_null_ex(retval, ZEND_STRS("firstBatch")); - } add_assoc_long_ex(retval, ZEND_STRS("server_id"), cursor->server_id); - add_assoc_bool_ex(retval, ZEND_STRS("is_command_cursor"), cursor->is_command_cursor); } /* }}} */ @@ -1560,14 +1555,11 @@ static void php_phongo_cursor_free_current(php_phongo_cursor_t *cursor) /* {{{ * void php_phongo_cursor_free(php_phongo_cursor_t *cursor) { - if (cursor->firstBatch) { - bson_clear(&cursor->firstBatch); - cursor->firstBatch = NULL; - } if (cursor->cursor) { mongoc_cursor_destroy(cursor->cursor); cursor->cursor = NULL; } + php_phongo_cursor_free_current(cursor); } @@ -1576,11 +1568,6 @@ static void php_phongo_cursor_iterator_dtor(zend_object_iterator *iter TSRMLS_DC { php_phongo_cursor_iterator *cursor_it = (php_phongo_cursor_iterator *)iter; - if (cursor_it->cursor->firstBatch) { - bson_clear(&cursor_it->cursor->firstBatch); - cursor_it->cursor->firstBatch = NULL; - } - php_phongo_cursor_free_current(cursor_it->cursor); if (cursor_it->intern.data) { @@ -1631,18 +1618,6 @@ static void php_phongo_cursor_iterator_move_forward(zend_object_iterator *iter T php_phongo_cursor_free_current(cursor); cursor_it->current++; - if (bson_iter_next(&cursor_it->first_batch_iter)) { - if (BSON_ITER_HOLDS_DOCUMENT (&cursor_it->first_batch_iter)) { - const uint8_t *data = NULL; - uint32_t data_len = 0; - - bson_iter_document(&cursor_it->first_batch_iter, &data_len, &data); - - MAKE_STD_ZVAL(cursor->visitor_data.zchild); - bson_to_zval(data, data_len, &cursor->visitor_data); - return; - } - } if (mongoc_cursor_next(cursor->cursor, &doc)) { MAKE_STD_ZVAL(cursor->visitor_data.zchild); bson_to_zval(bson_get_data(doc), doc->len, &cursor->visitor_data); @@ -1653,30 +1628,16 @@ static void php_phongo_cursor_iterator_rewind(zend_object_iterator *iter TSRMLS_ { php_phongo_cursor_iterator *cursor_it = (php_phongo_cursor_iterator *)iter; php_phongo_cursor_t *cursor = cursor_it->cursor; + const bson_t *doc; php_phongo_cursor_free_current(cursor); cursor_it->current = 0; - /* firstBatch is empty when the query simply didn't return any results */ - if (cursor->firstBatch) { - if (cursor->is_command_cursor) { - if (!bson_iter_init(&cursor_it->first_batch_iter, cursor->firstBatch)) { - return; - } - if (bson_iter_next (&cursor_it->first_batch_iter)) { - if (BSON_ITER_HOLDS_DOCUMENT (&cursor_it->first_batch_iter)) { - const uint8_t *data = NULL; - uint32_t data_len = 0; - - bson_iter_document(&cursor_it->first_batch_iter, &data_len, &data); - MAKE_STD_ZVAL(cursor->visitor_data.zchild); - bson_to_zval(data, data_len, &cursor->visitor_data); - } - } - } else { - MAKE_STD_ZVAL(cursor->visitor_data.zchild); - bson_to_zval(bson_get_data(cursor->firstBatch), cursor->firstBatch->len, &cursor->visitor_data); - } + doc = mongoc_cursor_current(cursor->cursor); + + if (doc) { + MAKE_STD_ZVAL(cursor->visitor_data.zchild); + bson_to_zval(bson_get_data(doc), doc->len, &cursor->visitor_data); } } /* }}} */ diff --git a/php_phongo_classes.h b/php_phongo_classes.h index 1d727e6e8..bb9c1749b 100644 --- a/php_phongo_classes.h +++ b/php_phongo_classes.h @@ -37,16 +37,13 @@ typedef struct { typedef struct { zend_object std; mongoc_cursor_t *cursor; - bson_t *firstBatch; mongoc_client_t *client; int server_id; - zend_bool is_command_cursor; php_phongo_bson_state visitor_data; } php_phongo_cursor_t; typedef struct { zend_object_iterator intern; - bson_iter_t first_batch_iter; php_phongo_cursor_t *cursor; long current; } php_phongo_cursor_iterator; diff --git a/tests/readPreference/002.phpt b/tests/readPreference/002.phpt index 23dfdaf98..c3fad4d2e 100644 --- a/tests/readPreference/002.phpt +++ b/tests/readPreference/002.phpt @@ -78,12 +78,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) { ["ns"]=> string(25) "phongo.readPreference_002" } - ["firstBatch"]=> - NULL ["server_id"]=> int(1) - ["is_command_cursor"]=> - bool(false) } object(MongoDB\Driver\Cursor)#%d (%d) { ["cursor"]=> @@ -146,12 +142,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) { ["ns"]=> string(25) "phongo.readPreference_002" } - ["firstBatch"]=> - NULL ["server_id"]=> int(1) - ["is_command_cursor"]=> - bool(false) } object(MongoDB\Driver\Cursor)#%d (%d) { ["cursor"]=> @@ -214,12 +206,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) { ["ns"]=> string(25) "phongo.readPreference_002" } - ["firstBatch"]=> - NULL ["server_id"]=> int(1) - ["is_command_cursor"]=> - bool(false) } object(MongoDB\Driver\Cursor)#%d (%d) { ["cursor"]=> @@ -282,12 +270,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) { ["ns"]=> string(25) "phongo.readPreference_002" } - ["firstBatch"]=> - NULL ["server_id"]=> int(1) - ["is_command_cursor"]=> - bool(false) } object(MongoDB\Driver\Cursor)#%d (%d) { ["cursor"]=> @@ -350,11 +334,7 @@ object(MongoDB\Driver\Cursor)#%d (%d) { ["ns"]=> string(25) "phongo.readPreference_002" } - ["firstBatch"]=> - NULL ["server_id"]=> int(1) - ["is_command_cursor"]=> - bool(false) } ===DONE=== diff --git a/tests/standalone/manager-executeCommand-001.phpt b/tests/standalone/manager-executeCommand-001.phpt index d86e79a43..c59924e57 100644 --- a/tests/standalone/manager-executeCommand-001.phpt +++ b/tests/standalone/manager-executeCommand-001.phpt @@ -91,15 +91,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) { float(1) } } - ["firstBatch"]=> - array(1) { - ["ok"]=> - float(1) - } ["server_id"]=> int(1) - ["is_command_cursor"]=> - bool(false) } Dumping response document: diff --git a/tests/standalone/manager-executeQuery-001.phpt b/tests/standalone/manager-executeQuery-001.phpt index 15201b549..37f842894 100644 --- a/tests/standalone/manager-executeQuery-001.phpt +++ b/tests/standalone/manager-executeQuery-001.phpt @@ -96,17 +96,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) { int(4) } } - ["firstBatch"]=> - array(2) { - ["_id"]=> - int(2) - ["y"]=> - int(4) - } ["server_id"]=> int(1) - ["is_command_cursor"]=> - bool(false) } bool(true) string(%d) "%s" diff --git a/tests/standalone/server-executeCommand-001.phpt b/tests/standalone/server-executeCommand-001.phpt index e708d441b..9d49f6e19 100644 --- a/tests/standalone/server-executeCommand-001.phpt +++ b/tests/standalone/server-executeCommand-001.phpt @@ -80,15 +80,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) { float(1) } } - ["firstBatch"]=> - array(1) { - ["ok"]=> - float(1) - } ["server_id"]=> int(1) - ["is_command_cursor"]=> - bool(false) } Dumping response document: From 80e69510288dd1546fe61e6aff561b356e185361 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 16 Apr 2015 14:35:01 -0500 Subject: [PATCH 3/5] Tests for multiple iterators sharing the same Cursor --- .../cursor-multiple_iterators-001.phpt | 50 ++++++++++++++++ .../cursor-multiple_iterators-002.phpt | 58 +++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 tests/standalone/cursor-multiple_iterators-001.phpt create mode 100644 tests/standalone/cursor-multiple_iterators-002.phpt diff --git a/tests/standalone/cursor-multiple_iterators-001.phpt b/tests/standalone/cursor-multiple_iterators-001.phpt new file mode 100644 index 000000000..1857e251a --- /dev/null +++ b/tests/standalone/cursor-multiple_iterators-001.phpt @@ -0,0 +1,50 @@ +--TEST-- +MongoDB\Driver\Cursor query result shared by multiple iterators +--SKIPIF-- + +--FILE-- +insert(array('_id' => $i)); +} + +$writeResult = $manager->executeBulkWrite(NS, $bulkWrite); +printf("Inserted: %d\n", $writeResult->getInsertedCount()); + +$cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); + +foreach ($cursor as $i => $document) { + printf("A: %d => {_id: %d}\n", $i, $document['_id']); + + if ($i == 2) { + foreach ($cursor as $j => $document) { + printf("B: %d => {_id: %d}\n", $j, $document['_id']); + + if ($j == 2) { + break; + } + } + } +} + +?> +===DONE=== + +--EXPECT-- +Inserted: 8 +A: 0 => {_id: 0} +A: 1 => {_id: 1} +A: 2 => {_id: 2} +B: 0 => {_id: 2} +B: 1 => {_id: 3} +B: 2 => {_id: 4} +A: 3 => {_id: 5} +A: 4 => {_id: 6} +A: 5 => {_id: 7} +===DONE=== diff --git a/tests/standalone/cursor-multiple_iterators-002.phpt b/tests/standalone/cursor-multiple_iterators-002.phpt new file mode 100644 index 000000000..eb5b12545 --- /dev/null +++ b/tests/standalone/cursor-multiple_iterators-002.phpt @@ -0,0 +1,58 @@ +--TEST-- +MongoDB\Driver\Cursor command result shared by multiple iterators +--SKIPIF-- + +--FILE-- +insert(array('_id' => $i)); +} + +$writeResult = $manager->executeBulkWrite(NS, $bulkWrite); +printf("Inserted: %d\n", $writeResult->getInsertedCount()); + +$command = new MongoDB\Driver\Command(array( + 'aggregate' => COLLECTION_NAME, + 'pipeline' => array( + array('$match' => new stdClass), + ), + 'cursor' => new stdClass, +)); + +$cursor = $manager->executeCommand(DATABASE_NAME, $command); + +foreach ($cursor as $i => $document) { + printf("A: %d => {_id: %d}\n", $i, $document['_id']); + + if ($i == 2) { + foreach ($cursor as $j => $document) { + printf("B: %d => {_id: %d}\n", $j, $document['_id']); + + if ($j == 2) { + break; + } + } + } +} + +?> +===DONE=== + +--EXPECT-- +Inserted: 8 +A: 0 => {_id: 0} +A: 1 => {_id: 1} +A: 2 => {_id: 2} +B: 0 => {_id: 2} +B: 1 => {_id: 3} +B: 2 => {_id: 4} +A: 3 => {_id: 5} +A: 4 => {_id: 6} +A: 5 => {_id: 7} +===DONE=== From f176cb7d910ae644ff022886c5659c0a912ad68d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 16 Apr 2015 15:18:44 -0500 Subject: [PATCH 4/5] Test Cursor iteration handlers and ensure rewind doesn't reset position --- php_phongo.c | 1 - .../cursor-iterator_handlers-001.phpt | 107 ++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 tests/standalone/cursor-iterator_handlers-001.phpt diff --git a/php_phongo.c b/php_phongo.c index c2e13e376..56558d785 100644 --- a/php_phongo.c +++ b/php_phongo.c @@ -1631,7 +1631,6 @@ static void php_phongo_cursor_iterator_rewind(zend_object_iterator *iter TSRMLS_ const bson_t *doc; php_phongo_cursor_free_current(cursor); - cursor_it->current = 0; doc = mongoc_cursor_current(cursor->cursor); diff --git a/tests/standalone/cursor-iterator_handlers-001.phpt b/tests/standalone/cursor-iterator_handlers-001.phpt new file mode 100644 index 000000000..bf588eeb5 --- /dev/null +++ b/tests/standalone/cursor-iterator_handlers-001.phpt @@ -0,0 +1,107 @@ +--TEST-- +MongoDB\Driver\Cursor iterator handlers +--SKIPIF-- + +--FILE-- +name = (string) $name; + } + + public function dump() + { + $key = parent::key(); + $current = parent::current(); + $position = is_int($key) ? (string) $key : 'null'; + $document = is_array($current) ? sprintf("{_id: %d}", $current['_id']) : 'null'; + printf("%s: %s => %s\n", $this->name, $position, $document); + } +} + +$manager = new MongoDB\Driver\Manager(STANDALONE); + +$bulkWrite = new MongoDB\Driver\BulkWrite; + +for ($i = 0; $i < 5; $i++) { + $bulkWrite->insert(array('_id' => $i)); +} + +$writeResult = $manager->executeBulkWrite(NS, $bulkWrite); +printf("Inserted: %d\n", $writeResult->getInsertedCount()); + +$cursor = $manager->executeQuery(NS, new MongoDB\Driver\Query(array())); +$a = new MyIteratorIterator($cursor, 'A'); +$b = new MyIteratorIterator($cursor, 'B'); + +echo "\nBefore rewinding, position and current element are not populated:\n"; +$a->dump(); +$b->dump(); + +echo "\nAfter rewinding, current element is populated:\n"; +$a->rewind(); +$b->rewind(); +$a->dump(); +$b->dump(); + +echo "\nMultiple iterators have their own position, but share the same Cursor buffer:\n"; +$a->next(); +$a->dump(); +$b->next(); +$b->dump(); +$a->next(); +$a->dump(); + +echo "\nRewinding only populates current element and does not alter position:\n"; +$a->rewind(); +$a->dump(); +$b->rewind(); +$b->dump(); + +echo "\nAdvancing first iterator until end of shared Cursor buffer is reached:\n"; +$a->next(); +$a->dump(); +$a->next(); +$a->dump(); + +echo "\nRewinding second iterator to position it at end of shared Cursor buffer:\n"; +$b->rewind(); +$b->dump(); + +?> +===DONE=== + +--EXPECT-- +Inserted: 5 + +Before rewinding, position and current element are not populated: +A: null => null +B: null => null + +After rewinding, current element is populated: +A: 0 => {_id: 0} +B: 0 => {_id: 0} + +Multiple iterators have their own position, but share the same Cursor buffer: +A: 1 => {_id: 1} +B: 1 => {_id: 2} +A: 2 => {_id: 3} + +Rewinding only populates current element and does not alter position: +A: 2 => {_id: 3} +B: 1 => {_id: 3} + +Advancing first iterator until end of shared Cursor buffer is reached: +A: 3 => {_id: 4} +A: null => null + +Rewinding second iterator to position it at end of shared Cursor buffer: +B: null => null +===DONE=== From 70b711000f13d140707186c0e061092e7b19ba4e Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 17 Apr 2015 10:15:47 -0500 Subject: [PATCH 5/5] Current element is already freed in php_phongo_cursor_free() php_phongo_cursor_iterator_dtor() should not need to free the current element, which is stored on our cursor struct. If the cursor is only used by one iterator, zval_ptr_dtor() on the iterator's intern.data property (i.e. our Cursor zval) will implicitly call the free_object handler, which will invoke php_phongo_cursor_free() and clear the current element. --- php_phongo.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/php_phongo.c b/php_phongo.c index 56558d785..230040f95 100644 --- a/php_phongo.c +++ b/php_phongo.c @@ -1568,8 +1568,6 @@ static void php_phongo_cursor_iterator_dtor(zend_object_iterator *iter TSRMLS_DC { php_phongo_cursor_iterator *cursor_it = (php_phongo_cursor_iterator *)iter; - php_phongo_cursor_free_current(cursor_it->cursor); - if (cursor_it->intern.data) { zval_ptr_dtor((zval**)&cursor_it->intern.data); cursor_it->intern.data = NULL;