Problem/Motivation
Function brings additional overhead for comment render by looping each comment listing and initializing
It doesn't do anything by itself, it only sets 'divs/divs_final' properties in comment entities, which are only used in one place: CommentViewBuilder::alterBuild(). (Formerly comment_view($comment), see commit #e9ca778b)
The comment that is in the code now
// The $divs element instructs #prefix whether to add an indent div or
// close existing divs (a negative value).
...doesn't make any sense by itself, and clearly refers to the code that is now in alterBuild(). The whole function should be moved into CommentViewBuilder.
And since it doesn't make any sense by itself, in this case I don't think it even needs marking @deprecated. The function removal can be marked in https://www.drupal.org/node/2299799 (if we don't care about the version number mentioned in there being exactly right).
Proposed resolution
Remove the function by incorporating it into \Drupal\comment\CommentViewBuilder::buildComponents() where it actually used.
Comment entity should not be changed by build/render layer.
Remaining tasks
agree on approach, commit
User interface changes
no
API changes
Removes comment_prepare_thread() as no longer needed and buggy.
Beta phase evaluation
| Issue category | Bug because changes entity properties without need. We should avoid dirtying entities. |
|---|---|
| Issue priority | Major because affects d.o and makes using #pre_render_cache impossible for those entities (needlessly). |
| Prioritized changes | The main goal of this issue is proper cacheability and removal of useless code. |
| Disruption | Not disruptive for core/contributed and custom modules/themes because it used only internally and the functionality incorporated into CommentViewBuilder |
| Comment | File | Size | Author |
|---|---|---|---|
| #34 | 2318579-comment_prepare_thread-33.patch | 11.36 KB | andypost |
| #28 | 2318579-comment_prepare_thread-28.patch | 11.34 KB | andypost |
| #28 | interdiff.txt | 1.4 KB | andypost |
Comments
Comment #1
roderikDisclaimer: this is the first time I'm looking at this EntityViewBuilder stuff.
Moved into buildComponents(). Seemed to make sense, because
drupal_render() -> #pre_render call -> EntityViewBuilder::buildMultiple() -> CommentViewBuilder::buildComponents() is called later than comment_prepare_thread() was called before this patch. So the $comment->divs properties are not set anymore during the viewMultiple() stage. If needed, we can say something like the following in the change notice:
About the patch: the logic that is moved from comment_prepare_thread() to buildDepth() is exactly the same. I just renamed a variable and commented things.
Comment #2
roderikOR (my preference):
We just get rid of the depth and divs properties in the comment object and don't care about hook_entity_prepare_view(). Almost noone is using this function anyway. We just make a small note about CommentViewBuilder::buildDepth() in a change notice (e.g. this one).
The properties shouldn't be on the comment entities; they're information about a specific way of rendering -> should properties of $build.
Also deleted: the $comment->depth property. It's not used anywhere. All code (including the 'Depth' field in views) deduces depth from Comment::getThread().
PLEASE NOTE: when testing this manually by creating comments, you may see strange results -- the same strange results you will see withouth this patch, until #2254181: Comment indentation is incorrect for comments following a replying-comment: don't render cache comments for which threading is enabled is fixed.
Comment #3
andypostIt looks a right way, otoh I think about #1920044: Move comment field settings that relate to rendering to formatter options and a way to skip this for non-threaded comments that's are used for forums now #2301247: Make comments for forum non-threaded by default
Comment #5
roderikWell, that was a bit silly. *puts missing code back*
@andypost I guess I'll go reroll that patch, and after looking at the code maybe I understand how #1920044 ties into 'skip this for non-threaded forums'.
Comment #6
roderikbump:
As far as I can see, this needs no change. The code that is moved only prepares things by adding 'metadata' to the render array, which we can keep doing in all cases; the code that actually decides whether to use that metadata (and output divs) is in CommentViewBuilder::alterBuild() and is correct.
Patch still applies (with offsets/minimal fuzz).
Comment #7
andypostIt's really interesting how that could work at all!
CommentViewBuilder does not know anything about comment field that holds setting about threading
nice, but this is a places that "knows" about thread and have to pass this to "builder"
this could be called for comments from different fields/entities so needs to make sure that thread is consistent
Comment #8
roderikDisclaimer: maybe you can skip the first part of this comment, it's only introduction.
I don't know much about ViewBuilders or the philosophy behind 'which component should do what when'. I just constructed this story from inspecting code.
Right now, comment_node_update_index() does not know anything about threading settings either. It just
- loads comments
- calls comment_prepare_thread() for inserting the $comment->div-stuff. The knowledge for this** is inside the $comments itself, not in the calling function.
- renders them
Why does this work? Because CommentViewBuilder 'knows' about threading settings through injected components (currently still entityManager->getFieldDefinitions).
**Note that the threading check is not done in comment_prepare_thread(); the $comment->div-stuff is always generated. The check is done in CommentViewBuilder::alterBuild() which decides whether or not to use the $comment->div-stuff, based on threading settings.
This behavior (where the check is done) is not changed by the patch.
Well, as said: CommentDefaultFormatter::viewElements() now calls comment_prepare_thread() but it does not pass the knowledge about threading settings to "builder". CommentViewBuilder::alterBuild() fetches and uses the knowledge, later, by itself.
I can see how you would want to start passing the threading knowledge explicitly into CommentViewBuilder, but I will need you to tell me more about how/when, because I don't know / cannot get enough info from the interfaces.
At this moment I do not agree. If you let CommentViewBuilder construct one #sorted render array with comments mixed up from different fields, you will get them rendered in a mixed-up way. That's your responsibility.
I can review my opinion after getting an answer on part #2 of this comment.
Comment #9
larowlanComment #10
vedpareek commentedRerolled
Comment #11
wim leersTabs that don't belong :)
All of this is indented incorrectly, I'm afraid, with 4-space instead of 2-space indentation.
More tabs, and code style violation.
Comment #12
ashutoshsngh commentedFixed identation issues.
Comment #13
wim leersCould you please provide an interdiff? See https://www.drupal.org/documentation/git/interdiff.
Comment #14
ashutoshsngh commentedInterdiff attached.
Comment #15
andypostI don't get the reason to make check
isset(divs) && is_numeric(divs)they are always a numbers so maybe!empty()is enoughunneeded change, please to not change this
current_user should be injected
needs doc-block fix about arguments
indent wrong
unneeded change
Comment #16
ajitsWorking on it now.
Comment #17
ajitsThe patch is no longer applicable. Will reroll first.
Comment #18
piyuesh23 commentedComment #19
ajitsJust rerolling for now.
Comment #21
ajitsNot sure if I did it right. I simply followed the procedure mentioned at documentation for patch reroll.
Comment #22
andypostI think the function is not needed in builder.
Here's a new patch:
1) removes usage and function
2) stores "threading" in
#comment_threadedkey of the entity build array - DX++ for contrib to not query field settings3) removes "commented entity" cache hitting because in 99% there's only one commented entity otherwise threading makes no sense (or we should implement threading as separate render function)
Comment #23
rteijeiro commentedRemoved commented line.
Comment #24
rteijeiro commentedForget that interdiff. This is the good one!
Comment #25
andypostThis is a type-hint not a commented line, this allows to easily use interface defined methods
Comment #26
larowlan+1 to
#comment_threadedapproach, patch at #22 looks good to go to meComment #27
wim leersThis is so much better! This no longer sets random properties on Entity objects just to pass information around; this now sets render array properties, as it should. Great work, thanks!
Only nitpicks:
s/Feed/Comment/
s/that helps/to/
s/how indented we are/the indentation level/
The first line of this comment makes is clear, these 2 lines aren't.
Comment #28
andypostfixed, 3 - is tricky to explain
Comment #30
wim leersI trust the test coverage in
\Drupal\comment\Tests\CommentThreadingTest, we significantly improved that test in #2254181: Comment indentation is incorrect for comments following a replying-comment: don't render cache comments for which threading is enabled.Comment #31
alexpottcomment_prepare_thread() is D7 function. Also has anyone done the perf testing to prove that the beta evaluation is correct?
Comment #32
joelpittetFor instructions on how to profile if someone wants to give it a try, see the instructions here for the setup: https://www.drupal.org/contributor-tasks/profiling
Comment #33
andypostRe-roll, comment generation is broken so use the patch #2422101-7: CommentItem should override the generateSampleValue method and provide sample values to generate comments.
Comment #34
andypostComment #35
rteijeiro commentedLooks good to me! :)
Comment #36
andypostIt needs CR and performance testing
My measurements shows less IO but more cpu... somehow
Comment #37
fabianx commented+1 to the change, this depth thingy made render caching difficult as I could not rely on the comment objects being the same as when loaded from the DB.
But yes needs profiling ...
Comment #38
andypostDraft CR posted https://www.drupal.org/node/2466759
Comment #39
fabianx commentedWith render cache off, the performance is exactly the same, which is expected.
Due to the refactoring the function call counts remains funnily enough exactly the same and we have -0.0% wall time (0.0028 ms) - way within margin of error.
With render cache on:
Again the function calls remain the same, which means this is done before the #pre_render is called, which is fine as such that data is always correct.
--
Patch looks good too and removes setting arbitrary properties on objects.
=> RTBC
Comment #40
alexpottSo #39 shows that we're not getting a performance improvement. We need to update the beta evaluation and provide another reason why we should make this change.
Comment #41
larowlanIs DX as indicated by @Fabianx at #39 a suitable reason?
Comment #42
fabianx commentedBack to RTBC.
The justification is that we should avoid dirtying entities, else they cannot be re-loaded lazily, which needlessly limits the usage of placeholders (as seen in #2469431-5: BigPipe for auth users: first send+render the cheap parts of the page, then the expensive parts).
While that issue is just in prototype stage, even now dirtying entities will make the job of contrib modules like my render_cache much harder and as the patch shows without any reason.
Comment #43
alexpottOkay @Fabianx - I agree that we should be avoiding dirty entities especially in the render pipeline. I think the disruption of removing
comment_prepare_thread()is worth the improvement and we've shown that there is no effect on performance. Committed 418da36 and pushed to 8.0.x. Thanks!