-
Notifications
You must be signed in to change notification settings - Fork 208
PHPC-2269: Add internal iterator logic for MongoDB\BSON\Iterator #1454
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PHPC-2269: Add internal iterator logic for MongoDB\BSON\Iterator #1454
Conversation
{ | ||
php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(&iter->data); | ||
|
||
return intern->valid ? SUCCESS : FAILURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm once again reminded how dumb PHP is for having SUCCESS
defined as 0
, when bools work exactly the other way around. Took me a moment to figure out why as I was initially returning intern->valid
directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been bitten by this before, but I've made peace with assuming PHP's behavior is inspired by process exit codes.
@@ -263,10 +298,92 @@ static HashTable* php_phongo_iterator_get_properties(phongo_compat_object_handle | |||
return php_phongo_iterator_get_properties_hash(object, false); | |||
} | |||
|
|||
/* Iterator handlers */ | |||
static void php_phongo_iterator_it_dtor(zend_object_iterator* iter) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This entire logic was shamelessly lifted from spl_array.c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does "this entire logic" refer to all of the iterator functions in this file (not just dtor
here)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - all of the php_phongo_iterator_it_*
methods were heavily inspired by PHP's standard implementation.
{ | ||
php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(&iter->data); | ||
|
||
return php_phongo_iterator_get_current(intern); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlike the current()
method itself, there's no need to copy/deref the zval we're returning here. Another notable difference to current()
is that we're leaving an IS_UNDEF
zval as-is, whereas current
returns null
in those cases. I don't think it makes a significant difference, and I'm not sure why Cursor::current()
(which inspired the BSON iterator) returns null
for an undef zval. I know there are some weird shenanigans going on when returning a IS_UNDEF
, but I don't think this will ever matter in practice, as having that value returned indicates that something went seriously wrong during the iteration and there should've been an exception anyways.
if (by_ref) { | ||
phongo_throw_exception(PHONGO_ERROR_LOGIC, "An iterator cannot be used with foreach by reference"); | ||
return NULL; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is precedent for this in PHP itself, although they emit an E_ERROR
in such cases. I opted to throw instead as it's more consistent how we expose errors.
We can't support iteration by reference as the BSON structures themselves are read-only, so assigning to the decoded value makes no sense.
src/BSON/Iterator.c
Outdated
php_phongo_iterator_it_get_current_key, | ||
php_phongo_iterator_it_move_forward, | ||
php_phongo_iterator_it_rewind, | ||
NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the function pointer for invalidate_current
, which isn't used. Quoting from phpinternalsbook:
The only handler that has no correspondence in userland is
invalidate_current
, which can be used to destroy the current key/value. The handler is largely unused though, in particularforeach
won’t even call it.
We could point this to php_phongo_iterator_free_current
, although I'm not sure what the benefits of that would be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
php_phongo_iterator_free_current
is already called from the necessary places.
I'm fine with leaving invalidate_current
unset, unless there's prior art for other iterator implementations using it.
I do think it'd be worth adding a /* invalidate_current */
comment here so we don't need to reference PHONGO_ITERATOR_FUNCS
's definition to see what's being omitted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the comment as suggested.
3904abe
to
cbc8eb9
Compare
cbc8eb9
to
8171ae3
Compare
Here are some results from the performance tests done using the tests added in mongodb/mongo-php-library#1141. Results in PHP 8.2-debug:
This shows an improvement of 79% with this new logic. Using a non-debug version of PHP however yields wildly different results:
Here, there is no improvement whatsoever, but interestingly enough the test is slower than in the debug version, which has me somewhat confused. The extension was compiled the same way for both runs, always including the developer flags ( |
8171ae3
to
08fb5d9
Compare
Here are the latest results comparing iteration in non-debug PHP:
These are the results I was looking for - turns out |
08fb5d9
to
a9a1be5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some small comment suggestions but implementation LGTM.
void php_phongo_iterator_init_ce(INIT_FUNC_ARGS) | ||
{ | ||
php_phongo_iterator_ce = register_class_MongoDB_BSON_Iterator(zend_ce_iterator); | ||
php_phongo_iterator_ce->create_object = php_phongo_iterator_create_object; | ||
php_phongo_iterator_ce->get_iterator = php_phongo_iterator_get_iterator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quoting PHPC-2269's description:
If this speeds up iteration, we should consider adding the same logic to The MongoDB\Cursor class, which may suffer from the same performance overhead.
Given that this does appear to speed things up, would you like to create a separate issue for making a similar change to Cursor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created PHPC-2278.
src/BSON/Iterator.c
Outdated
php_phongo_iterator_it_get_current_key, | ||
php_phongo_iterator_it_move_forward, | ||
php_phongo_iterator_it_rewind, | ||
NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
php_phongo_iterator_free_current
is already called from the necessary places.
I'm fine with leaving invalidate_current
unset, unless there's prior art for other iterator implementations using it.
I do think it'd be worth adding a /* invalidate_current */
comment here so we don't need to reference PHONGO_ITERATOR_FUNCS
's definition to see what's being omitted.
{ | ||
php_phongo_iterator_t* intern = Z_ITERATOR_OBJ_P(&iter->data); | ||
|
||
return intern->valid ? SUCCESS : FAILURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been bitten by this before, but I've made peace with assuming PHP's behavior is inspired by process exit codes.
src/phongo_compat.h
Outdated
(invalidate_current), \ | ||
(get_gc), \ | ||
} | ||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#else | |
#else /* PHP_VERSION_ID < 80000 */ |
This is used in some other longer #if
blocks elsewhere in the file.
Note that we don't have prior art for this with #if(n)def
, so I didn't suggest it below.
src/phongo_compat.h
Outdated
(rewind), \ | ||
(invalidate_current), \ | ||
} | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#endif | |
#endif /* PHP_VERSION_ID >= 80000 */ |
@@ -263,10 +298,92 @@ static HashTable* php_phongo_iterator_get_properties(phongo_compat_object_handle | |||
return php_phongo_iterator_get_properties_hash(object, false); | |||
} | |||
|
|||
/* Iterator handlers */ | |||
static void php_phongo_iterator_it_dtor(zend_object_iterator* iter) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does "this entire logic" refer to all of the iterator functions in this file (not just dtor
here)?
a9a1be5
to
75d478f
Compare
PHPC-2269
Adding to v1.17 only as we'd be backporting a number of compat macros from PHP itself, in addition to
ZVAL_OBJ_COPY
. Waiting on #1450 to be merged so I don't have to bother fixing the PHP 7.2 build.