Submitting Fixes to Drupal

  • Want a fresh pair of eyes?

    A lot of times we find an outside perspective can work wonders. If you'd like to send us your information, we have no problems listening and offering our thoughts.

Like Us On Facebook:  

A Drupal site runs very quickly out of the box, but with every module that gets installed the performance degrades a bit. Troubleshooting a slow Drupal site without the proper tools can be a nightmare. Luckily there are a few programs that help, namely Xdebug. Recently, I had a Drupal site that ran so very slow, anytime a user would edit anything, the server would timeout. With Xdebug the problem function screamed at me: token_menu_link_load in the token module was called 1.5 million times, running for a total of 24 seconds.

While this function isn’t the root cause of the problem, the function was performing too many queries in the 1.5 million times it ran. While continuing to troubleshoot, I decided to rewrite the function to speed things up so people can still use the site. Here’s the function before I modified it:


function token_menu_link_load($mlid) {
  $cache = &drupal_static(__FUNCTION__, array());
  if (!is_numeric($mlid)) {
    return FALSE;
  }
  if (!isset($cache[$mlid])) {
    $item = db_query("SELECT * FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.mlid = :mlid", array(':mlid' => $mlid))->fetchAssoc();
    if (!empty($item)) {
      _token_menu_link_translate($item);
    }
    $cache[$mlid] = $item;
  }
  return $cache[$mlid];
}

That query has the potential to run millions of times. The new function executes the query once and caches all the results:


function token_menu_link_load($mlid) {
  $cache = &drupal_static(__FUNCTION__, array());
  if (!is_numeric($mlid)) {
    return FALSE;
  }
  if (!isset($cache['loaded'])) {
    $items = db_query("SELECT * FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path");
    while( $item = $items->fetchAssoc() ) {
      if (!empty($item)) {
        _token_menu_link_translate($item);
      }
      $cache[$mlid] = $item;
    }
    $cache['loaded'] = 1;
  }
  if (!isset($cache[$mlid])) {
    $cache[$mlid] = null;
  }
  return $cache[$mlid];
}

While this works well for the site I’m working on, it may not be a good solution for everyone. The above query returns 833 records for my installation, which takes very little time to process. If the query returns many thousands of records, this could cause PHP to hit it’s memory or time limit.

Once the fix is working, I created a patch file using git:


git diff token.module > token.patch

You can also create a patch using plain jane diff:


diff -u original/token.module updated/token.module > token.patch

The final step in the process is to submit the code to drupal. This is actually a lot easier than you might think. All I had to do was create and issue for the module and upload a patch file. It will need to be reviewed, of course, but submitting the issue with a patch will greatly increase the odds of the patch being applied.


Have your say!

Have your say!

Message

Name *

Email *

  • Want a fresh pair of eyes?

    A lot of times we find an outside perspective can work wonders. If you'd like to send us your information, we have no problems listening and offering our thoughts.

Recent Posts
Tags
Archives