=== 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'); @@ -3269,7 +3270,7 @@ function drupal_render_page($page) { * * Recursively iterates over each of the array elements, generating HTML code. * - * HTML generation is controlled by two properties containing theme functions, + * HTML generation is controlled by two properties containing theme functions, * #theme and #theme_wrapper. * * #theme is the theme function called first. If it is set and the element has any @@ -3280,13 +3281,13 @@ function drupal_render_page($page) { * * The theme function in #theme_wrapper will be called after #theme has run. It * can be used to add further markup around the rendered children, e.g. fieldsets - * add the required markup for a fieldset around their rendered child elements. + * add the required markup for a fieldset around their rendered child elements. * A wrapper theme function always has to include the element's #children property - * in its output, as this contains the rendered children. + * in its output, as this contains the rendered children. * * For example, for the form element type, by default only the #theme_wrapper * property is set, which adds the form markup around the rendered child elements - * of the form. This allows you to set the #theme property on a specific form to + * of the form. This allows you to set the #theme property on a specific form to * a custom theme function, giving you complete control over the placement of the * form's children while not at all having to deal with the form markup itself. * @@ -3320,7 +3321,7 @@ function drupal_render(&$elements) { else { $elements += element_basic_defaults(); } - + // If #markup is not empty and no theme function is set, use theme_markup. // This allows to specify just #markup on an element without setting the #type. if (!empty($elements['#markup']) && empty($elements['#theme'])) { === added file 'includes/queue.inc' --- includes/queue.inc 1970-01-01 00:00:00 +0000 +++ includes/queue.inc 2009-03-04 21:26:07 +0000 @@ -0,0 +1,97 @@ +queue($item); +} + + +/** + * Dequeue an item.from a queue.. + * + * @param $queue_name + * Arbitrary string. The name of the queue to work with. + * @param $timeout + * How long to wait for an item in second, defaults to 30 seconds. + * @return + * An object, key data holds the item passed to queue. Change data and pass + * to finish(). + */ +function queue_dequeue($queue_name, $timeout = 30) { + return _queue_get_queue($queue_name)->dequeue($timeout); +} + +/** + * Mark an item.as finsihed and save its data back to the queue. + * + * @param $queue_name + * Arbitrary string. The name of the queue to work with. + * @param $item + * The item as got from dequeue. + */ +function queue_finish($queue_name, $item) { + return _queue_get_queue($queue_name)->finish($item); +} === 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-04 22:13:33 +0000 @@ -0,0 +1,72 @@ + '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.', + ), + 'status' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => 'The item status.', + ), + 'process_id' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The ID of the processing.', + ), + 'data' => array( + 'type' => 'text', + 'not null' => FALSE, + 'size' => 'big', + 'serialize' => TRUE, + 'description' => 'The item itself.', + ), + 'timestamp' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The time processing started.', + ), + ), + 'primary key' => array('item_id'), + 'indexes' => array( + 'sqp' => array('status', 'queue_name', 'process_id'), + ), + ); + + $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-04 22:13:33 +0000 @@ -0,0 +1,51 @@ +queue_name = $queue_name; + } + + function queue($item) { + $record->queue_name = $this->queue_name; + $record->status = QUEUE_NEEDS_PROCESSING; + $record->data = $item; + $record->process_id = 0; + return drupal_write_record('queue', $record); + } + + function dequeue($timeout = 30) { + if (!isset($this->process_id)) { + $this->process_id = db_insert('queue_process_id')->useDefaults(array('process_id'))->execute(); + } + $start = time(); + $item = FALSE; + $statement = db_select('queue', 'q'); + $statement->addField('q', 'item_id'); + $statement->condition('status', QUEUE_NEEDS_PROCESSING); + $statement->condition('queue_name', $this->queue_name); + $statement->range(0, 1); + do { + $item_id = $statement->execute()->fetchField(); + if ($item_id) { + db_update('queue')->fields(array('status' => QUEUE_UNDER_PROCESSING, 'process_id' => $this->process_id, 'timestamp' => time()))->condition('item_id', $item_id)->execute(); + $item = db_query('SELECT data, item_id FROM {queue} WHERE status = :status AND queue_name = :queue_name AND process_id = :process_id AND item_id = :item_id', array('status' => QUEUE_UNDER_PROCESSING, 'queue_name' => $this->queue_name, 'process_id' => $this->process_id, 'item_id' => $item_id))->fetchObject(); + } + else { + sleep(1); + } + } while (!$item && time() - $start < $timeout); + if ($item) { + $item->data = unserialize($item->data); + return $item; + } + } + + function finish($item) { + $item->status = QUEUE_DONE; + return drupal_write_record('queue', $item); + } +} === added file 'modules/queue/queue.test' --- modules/queue/queue.test 1970-01-01 00:00:00 +0000 +++ modules/queue/queue.test 2009-03-04 22:13:33 +0000 @@ -0,0 +1,50 @@ + 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]); + $new_items[] = queue_dequeue($queue1)->data; + $new_items[] = queue_dequeue($queue1)->data; + // 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]); + $new_items[] = queue_dequeue($queue1)->data; + $new_items[] = queue_dequeue($queue1)->data; + // 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')); + } + + function score($items, $new_items) { + $score = 0; + foreach ($items as $item) { + foreach ($new_items as $new_item) { + if ($item === $new_item) { + $score++; + } + } + } + return $score; + } +}