Same filename and directory in other branches
  1. 4.7.x modules/throttle.module

Allows configuration of congestion control auto-throttle mechanism.

File

modules/throttle.module
View source
<?php

/**
 * @file
 * Allows configuration of congestion control auto-throttle mechanism.
 */

/**
 * Determine the current load on the site.
 *
 * Call the throttle_status() function from your own modules, themes, blocks,
 * etc. to determine the current throttle status. For example, in your theme
 * you might choose to disable pictures when your site is too busy (reducing
 * bandwidth), or in your modules you might choose to disable some complicated
 * logic when your site is too busy (reducing CPU utilization).
 *
 * @return
 *   0 or 1.  0 means that the throttle is currently disabled.  1 means that
 *   the throttle is currently enabled.  When the throttle is enabled, CPU
 *   and bandwidth intensive functionality should be disabled.
 */
function throttle_status() {
  return variable_get('throttle_level', 0);
}

/**
 * Implementation of hook_exit().
 *
 * Changes the current throttle level based on page hits.
 */
function throttle_exit() {

  // The following logic determines what the current throttle level should
  //  be, and can be disabled by the admin.  If enabled, the rand() function
  //  returns a number between 0 and N, N being specified by the admin. If
  //  0 is returned, the throttle logic is run, adding two additional database
  //  queries.  Otherwise, the following logic is skipped.  This mechanism is
  //  referred to in the admin page as the 'probability limiter', roughly
  //  limiting throttle related database calls to 1 in N.
  if (!rand(0, variable_get('throttle_probability_limiter', 9))) {

    // Note:  The rand() function is supported by PHP 3+.  However, prior to
    // PHP 4.2.0 it needs to be seeded with a call to srand().  It is important
    // that this only happens once, so this should be managed by the Drupal
    // engine, not this module.  The Drupal engine should use phpversion() to
    // detect and automatically seed pre-4.2.0 systems.
    // Count users with activity in the past n seconds, defined in user module
    $time_period = variable_get('user_block_seconds_online', 2700);
    $throttle = module_invoke('throttle', 'status');
    if ($max_guests = variable_get('throttle_anonymous', 0)) {
      $guests = db_result(db_query('SELECT COUNT(sid) AS count FROM {sessions} WHERE timestamp >= %d AND uid = 0', time() - $time_period));
    }
    else {
      $guests = 0;
    }
    if ($max_users = variable_get('throttle_user', 0)) {
      $users = db_result(db_query('SELECT COUNT(DISTINCT(uid)) AS count FROM {sessions} WHERE timestamp >= %d AND uid != 0 GROUP BY uid ORDER BY timestamp DESC', time() - $time_period));
    }
    else {
      $users = 0;
    }

    // update the throttle status
    $message = '';
    if ($max_users && $users > $max_users) {
      if (!$throttle) {
        variable_set('throttle_level', 1);
        $message = format_plural($users, '1 user accessing site; throttle enabled.', '%count users accessing site; throttle enabled.');
      }
    }
    elseif ($max_guests && $guests > $max_guests) {
      if (!$throttle) {
        variable_set('throttle_level', 1);
        $message = format_plural($guests, '1 guest accessing site; throttle enabled.', '%count guests accessing site; throttle enabled.');
      }
    }
    else {
      if ($throttle) {
        variable_set('throttle_level', 0);

        // Note: unorthodox format_plural() usage due to Gettext plural limitations.
        $message = format_plural($users, '1 user', '%count users') . ', ';
        $message .= format_plural($guests, '1 guest accessing site; throttle disabled', '%count guests accessing site; throttle disabled');
      }
    }
    if ($message) {
      cache_clear_all();
      watchdog('throttle', t('Throttle') . ': ' . $message);
    }
  }
}
function _throttle_validate($value, $form) {
  if ($value != NULL) {
    if (!is_numeric($value) || $value < 0) {
      form_set_error($form, t("'%value' is not a valid auto-throttle setting.  Please enter a positive numeric value.", array(
        '%value' => theme('placeholder', $value),
      )));
    }
  }
}

/**
 * Implementation of hook_help().
 */
function throttle_help($section) {
  switch ($section) {
    case 'admin/modules#description':
      return t('Handles the auto-throttling mechanism, to control site congestion.');
    case 'admin/settings/throttle':
      return t('If your site gets linked to by a popular website, or otherwise comes under a "Denial of Service" (DoS) attack, your webserver might become overwhelmed.  This module provides a congestion control throttling mechanism for automatically detecting a surge in incoming traffic.  This mechanism is utilized by other Drupal modules to automatically optimize their performance by temporarily disabling CPU-intensive functionality.');
  }
}

/**
 * Implementation of hook_settings().
 */
function throttle_settings() {

  // Tune auto-throttle.
  _throttle_validate(variable_get('throttle_anonymous', ''), 'throttle_anonymous');
  _throttle_validate(variable_get('throttle_user', ''), 'throttle_user');
  $group = form_textfield(t('Auto-throttle on anonymous users'), 'throttle_anonymous', variable_get('throttle_anonymous', 0), 5, 6, t('The congestion control throttle can be automatically enabled when the number of anonymous users currently visiting your site exceeds the specified threshold.  For example, to start the throttle when your site has 250 anonymous users online at once, enter \'250\' in this field. Leave this value blank or set to "0" if you do not wish to auto-throttle on anonymous users.  You can inspect the current number of anonymous users using the "Who\'s online" block.'));
  $group .= form_textfield(t('Auto-throttle on authenticated users'), 'throttle_user', variable_get('throttle_user', 0), 5, 6, t('The congestion control throttle can be automatically enabled when the number of authenticated users currently visiting your site exceeds the specified threshold.  For example, to start the throttle when your site has 50 registered users online at once, enter \'50\' in this field. Leave this value blank or set to "0" if you do not wish to auto-throttle on authenticated users.  You can inspect the current number of authenticated users using the "Who\'s online" block.'));
  $probabilities = array(
    0 => '100%',
    1 => '50%',
    2 => '33.3%',
    3 => '25%',
    4 => '20%',
    5 => '16.6%',
    7 => '12.5%',
    9 => '10%',
    19 => '5%',
    99 => '1%',
    199 => '.5%',
    399 => '.25%',
    989 => '.1%',
  );
  $group .= form_select(t('Auto-throttle probability limiter'), 'throttle_probability_limiter', variable_get('throttle_probability_limiter', 9), $probabilities, t('The auto-throttle probability limiter is an efficiency mechanism to statistically reduce the overhead of the auto-throttle.  The limiter is expressed as a percentage of page views, so for example if set to the default of 10% we only perform the extra database queries to update the throttle status 1 out of every 10 page views.  The busier your site, the lower you should set the limiter value.'));
  $period = drupal_map_assoc(array(
    1800,
    3600,
    7200,
    10800,
    14400,
    18000,
    21600,
    43200,
    64800,
    86400,
    172800,
    259200,
    604800,
  ), 'format_interval');
  $output .= form_group(t('Auto-throttle tuning'), $group);
  return $output;
}

Functions

Namesort descending Description
throttle_exit Implementation of hook_exit().
throttle_help Implementation of hook_help().
throttle_settings Implementation of hook_settings().
throttle_status Determine the current load on the site.
_throttle_validate