media_gallery_block_view() is currently uncached. It currently takes 12% of request time for a gallery showing four images on a site I'm profiling at the moment.

Here's an untested patch, uses the drupal_render() cache and clears on node update/delete will do some actual testing of it a bit later.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

catch’s picture

Better patch. This is working for me although I'm occasionally getting 'no content available', but I get that without the patch too. Should be ready for testing. Attached webgrind screenshots to show the difference - reduces it from 10% to 1% of the request.

catch’s picture

Assigned: Unassigned » catch

Figured out my testing issue - applying the patch was changing file permissions. This seems to be working fine.

JacobSingh’s picture

This looks good, but hard to review since CVS decided to diff the entire thing (not sure why). Can you re-roll so it just diffs the new parts?

Thanks,
J

catch’s picture

The reason it did that is the indentation, if it helps there are only a handful of lines changed from the original code in media_gallery_block_build() and they're only at the very top and very bottom.

paul.lovvik’s picture

Status: Needs review » Needs work

The patch looks good to me, but in testing I noticed that the link to the images shows a lightbox in the original implementation, and goes to the detail page after applying the patch. The behavior is very consistent - roll back the patch, get a lightbox, apply it again, get the detail page.

catch’s picture

This is almost certainly down to #859602: #cache does not record the #attached declared in child elements, I'll confirm this and work on a patch for that issue to unblock this one.

catch’s picture

Status: Needs work » Needs review

Added a patch at #859602: #cache does not record the #attached declared in child elements. I tested this with a local test case, not with media_gallery itself yet. The issue is with hook_node_view() setting #attached - current drupal_render() caching logic can't handle this - so on a cache hit, hook_node_view() doesn't run, and you end up with no css/js from there. If you have time to test again with that patch applied, would be great - if not I'll try to get the boilerplate tests written alongside testing with media_gallery next time I'm working on this.

Marking back to CNR since this bug isn't really specific to the patch here, although this issue might also have to be 'postponed' on the core patch.

paul.lovvik’s picture

Status: Needs review » Reviewed & tested by the community
effulgentsia’s picture

Version: 7.x-1.0-beta2 » 7.x-1.x-dev
Status: Reviewed & tested by the community » Postponed
Issue tags: +Performance

Thanks for the work on this. As per #7, postponing until #859602: #cache does not record the #attached declared in child elements lands in core, but @catch, if you want to add tests and re-roll, go for it!

catch’s picture

I meant boilerplate tests for the core bug rather than the block itself, although bfroehle ended up adding those. Do you think it'd be worth adding tests here as well? (I haven't looked at media_gallery's test coverage at all)

effulgentsia’s picture

There is no test coverage at all yet for Media Gallery. It would be great to get some, but no one has had the time yet to work on that. I haven't studied either the core patch or this one in depth enough to offer an opinion on whether this particular patch is one worth adding tests to. In any case, it certainly won't hold up this patch being committed once the core one lands, but if anyone is inspired to write tests for any part of Media Gallery, please do!

JacobSingh’s picture

Status: Postponed » Needs work

This patch seems to have caused some issues.

1 is that the block caches, even if I have block caching turned off.

2 Adds the "Add media" link to every block regardless of display settings and as a side effect, makes people add images to the wrong gallery sometimes if they are on the full view for one gallery and the block of another is on the page.

james.elliott’s picture

I've rerolled the patch to address concern #2

catch’s picture

@Jacob: block caching settings only affects the core block caching mechanism, which this patch doesn't use, this is the same pattern as the forum block in core which also ignores block caching settings and uses the render cache.

Having said that, I think we probably need to invalidate the cache explicitly here on media update and instance changes, most of that logic is in the filter patch so I'll add that today.

Attaching an interdiff of james.elliot's patch, if those links are part of the rendered block, we'll also want to make the cache keys a bit more granular to handle permissions, will look into this as well.

effulgentsia’s picture

