See: title.

Why are, even new Beans, calling bean_reset() when they are created?

Why does this need to happen at all?

vim bean/includes/bean.core.inc +362
Changed line to:
//bean_reset();

I am not seeing any differences around the site, even after updating existing beans with that commented out.

Oh wait... here's a difference.

Before:
bean-reset-before.png

After:
bean-reset-after.png

Is this something, perhaps legacy, that had to do with EntityAPI? I am wondering why this helper function needs to be peppered in here.

I am posting a patch for people to try out. It proposes a minor change. In this patch, we don't rebuild all menus and clear all caches whenever a bean is saved. I believe the custom bean still does this override in its save method and maybe the bean_admin_ui beans need it. It seems the bean plugins I have created do not need this extra help.

In addition, I can deploy beans using uuid_features module much more quickly with this patch.

Comments

saltednut’s picture

StatusFileSize
new21.49 KB
new20.97 KB

In this test, we are enabling a Feature that creates 7 new beans via uuid_features integration. The feature is very large, containing many content types, fields and other things that make it slow to enable...

However, I am able to reduce the overhead of enabling this large Feature by 53% if Bean::save does not invoke bean_reset() when these new beans are being created.

With bean_reset() during Bean::save()
bean-before.png

Without bean_reset() during Bean::save()
bean-after.png

The beans are still created fine and I am seeing no errors. Using the patch from above.

saltednut’s picture

Issue tags: +demo_framework

adding tags

indytechcook’s picture

Hey, nice work. I added bean-reset to clear the block caching (and other layers of drupal caching hell).

I'd really like to get rid of if necessary but I think it is necessary. The call to bean reset wasn't in the initial code.

saltednut’s picture

Perhaps plugins should provide this but the core api does not? Otherwise, can we at least check for whether or not the Bean is New vs being updated ? I don't believe caching would affect a new bean - only ones changes are made to.

I'd also like to see tests that show we need this reset on every save. Clearing caches is very hammer-ish and is making Bean slow, keeping the project off production sites for some, etc.

Perhaps we can just provide a bean reset callback? Other modules do this sometimes.

spotzero’s picture

This is likely related to this issue: https://drupal.org/node/20655511

spotzero’s picture

I did some digging, here's an example of the issues you can expect while running with bean_reset() commented out: https://drupal.org/node/1786036, https://drupal.org/node/1850814

After looking over the code for bean_reset(), the only "slow" function call appears to be the menu_rebuild().

function bean_reset($skip_menu_rebuild = FALSE) {
  // Clear ctools cache.
  ctools_include('plugins');
  ctools_get_plugins_reset();
  cache_clear_all('plugins:bean:types', 'cache');
  cache_clear_all('ctools_plugin_files', 'cache', TRUE);

  // Invoke modules to clear their caches.
  foreach (module_implements('bean_cache_clear') as $module) {
    module_invoke($module, 'bean_cache_clear');
  }

  // Rebuild ctools plugin types and the menu.
  ctools_plugin_get_plugin_type_info(TRUE);
  if (!$skip_menu_rebuild) {
    menu_rebuild();
  }
}

ctools_include('plugins'); => runs a few includes, pretty fast
ctools_get_plugins_reset(); => runs drupal_static_reset on a few things, very fast
cache_clear_all('plugins:bean:types', 'cache'); => deletes cache entries, usually fast
cache_clear_all('ctools_plugin_files', 'cache', TRUE); => deletes cache entries, usually fast
module_invoke($module, 'bean_cache_clear'); => runs drupal_static_reset on a few items and deletes more cache entries, usually fast
ctools_plugin_get_plugin_type_info(TRUE); => Usually pretty fast

menu_rebuild(); => Slow even on an empty site.

The above is all speculation, but my guess is that if the dependence on menu_rebuild can be removed, bean_reset() will probably become fast enough to run on save (and then you wouldn't have any caching issues).

saltednut’s picture

This is interesting. What does the menu_rebuild do for us on save?

Additionally, we could look at the bid to determine if this is an update or a new bean. The bid will resolve to NULL if this is a new bean, but if it is an update, there will be a bid.

I am thinking we can get around some of these issues if we only call bean_reset() during updates. I don't believe we should need bean_reset() when creating a new bean.

Psuedocode, but should work:

    $return = parent::save();
    if (isset($this->bid)) {
      bean_reset();
    }

    return $return;
ottawadeveloper’s picture

Based on #1850814: After creating a new bean type, cache clear is required to manage fields of a bean and #2065551: Performance with bean->save and menu_rebuild, it looks like the call to menu_rebuild() is essential for new bean types (as the code is currently written) in order to get the block/add/type page to work. It's also necessary for Field UI to attach all the field management elements. (see field_ui_menu for why this is necessary for new bean types).

It looks like because of the way the code is written, both new beans and new block types call the same function (bean_reset()), so removing it from bean_reset() is going to break the creation of bean types on the fly.

You likely don't notice these problems because enabling a module calls cache_clear anyways which rebuilds the menu anyways.

What would be nice as a solution I think is the following:

  1. Add a parameter to bean_reset() in order to trigger clearing the menu (default: false)
  2. Only trigger bean_reset(TRUE) from the BeanCustom plugin where it's needed to rebuild the menu

However, this still causes a problem for Features and such sortof: consider, if you've created 10 bean types and put them in a feature, then the menu cache gets cleared 11 times: once for each bean type and once for the module being enabled. It would be nice to add some method of preventing the menu cache from being cleared that can be used by Features in order to not destroy the cache (maybe giving BeanCustom::save() an additional parameter for whether or not to kill the menu?)

Edit: Alternatively, we could just remove the menu cache clearing completely and call it manually from the admin interface when needed.

ottawadeveloper’s picture

I'm kindof an idiot for not looking further before I posted... there's already a flag on bean_reset() in 1.x and the admin UI page is already calling drupal_flush_all_caches(). With those in place, there's no real reason for the menu cache to ever be cleared by bean_reset() that I can find.

spotzero’s picture

It sound like the menu doesn't need to be rebuilt when saving a bean. However, when updating/deleting/creating bean types, it does need a rebuild.

The fix to this issue then is to update the bean_reset() call in bean->save() to be "bean_reset(TRUE);"

This won't change anything when working with bean types, but solves the bean save slowness.

sylus’s picture

StatusFileSize
new335 bytes

Attaching patch based on above.

indytechcook’s picture

Status: Needs review » Reviewed & tested by the community

I like that solution.

saltednut’s picture

Status: Reviewed & tested by the community » Fixed
StatusFileSize
new151.63 KB
new162.89 KB

Just profiled this patch using the exact same environment. (Hey, distributions are nice!)

Here are the results... *drumroll*

Before patch:
bean-reset-menu-rebuild-before.png

After patch:
bean-reset-menu-rebuild-after.png

This is a serious improvement! I think its a good compromise too - we can keep bean_reset() without the overhead on Bean::save

Nice work, everyone!

Committed to dev: http://drupalcode.org/project/bean.git/commit/a3d05d2

saltednut’s picture

Erp, just realized should have included spotzero in the commit message too for thinking up the solution. Sorry about that. (Stupid dreditor making me lazy...)

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