Skip to content

Commit c7b7891

Browse files
committed
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.
1 parent cb3e96d commit c7b7891

File tree

6 files changed

+39
-124
lines changed

6 files changed

+39
-124
lines changed

php_phongo.c

Lines changed: 39 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ static void php_phongo_log(mongoc_log_level_t log_level, const char *log_domain,
235235
/* }}} */
236236

237237
/* {{{ Init objects */
238-
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) /* {{{ */
238+
void phongo_cursor_init(zval *return_value, mongoc_cursor_t *cursor, mongoc_client_t *client TSRMLS_DC) /* {{{ */
239239
{
240240
php_phongo_cursor_t *intern;
241241

@@ -245,8 +245,6 @@ void phongo_cursor_init(zval *return_value, mongoc_cursor_t *cursor, const bson_
245245
intern->cursor = cursor;
246246
intern->server_id = mongoc_cursor_get_hint(cursor);
247247
intern->client = client;
248-
intern->is_command_cursor = is_command_cursor;
249-
intern->firstBatch = bson ? bson_copy(bson) : NULL;
250248
} /* }}} */
251249

252250
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
589587
return true;
590588
}
591589

592-
phongo_cursor_init(return_value, cursor, doc, client, 0 TSRMLS_CC);
590+
phongo_cursor_init(return_value, cursor, client TSRMLS_CC);
593591
return true;
594592
} /* }}} */
595593

@@ -619,36 +617,43 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, const bson_t
619617
return true;
620618
}
621619