Thanks catch. If the Media module needs to invoke a new hook somewhere in order to support cache invalidation for modules that render media, like Media Gallery, please feel free to post a patch to the Media queue to do so, link to it from here, and I'll review it.

catch’s picture

New hook was a good idea, added a patch to the media queue here #1032186: Add hook_media_rendered_flush().

Uploading a new version of this patch:

- implements the new hook

- additionally implements hook_node_update() to catch changes in there, and uses node_access('update', $node); as one of the cid parts now which ought to make the link appear correctly.

- Since the link is controlled by hook_field_extra_fields(), and there's no hook that runs when those are updated, I used hook_field_update_instance() and checked for the 'media_gallery' bundle as the closest thing, this also catches any other changes to media gallery instances which might affect the node view.

- adds $is_https as one of the cid keys - images are sometimes linked by absolute urls - see http://api.drupal.org/api/drupal/modules--image--image.module/function/i..., so we should ensure there are never mixed content messages. That could be solved more generically by either #1025124: Remove cruft from theme_image_style() and image_style_url() or #1032210: drupal_render_cid_parts() should add http vs. https protocol to cache keys or both.

However I looked through the media gallery code a bit more and there seem to be more issues here:

1. media_gallery_add_images_link_pre_render() is using drupal_add_*() to add assets for the add media link, as does media_include_browser_js() - these would need to change to #attached for this to work properly no?

2. This is the interdiff of james.elliot's patch which I failed to upload earlier:

