Skip to content
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

EZP-29613: As a developer I want access to ContentType on Content to avoid re-loading it #2444

Merged
merged 25 commits into from Dec 4, 2018

Conversation

andrerom
Copy link
Contributor

@andrerom andrerom commented Sep 14, 2018

Question Answer
JIRA issue EZP-29613
New feature yes
Target version master
BC breaks no
Tests pass yes
Doc needed yes

Like in #2328 where Location->getContent() was added, this is about adding Content->getContentType() to avoid having to deal with loading logic and also furthermore to avoid repeated loads of content types in the system when we already have the Type (as we need it to build Content anyway) and can thus pass it around on Content Items.

This breaks the internal Repository\Helper\DomainMapper->buildContentDomainObject() a bit in that it now requires ContentType to be passed instead of implicit loading it for you from SPI if not provided. This is done to make us more aware of the loading going on and take advantage to optimize (done several places in this PR).

This implicit involves improving performance:

  • No repeated content types loading when calling field functions in Twig, as they can now use this
    • No implicit repeated loads for same language when having to build these content types
  • Add possibility to bulk load ContentTypes in SPI in order to handle this even more efficient when bulk loading content (when bulk load Content and on Location/Content Search results)

Reduced cache lookups just with this on clean install: 84/184 => 44/139
Heavy use of twig field functions will see more noticeable gains, and there might be cases in other bundles (PageBuilder?) where we can now optimize and take advantage of getContent() and getContentType(). But for other cases re-introducing a safe form of inMemory cache will provide grater gains (For more context/info on that see JIRA issue).

TODO:

* Missing items (NotFound) will be missing from the array and not cause an exception, it's up
* to calling logic to determine if this should cause exception or not.
*
* @param mixed $contentTypeIds
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NItpick: Wrong type hint for $contentTypeIds param

