I noticed my site was feeling really sluggish -- the culprit wound up being nearly 1000 calls to menu_token_get() on each page load, each one causing a database lookup.

In my case (and I assume that most sites won't have very many), there's only one row in my menu_tokens table.

It might be good to just fill up a static array with the contents of that database table the first time menu_token_get() gets called, then perform subsequent lookups there. Much faster.

Or maybe this is a bug with the "uses tokens" flag -- it seems like I shouldn't be experiencing hundreds of calls to that function in regular use? Seems like menu_token_get() should only get called on menu items that have the "uses tokens" flag... If this was working correctly I think there wouldn't be a need for caching since it would only get called for the menu items that actually use tokens.

Thoughts? Thanks!!

Comments

jruberto’s picture

Status: Active » Closed (works as designed)

well, i had caching turned off. how about that. this still adds a good bit of overhead to a full menu rebuild, which is high overhead enough, could still benefit from static caching..

arcaic’s picture

I have had this issue myself. I'd added some functionality to a site and it felt decidedly sluggish so took a look in my test site with devel and found that menu_token_get was issuing about 250 db calls per page load. I only have 5 menu tokens so this seemed a little excessive.

I have normal drupal caching enabled and my views/blocks are cached where practicle so I thought I would take a stab at fixing it.

The following is a modification to menu_token.inc version 6.x-1.0-alpha2.

It replaces menu_token_get and adds a new function called function menu_token_load_tokens.

function menu_token_get($mlid) {

  global $menu_token_conf;

  if (!$mlid) {
    return NULL;
  }

  if ($cached_all = variable_get('MENU_TOKEN_CACHE_ALL', TRUE)) {
    if(!isset($menu_token_conf)) {
      menu_token_load_tokens();
    }
  }

  if (!isset($menu_token_conf[$mlid])) {
    if (!$cached_all) {
      $item_conf = db_fetch_array(db_query('SELECT * FROM {menu_token} WHERE mlid = %d', $mlid));
      $menu_token_conf[$mlid] = empty($item_conf) ? NULL : $item_conf;
    }
  }

  return $menu_token_conf[$mlid];
}

/*
 * Load menu all token configurations from database.
 */
function menu_token_load_tokens() {

  global $menu_token_conf;

  $results = db_query('SELECT * FROM {menu_token}');

  while ($result = db_fetch_array($results)){
    $menu_token_conf[$result['mlid']] = $result;
  }
}

With the above all menu tokens are loaded and cached on the first call.

This has been running on my live site for a week with no negative reports from users but you should test thoroughly for your own use case.

You'll see I've added a drupal_variable that is checked to see whether or not the caching should be used (default above is - caching enabled). With this set false then it should perform as normal. No UI to change the variable is provided so you would have to add/change it in the DB yourself should you need to turn caching off quickly.