--- session_expire.module	2010-10-08 12:34:48.000000000 -0400
+++ session_expireNew.module	2010-10-08 12:30:00.000000000 -0400
@@ -4,10 +4,10 @@
 /**
  * @file
  * Expires rows from the session table older than a certain time.
- *
- * @copyright Copyright 2007 Khalid Baheyeldin http://2bits.com
  */
 
+define('SESSION_EXPIRE_ENABLED',  'session_expire_enabled');
+define('SESSION_EXPIRE_MAX_DELETIONS', 'session_expire_max_deletions');
 define('SESSION_EXPIRE_INTERVAL', 'session_expire_interval');
 define('SESSION_EXPIRE_AGE',      'session_expire_age');
 define('SESSION_EXPIRE_MODE',     'session_expire_mode');
@@ -36,6 +36,15 @@ function session_expire_settings() {
     '#value' => t('This module requires cron to be correctly configured and running for Drupal.'),
   );
 
+  $session_count = db_result(db_query('SELECT count(*) FROM {sessions}'));
+  $form[SESSION_EXPIRE_ENABLED] = array(
+    '#type' => 'radios',
+    '#title' => t('Session expiration is'),
+    '#default_value' => variable_get(SESSION_EXPIRE_ENABLED, 0),
+    '#options' => array(t('Disabled'), t('Enabled')),
+    '#description' => t('Enable or disable session expiration. Disabled by default so you can adjust settings before the first cron execution.'),
+  );
+  
   $interval = drupal_map_assoc(array(0, 7200, 10800, 21600, 43200, 86400, 172800, 259200, 604800), 'format_interval');
   $interval['0'] = t('Everytime');
   $form[SESSION_EXPIRE_INTERVAL] = array(
@@ -68,6 +77,16 @@ function session_expire_settings() {
     '#description'   => t('Types of sessions to discard. This option indicates whether only anonymous users, or both anonymous and authenticated users are expired. Note that if you choose authenticated users, they will be logged off and have to login again after the "age" specified above.'),
   );
 
+  $max_deletions = drupal_map_assoc(array(100, 500, 1000, 2500, 5000, 10000));
+  $max_deletions['0'] = t('Unlimited');
+  $form[SESSION_EXPIRE_MAX_DELETIONS] = array(
+    '#type'          => 'select',
+    '#title'         => t('Maximum deletions per run'),
+    '#default_value' => variable_get(SESSION_EXPIRE_MAX_DELETIONS, 1000),
+    '#options'       => $max_deletions,
+    '#description'   => t('Limit the number of sessions deleted during each invocation of the cron job by this amount. This is important if your sessions table is very large (e.g. more than 10,000 rows) because the DELETE can lock the sessions table and prevent users from loading pages until it finishes. Only increase this value if you\'re sure there are no user ramifications. One strategy is to use <a href="!url">Elysia Cron</a> to manage the frequency of execution of your cron jobs and set session_expire_cron to run hourly with this value set relatively low (1000 should be ok on most servers).', array('!url' => 'http://drupal.org/project/elysia_cron'))
+  );
+
   return system_settings_form($form);
 }
 
@@ -75,6 +94,11 @@ function session_expire_settings() {
  * Implementation of hook_cron().
  */
 function session_expire_cron() {
+  // Only run if enabled
+  if (!variable_get(SESSION_EXPIRE_ENABLED, 0)) {
+    return;
+  }
+  
   // Check if it is the first time this hook fires
   $last_run_time = variable_get(SESSION_EXPIRE_LAST, 0);
   if (!$last_run_time) {
@@ -92,12 +116,26 @@ function session_expire_cron() {
     if (!$mode) {
       $extra_cond = 'AND uid = 0';
     }
-
-    // Perform the deletion
-    db_query("DELETE FROM {sessions} WHERE timestamp < %d $extra_cond", $timestamp);
+    
+    // Delete the sessions
+    $max_deletions = variable_get(SESSION_EXPIRE_MAX_DELETIONS, 1000);
+    if ($max_deletions) {
+      // Restricted number of deletions
+      $affected_rows = 0;
+      $result = db_query_range("SELECT sid FROM {sessions} WHERE timestamp < %d $extra_cond", $timestamp, 0, $max_deletions);
+      while ($row = db_fetch_object($result)) {
+        db_query("DELETE FROM {sessions} WHERE sid = %d", $row->sid);
+        $affected_rows += 1;
+      }
+    }
+    else {
+      // Unlimited deletions
+      db_query("DELETE FROM {sessions} WHERE timestamp < %d $extra_cond", $timestamp);
+      $affected_rows = db_affected_rows();
+    }
 
     // Write to the watchdog
-    watchdog('cron', 'Number of sessions deleted: '. db_affected_rows());
+    watchdog('cron', 'Number of sessions deleted: '. $affected_rows);
 
     // Set the last time we deleted
     variable_set(SESSION_EXPIRE_LAST, time());
