13

Cache table's size had increased to 10+ GB last month, and I had fixed it temporarily by truncating it. Last time I checked it was around 1GB. So in couple of months it will hit 10GB again. How should this be dealt with ?

Note that I have disabled all cron jobs on this site. If this is the reason, which cron should be enabled ?

24

The {cache_form} table is a little funny, and behaves in a slightly different manner than other cache tables.

If you take a look at drupal_flush_all_caches() you will see that {cache_form} isn't cleared. This is to protect in-progress forms from being nuked.

The system_cron() function does take care of pruning out old data from {cache_form} along with the other cache tables.

You really should run cron on all Drupal sites. If you {cache_form} table is ginourmous, then I bet your {watchdog} and {session} tables are, too. Many other modules run housekeeping activity as part of their own hook_cron() functions.

You may also want to poke around the issue queue. There have been some bugs with {cache_form}, and you may be running into one.

  • Ok I had set up the crons properly now, but still I could see that it grew to 2 GB in one day, but its been constant since one week. What will be stored in these tables ? – GoodSp33d Apr 26 '13 at 12:30
  • 1
    {cache_form} has in-progress form submissions. {watchdog} has the logs, and {session} has the session information (per-user state). – mpdonadio Apr 26 '13 at 12:54
6

Thumb Rule: Cron should be run regularly for the housekeeping of your website.

You mentioned in your comment to MPD that in-spite of setting up the cron and running them regularly your cache_form table is growing up quickly.

One solution to that is to run your cron more frequently. Say every six hours or lesser? If you cannot afford to do it read further.

Alternate Solution :

mymodule_cron() {
    cache_clear_all(NULL, 'cache_form');
}

Install Elysia Cron and now you can run the cron function of your module separately. You can keep the frequency of the Elysia cron for you module to run every six hours. So that your cache_form table is pruned every six hours.

During this pruning process the entries which are not older than 6 hours will not be deleted. The reason being, if all the entries are deleted then any forms which are being submitted at the time of deleting the entries can behave weirdly.

Look at the code in https://api.drupal.org/api/drupal/includes!form.inc/function/form_set_cache/7

function form_set_cache($form_build_id, $form, $form_state) {
  // 6 hours cache life time for forms should be plenty.
  $expire = 21600;

As the comment reads they are assuming it should be plenty and in your case it is becoming too plenty for you. So the trick is to either clear the cache_form table more frequently and reduce the value of $expire to a lower value, if you want to clear the cache_form entries more frequently than the default value of 6 six hours then you need to alter the TTL of the cache_form entries.

You can do that by installing cacheboject and then implementing the hook_cacheobject_presave within which you can alter the TTL to may be 2 or 3 hours.

mymodule_cacheobject_presave()($object, $cid, $bin) {
  // Extend the expiry period for prototype forms used in ajax enabled forms.                                                                  
  $cache_ttl = 1 ; // Change it to any number of hours
  if ($bin == 'cache_form') {
    $object->expire = REQUEST_TIME + $cache_ttl * 3600;
  }
}

One downside of this approach is if the forms are not submitted within 2 hours(the RTL value you set) the the form data can be lost and you might get some form expired issues.

1

As a workaround on this problem, I have created module https://www.drupal.org/project/session_cache_form

1

When I was having performance issues on a site I was working, I ran into this after I fixed caching. You can read the article here: https://thinktandem.io/blog/2017/11/22/debugging-with-new-relic-blazemeter-strace-more/

From my blog post, you can add a queue and cron setup, then use something like Elysia Cron to make it all work together well:

/**
 * Implements hook_cron_queue_info()
 */
function THE MODULE_cron_queue_info() {
  // Set up the worker queue.
  $queues['THE MODULE_queue'] = array(
    'worker callback' => 'THE MODULE_queue_process',
    'time' => 600,
  );
  return $queues;
}

/**
 * Implements hook_cron()
 */
function THE MODULE_cron() {
  // Load up our worker queue.
  $queue = DrupalQueue::get('THE MODULE_queue');

  // Set up the query for expired results.
  $sql = "SELECT cid FROM {cache_form} WHERE expire < :time";
  $query = db_query($sql, array(':time' => REQUEST_TIME));
  $results = $query->fetchAll(PDO::FETCH_ASSOC);

  // Split this into chunks for safety and speed.
  $chunks = array_chunk($results, 5000);
  foreach ($chunks as $chunk) {
    // Add the chunk to the queue worker.
    $queue->createItem($chunk);
  }
}

/**
 * Worker callback defined in hook_cron_queue_info().
 *
 * @param array $data
 *   The array of cids we want to delete.
 */
function THE MODULE_queue_process($data) {
  db_delete('cache_form')
    ->condition('cid', $data, 'IN')
    ->execute();
}
1

Use the Safe cache_form Clear module.

It will let you prune the table to a reasonable size first, then maintain it.

Excerpted summary from the project page:

Safely remove a limited number of items from the cache_form table.

Once the module is installed, first prune cache_form: run drush safe-cache-form-clear until the table size stays consistent, indicating you've removed all records older than 6 hrs.

It will then continue running on cron.

This is the module documented for this purpose by Acquia for their subscribers. The Acquia documentation page provides good additional information.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.