diff --git a/README.txt b/README.txt
index 9ea75ed..6ea6252 100644
--- a/README.txt
+++ b/README.txt
@@ -210,12 +210,6 @@ search_api_index_worker_callback_runtime:
   API will spend indexing (for all indexes combined) in each cron run. The
   default is 15 seconds.
 
-search_api_batch_per_cron:
-  By changing this variable, you can define how many batch items are created on
-  a single cron run. The value is per index, so on a site with 5 indexes with a
-  cron limit of 100 each, the default value of 10 will load and queue up to 5000
-  search items in up to 50 batch items.
-
 
 Information for developers
 --------------------------
diff --git a/includes/datasource.inc b/includes/datasource.inc
index ba0d2ba..a515d66 100644
--- a/includes/datasource.inc
+++ b/includes/datasource.inc
@@ -160,7 +160,9 @@ interface SearchApiDataSourceControllerInterface {
    * @param array $indexes
    *   The indexes for which the change should be tracked.
    * @param $dequeue
-   *   If set to TRUE, also change the status of queued items.
+   *   (deprecated) If set to TRUE, also change the status of queued items.
+   *   The concept of queued items will be removed in the Drupal 8 version of
+   *   this module.
    *
    * @throws SearchApiDataSourceException
    *   If any of the indexes doesn't use the same item type as this controller.
@@ -180,7 +182,12 @@ interface SearchApiDataSourceControllerInterface {
    *   The index for which the items were queued.
    *
    * @throws SearchApiDataSourceException
-   *   If any of the indexes doesn't use the same item type as this controller.
+   *   If the index doesn't use the same item type as this controller.
+   *
+   * @deprecated
+   *   As of Search API 1.10, the cron queue is not used for indexing anymore,
+   *   therefore this method has become useless. It will be removed in the
+   *   Drupal 8 version of this module.
    */
   public function trackItemQueued($item_ids, SearchApiIndex $index);
 
@@ -189,7 +196,7 @@ interface SearchApiDataSourceControllerInterface {
    *
    * @param array $item_ids
    *   The IDs of the indexed items.
-   * @param SearchApiIndex $indexes
+   * @param SearchApiIndex $index
    *   The index on which the items were indexed.
    *
    * @throws SearchApiDataSourceException
@@ -571,21 +578,7 @@ abstract class SearchApiAbstractDataSourceController implements SearchApiDataSou
   }
 
   /**
-   * Set the tracking status of the given items to "changed"/"dirty".
-   *
-   * Unless $dequeue is set to TRUE, this operation is ignored for items whose
-   * status is not "indexed".
-   *
-   * @param $item_ids
-   *   Either an array with the IDs of the changed items. Or FALSE to mark all
-   *   items as changed for the given indexes.
-   * @param array $indexes
-   *   The indexes for which the change should be tracked.
-   * @param $dequeue
-   *   If set to TRUE, also change the status of queued items.
-   *
-   * @throws SearchApiDataSourceException
-   *   If any of the indexes doesn't use the same item type as this controller.
+   * {@inheritdoc}
    */
   public function trackItemChange($item_ids, array $indexes, $dequeue = FALSE) {
     if (!$this->table) {
@@ -609,21 +602,10 @@ abstract class SearchApiAbstractDataSourceController implements SearchApiDataSou
   }
 
   /**
-   * Set the tracking status of the given items to "queued".
-   *
-   * Queued items are not marked as "dirty" even when they are changed, and they
-   * are not returned by the getChangedItems() method.
-   *
-   * @param $item_ids
-   *   Either an array with the IDs of the queued items. Or FALSE to mark all
-   *   items as queued for the given indexes.
-   * @param SearchApiIndex $index
-   *   The index for which the items were queued.
-   *
-   * @throws SearchApiDataSourceException
-   *   If any of the indexes doesn't use the same item type as this controller.
+   * {@inheritdoc}
    */
   public function trackItemQueued($item_ids, SearchApiIndex $index) {
+    $this->checkIndex($index);
     if (!$this->table) {
       return;
     }
diff --git a/includes/index_entity.inc b/includes/index_entity.inc
index d36b2f8..dc45666 100644
--- a/includes/index_entity.inc
+++ b/includes/index_entity.inc
@@ -230,7 +230,6 @@ class SearchApiIndex extends Entity {
    */
   public function dequeueItems() {
     $this->datasource()->stopTracking(array($this));
-    _search_api_empty_cron_queue($this);
   }
 
   /**
diff --git a/search_api.install b/search_api.install
index 8a3366c..f39608c 100644
--- a/search_api.install
+++ b/search_api.install
@@ -330,7 +330,6 @@ function search_api_disable() {
       // Modules defining entity or item types might have been disabled. Ignore.
     }
   }
-  DrupalQueue::get('search_api_indexing_queue')->deleteQueue();
 }
 
 /**
@@ -813,3 +812,17 @@ function search_api_update_7114() {
     }
   }
 }
+
+/**
+ * Switch to indexing without the use of a cron queue.
+ */
+function search_api_update_7115() {
+  variable_del('search_api_batch_per_cron');
+  DrupalQueue::get('search_api_indexing_queue')->deleteQueue();
+  db_update('search_api_item')
+    ->fields(array(
+      'changed' => 1,
+    ))
+    ->condition('changed', 0, '<')
+    ->execute();
+}
diff --git a/search_api.module b/search_api.module
index 395a230..2c66198 100644
--- a/search_api.module
+++ b/search_api.module
@@ -265,51 +265,66 @@ function search_api_permission() {
  * Will index $options['cron-limit'] items for each enabled index.
  */
 function search_api_cron() {
-  $queue = DrupalQueue::get('search_api_indexing_queue');
-  foreach (search_api_index_load_multiple(FALSE, array('enabled' => TRUE, 'read_only' => 0)) as $index) {
-    $limit = isset($index->options['cron_limit'])
+  // Load all enabled, not read-only indexes.
+  $conditions = array(
+    'enabled' => TRUE,
+    'read_only' => 0
+  );
+  $indexes = search_api_index_load_multiple(FALSE, $conditions);
+  if (!$indexes) {
+    return;
+  }
+  // Remember servers which threw an exception.
+  $ignored_servers = array();
+  // Continue indexing, one batch from each index, until the time is up, but at
+  // least index one batch per index.
+  $end = time() + variable_get('search_api_index_worker_callback_runtime', 15);
+  $first_pass = TRUE;
+  while (TRUE) {
+    if (!$indexes) {
+      break;
+    }
+    foreach ($indexes as $id => $index) {
+      if (!$first_pass && time() >= $end) {
+        break 2;
+      }
+      if (!empty($ignored_servers[$index->server])) {
+        continue;
+      }
+
+      $limit = isset($index->options['cron_limit'])
         ? $index->options['cron_limit']
         : SEARCH_API_DEFAULT_CRON_LIMIT;
-    if ($limit) {
-      try {
-        $task = array('index' => $index->machine_name);
-        // Fetch items to index, do not fetch more than the configured amount
-        // of batches to be created per cron run to avoid timeouts.
-        $ids = search_api_get_items_to_index($index, $limit > 0 ? $limit * variable_get('search_api_batch_per_cron', 10) : -1);
-        if (!$ids) {
-          continue;
+      $num = 0;
+      if ($limit) {
+        try {
+          $num = search_api_index_items($index, $limit);
+          if ($num) {
+            $variables = array(
+              '@num' => $num,
+              '%name' => $index->name
+            );
+            watchdog('search_api', 'Indexed @num items for index %name.', $variables, WATCHDOG_INFO);
+          }
         }
-        $batches = $limit > 0 ? array_chunk($ids, $limit, TRUE) : array($ids);
-        foreach ($batches as $batch) {
-          $task['items'] = $batch;
-          $queue->createItem($task);
+        catch (SearchApiException $e) {
+          // Exceptions will probably be caused by the server in most cases.
+          // Therefore, don't index for any index on this server.
+          $ignored_servers[$index->server] = TRUE;
+          watchdog_exception('search_api', $e);
         }
-        // Mark items as queued so they won't be inserted into the queue again
-        // on the next cron run.
-        search_api_track_item_queued($index, $ids);
       }
-      catch (SearchApiException $e) {
-        watchdog_exception('search_api', $e);
+      if  (!$num) {
+        // Couldn't index any items => stop indexing for this index in this
+        // cron run.
+        unset($indexes[$id]);
       }
     }
+    $first_pass = FALSE;
   }
 }
 
 /**
- * Implements hook_cron_queue_info().
- *
- * Defines a queue for saved searches that should be checked for new items.
- */
-function search_api_cron_queue_info() {
-  return array(
-    'search_api_indexing_queue' => array(
-      'worker callback' => '_search_api_indexing_queue_process',
-      'time' => variable_get('search_api_index_worker_callback_runtime', 15),
-    ),
-  );
-}
-
-/**
  * Implements hook_entity_info().
  */
 function search_api_entity_info() {
@@ -696,15 +711,6 @@ function search_api_search_api_index_update(SearchApiIndex $index) {
       $index->queueItems();
     }
   }
-
-  // If the cron batch size changed, empty the cron queue for this index.
-  $old_cron = $index->original->options + array('cron_limit' => NULL);
-  $old_cron = $old_cron['cron_limit'];
-  $new_cron = $index->options + array('cron_limit' => NULL);
-  $new_cron = $new_cron['cron_limit'];
-  if ($old_cron !== $new_cron) {
-    _search_api_empty_cron_queue($index, TRUE);
-  }
 }
 
 /**
@@ -1142,6 +1148,12 @@ function search_api_track_item_change($type, array $item_ids) {
  *   The index on which items were queued.
  * @param array $item_ids
  *   The ids of the queued items.
+ *
+ * @deprecated
+ *   As of Search API 1.10, the cron queue is not used for indexing anymore,
+ *   therefore this function has become useless. It will, along with
+ *   SearchApiDataSourceControllerInterface::trackItemQueued(), be removed in
+ *   the Drupal 8 version of this module.
  */
 function search_api_track_item_queued(SearchApiIndex $index, array $item_ids) {
   $index->datasource()->trackItemQueued($item_ids, $index);
@@ -1278,53 +1290,31 @@ function _search_api_settings_equals($setting1, $setting2) {
 }
 
 /**
- * Indexes items for the specified index. Only items marked as changed are
- * indexed, in their order of change (if known).
+ * Indexes items for the specified index.
+ *
+ * Only items marked as changed are indexed, in their order of change (if
+ * known).
  *
  * @param SearchApiIndex $index
  *   The index on which items should be indexed.
- * @param $limit
- *   The number of items which should be indexed at most. -1 means no limit.
+ * @param int $limit
+ *   (optional) The number of items which should be indexed at most. Defaults to
+ *   -1, which means that all changed items should be indexed.
+ *
+ * @return int
+ *   Number of successfully indexed items.
  *
  * @throws SearchApiException
  *   If any error occurs during indexing.
- *
- * @return
- *   Number of successfully indexed items.
  */
 function search_api_index_items(SearchApiIndex $index, $limit = -1) {
-  // Don't try to index read-only indexes.
+  // Don't try to index on read-only indexes.
   if ($index->read_only) {
     return 0;
   }
 
-  $queue = DrupalQueue::get('search_api_indexing_queue');
-  $queue->createQueue();
-  $indexed = 0;
-  $unlimited = $limit < 0;
-  $release_items = array();
-  while (($unlimited || $indexed < $limit) && ($item = $queue->claimItem(30))) {
-    if ($item->data['index'] === $index->machine_name) {
-      $indexed += _search_api_indexing_queue_process($item->data);
-      $queue->deleteItem($item);
-    }
-    else {
-      $release_items[] = $item;
-    }
-  }
-
-  foreach ($release_items as $item) {
-    $queue->releaseItem($item);
-  }
-
-  if ($unlimited || $indexed < $limit) {
-    $ids = search_api_get_items_to_index($index, $unlimited ? -1 : $limit - $indexed);
-    if ($ids) {
-      $indexed += count(search_api_index_specific_items($index, $ids));
-    }
-  }
-
-  return $indexed;
+  $ids = search_api_get_items_to_index($index, $limit);
+  return $ids ? count(search_api_index_specific_items($index, $ids)) : 0;
 }
 
 /**
@@ -1337,11 +1327,11 @@ function search_api_index_items(SearchApiIndex $index, $limit = -1) {
  * @param array $ids
  *   The IDs of the items which should be indexed.
  *
+ * @return array
+ *   The IDs of all successfully indexed items.
+ *
  * @throws SearchApiException
  *   If any error occurs during indexing.
- *
- * @return
- *   The IDs of all successfully indexed items.
  */
 function search_api_index_specific_items(SearchApiIndex $index, array $ids) {
   $items = $index->loadItems($ids);
@@ -2475,42 +2465,6 @@ function search_api_index_reindex($id) {
  */
 function _search_api_index_reindex(SearchApiIndex $index) {
   $index->datasource()->trackItemChange(FALSE, array($index), TRUE);
-  _search_api_empty_cron_queue($index);
-}
-
-/**
- * Helper method for removing all of an index's jobs from the cron queue.
- *
- * @param SearchApiIndex $index
- *   The index whose jobs should be removed.
- * @param $mark_changed
- *   If TRUE, mark all items in the queue as "changed" again. Defaults to FALSE.
- */
-function _search_api_empty_cron_queue(SearchApiIndex $index, $mark_changed = FALSE) {
-  $index_id = $index->machine_name;
-  $queue = DrupalQueue::get('search_api_indexing_queue');
-  $queue->createQueue();
-  $ids = array();
-  $release_items = array();
-  while ($item = $queue->claimItem()) {
-    if ($item->data['index'] === $index_id) {
-      $queue->deleteItem($item);
-      if ($mark_changed) {
-        $ids = array_merge($ids, $item->data['items']);
-      }
-    }
-    else {
-      $release_items[] = $item;
-    }
-  }
-
-  foreach ($release_items as $item) {
-    $queue->releaseItem($item);
-  }
-
-  if ($ids) {
-    $index->datasource()->trackItemChange($ids, array($index), TRUE);
-  }
 }
 
 /**
@@ -2563,42 +2517,6 @@ function search_api_index_options_list() {
 }
 
 /**
- * Cron queue worker callback for indexing some items.
- *
- * @param array $task
- *   An associative array containing:
- *   - index: The ID of the index on which items should be indexed.
- *   - items: The items that should be indexed.
- *
- * @return
- *   The number of successfully indexed items.
- */
-function _search_api_indexing_queue_process(array $task) {
-  $index = search_api_index_load($task['index']);
-  try {
-    if ($index && $index->enabled && !$index->read_only && $task['items']) {
-      $indexed = search_api_index_specific_items($index, $task['items']);
-      $num = count($indexed);
-      // If some items couldn't be indexed, mark them as dirty again.
-      if ($num < count($task['items'])) {
-        // Believe it or not but this is actually quite faster than the equivalent
-        // $diff = array_diff($task['items'], $indexed);
-        $diff = array_keys(array_diff_key(array_flip($task['items']), array_flip($indexed)));
-        // Mark the items as dirty again.
-        $index->datasource()->trackItemChange($diff, array($index), TRUE);
-      }
-      if ($num) {
-        watchdog('search_api', t('Indexed @num items for index @name', array('@num' => $num, '@name' => $index->name)), NULL, WATCHDOG_INFO);
-      }
-      return $num;
-    }
-  }
-  catch (SearchApiException $e) {
-    watchdog_exception('search_api', $e);
-  }
-}
-
-/**
  * Shutdown function which indexes all queued items, if any.
  */
 function _search_api_index_queued_items() {
diff --git a/search_api.test b/search_api.test
index 1748627..bc80cb4 100644
--- a/search_api.test
+++ b/search_api.test
@@ -43,13 +43,14 @@ class SearchApiWebTest extends DrupalWebTestCase {
     $this->insertItems();
     $this->checkOverview1();
     $this->createIndex();
-    $this->insertItems(5);
+    $this->insertItems();
     $this->createServer();
     $this->checkOverview2();
     $this->enableIndex();
     $this->searchNoResults();
     $this->indexItems();
     $this->searchSuccess();
+    $this->checkIndexingOrder();
     $this->editServer();
     $this->clearIndex();
     $this->searchNoResults();
@@ -61,40 +62,19 @@ class SearchApiWebTest extends DrupalWebTestCase {
     $this->drupalPost('admin/config/search/search_api/index/default_node_index/delete', array(), t('Confirm'));
   }
 
-  protected function insertItems($offset = 0) {
+  protected function insertItems($number = 5) {
     $count = db_query('SELECT COUNT(*) FROM {search_api_test}')->fetchField();
-    $this->insertItem(array(
-      'id' => $offset + 1,
-      'title' => 'Title 1',
-      'body' => 'Body text 1.',
-      'type' => 'Item',
-    ));
-    $this->insertItem(array(
-      'id' => $offset + 2,
-      'title' => 'Title 2',
-      'body' => 'Body text 2.',
-      'type' => 'Item',
-    ));
-    $this->insertItem(array(
-      'id' => $offset + 3,
-      'title' => 'Title 3',
-      'body' => 'Body text 3.',
-      'type' => 'Item',
-    ));
-    $this->insertItem(array(
-      'id' => $offset + 4,
-      'title' => 'Title 4',
-      'body' => 'Body text 4.',
-      'type' => 'Page',
-    ));
-    $this->insertItem(array(
-      'id' => $offset + 5,
-      'title' => 'Title 5',
-      'body' => 'Body text 5.',
-      'type' => 'Page',
-    ));
+    for ($i = 1; $i <= $number; ++$i) {
+      $id = $count + $i;
+      $this->insertItem(array(
+        'id' => $id,
+        'title' => "Title $id",
+        'body' => "Body text $id.",
+        'type' => 'Item',
+      ));
+    }
     $count = db_query('SELECT COUNT(*) FROM {search_api_test}')->fetchField() - $count;
-    $this->assertEqual($count, 5, '5 items successfully inserted.');
+    $this->assertEqual($count, $number, "$number items successfully inserted.");
   }
 
   protected function insertItem($values) {
@@ -299,8 +279,8 @@ class SearchApiWebTest extends DrupalWebTestCase {
 
     // Here we test the indexing + the warning message when some items
     // can not be indexed.
-    // The server refuses (for test purpose) to index items with IDs that are
-    // multiples of 8 unless the "search_api_test_index_all" variable is set.
+    // The server refuses (for test purpose) to index the item that has the same
+    // ID as the "search_api_test_indexing_break" variable (default: 8).
     $values = array(
       'limit' => 8,
     );
@@ -322,7 +302,7 @@ class SearchApiWebTest extends DrupalWebTestCase {
     $this->assertText(t("Couldn't index items. Check the logs for details."), 'Index error is displayed.');
 
     // Here we test the indexing of all the remaining items.
-    variable_set('search_api_test_index_all', TRUE);
+    variable_set('search_api_test_indexing_break', 0);
     $values = array(
       'limit' => -1,
     );
@@ -344,6 +324,87 @@ class SearchApiWebTest extends DrupalWebTestCase {
     $this->assertText('results = (3, 4, 5, 6)', 'Correct search results with ranged query.');
   }
 
+  protected function checkIndexingOrder() {
+    // Set cron batch size to 1 so not all items will get indexed right away.
+    $values = array(
+      'options[cron_limit]' => 1,
+    );
+    $this->drupalPost("admin/config/search/search_api/index/{$this->index_id}/edit", $values, t('Save settings'));
+    $this->assertText(t('The search index was successfully edited.'));
+
+    // Manually clear the server's item storage – that way, the items will still
+    // count as  indexed for the Search API, but won't be returned in searches.
+    // We do this so we have finer-grained control over the order in which items
+    // are indexed.
+    search_api_server_load($this->server_id, TRUE)->deleteItems();
+    $this->drupalGet('search_api_test/query/' . $this->index_id);
+    $this->assertText('result count = 0', 'Indexed items were successfully deleted from the server.');
+    $this->assertText('results = ()', 'Indexed items were successfully deleted from the server.');
+
+    // Now insert some new items, and mark others as changed.
+    $this->drupalGet('search_api_test/touch/8');
+    $this->insertItems(1);// item 11
+    $this->drupalGet('search_api_test/touch/2');
+    $this->insertItems(1);// item 12
+    $this->drupalGet('search_api_test/touch/5');
+    $this->insertItems(1);// item 13
+    $this->drupalGet('search_api_test/touch/8');
+    $this->insertItems(1); // item 14
+
+    // Check whether the status display is right.
+    $this->drupalGet("admin/config/search/search_api/index/{$this->index_id}/status");
+    $variables = array(
+      '@indexed' => 7,
+      '@total' => 14,
+      '@percentage' => 50,
+    );
+    $this->assertText(t('About @percentage% of all items have been indexed in their latest version (@indexed / @total).', $variables), 'Correct index status displayed after inserting and changing items.');
+
+    // Indexing order should now be: 11, 12, 13, 14, 8, 2, 4. Let's try it out!
+    // First manually index one item, and see if it's 11.
+    $values = array(
+      'limit' => 1,
+    );
+    $this->drupalPost(NULL, $values, t('Index now'));
+    $this->assertText(t('Successfully indexed @count item.', array('@count' => 1)));
+    $this->assertNoText(t("Some items couldn't be indexed. Check the logs for details."), "Index errors warning isn't displayed.");
+    $this->assertNoText(t("Couldn't index items. Check the logs for details."), "Index error isn't displayed.");
+    $variables = array(
+      '@indexed' => 8,
+      '@total' => 14,
+      '@percentage' => 57,
+    );
+    $this->assertText(t('About @percentage% of all items have been indexed in their latest version (@indexed / @total).', $variables), 'Correct index status displayed after inserting and changing items.');
+
+    $this->drupalGet('search_api_test/query/' . $this->index_id);
+    $this->assertText('result count = 1', 'Indexing order test 1: correct result count.');
+    $this->assertText('results = (11)', 'Indexing order test 1: correct results.');
+
+    // Now index with a cron run, but stop at item 8.
+    variable_set('search_api_test_indexing_break', 8);
+    $this->cronRun();
+    // Now just the four new items should have been indexed.
+    $this->drupalGet('search_api_test/query/' . $this->index_id);
+    $this->assertText('result count = 4', 'Indexing order test 2: correct result count.');
+    $this->assertText('results = (11, 12, 13, 14)', 'Indexing order test 2: correct results.');
+
+    // This time stop at item 4 (should be the last one).
+    variable_set('search_api_test_indexing_break', 5);
+    $this->cronRun();
+    // Now all new and changed items should have been indexed, except 4.
+    $this->drupalGet('search_api_test/query/' . $this->index_id);
+    $this->assertText('result count = 6', 'Indexing order test 3: correct result count.');
+    $this->assertText('results = (2, 8, 11, 12, 13, 14)', 'Indexing order test 3: correct results.');
+
+    // Index the remaining items.
+    variable_set('search_api_test_indexing_break', 0);
+    $this->cronRun();
+    // Now all new and changed items should have been indexed.
+    $this->drupalGet('search_api_test/query/' . $this->index_id);
+    $this->assertText('result count = 7', 'Indexing order test 4: correct result count.');
+    $this->assertText('results = (2, 5, 8, 11, 12, 13, 14)', 'Indexing order test 4: correct results.');
+  }
+
   protected function editServer() {
     $values = array(
       'name' => 'test-name-foo',
@@ -360,7 +421,7 @@ class SearchApiWebTest extends DrupalWebTestCase {
   protected function clearIndex() {
     $this->drupalPost("admin/config/search/search_api/index/{$this->index_id}/status", array(), t('Clear index'));
     $this->assertText(t('The index was successfully cleared.'));
-    $this->assertText(t('All items still need to be indexed (@total total).', array('@total' => 10)), 'Correct index status displayed.');
+    $this->assertText(t('All items still need to be indexed (@total total).', array('@total' => 14)), 'Correct index status displayed.');
   }
 
   protected function deleteServer() {
diff --git a/tests/search_api_test.module b/tests/search_api_test.module
index 8a4ff82..659a5fe 100644
--- a/tests/search_api_test.module
+++ b/tests/search_api_test.module
@@ -11,10 +11,16 @@ function search_api_test_menu() {
       'page arguments' => array('search_api_test_insert_item'),
       'access callback' => TRUE,
     ),
-    'search_api_test/%search_api_test' => array(
+    'search_api_test/view/%search_api_test' => array(
       'title' => 'View item',
       'page callback' => 'search_api_test_view',
-      'page arguments' => array(1),
+      'page arguments' => array(2),
+      'access callback' => TRUE,
+    ),
+    'search_api_test/touch/%search_api_test' => array(
+      'title' => 'Mark item as changed',
+      'page callback' => 'search_api_test_touch',
+      'page arguments' => array(2),
       'access callback' => TRUE,
     ),
     'search_api_test/query/%search_api_index' => array(
@@ -81,6 +87,13 @@ function search_api_test_view($entity) {
 }
 
 /**
+ * Menu callback for marking a "search_api_test" entity as changed.
+ */
+function search_api_test_touch($entity) {
+  module_invoke_all('entity_update', $entity, 'search_api_test');
+}
+
+/**
  * Menu callback for executing a search.
  */
 function search_api_test_query(SearchApiIndex $index, $keys = 'foo bar', $offset = 0, $limit = 10, $fields = NULL, $sort = NULL, $filters = NULL) {
@@ -250,25 +263,23 @@ class SearchApiTestService extends SearchApiAbstractService {
   }
 
   public function indexItems(SearchApiIndex $index, array $items) {
-    // Refuse to index items with IDs that are multiples of 8 unless the
-    // "search_api_test_index_all" variable is set.
-    if (variable_get('search_api_test_index_all', FALSE)) {
-      return $this->index($index, array_keys($items));
-    }
-    $ret = array();
-    foreach ($items as $id => $item) {
-      if ($id % 8) {
-        $ret[] = $id;
+    // Refuse to index the item with the  same ID as the
+    // "search_api_test_indexing_break" variable, if it is set.
+    if ($mod = variable_get('search_api_test_indexing_break', 8)) {
+      foreach ($items as $id => $item) {
+        if ($id == $mod) {
+          unset($items[$id]);
+        }
       }
-    }
-    return $this->index($index, $ret);
+  }
+    return $this->index($index, array_keys($items));
   }
 
   protected function index(SearchApiIndex $index, array $ids) {
     $this->options += array('indexes' => array());
     $this->options['indexes'] += array($index->machine_name => array());
     $this->options['indexes'][$index->machine_name] += drupal_map_assoc($ids);
-    sort($this->options['indexes'][$index->machine_name]);
+    asort($this->options['indexes'][$index->machine_name]);
     $this->server->save();
     return $ids;
   }