diff -u media_gallery.module media_gallery.module
--- media_gallery.module  2 Dec 2010 13:37:57 -0000
+++ media_gallery.module  18 Jan 2011 20:09:17 -0000
@@ -548,7 +548,7 @@
   else {
     $block['content'] = array(
       '#node' => $node,
-      '#pre_render' => array('media_gallery_block_build'),
+      '#pre_render' => array('media_gallery_block_build', '_field_extra_fields_pre_render'),
       '#cache' => array(
         'cid' => 'media_gallery_block:' . $node->nid,
         'bin' => 'cache_block',

I'm not at all clear why the node_view() in media_gallery_block_build() wouldn't end up calling _field_extra_fields_pre_render() anyway, so that doesn't look like the right fix, and it's a shame we have to call a private function there. Could you explain how you arrived at that change?

So leaving at needs work for those two questions, but would be great to get reviews of the changes so far.

catch’s picture

I opened this issue against media module for the #attached issue #1034838: media_include_browser_js() should use #attached instead of drupal_add_*, no patch yet but will try to get that done over the weekend. Once that's resolved the changes to media_gallery_add_images_link_pre_render() should be quite small.

catch’s picture

Status: Needs work » Needs review
FileSize
7.15 KB

Re-rolled this, depends on #1034838: media_include_browser_js() should use #attached instead of drupal_add_*.

By doing $elements['node'] = node_view($node, 'media_gallery_block'); instead $elements += node_view($node, 'media_gallery_block'); I was able to fix the link appearing all the time without having to manually specify _field_extra_fields_pre_render, I think drupal_render() wasn't picking up the pre_render when the node was mixed in the top of the block content array.

catch’s picture

FileSize
7.95 KB

Updated patch to go with the new one from #1034838: media_include_browser_js() should use #attached instead of drupal_add_*.

Main change here is I removed the link pre_render - instead adding attached directly to the element. Two reasons for this, drupal_render_collect_attached() apparently does not pick up #attached at the level of an element added by a pre_render - so without the change, the css/js wouldn't appear when the block refreshes.

However the pre_render here isn't necessary because if the link isn't rendered, the #attached doesn't get added to the page anyway, so adding it directly works the same.

I also can't think of a use case to use #attached to an element directly inside a pre_render callback, but if I can figure out a reproducible test case will try to add it to the core issue. Started debugging this but didn't get to the root cause yet.

Confirmed that:

- the block is cached.
- link only shows up when set in field settings
- the link uses the pop-up whether cached or not.

David_Rothstein’s picture

I reviewed this patch and it looked good to me. It seems to catch all the edge cases I could think of, although as we've seen above this is obviously a pretty scary change :) I haven't actually tested it (and don't have time to right at the moment) so it still needs some testing, but otherwise seems good.

I have also reviewed and commented on the two media issues this depends on:
#1032186: Add hook_media_rendered_flush()
#1034838: media_include_browser_js() should use #attached instead of drupal_add_*

There is one simple problem, though, which is that the patch here was out of date with respect to the name of the hook that was introduced by the media issue linked to above. So, the attached patch changes to use the correct hook name so that it works with the latest patch on that issue. I've attached an interdiff file as well.

catch’s picture

Arghh, good catch David, thanks for reviewing!

David_Rothstein’s picture

Status: Needs review » Needs work

By doing $elements['node'] = node_view($node, 'media_gallery_block'); instead $elements += node_view($node, 'media_gallery_block'); I was able to fix the link appearing all the time without having to manually specify _field_extra_fields_pre_render, I think drupal_render() wasn't picking up the pre_render when the node was mixed in the top of the block content array.

It turns out this change has a side effect: It messes up the block's contextual links. We have special code in media_gallery_contextual_links_view_alter() which massages the contextual links, but which no longer runs once this patch is applied.

However, the contextual links were already messed up in a different way to begin with. That is described in #870434: Contextual links can be displayed more than once for the same element (Drupal core issue) but it turns out that core patch has problems of its own, so fixing it in the media gallery is the way to go, and moving the node down a level in the block array is part of the solution for that.

So bottom line is that I wrote a separate patch at #1069750: Contextual links appear twice on the media gallery block which moves it down a level in a way that shouldn't break anything. We either need to incorporate those changes here (or commit that first and reroll this).

catch’s picture

Status: Needs work » Needs review
FileSize
8.15 KB

The other patch looks good to me. This patch didn't apply cleanly any more, so I re-rolled with that change added. Note I didn't test this version yet.

noizo’s picture

Hi, i was trying to implement patch #23.

Got some lines rejected.
I think its because .module was patched before.

Thats an rejected code.

patching file media_gallery.module
Hunk #1 FAILED at 226.
Hunk #2 FAILED at 354.
Hunk #3 succeeded at 503 (offset 10 lines).
Hunk #4 FAILED at 569.
Hunk #5 succeeded at 605 (offset 25 lines).
3 out of 5 hunks FAILED -- saving rejects to file media_gallery.module.rej
***************
*** 226,235 ****
        // @todo Drupal could really use a theme_menu_local_actions() function...
        '#prefix' => '<ul class="field action-links">',
        '#suffix' => '</ul>',
-       // Add front-end resources related to this link, only when it is actually
-       // being rendered.
-       '#pre_render' => array('media_gallery_add_images_link_pre_render'),
      );
  
      // These JS settings are used by the "add media" link but are also shared
      // by the drag-and-drop code below.
--- 226,236 ----
        // @todo Drupal could really use a theme_menu_local_actions() function...
        '#prefix' => '<ul class="field action-links">',
        '#suffix' => '</ul>',
      );
+     // Add front end resources related to this link.
+     $node->content['add_media_link']['#attached']['js'][] = drupal_get_path('module', 'media_gallery') . '/media_gallery.addimage.js';
+     module_load_include('inc', 'media', 'media.browser');
+     media_attach_browser_js($node->content['add_media_link']);
  
      // These JS settings are used by the "add media" link but are also shared
      // by the drag-and-drop code below.
***************
*** 353,369 ****
  }
  
  /**
-  * Prerender function to add front-end resources for the "Add media" link.
-  */
- function media_gallery_add_images_link_pre_render($elements) {
-   drupal_add_library('media', 'media_browser');
-   module_load_include('inc', 'media', 'media.browser');
-   media_attach_browser_js($elements);
-   drupal_add_js(drupal_get_path('module', 'media_gallery') . '/media_gallery.addimage.js');
-   return $elements;
- }
- 
- /**
   * Implements hook_field_extra_fields().
   */
  function media_gallery_field_extra_fields() {
--- 354,359 ----
  }
  
  /**
   * Implements hook_field_extra_fields().
   */
  function media_gallery_field_extra_fields() {
***************
*** 556,604 ****
      $block['content'] = t('No content available.');
    }
    else {
-     // Collect an array of file IDs associated with this gallery. For
-     // simplicity we will assume (here and below) that this is not a
-     // multilingual field. Also note that the node may have been loaded and
-     // viewed elsewhere on the page, in which case the 'media_gallery_media'
-     // field was modified and does not contain what we want, so we have to go
-     // back to the original field value set in hook_node_load() instead, and
-     // also clone the node before changing it so our modifications do not
-     // affect other places where it might be being viewed.
-     $node = clone $node;
-     $node->media_gallery_media = $node->media_gallery_media_original;
-     $files = &$node->media_gallery_media[LANGUAGE_NONE];
-     $gallery_fids = array();
-     foreach ($files as $file) {
-       $gallery_fids[] = _media_gallery_get_media_fid($file);
-     }
-     // Construct a list of file IDs that is limited to the specified number of
-     // items and ordered by most recent; these are the files that will be
-     // displayed in the block.
-     $columns = !empty($node->media_gallery_block_columns[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_columns[LANGUAGE_NONE][0]['value'] : 1;
-     $rows = !empty($node->media_gallery_block_rows[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_rows[LANGUAGE_NONE][0]['value'] : 1;
-     $number_to_show = $columns * $rows;
-     $block_fids = db_select('file_managed', 'f')
-       ->fields('f', array('fid'))
-       ->condition('fid', $gallery_fids, 'IN')
-       ->orderBy('timestamp', 'DESC')
-       ->range(0, $number_to_show)
-       ->execute()
-       ->fetchCol();
-     // Before sorting, remove any items that will not display in the block.
-     $fid_order = array_flip($block_fids);
-     if ($number_to_show < count($files)) {
-       foreach ($files as $key => $file) {
-         if (!isset($fid_order[_media_gallery_get_media_fid($file)])) {
-           unset($files[$key]);
-         }
-       }
-     }
-     // Prepare the sorting function with the list of file ID orders.
-     _media_gallery_sort_by_recent(NULL, NULL, $fid_order);
-     // Perform the sort.
-     usort($files, '_media_gallery_sort_by_recent');
-     // Display the block.
-     $block['content'] = node_view($node, 'media_gallery_block');
      $block['content']['more_link'] = array(
        '#theme' => 'more_link',
        '#url' => 'node/' . $node->nid,
--- 569,588 ----
      $block['content'] = t('No content available.');
    }
    else {
+     $block['content'] = array(
+       '#node' => $node,
+       '#pre_render' => array('media_gallery_block_build'),
+       '#cache' => array(
+         'keys' => array(
+           'media_gallery_block',
+           $node->nid,
+           (int) node_access('update', $node),
+           (int) $GLOBALS['is_https'],
+         ),
+         'bin' => 'cache_block',
+         'expire' => 86400,
+       ),
+     );
      $block['content']['more_link'] = array(
        '#theme' => 'more_link',
        '#url' => 'node/' . $node->nid,

Would love to see just the list of manual "to do" changes regarding to original code.
I mean like:
line 200 change to this, and line 400 change to that...

Thanks

lsolesen’s picture

Could any of you who worked on this please roll a new patch that applies to the current dev?

lsolesen’s picture

Status: Needs review » Needs work
ivnish’s picture

Issue summary: View changes
Status: Needs work » Closed (outdated)