@@ -99,24 +106,18 @@ public function __construct(
* Builds a Content domain object from value object returned from persistence.
*
* @param \eZ\Publish\SPI\Persistence\Content $spiContent
* @param ContentType|SPIType $contentType
* @param ContentType $contentType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Please use FQCN

if (isset($this->contentTypes[$contentTypeId])) {
$contentTypes[$contentTypeId] = $this->contentTypes[$contentTypeId];
} else {
$contentTypes[$contentTypeId] = $this->contentTypes[$contentTypeId] = $this->innerHandler->load($contentTypeId);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should improve this here and in loadGroups as otherwise it means singular load is always done.

@ezrobot

This comment has been minimized.

@andrerom andrerom force-pushed the content_type_on_content branch 2 times, most recently from 46849a6 to 98c1642 Compare September 18, 2018 11:44
@ezrobot

This comment has been minimized.

1 similar comment
@ezrobot

This comment has been minimized.

@andrerom

This comment has been minimized.

andrerom added a commit to ezsystems/ezplatform-admin-ui that referenced this pull request Sep 19, 2018
…id re-loading it

Uses ezsystems/ezpublish-kernel#2444, and $location->getContent()
(v2.2) in order avoid several repository loads not needed anymore.

Here are some numbers for cache lookups on clean install, expect difference to be bigger when you have more data (demo or project):

dashboard:
418 / 1240 (33.71%) _(master)_
468 / 1315 (35.59%) _(with kernel PR, only)_*
364 / 1043 (34.9%) _(with this PR + kernel PR)_

content structure:
478 / 1401 (34.12%)  _(master)_
450 / 1359 (33.11%) _(with kernel PR, only)_
436 / 1327 (32.86%) _(with this PR + kernel PR)_

_* So withouth this patch there is a slight regression with more cache loads with the kernel PR on dashboard.
Probably due to kernel now always loading content types from API instead of falling back to using SPI,
and via api language loading and mapping is needed. With this PR we get rid of the duplicated loads,
and for other apps the extra lanfguage load and much more will go away once we have inMemory cache again (v2.4)._
@andrerom

This comment has been minimized.

@andrerom andrerom force-pushed the content_type_on_content branch 4 times, most recently from 91c61cd to 042481c Compare September 23, 2018 08:27
@andrerom
Copy link
Contributor Author

andrerom commented Sep 23, 2018

Passing ✅

@andrerom
Copy link
Contributor Author

andrerom commented Oct 17, 2018

With 7.3 branched, rebased and ready for final review @alongosz

Edit: Fixed merge conflict causing test failure.

Copy link
Member

@alongosz alongosz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, but with nitpicks 😜

*
* @return array Data rows.
*/
abstract public function loadTypesDataList(array $typeIds): array;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming seems awkward to me, loadTypesListData makes more sense, but for Content we used loadContentList so I would stick to that convention and name it simply loadTypesList. However, since we have loadTypeData later on, I'm fine with both.

@@ -185,6 +185,15 @@
*/
abstract public function updateType($typeId, $status, UpdateStruct $updateStruct);

/**
* Loads an array with data about several Types in defined status..
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: double dot.

'c',
'ezcontentclass_attribute',
'a',
'c.id = a.contentclass_id AND c.version = a.version'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: please use $q->expr()->eq() and $q->expr()->andX().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally find that harder to read, but if there is consensus in engineering to rather use that, that's ok.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You never know what next database vendor will figure out for comparison and logic expressions ;)

Copy link
Contributor Author

@andrerom andrerom Nov 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that vendor dismisses SQL standards more then current bunch of vendors do, then we have bigger problemas and it won't be supported anytime soon I think.

Besides, feels like you build your argument on the same assumption I did wrongly ;)
ref: doctrine/dbal#3302
"Doc + PHP Doc should clarify QueryBuilder features not supported across databases"

Aka QueryBuilder does not currently handle DB differences at all.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that vendor dismisses SQL standards more then current bunch of vendors do, then we have bigger problemas and it won't be supported anytime soon I think.

True.

Besides, feels like you build your argument on the same assumption I did wrongly ;)
ref: doctrine/dbal#3302
"Doc + PHP Doc should clarify QueryBuilder features not supported across databases"

Aka QueryBuilder does not currently handle DB differences at all.

Well, it doesn't mean that it won't be supported in the future. Once it will, you'll end up with a lot of code to refactor to benefit from that. This is why I prefer using Expressions everywhere it's possible.

Pinging @adamwojs for POV on that ;)

Copy link
Contributor Author

@andrerom andrerom Nov 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it doesn't mean that it won't be supported in the future.

I know, and personally I think that should be added. Maybe we should contribute it even as we rely on it and it would be helpful when starting to look into supporting oracle..

So I'm not against for more complex queries, including inserts and updates, but maybe we should do it for all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c89fb22 ;)

Now let's make sure we try to set aside some time to propose imporvments to DBAL beginning of next year.. ;)

@@ -85,12 +90,14 @@ public function __construct(
ContentHandler $contentHandler,
LocationHandler $locationHandler,
TypeHandler $contentTypeHandler,
ContentTypeDomainMapper $contentTypeDomainMapper,

This comment was marked as resolved.

This comment was marked as resolved.

{
if (!self::$setup) {
parent::setUp();
$this->insertDatabaseFixture(__DIR__ . '/../_fixtures/full_dump.php');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but then it means we're testing on SQLite only, since it is eZ\Publish\Core\Search\Legacy\Tests\Content namespace.

Update: ok... seems it was like that before in child class, so it's rather a follow up for later

* Missing items (NotFound) will be missing from the array and not cause an exception, it's up
* to calling logic to determine if this should cause exception or not.
*
* @param mixed[] $contentTypeIds
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NItpick: Wrong type hint for $contentTypeIds param

This is still valid nitpick.

andrerom added a commit to ezsystems/ezplatform-admin-ui that referenced this pull request Nov 18, 2018
…id re-loading it

Uses ezsystems/ezpublish-kernel#2444, and $location->getContent()
(v2.2) in order avoid several repository loads not needed anymore.

Here are some numbers for cache lookups on clean install, expect difference to be bigger when you have more data (demo or project):

dashboard:
418 / 1240 (33.71%) _(master)_
468 / 1315 (35.59%) _(with kernel PR, only)_*
364 / 1043 (34.9%) _(with this PR + kernel PR)_

content structure:
478 / 1401 (34.12%)  _(master)_
450 / 1359 (33.11%) _(with kernel PR, only)_
436 / 1327 (32.86%) _(with this PR + kernel PR)_

_* So withouth this patch there is a slight regression with more cache loads with the kernel PR on dashboard.
Probably due to kernel now always loading content types from API instead of falling back to using SPI,
and via api language loading and mapping is needed. With this PR we get rid of the duplicated loads,
and for other apps the extra lanfguage load and much more will go away once we have inMemory cache again (v2.4)._
andrerom added a commit to ezsystems/ezplatform-admin-ui that referenced this pull request Nov 19, 2018
…id re-loading it

Uses ezsystems/ezpublish-kernel#2444, and $location->getContent()
(v2.2) in order avoid several repository loads not needed anymore.

Here are some numbers for cache lookups on clean install, expect difference to be bigger when you have more data (demo or project):

dashboard:
418 / 1240 (33.71%) _(master)_
468 / 1315 (35.59%) _(with kernel PR, only)_*
364 / 1043 (34.9%) _(with this PR + kernel PR)_

content structure:
478 / 1401 (34.12%)  _(master)_
450 / 1359 (33.11%) _(with kernel PR, only)_
436 / 1327 (32.86%) _(with this PR + kernel PR)_

_* So withouth this patch there is a slight regression with more cache loads with the kernel PR on dashboard.
Probably due to kernel now always loading content types from API instead of falling back to using SPI,
and via api language loading and mapping is needed. With this PR we get rid of the duplicated loads,
and for other apps the extra lanfguage load and much more will go away once we have inMemory cache again (v2.4)._
andrerom added a commit to ezsystems/ezplatform-admin-ui that referenced this pull request Nov 26, 2018
…id re-loading it

Uses ezsystems/ezpublish-kernel#2444, and $location->getContent()
(v2.2) in order avoid several repository loads not needed anymore.

Here are some numbers for cache lookups on clean install, expect difference to be bigger when you have more data (demo or project):

dashboard:
418 / 1240 (33.71%) _(master)_
468 / 1315 (35.59%) _(with kernel PR, only)_*
364 / 1043 (34.9%) _(with this PR + kernel PR)_

content structure:
478 / 1401 (34.12%)  _(master)_
450 / 1359 (33.11%) _(with kernel PR, only)_
436 / 1327 (32.86%) _(with this PR + kernel PR)_

_* So withouth this patch there is a slight regression with more cache loads with the kernel PR on dashboard.
Probably due to kernel now always loading content types from API instead of falling back to using SPI,
and via api language loading and mapping is needed. With this PR we get rid of the duplicated loads,
and for other apps the extra lanfguage load and much more will go away once we have inMemory cache again (v2.4)._
@micszo micszo self-assigned this Nov 30, 2018
andrerom added a commit to ezsystems/ezplatform-admin-ui that referenced this pull request Nov 30, 2018
…id re-loading it

Uses ezsystems/ezpublish-kernel#2444, and $location->getContent()
(v2.2) in order avoid several repository loads not needed anymore.

Here are some numbers for cache lookups on clean install, expect difference to be bigger when you have more data (demo or project):

dashboard:
418 / 1240 (33.71%) _(master)_
468 / 1315 (35.59%) _(with kernel PR, only)_*
364 / 1043 (34.9%) _(with this PR + kernel PR)_

content structure:
478 / 1401 (34.12%)  _(master)_
450 / 1359 (33.11%) _(with kernel PR, only)_
436 / 1327 (32.86%) _(with this PR + kernel PR)_

_* So withouth this patch there is a slight regression with more cache loads with the kernel PR on dashboard.
Probably due to kernel now always loading content types from API instead of falling back to using SPI,
and via api language loading and mapping is needed. With this PR we get rid of the duplicated loads,
and for other apps the extra lanfguage load and much more will go away once we have inMemory cache again (v2.4)._
Copy link
Member

@micszo micszo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@micszo micszo removed their assignment Dec 4, 2018
@andrerom
Copy link
Contributor Author

andrerom commented Dec 4, 2018

@alongosz / @micszo Ok if I merge this and rebase UI PR so it can get final label?

@andrerom andrerom merged commit 0dc4f63 into master Dec 4, 2018
@andrerom andrerom deleted the content_type_on_content branch December 4, 2018 12:44
andrerom added a commit to ezsystems/ezplatform-admin-ui that referenced this pull request Dec 4, 2018
…id re-loading it

Uses ezsystems/ezpublish-kernel#2444, and $location->getContent()
(v2.2) in order avoid several repository loads not needed anymore.

Here are some numbers for cache lookups on clean install, expect difference to be bigger when you have more data (demo or project):

dashboard:
418 / 1240 (33.71%) _(master)_
468 / 1315 (35.59%) _(with kernel PR, only)_*
364 / 1043 (34.9%) _(with this PR + kernel PR)_

content structure:
478 / 1401 (34.12%)  _(master)_
450 / 1359 (33.11%) _(with kernel PR, only)_
436 / 1327 (32.86%) _(with this PR + kernel PR)_

_* So withouth this patch there is a slight regression with more cache loads with the kernel PR on dashboard.
Probably due to kernel now always loading content types from API instead of falling back to using SPI,
and via api language loading and mapping is needed. With this PR we get rid of the duplicated loads,
and for other apps the extra lanfguage load and much more will go away once we have inMemory cache again (v2.4)._
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
5 participants