=== modified file 'includes/common.inc'
--- includes/common.inc	2009-02-28 07:36:06 +0000
+++ includes/common.inc	2009-03-04 22:13:33 +0000
@@ -2980,6 +2980,7 @@ function _drupal_bootstrap_full() {
   require_once DRUPAL_ROOT . '/includes/form.inc';
   require_once DRUPAL_ROOT . '/includes/mail.inc';
   require_once DRUPAL_ROOT . '/includes/actions.inc';
+  require_once DRUPAL_ROOT . '/includes/queue.inc';
   // Set the Drupal custom error handler.
   set_error_handler('_drupal_error_handler');
   set_exception_handler('_drupal_exception_handler');

=== added file 'includes/queue.inc'
--- includes/queue.inc	1970-01-01 00:00:00 +0000
+++ includes/queue.inc	2009-03-06 20:59:14 +0000
@@ -0,0 +1,98 @@
+<?php
+
+interface DrupalQueue {
+  /**
+   * Start working with a queue.
+   *
+   * @param $queue_name
+   *   Arbitrary string. The name of the queue to work with.
+   */
+  function __construct($queue_name);
+
+  /**
+   * Queue an item.
+   *
+   * @param $item
+   *   Arbitrary value to be queued.
+   */
+  function queue($item);
+
+  /**
+   * Get an item from a queue.
+   *
+   * @param $process_time
+   *   How long the processing is expected to take in seconds, Defaults to 30.
+   * @param $wait_time
+   *   How long to wait for an item if the queue is empty. Defaults to
+   *   30 seconds.
+   * @return
+   *   A queue entry which is an object. The 'item' property contains $item
+   *   which is what was passed to queue().
+   */
+  function dequeue($process_time = 30, $wait_time = 30);
+
+  /**
+   * Remove a finished item from the queue.
+   *
+   * @param $item_id
+   *  The item_id coming from the entry dequeue() returned.
+   */
+  function finish($item_id);
+}
+
+/**
+ * Get a queue object for a given queue_name.
+ *
+ * @param $queue_name
+ *   Arbitrary string. The name of the queue to work with.
+ */
+function _queue_get_queue($queue_name) {
+  static $queues;
+  if (!isset($queues[$queue_name])) {
+    $class = variable_get('queue_module', 'queue') . 'Queue';
+    $queues[$queue_name] = new $class($queue_name);
+  }
+  return $queues[$queue_name];
+}
+
+/**
+ * Queue an item.in a queue.
+ *
+ * @param $queue_name
+ *   Arbitrary string. The name of the queue to work with.
+ * @param $item
+ *   Arbitrary value to be queued.
+ */
+function queue_queue($queue_name, $item) {
+  return _queue_get_queue($queue_name)->queue($item);
+}
+
+
+/**
+ * Get an item from a queue.
+ *
+ * @param $queue_name
+ *   Arbitrary string. The name of the queue to work with.
+ * @param $process_time
+ *   How long the processing is expected to take in seconds, Defaults to 30.
+ * @param $wait_time
+ *   How long to wait for an item if the queue is empty. Defaults to
+ *   30 seconds.
+ * @return
+ *   A queue entry which is an object. The 'item' property contains $item which
+ *   is what was passed to queue(). This queue entry needs to be passed to
+ *   queue_finish() once processing is completed.
+ */
+function queue_dequeue($queue_name, $process_time = 30, $wait_time = 30) {
+  return _queue_get_queue($queue_name)->dequeue($process_time, $wait_time);
+}
+
+/**
+ * Remove a finished entry from the queue.
+ *
+ * @param $entry
+ *  The entry object returned by dequeue().
+ */
+function queue_finish($entry) {
+  return _queue_get_queue($entry->queue_name)->finish($entry->item_id);
+}

=== added directory 'modules/queue'
=== added file 'modules/queue/queue.info'
--- modules/queue/queue.info	1970-01-01 00:00:00 +0000
+++ modules/queue/queue.info	2009-03-04 22:13:33 +0000
@@ -0,0 +1,9 @@
+; $Id$
+
+name = Queue
+description = Default queue implementation
+package = Core
+version = VERSION
+core = 7.x
+files[] = queue.module
+files[] = queue.install

=== added file 'modules/queue/queue.install'
--- modules/queue/queue.install	1970-01-01 00:00:00 +0000
+++ modules/queue/queue.install	2009-03-06 20:57:25 +0000
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * Implementation of hook_install().
+ */
+function queue_install() {
+  drupal_install_schema('queue');
+}
+
+function queue_schema() {
+  $schema['queue'] = array(
+    'description' => 'Stores items in queues.',
+    'fields' => array(
+      'item_id' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique item ID.',
+      ),
+      'queue_name' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The queue name.',
+      ),
+      'process_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The ID of the dequeuing process.',
+      ),
+      'item' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'size' => 'big',
+        'serialize' => TRUE,
+        'description' => 'The item itself.',
+      ),
+      'expire' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The time processing started.',
+      ),
+    ),
+    'primary key' => array('item_id'),
+    'indexes' => array(
+      'process_queue' => array('process_id', 'queue_name'),
+      'process_expire' => array('process_id', 'expire'),
+    ),
+  );
+
+  $schema['queue_process_id'] = array(
+    'description' => 'Stores queue process IDs, used to auto-incrament the process ID so that a unique process ID is used.',
+    'fields' => array(
+      'process_id'  => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique process ID used to make sure only one consumer gets one item.',
+      ),
+    ),
+    'primary key' => array('process_id'),
+  );
+  return $schema;
+}
\ No newline at end of file

