Came across a slow running busy site that was re-generating the variables cache in cache_bootstrap. Tracing it back led to noticing that drupal_build_css_cache() was calling variable_set() on a lot of pages. Debugging that, and I noticed that despite the output cache file remaining the same, the $key being used was different. This turned out to be because although the CSS files were in the same order, the 'weight' was different.

An example of the relevant variables on 2 separate pages:

Array (
    [key] => c9d2d17ceadfc9b67b52ef260f057246175a91f4d9dc8d1e341897a98245c60b
    [file] => public://css/css_7z4p4LzjWe3WS10-kJMZFxLoBlJ0wlOUi3zeH4cvC4E.css
    [css] => Array (
            [0] => Array (
                    [group] => -100
                    [type] => file
                    [weight] => 0.017
                    [every_page] => 
                    [media] => all
                    [preprocess] => 1
                    [data] => modules/contextual/contextual.css
                    [browsers] => Array([!IE] => 1, [IE] => 1)
                )
        )
)

================

Array(
    [key] => 4738f07c9a6ad3d5653ba27b72455797feb53b3c8f1aabd8968c6fe3c97bb227
    [file] => public://css/css_7z4p4LzjWe3WS10-kJMZFxLoBlJ0wlOUi3zeH4cvC4E.css
    [css] => Array(
            [0] => Array(
                    [group] => -100
                    [type] => file
                    [weight] => 0.018
                    [every_page] => 
                    [media] => all
                    [preprocess] => 1
                    [data] => modules/contextual/contextual.css
                    [browsers] => Array([!IE] => 1, [IE] => 1)
                )
        )
)

As you can see, the key (the value used to see if the $css variable has been cached yet) is different, yet the output file remains the same. Attached a relatively simple patch that removes the 'weight' key from the CSS/JS arrays before checking if they have been aggregated already.

Comments

sun’s picture

Component: cache system » base system
Priority: Normal » Major
Status: Active » Needs review
Issue tags: +Needs tests, +frontend performance, +WPO

Thanks!

Not sure whether this is the best solution, but yeah, those bogus/wonky weights are already added in drupal_add_js/css(), and it's a fairly long way from drupal_add_css() to drupal_get_css() to drupal_build_css_cache().

We need to prevent this from happening again through a test. Simply enabling aggregation and adding and getting/rendering the same files two times, but merely with a different drupal_add_css/js() call order, should be sufficient.

tim.plunkett’s picture

Component: base system » cache system
Priority: Major » Normal
Status: Needs review » Active
Issue tags: -Needs tests, -frontend performance, -WPO
mjpa’s picture

Component: cache system » base system
Priority: Normal » Major
Status: Active » Needs review

@tim.plunkett as noted in IRC, that issue about the weights changing is related and more of a trigger for this issue. Without testing, I'm pretty sure it's still possible for the weights to change even without adding the same files twice.

If the last 2 CSS files are foo.css and bar.css but foo.css is set so it's not aggregated, bar.css will be aggregated by itself. However, if the CSS files added before foo.css change in number, bar.css' weight will be different but still be by itself when aggregated (if that makes sense?).

sun’s picture

Right, the issues referenced in #2 do not seem to be related to this issue.

Restoring tags.

msonnabaum’s picture

StatusFileSize
new952 bytes

Here's a slightly different approach.

From what I can tell, the only thing relevant for the hash is the files and the order they are in. This patch creates a new array of just the file paths and hashes that instead.

sun’s picture

Status: Needs review » Needs work

So the only thing that's missing here are proper inline code comments that explain why the additional processing is needed.

And of course, tests, that prove 1) the bug exists, and 2) this patch fixes the bug.

msonnabaum’s picture

StatusFileSize
new1.15 KB

New version with comments, still needs tests.

msonnabaum’s picture

StatusFileSize
new1.13 KB

Here's a D7 version as well.

xjm’s picture

Status: Needs work » Needs review
Issue tags: +Needs steps to reproduce

NR for the bot to test #7. (#8 is named using the old pattern so it'll be tested and fail whenever this issue is set to NR anyway. The name suffix to use now is -do-not-test.patch.)

From #3:

If the last 2 CSS files are foo.css and bar.css but foo.css is set so it's not aggregated, bar.css will be aggregated by itself. However, if the CSS files added before foo.css change in number, bar.css' weight will be different but still be by itself when aggregated (if that makes sense?).

More detailed steps to reproduce this would help with writing a test.

Status: Needs review » Needs work

The last submitted patch, 1404380-unnecessary_aggregation-d7.patch, failed testing.

msonnabaum’s picture

Status: Needs work » Needs review
StatusFileSize
new1.22 KB
new1.21 KB

Here's a new version to retest, only changes are grammer fixes in the comments.

For a test, you'd just have to trigger a page load normally, then trigger it again doing a drupal_add_js/css in hook_init. That should throw off the weights of at least one or more the aggregate groups, and those groups should get a new aggregated file, even though the css/js that was added is not in that group.

msonnabaum’s picture

StatusFileSize
new2.94 KB

And here's one with a test.

xjm’s picture

Assigned: Unassigned » xjm

Polishing a couple things and adding some inline docs.

xjm’s picture

Assigned: xjm » Unassigned
Issue tags: -Needs tests, -Needs steps to reproduce
StatusFileSize
new2.14 KB
new3.26 KB
new2.04 KB

Attached:

I'm also uploading the test in a patch by itself to expose the expected failures on QA.

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

This looks great, especially with the addition of the latest inline docs.

catch’s picture

Version: 8.x-dev » 7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)
Issue tags: +Needs backport to D7

OK I think this is fine, and thanks for the nice tests. I don't think #1388546: Adding CSS or JS files twice changes weight is a duplicate - I've seen dependent JavaScript moved after js that it depends on and even into different aggregates due to the automatic weight changing due to repeated calls to drupal_add_js() on a page, but we have that open so we don't need to fix it in this issue.

Committed/pushed to 8.x, moving to 7.x for backport.

msonnabaum’s picture

StatusFileSize
new3.17 KB

Here's a re-roll for D7.

msonnabaum’s picture

Status: Patch (to be ported) » Needs review
damien tournoud’s picture

Status: Needs review » Needs work

The test needs to be ported as well (there is a config() in there).

msonnabaum’s picture

Status: Needs work » Needs review
StatusFileSize
new3.15 KB

Yup, just caught that.

xjm’s picture

Status: Needs review » Reviewed & tested by the community

Backport looks correct now.

webchick’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: +7.13 release notes

Wow. Nice catch, and nice tests. Performance FTW.

Committed and pushed to 7.x. Thanks! This is probably worth calling out in the 7.13 release notes.

wim leers’s picture

Very nice work, @msonnabaum :)

Automatically closed -- issue fixed for 2 weeks with no activity.