-
Notifications
You must be signed in to change notification settings - Fork 15
IBX-10186 Add limits to count and subtree queries #600
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
base: 4.6
Are you sure you want to change the base?
Conversation
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.
Thank you for valuable contribution @ryanolee! I've add some minor comments from my side and asked team to review PR.
src/lib/Persistence/Legacy/Traits/Doctrine/LimitedCountQueryTrait.php
Outdated
Show resolved
Hide resolved
Co-authored-by: Adam Wójs <[email protected]>
…ait.php Co-authored-by: Adam Wójs <[email protected]>
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.
Makes sense from the functional standpoint. I was considering how those COUNT
queries impact larger databases, and I'm happy to research this approach. Thanks for showing me this :)
I've given a few remarks that I would have in the following comments.
In general, I would love to have this trait converted into a class, and unit tests added for it (which should be easier once it's not a trait).
For 3.3 version, since it's in "maintenance mode", it will probably not be added there. It's supposed to be security fixes only.
As for the API changes, we might consider taking Symfony's approach and adding additional argument via func_get_arg()
+ comment. Depends on how likely it is that those services are reimplemented. In majority of cases a decorator exists (afaik) that should be used, but I don't want to break someone's application regardless of our API contract.
We'll discuss it internally probably at the start of next week.
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 am not a fan of traits under certain circumstances. I somewhat prefer object composition approach unless there are valid reasons.
In this case, trait is used to prevent code duplication only, and it requires presence of connection
property (which is an implicit assumption not visible outside of trait).
Since the method added is using protected
visibility, it is immediately available to descendants. While not a big deal, I would personally prefer it to use private
visibility (if left as-is, that is).
Additionally, since it is a trait, unit tests are more difficult to provide.
Overall, I'd suggest making it it's own class, and injecting it into relevant gateways via constructor. To facilitate usage of the correct Connection
object, it could be passed as part of the method arguments.
WDYT?
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 a bit awkward given it is multiple inheritance of a shared bit of functionality. Though do agree it should probably be refactored into it's own thing. Will take a look at refactoring into something that can be unit tested and refactor. The connection was misued here as it can be pulled from the passed query builder so there is no implicit requirement on there being a connection
present as seen with a few lines below where $queryBuilder->getConnection()->getDatabasePlatform()->getCountExpression('*') is used. But based on everything else that is a mute point.
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.
Oh yes, right, now I've noticed it.
By the by, note that Platform::getCountExpression()
is deprecated and removed in DBAL v3. We are now expected to use "COUNT(*)"
directly, without asking platform for their variant. I assume that is because COUNT()
is ANSI SQL, and there were never any platform differences to begin with.
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.
Ah that makes sense I am currently aiming to keep things as closeley aligned with the way ibexa currently generates it's queries internally. It is likely Platform::getCountExpression
is better placed to be updated globally in a separate ticket considering that is what is already in use now and this is not a wide sweeping change targeting specifically that
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.
It is updated in 5.x. I'd only ask to not use it here, as it will make merge up simpler :)
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.
Ahh that makes sense! Sorry saw all of the other references to it and got a bit confused. Updated as outlined here https://github.com/doctrine/dbal/blob/4.2.x/UPGRADE.md#deprecated-redundant-abstractplatform-methods
src/lib/Persistence/Legacy/Traits/Doctrine/LimitedCountQueryTrait.php
Outdated
Show resolved
Hide resolved
Thanks for the review 🤩 Just as a follow up for this the func_get_arg is somewhat problematic due to https://github.com/FriendsOfPHP/proxy-manager-lts dropping the extra arg in lazy loaded servies See the following: In order to add BC break compatibility this PR might need pushing to The only other option I can think of is in 4.6 to have the admin UI ensure it uses instances of the Location and Content services that are either not lazy loaded or have back channels used specifically by the admin UI/ For instance directly call the underlying persistence handler for queries until v5 where the fix can be pulled up to the overall API . In either case this is really less than ideal 😓 It does work when the "lazy" option is removed from the inner service. But not making it lazy will likely have much more far widespread performance implications so likely needs to be weighed if the internal admin optimisations make sense with it. For now have removed the "lazy" from the location service to get this to work Let me know what you think appropriate next steps are @adamwojs @Steveb-p as the Symfony BC break strategy will probably not work due reliably to the number of lazy loaded services in Ibexa core 🤔 The suggested changes as given above
See: ibexa/admin-ui#1605 for the relevant places the queries have been changed If you would like me to port this further to Ibexa version 5 please do considering the impact of these queries as shown in prior PR's can become significant. |
522d5b1
to
804f1a7
Compare
1 liners required for BC breaks. Would make no sense to extract into it's own function and based on the |
All comments should be addressed 🙌 @adamwojs @Steveb-p In line with this ibexa/admin-ui#1605 leverages these new changes to make the admin UI much faster for users with larger databases (Many sub items in commonly traveled paths) Thanks for having a look an let me know if there is anything else you need from me with relation to this! |
I was thinking how to deal with proxies being generated without the right amount of arguments, and there is technically an option of asking the proxy generator to generate a proxy against a specific interface. And while the original interface does not contain Weird and going against common sense maybe, but it would solve the functional issue of proxy generation. Regardless of approach, I'm pretty sure we will also introduce a rector rule to allow this new concept of |
Ah thanks for the feedback @Steveb-p that actually seems to work quite nicely. Code gen is also working as expected public function getSubtreeSize(\Ibexa\Contracts\Core\Repository\Values\Content\Location $location, ?int $limit = null) : int
{
$this->initializerdb498 && ($this->initializerdb498->__invoke($valueHolder69884, $this, 'getSubtreeSize', array('location' => $location, 'limit' => $limit), $this->initializerdb498) || 1) && $this->valueHolder69884 = $valueHolder69884;
if ($this->valueHolder69884 === $returnValue = $this->valueHolder69884->getSubtreeSize($location, $limit)) {
return $this;
}
return $returnValue;
} All working as expected. Thanks! |
Ok should all be fixed up. Tests pass on PHP 7.4 and 8.1
Whittled down the errors to these. I don't have any IDE tooling for controlling ignore errors in the In either case spammed a bunch of |
Don't want to keep you hanging there without a response 😅 We were considering if we want to pursue the "Symfony way" of introducing a new argument to primary API methods, or if we should instead add that argument immediately. This is somewhat due to the implicit expectation that We also have a few team members that wanted to review this properly themselves and see if they can come up with a different solution. As for the PHPStan errors, we will address them once my colleagues are happy with the approach :) The work you've done is awesome and I hope you give it a little bit more time? 🙇 |
Ahh certainly no rush @Steveb-p ! We have implemented https://github.com/cweagans/composer-patches to backport this to our version of 3.3 so for us internally the problem is solved 🙌 Much appreciated once again for you looking into it. Can understand this has spiraled a bit from just being a performance fix to setting some standards on how If there is a better way of fixing this problem (Especially one that does not require surfacing this new "limit" argument to core contract API's) on the count queries (Like adding new methods / query constraints to the |
@ryanolee I've taken the liberty to update PHPStan baseline to check how the actual tests look. As for the approach for PHPStan and ignoring errors, we decided to prefer in majority of cases putting errors into baseline file. Our reasoning is that this is a list of "issues" that PHPStan has detected that we intend to fix at some point. We only use Easy way to regenerate baseline is by calling: composer run phpstan -- --generate-baseline (note the additional |
Thanks for the reply @Steveb-p. Test should hopefully pass this time. The seem to work fine locally 🤞 |
|
Ok all tests seem to be passing locally now so hopefully should be the last pass on this. https://gist.github.com/ryanolee/8129399f45cd0e803b9c87967758f8c8 all the tests pass as expected using https://github.com/nektos/act (The ones that will run successfully in there) @Steveb-p 🫠 |
Woo all tests pass but the sonar cube one. (Which I assume just needs a manual exclusion adding) Let me know if you need anything else from me @Steveb-p 👏 |
Any further progress on this @Steveb-p or likely going to wait until Ibexa 5 is out 🤔 ? |
@ryanolee Sorry for delay, as you noticed we are currently occupied with v5 release. I will back to you as soon as possible. |
Warning
Please check ezsystems/ezplatform-kernel#413 for detailed reasons for this PR. Though the TLDR is count queries cause disproportionate impact on Ibexa Platform instances with large amounts of content (100,000+ content objects)
Related PRs:
Required by
ibexa/admin-ui#1605
Description:
This is a forward facing patch from issues present in Ibexa 3.3 (The version we are still using) to port the fixes and public API updates into 4.6.
Understandably considering this PR makes changes to Contracts it might need to go into 4.7 (If a release is planned beyond LTS) or v5 given implementing clients will break. I am not sure on the release cadence for contracts so this might be somewhat problematic.
Given Ibexa 4.6 has the same database schema as 3.3 (And makes the same DB Queries when performing counts) It is susceptible to the same issues present in 3.3 when querying large amounts of content.
For more details please read here where performance implications are described more clearly.
ezsystems/ezplatform-kernel#413
For QA:
Test using instructions given in ibexa/admin-ui#1605
Documentation:
Check ezsystems/ezplatform-kernel#413 for relevant details.
Notes