=== added file 'modules/queue/queue.module'
--- modules/queue/queue.module	1970-01-01 00:00:00 +0000
+++ modules/queue/queue.module	2009-03-06 20:59:49 +0000
@@ -0,0 +1,58 @@
+<?php
+
+class queueQueue implements DrupalQueue {
+  protected $process_id;
+
+  protected $queue_name;
+
+  function __construct($queue_name) {
+    $this->queue_name = $queue_name;
+  }
+
+  function queue($item) {
+    $record->queue_name = $this->queue_name;
+    $record->item = $item;
+    $record->process_id = 0;
+    return drupal_write_record('queue', $record);
+  }
+
+  function dequeue($process_time = 30, $wait_time = 30) {
+    if (!isset($this->process_id)) {
+      $this->process_id = db_insert('queue_process_id')->useDefaults(array('process_id'))->execute();
+    }
+    $start = time();
+    $entry = FALSE;
+    $statement = db_select('queue', 'q');
+    $statement->addField('q', 'item_id');
+    $statement->condition('process_id', 0);
+    $statement->condition('queue_name', $this->queue_name);
+    $statement->range(0, 1);
+    do {
+      $item_id = $statement->execute()->fetchField();
+      if ($item_id) {
+        // Try to mark the item as ours.
+        db_update('queue')->fields(array('process_id' => $this->process_id, 'expire' => time() + $process_time))->condition('item_id', $item_id)->condition('process_id', 0)->execute();
+        // Grab the entry if it's ours.
+        $entry = db_query('SELECT item, item_id, queue_name FROM {queue} WHERE process_id = :process_id AND item_id = :item_id', array('process_id' => $this->process_id, 'item_id' => $item_id))->fetchObject();
+      }
+      else {
+        sleep(1);
+      }
+    } while (!$entry && time() - $start < $wait_time);
+    if ($entry) {
+      $entry->item = unserialize($entry->item);
+      return $entry;
+    }
+  }
+
+  function finish($item_id) {
+    db_delete('queue')->condition('item_id', $item_id);
+  }
+}
+
+/**
+ * Reset expired items.
+ */
+function queue_cron() {
+  db_update('queue')->fields(array('process_id' => 0, 'expire' => 0))->condition('expire', time(), '<')->condition('process_id', 0, '!=');
+}

=== added file 'modules/simpletest/tests/queue.test'
--- modules/simpletest/tests/queue.test	1970-01-01 00:00:00 +0000
+++ modules/simpletest/tests/queue.test	2009-03-06 20:57:37 +0000
@@ -0,0 +1,63 @@
+<?php
+
+class QueueTestCase extends DrupalWebTestCase {
+  function getInfo() {
+    return array(
+      'name' => t('Queue functionality'),
+      'description' => t('Queues and dequeues an item.'),
+      'group' => t('Queue')
+    );
+  }
+
+  function setUp() {
+    return parent::setUp('queue');
+  }
+
+  function testQueue() {
+    $queue1 = $this->randomName();
+    $queue2 = $this->randomName();
+    $items = array();
+    for ($i = 0; $i < 4; $i++) {
+      $items[] = array($this->randomName() => $this->randomName());
+    }
+    queue_queue($queue1, $items[0]);
+    queue_queue($queue1, $items[1]);
+    $entry = queue_dequeue($queue1);
+    $entries[] = $entry;
+    $new_items[] = $entry->item;
+    $entry = queue_dequeue($queue1);
+    $entries[] = $entry;
+    $new_items[] = $entry->item;
+    // Two dequeued items should match the two items we queued.
+    $this->assertEqual($this->score($items, $new_items), 2, t('Two items matched'));
+    queue_queue($queue1, $items[2]);
+    queue_queue($queue1, $items[3]);
+    $entry = queue_dequeue($queue1);
+    $entries[] = $entry;
+    $new_items[] = $entry->item;
+    $entry = queue_dequeue($queue1);
+    $entries[] = $entry;
+    $new_items[] = $entry->item;
+    // All dequeued items should match the items we queued.
+    $this->assertEqual($this->score($items, $new_items), 4, t('Four items matched'));
+    // There should not be equal dequeued items.
+    $this->assertEqual($this->score($new_items, $new_items), 4, t('Four items matched'));
+    foreach ($entries as $entry) {
+      queue_finish($entry);
+    }
+    $this->assertFalse(queue_dequeue($queue1, 1, 1), t('Queue 1 is empty'));
+    $this->assertFalse(queue_dequeue($queue2, 1, 1), t('Queue 2 is empty'));
+  }
+
+  function score($items, $new_items) {
+    $score = 0;
+    foreach ($items as $item) {
+      foreach ($new_items as $new_item) {
+        if ($item === $new_item) {
+          $score++;
+        }
+      }
+    }
+    return $score;
+  }
+}