622-
/* Detect if its an command cursor */
623-
if (bson_iter_init_find (&iter, doc, "cursor") && BSON_ITER_HOLDS_DOCUMENT (&iter) && bson_iter_recurse (&iter, &child)) {
624-
while (bson_iter_next (&child)) {
625-
if (BSON_ITER_IS_KEY (&child, "id")) {
626-
cursor->rpc.reply.cursor_id = bson_iter_as_int64 (&child);
627-
} else if (BSON_ITER_IS_KEY (&child, "ns")) {
620+
/* This code is adapated from _mongoc_cursor_cursorid_prime(), but we avoid
621+
* advancing the cursor, since we are already positioned at the first result
622+
* after the error checking above. */
623+
if (bson_iter_init_find(&iter, doc, "cursor") && BSON_ITER_HOLDS_DOCUMENT(&iter) && bson_iter_recurse(&iter, &child)) {
624+
mongoc_cursor_cursorid_t *cid;
625+
626+
_mongoc_cursor_cursorid_init(cursor);
627+
cursor->limit = 0;
628+
629+
cid = cursor->iface_data;
630+
cid->has_cursor = true;
631+
632+
while (bson_iter_next(&child)) {
633+
if (BSON_ITER_IS_KEY(&child, "id")) {
634+
cursor->rpc.reply.cursor_id = bson_iter_as_int64(&child);
635+
} else if (BSON_ITER_IS_KEY(&child, "ns")) {
628636
const char *ns;
629637

630-
ns = bson_iter_utf8 (&child, &cursor->nslen);
631-
bson_strncpy (cursor->ns, ns, sizeof cursor->ns);
632-
} else if (BSON_ITER_IS_KEY (&child, "firstBatch")) {
633-
if (BSON_ITER_HOLDS_ARRAY (&child)) {
634-
const uint8_t *data = NULL;
635-
uint32_t data_len = 0;
636-
bson_t first_batch;
637-
638-
bson_iter_array (&child, &data_len, &data);
639-
if (bson_init_static (&first_batch, data, data_len)) {
640-
_mongoc_cursor_cursorid_init(cursor);
641-
cursor->limit = 0;
642-
cursor->is_command = false;
643-
phongo_cursor_init(return_value, cursor, &first_batch, client, 1 TSRMLS_CC);
644-
return true;
645-
}
638+
ns = bson_iter_utf8(&child, &cursor->nslen);
639+
bson_strncpy(cursor->ns, ns, sizeof cursor->ns);
640+
} else if (BSON_ITER_IS_KEY(&child, "firstBatch")) {
641+
if (BSON_ITER_HOLDS_ARRAY(&child) && bson_iter_recurse(&child, &cid->first_batch_iter)) {
642+
cid->in_first_batch = true;
646643
}
647644
}
648645
}
646+
647+
cursor->is_command = false;
648+
649+
/* The cursor's current element is the command's response document.
650+
* Advance once so that the cursor is positioned at the first document
651+
* within the command cursor's result set.
652+
*/
653+
mongoc_cursor_next(cursor, &doc);
649654
}
650655

651-
phongo_cursor_init(return_value, cursor, doc, client, 0 TSRMLS_CC);
656+
phongo_cursor_init(return_value, cursor, client TSRMLS_CC);
652657
return true;
653658
} /* }}} */
654659

@@ -1291,17 +1296,7 @@ void php_phongo_cursor_to_zval(zval *retval, php_phongo_cursor_t *cursor) /* {{{
12911296
add_assoc_null_ex(retval, ZEND_STRS("cursor"));
12921297
}
12931298

1294-
if (cursor->firstBatch) {
1295-
php_phongo_bson_state state = PHONGO_BSON_STATE_INITIALIZER;
1296-
1297-
MAKE_STD_ZVAL(state.zchild);
1298-
bson_to_zval(bson_get_data(cursor->firstBatch), cursor->firstBatch->len, &state);
1299-
add_assoc_zval_ex(retval, ZEND_STRS("firstBatch"), state.zchild);
1300-
} else {
1301-
add_assoc_null_ex(retval, ZEND_STRS("firstBatch"));
1302-
}
13031299
add_assoc_long_ex(retval, ZEND_STRS("server_id"), cursor->server_id);
1304-
add_assoc_bool_ex(retval, ZEND_STRS("is_command_cursor"), cursor->is_command_cursor);
13051300

13061301
} /* }}} */
13071302

@@ -1560,14 +1555,11 @@ static void php_phongo_cursor_free_current(php_phongo_cursor_t *cursor) /* {{{ *
15601555

15611556
void php_phongo_cursor_free(php_phongo_cursor_t *cursor)
15621557
{
1563-
if (cursor->firstBatch) {
1564-
bson_clear(&cursor->firstBatch);
1565-
cursor->firstBatch = NULL;
1566-
}
15671558
if (cursor->cursor) {
15681559
mongoc_cursor_destroy(cursor->cursor);
15691560
cursor->cursor = NULL;
15701561
}
1562+
15711563
php_phongo_cursor_free_current(cursor);
15721564
}
15731565

@@ -1576,11 +1568,6 @@ static void php_phongo_cursor_iterator_dtor(zend_object_iterator *iter TSRMLS_DC
15761568
{
15771569
php_phongo_cursor_iterator *cursor_it = (php_phongo_cursor_iterator *)iter;
15781570

1579-
if (cursor_it->cursor->firstBatch) {
1580-
bson_clear(&cursor_it->cursor->firstBatch);
1581-
cursor_it->cursor->firstBatch = NULL;
1582-
}
1583-
15841571
php_phongo_cursor_free_current(cursor_it->cursor);
15851572

15861573
if (cursor_it->intern.data) {
@@ -1631,18 +1618,6 @@ static void php_phongo_cursor_iterator_move_forward(zend_object_iterator *iter T
16311618
php_phongo_cursor_free_current(cursor);
16321619
cursor_it->current++;
16331620

1634-
if (bson_iter_next(&cursor_it->first_batch_iter)) {
1635-
if (BSON_ITER_HOLDS_DOCUMENT (&cursor_it->first_batch_iter)) {
1636-
const uint8_t *data = NULL;
1637-
uint32_t data_len = 0;
1638-
1639-
bson_iter_document(&cursor_it->first_batch_iter, &data_len, &data);
1640-
1641-
MAKE_STD_ZVAL(cursor->visitor_data.zchild);
1642-
bson_to_zval(data, data_len, &cursor->visitor_data);
1643-
return;
1644-
}
1645-
}
16461621
if (mongoc_cursor_next(cursor->cursor, &doc)) {
16471622
MAKE_STD_ZVAL(cursor->visitor_data.zchild);
16481623
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_
16531628
{
16541629
php_phongo_cursor_iterator *cursor_it = (php_phongo_cursor_iterator *)iter;
16551630
php_phongo_cursor_t *cursor = cursor_it->cursor;
1631+
const bson_t *doc;
16561632

16571633
php_phongo_cursor_free_current(cursor);
16581634
cursor_it->current = 0;
16591635

1660-
/* firstBatch is empty when the query simply didn't return any results */
1661-
if (cursor->firstBatch) {
1662-
if (cursor->is_command_cursor) {
1663-
if (!bson_iter_init(&cursor_it->first_batch_iter, cursor->firstBatch)) {
1664-
return;
1665-
}
1666-
if (bson_iter_next (&cursor_it->first_batch_iter)) {
1667-
if (BSON_ITER_HOLDS_DOCUMENT (&cursor_it->first_batch_iter)) {
1668-
const uint8_t *data = NULL;
1669-
uint32_t data_len = 0;
1670-
1671-
bson_iter_document(&cursor_it->first_batch_iter, &data_len, &data);
1672-
MAKE_STD_ZVAL(cursor->visitor_data.zchild);
1673-
bson_to_zval(data, data_len, &cursor->visitor_data);
1674-
}
1675-
}
1676-
} else {
1677-
MAKE_STD_ZVAL(cursor->visitor_data.zchild);
1678-
bson_to_zval(bson_get_data(cursor->firstBatch), cursor->firstBatch->len, &cursor->visitor_data);
1679-
}
1636+
doc = mongoc_cursor_current(cursor->cursor);
1637+
1638+
if (doc) {
1639+
MAKE_STD_ZVAL(cursor->visitor_data.zchild);
1640+
bson_to_zval(bson_get_data(doc), doc->len, &cursor->visitor_data);
16801641
}
16811642
} /* }}} */
16821643

php_phongo_classes.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,13 @@ typedef struct {
3737
typedef struct {
3838
zend_object std;
3939
mongoc_cursor_t *cursor;
40-
bson_t *firstBatch;
4140
mongoc_client_t *client;
4241
int server_id;
43-
zend_bool is_command_cursor;
4442
php_phongo_bson_state visitor_data;
4543
} php_phongo_cursor_t;
4644

4745
typedef struct {
4846
zend_object_iterator intern;
49-
bson_iter_t first_batch_iter;
5047
php_phongo_cursor_t *cursor;
5148
long current;
5249
} php_phongo_cursor_iterator;

tests/readPreference/002.phpt

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) {
7878
["ns"]=>
7979
string(25) "phongo.readPreference_002"
8080
}
81-
["firstBatch"]=>
82-
NULL
8381
["server_id"]=>
8482
int(1)
85-
["is_command_cursor"]=>
86-
bool(false)
8783
}
8884
object(MongoDB\Driver\Cursor)#%d (%d) {
8985
["cursor"]=>
@@ -146,12 +142,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) {
146142
["ns"]=>
147143
string(25) "phongo.readPreference_002"
148144
}
149-
["firstBatch"]=>
150-
NULL
151145
["server_id"]=>
152146
int(1)
153-
["is_command_cursor"]=>
154-
bool(false)
155147
}
156148
object(MongoDB\Driver\Cursor)#%d (%d) {
157149
["cursor"]=>
@@ -214,12 +206,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) {
214206
["ns"]=>
215207
string(25) "phongo.readPreference_002"
216208
}
217-
["firstBatch"]=>
218-
NULL
219209
["server_id"]=>
220210
int(1)
221-
["is_command_cursor"]=>
222-
bool(false)
223211
}
224212
object(MongoDB\Driver\Cursor)#%d (%d) {
225213
["cursor"]=>
@@ -282,12 +270,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) {
282270
["ns"]=>
283271
string(25) "phongo.readPreference_002"
284272
}
285-
["firstBatch"]=>
286-
NULL
287273
["server_id"]=>
288274
int(1)
289-
["is_command_cursor"]=>
290-
bool(false)
291275
}
292276
object(MongoDB\Driver\Cursor)#%d (%d) {
293277
["cursor"]=>
@@ -350,11 +334,7 @@ object(MongoDB\Driver\Cursor)#%d (%d) {
350334
["ns"]=>
351335
string(25) "phongo.readPreference_002"
352336
}
353-
["firstBatch"]=>
354-
NULL
355337
["server_id"]=>
356338
int(1)
357-
["is_command_cursor"]=>
358-
bool(false)
359339
}
360340
===DONE===

