[development] The menu - does it have to be different on eachpage?

George Kappel gkappel at herrspacific.com
Wed Aug 30 01:28:23 UTC 2006


Had major menu performance issues as well, following changes made an
incredible difference with 5,000 menu items and 50,000 nodes

1) _menu_sort gets called recursively so "$menu = menu_get_menu();" was a
huge problem, switched to the global $_menu instead.

2) menu_get_menu() was altered to cache (APC) menus by ROLES & locale not
user.  When retrieved from cache the user specific callbacks and stuff gets
fixed up

As far as I can tell when using APC cache with PHP5 there is no
serialize/unserialize penalty when using simple types (not objects).  Since
menu is a simple array this helps.

This is nothing more than a hack but I had little choice at the time.  The
APC cache needs to be manually cleared in order for menu changes to show but
that seems to be the only downside so far.



function _menu_sort($a, $b) {
//  $menu = menu_get_menu();
  global $_menu;
.
.
.



function menu_get_menu() {
  global $_menu;
  global $user;
  global $locale;

  if (!isset($_menu['items'])) {
    // _menu_build() may indirectly call this function, so prevent infinite
loops.
    $_menu['items'] = array();
    $menukey = implode(':',array_keys($user->roles));
    if ($user->uid == 1) {
      $cid = "adminmenu";
    } else {
      $cid = "menu:$menukey:$locale";
    }
    if ($_menu = apc_fetch($cid)) {
      //loaded menu from cache need to fixup user specific menu
      $newpath = 'user/'.$user->uid;
      $matched = preg_grep('/user\/\d/',array_keys($_menu['path index']));
      $result = count($matched);
      if ($result == 1) {
        $target = array_pop($matched);
        $targetvalue = $_menu['path index'][$target];

        unset($_menu['path index'][$target]);
        $_menu['path index'][$newpath] = $targetvalue;

        $_menu['callbacks'][$newpath] = $_menu['callbacks'][$target];
        unset($_menu['callbacks'][$target]);

        $_menu['visible'][$targetvalue]['path'] = $newpath;
        $_menu['items'][$targetvalue]['path'] = $newpath;
      }


    } else {
      _menu_build();
      apc_store($cid,$_menu,100000);
    }


    // Make sure items that cannot be cached are added.
    _menu_append_contextual_items();

    // Reset the cached $menu in menu_get_item().
    menu_get_item(NULL, NULL, TRUE);
  }

  return $_menu;
}



George Kappel
 

> -----Original Message-----
> From: development-bounces at drupal.org 
> [mailto:development-bounces at drupal.org] On Behalf Of Moshe Weitzman
> Sent: Tuesday, August 29, 2006 6:28 PM
> To: development at drupal.org
> Subject: Re: [development] The menu - does it have to be 
> different on eachpage?
> 
> 
> > Caching the whole rendered menu block would have some serious 
> > performance implications.
> 
> unless i am missing something, this focus on rendering is 
> misplaced. you 
> still have calculate the whole menu tree to find the right 
> path for callback 
> and breadcrumb. thats where the performance cost is. building 
> the rendering 
> isn't too bad. furthermore, most big sites just disable 
> navigation block and 
> do own navigation using a different menu or separate from menu system.
> 
> now if we could determine callback without building the menu 
> tree we would 
> be in real fine shape.
> 
> -moshe
> 



More information about the development mailing list