 apachesolr.index.inc | 101 ++++++++++++++++++++++-----------------------------
 1 file changed, 44 insertions(+), 57 deletions(-)

diff --git a/apachesolr.api.php b/apachesolr.api.php
old mode 100755
new mode 100644
diff --git a/apachesolr.index.inc b/apachesolr.index.inc
index b7479cf..2ed01c1 100644
--- a/apachesolr.index.inc
+++ b/apachesolr.index.inc
@@ -47,20 +47,8 @@ function apachesolr_index_entities($env_id, $limit) {
     $indexed = apachesolr_index_send_to_solr($env_id, $documents);
     if ($indexed !== FALSE) {
       $documents_submitted += count($documents);
-      $index_position = apachesolr_get_last_index_position($env_id, $entity_type);
-      $max_changed = $index_position['last_changed'];
-      $max_entity_id = $index_position['last_entity_id'];
-      foreach ($rows as $row) {
-        if (!empty($row->status)) {
-          if ($row->changed > $max_changed) {
-            $max_changed = $row->changed;
-          }
-          if ($row->entity_id > $max_entity_id) {
-            $max_entity_id = $row->entity_id;
-          }
-        }
-      }
-      apachesolr_set_last_index_position($env_id, $entity_type, $max_changed, $max_entity_id);
+      $last_row = end($rows);
+      apachesolr_set_last_index_position($env_id, $entity_type, $last_row->changed, $last_row->entity_id);
       apachesolr_set_last_index_updated($env_id, REQUEST_TIME);
     }
   }
@@ -96,6 +84,7 @@ function apachesolr_index_entities_document($row, $entity_type, $env_id) {
   }
   return $documents;
 }
+
 /**
  * Returns the total number of documents that are able to be indexed and the
  * number of documents left to be indexed.
@@ -126,26 +115,7 @@ function apachesolr_index_status($env_id) {
     $query = db_select($table, 'asn')->condition('asn.status', 1)->condition('asn.bundle', $bundles);
     $total += $query->countQuery()->execute()->fetchField();
 
-    // Get $last_entity_id and $last_change.
-    extract(apachesolr_get_last_index_position($env_id, $entity_type));
-    // Find the next batch of entities to index for this entity type.  Note that
-    // for ordering we're grabbing the oldest first and then ordering by ID so
-    // that we get a definitive order.
-    $query = db_select($table, 'aie')
-      ->condition('aie.bundle', $bundles)
-      ->condition('aie.status', 1)
-      ->condition(db_or()
-        ->condition('aie.changed', $last_changed, '>')
-        ->condition(db_and()
-          ->condition('aie.changed', $last_changed, '<=')
-          ->condition('aie.entity_id', $last_entity_id, '>')))
-      ->addTag('apachesolr_index_' . $entity_type);
-
-
-    if ($table == 'apachesolr_index_entities') {
-      // Other, entity-specific tables don't need this condition.
-      $query->condition('aie.entity_type', $entity_type);
-    }
+    $query = apachesolr_index_get_entities_to_index_get_query($env_id, $entity_type);
     $remaining += $query->countQuery()->execute()->fetchField();
   }
   return array('remaining' => $remaining, 'total' => $total);
@@ -440,29 +410,7 @@ function apachesolr_index_get_entities_to_index($env_id, $entity_type, $limit) {
     return $rows;
   }
 
-  $table = apachesolr_get_indexer_table($entity_type);
-  // Get $last_entity_id and $last_change.
-  extract(apachesolr_get_last_index_position($env_id, $entity_type));
-  // Find the next batch of entities to index for this entity type.  Note that
-  // for ordering we're grabbing the oldest first and then ordering by ID so
-  // that we get a definitive order.
-  // Also note that we fetch ALL fields from the indexer table
-  $query = db_select($table, 'aie')
-    ->fields('aie')
-    ->condition('aie.bundle', $bundles)
-    ->condition(db_or()
-      ->condition('aie.changed', $last_changed, '>')
-      ->condition(db_and()
-        ->condition('aie.changed', $last_changed, '<=')
-        ->condition('aie.entity_id', $last_entity_id, '>')))
-    ->orderBy('aie.changed', 'ASC')
-    ->orderBy('aie.entity_id', 'ASC')
-    ->addTag('apachesolr_index_' . $entity_type);
-
-  if ($table == 'apachesolr_index_entities') {
-    // Other, entity-specific tables don't need this condition.
-    $query->condition('aie.entity_type', $entity_type);
-  }
+  $query = apachesolr_index_get_entities_to_index_get_query($env_id, $entity_type);
   $query->range(0, $limit);
   $records = $query->execute();
 
@@ -484,6 +432,45 @@ function apachesolr_index_get_entities_to_index($env_id, $entity_type, $limit) {
 }
 
 /**
+ * Internal function to avoid duplicating logic that identifies entities
+ * still due to be indexed
+ *
+ * @param string $env_id Environment ID
+ * @param string $entity_type
+ * @return SelectQuery
+ */
+function apachesole_index_get_entities_to_index_get_query($env_id, $entity_type) {
+  $table = apachesolr_get_indexer_table($entity_type);
+  $last_index_position = apachesolr_get_last_index_position($env_id, $entity_type);
+
+  // Find the next batch of entities to index for this entity type.
+  // Also note that we fetch ALL fields from the indexer table
+  $query = db_select($table, 'aie')
+    ->fields('aie')
+    ->condition('aie.bundle', $bundles)
+    ->condition(db_or()
+      // Entities that have been changed more recently than the most up to date indexed entity
+      ->condition('aie.changed', $last_index_position['last_changed'], '>')
+      // Tie breaker for entities that were changed at exactly the same second as the last indexed entity
+      ->condition(db_and()
+        ->condition('aie.changed', $last_index_position['last_changed'], '=')
+        ->condition('aie.entity_id', $last_index_position['last_entity_id'], '>')
+      )
+    )
+    // It is important that everything is indexed in order of changed date
+    // then entity id, or the conditions above will not match correctly
+    ->orderBy('aie.changed', 'ASC')
+    ->orderBy('aie.entity_id', 'ASC')
+    ->addTag('apachesolr_index_' . $entity_type);
+
+  if ($table == 'apachesolr_index_entities') {
+    // Other, entity-specific tables don't need this condition.
+    $query->condition('aie.entity_type', $entity_type);
+  }
+  return $query;
+}
+
+/**
  * Delete the whole index for an environment.
  *
  * @param string $env_id
diff --git a/tests/solr_index_and_search.test b/tests/solr_index_and_search.test
old mode 100755
new mode 100644