tests/standalone/manager-executeCommand-001.phpt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) {
9191
float(1)
9292
}
9393
}
94-
["firstBatch"]=>
95-
array(1) {
96-
["ok"]=>
97-
float(1)
98-
}
9994
["server_id"]=>
10095
int(1)
101-
["is_command_cursor"]=>
102-
bool(false)
10396
}
10497

10598
Dumping response document:

tests/standalone/manager-executeQuery-001.phpt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) {
9696
int(4)
9797
}
9898
}
99-
["firstBatch"]=>
100-
array(2) {
101-
["_id"]=>
102-
int(2)
103-
["y"]=>
104-
int(4)
105-
}
10699
["server_id"]=>
107100
int(1)
108-
["is_command_cursor"]=>
109-
bool(false)
110101
}
111102
bool(true)
112103
string(%d) "%s"

tests/standalone/server-executeCommand-001.phpt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,8 @@ object(MongoDB\Driver\Cursor)#%d (%d) {
8080
float(1)
8181
}
8282
}
83-
["firstBatch"]=>
84-
array(1) {
85-
["ok"]=>
86-
float(1)
87-
}
8883
["server_id"]=>
8984
int(1)
90-
["is_command_cursor"]=>
91-
bool(false)
9285
}
9386

9487
Dumping response document:

0 commit comments

Comments
 (0)