[IDEA] How to handle performance bottlenecks due to extensive link building #1866
michaelkubina
started this conversation in
Ideas
Replies: 1 comment
-
|
Thanks for this great investigation and analysis! Before looking into it in detail I just want to point you to #878 by @beatrycze-volk, which follows a different (or maybe complementary?) approach by trying to get rid of page reloads at all. It uses AJAX requests instead to navigate through a document, fetching data from the backend and updating the view dynamically. It's still work in progress, but certainly worth discussing! |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi,
this one touches two topics actually, that are closely related. The main issue is, that we observed massive performance losses on big and highly structured Objects. We were able to get rid of some causes in some PRs, cutting response Time from about 18 seconds to roughly 5 seconds...which is still a lot. We are left with one big spot that causes this and that needs further discussion, before we can work on an actual solution. The example document will be our "Hamburger Adressbuch" from 1960 - around 4600 pages, 4000 structure elements, 7 file groups:
https://mets.sub.uni-hamburg.de/kitodo/PPN773134158_1960
Problem
When navigating within the document, we observe loading times of still about 6 seconds. This is mainly, because we precalculate all the Links in the
TableOfContentsControllers fluid-template, as well as in thePageGridControllersfluid-template. Each link creation via theKitodo:LinkViewHelperor FluidsLinkViewhelpertakes about 1ms - which by itself is not a lot, but it grows linearly with structure depth and pagecount.Experiments
We have experimented with moving link creation from the template to the controller, to skip the overhead of the viewhelper invocation. We observed this way, that the viewhelper invocation has an overhead of roughly 25% compared to link generation in the controller itself. Calculating all links in the controller (for our example object) and simply writing them out in the template took around 4 seconds, while via the viewhelper it took around 5 seconds. That is already a significant change, but not enough to satisfy user experience - navigation is still annoyingly slow. We also experimented with putting all the link generation into a
LinkBuilderService, so that any controller can use it. It basically the code of theKitodo:Linkviewhelperbut as a service that can be used via dependency injection. This way the ViewHelper could have used it as well and we would have had link generation logic in only one place. This had no performance implications, but it would have created a single source of truth we considered a good design pattern.The links built in the
PageGridalso lack using any additional parameters for theMultiView, as here the fluid linkviewhelper is used and not the kitodo:linkviewhelper that accounts for it.PageSelecton the other hand uses them...this shows that link building is not handled identical across all controllers and templates, suggesting an approach that is implemented once and reused...like the linkbuilderservice for example.Interstingly using
PageSelectinstead of a Link in ToC took twice as long to generate a response (see: #1867)! While creating the form itself was blazingly fast, the way Typo3 handles thepageSelectActionresulted in actual double loading of the target page. This is because Typo3 once calls all plugin controllers from the target page (as we are not targeting a distinct controller, but the target page itself), returns a response to the POST-Request and then handles the Redirect from said action, processing the target page again and returning the actual webpage.What we then did, was to implement a POST-Request-Middleware that handle the form-action from the
PageSelectForm, stopping the Request before it reaches controllers, creating the link there and redirect before any other content is processed. Then the target page is processed normally. This way the response time forPageSelectnearly halved (what was estimated).PageSelect,PageGridandToCare the three main navigation controlls, that potentially have A LOT of links. Precalculating them in the Templates or even Controllers (except PageSelect which already is a form) causes massive slowdowns on large object. ButPageSelects approach show, that we not necessarily need to now all links beforehand, but only need the one for the link that was actually clicked! So, instead of calculating potentially thousands of links, we only calculate one.This is why we also experimented with refactoring the
ToCandPageGridto a HTML-Form, that sends a POST-Request with the required Form-Date for a POST-Request-Middleware instead of using a GET-Request, that requires all links beforehand.This way, we were able to cut responsetime from 5 seconds to a 2 seconds - around 250% faster.
Discussion
The experiments showed, that we would need to touch a lot of places in code, that we already have issues with the way how POST-Request from
PageSelectare handled, that link generation itself is incomplete across controllers and that performance would benefit from it very significantly. But we are aware, that we would need to consider how changing it would effect current installations, the DFG-Viewer and so on.Changing
ToCto a HTML form and POST-Request behaviour by itself is not that hard. We can use HTML data dictionaries for each entry, a small JavaScript placing them in the Form that gets postet and handling everything in the newPOST-Request-Middlewarewith aLinkBuilderService(for the Middleware AND the ViewHelper) we mentioned. This wayPageSelect,PageGridandToCwould use the same code patterns.But we would loose actual HTML link interactions in the webbrowser like "Right-Click -> open in new tab/window". Something already not possible in Mirador for example.
The Question is, what would be an approach to resolve this, that all can agree upon?
Our suggestion is something we believe works fine, but there are likely things we have not considered...
Beta Was this translation helpful? Give feedback.
All reactions