Commit ddd534f8 authored by Andy Fowlston's avatar Andy Fowlston Committed by Thomas Seidl
Browse files

Issue #3229495 by AndyF, drunken monkey: Fixed "start batch tracking" functionality for indexes.

parent 597366b0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
Search API 1.x, dev (xxxx-xx-xx):
---------------------------------
- #3229495 by AndyF, drunken monkey: Fixed "start batch tracking" functionality
  for indexes.
- #3238635 by drunken monkey, mkalkbrenner: Added the
  AutocompleteBackendInterface.
- #3221103 by drunken monkey: Fixed small bug in Views fulltext search filter.
+14 −12
Original line number Diff line number Diff line
@@ -96,6 +96,13 @@ class Index extends ConfigEntityBase implements IndexInterface {
  use InstallingTrait;
  use LoggerTrait;

  /**
   * The number of currently active "batch tracking" modes for each index.
   *
   * @var int[]
   */
  protected static $batchTrackingIndexes = [];

  /**
   * The ID of the index.
   *
@@ -272,13 +279,6 @@ class Index extends ConfigEntityBase implements IndexInterface {
   */
  protected $properties = [];

  /**
   * The number of currently active "batch tracking" modes.
   *
   * @var int
   */
  protected $batchTracking = 0;

  /**
   * {@inheritdoc}
   */
@@ -1030,14 +1030,15 @@ class Index extends ConfigEntityBase implements IndexInterface {
   * {@inheritdoc}
   */
  public function isBatchTracking() {
    return (bool) $this->batchTracking;
    return (static::$batchTrackingIndexes[$this->id] ?? 0) > 0;
  }

  /**
   * {@inheritdoc}
   */
  public function startBatchTracking() {
    $this->batchTracking++;
    static::$batchTrackingIndexes += [$this->id => 0];
    ++static::$batchTrackingIndexes[$this->id];
    return $this;
  }

@@ -1045,10 +1046,10 @@ class Index extends ConfigEntityBase implements IndexInterface {
   * {@inheritdoc}
   */
  public function stopBatchTracking() {
    if (!$this->batchTracking) {
    if (!$this->isBatchTracking()) {
      throw new SearchApiException('Trying to leave "batch tracking" mode on index "' . $this->label() . '" which was not entered first.');
    }
    $this->batchTracking--;
    --static::$batchTrackingIndexes[$this->id];
    return $this;
  }

@@ -1087,7 +1088,8 @@ class Index extends ConfigEntityBase implements IndexInterface {
        $item_ids[] = Utility::createCombinedId($datasource_id, $id);
      }
      $this->getTrackerInstance()->$tracker_method($item_ids);
      if (!$this->isReadOnly() && $this->getOption('index_directly') && !$this->batchTracking) {
      if (!$this->isReadOnly() && $this->getOption('index_directly')
          && !$this->isBatchTracking()) {
        \Drupal::getContainer()->get('search_api.post_request_indexing')
          ->registerIndexingOperation($this->id(), $item_ids);
      }
+161 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\search_api\Kernel;

use Drupal\entity_test\Entity\EntityTest;
use Drupal\KernelTests\KernelTestBase;
use Drupal\search_api\Entity\Index;
use Drupal\search_api\Entity\Server;
use Drupal\search_api\IndexInterface;
use Drupal\search_api\SearchApiException;

/**
 * Provides tests for the "index_directly" functionality.
 *
 * @group search_api
 */
class DirectIndexingTest extends KernelTestBase {

  use PostRequestIndexingTrait;

  /**
   * The search server used for testing.
   *
   * @var \Drupal\search_api\ServerInterface
   */
  protected $server;

  /**
   * {@inheritdoc}
   */
  protected static $modules = [
    'search_api',
    'search_api_test',
    'user',
    'system',
    'entity_test',
  ];

  /**
   * {@inheritdoc}
   */
  public function setUp(): void {
    parent::setUp();

    $this->installSchema('search_api', ['search_api_item']);
    $this->installEntitySchema('entity_test');
    $this->installEntitySchema('search_api_task');
    $this->installConfig('search_api');

    // Create a test server.
    $this->server = Server::create([
      'name' => 'Test server',
      'id' => 'test',
      'status' => 1,
      'backend' => 'search_api_test',
    ]);
    $this->server->save();
  }

  /**
   * Tests index_directly works and is overridden by start/stopBatchTracking().
   */
  public function testDirectIndexing(): void {
    // Create a test entity for indexing.
    $entity = EntityTest::create([
      'name' => 'Test entity',
      'type' => 'entity_test',
    ]);
    $entity->save();
    // Create a second test entity that never gets updated and should never get
    // directly indexed.
    EntityTest::create([
      'name' => 'Test entity 2',
      'type' => 'entity_test',
    ])->save();

    // Create two indexes to ensure batch tracking is isolated.
    $index_1 = $this->createIndex();
    $index_1->save();
    $tracker_1 = $index_1->getTrackerInstance();
    $index_2 = $this->createIndex();
    $index_2->save();
    $tracker_2 = $index_2->getTrackerInstance();

    // At first nothing is indexed.
    $this->assertEquals(2, $tracker_1->getTotalItemsCount());
    $this->assertEquals(0, $tracker_1->getIndexedItemsCount());
    $this->assertEquals(2, $tracker_2->getTotalItemsCount());
    $this->assertEquals(0, $tracker_2->getIndexedItemsCount());

    // Start batch tracking mode for index 1 only.
    $index_1->startBatchTracking();
    $entity->save();
    $this->triggerPostRequestIndexing();

    // Index 1 shouldn't have indexed the entity; index 2 should've indexed as
    // normal.
    $this->assertEquals(2, $tracker_1->getTotalItemsCount());
    $this->assertEquals(0, $tracker_1->getIndexedItemsCount());
    $this->assertEquals(2, $tracker_2->getTotalItemsCount());
    $this->assertEquals(1, $tracker_2->getIndexedItemsCount());

    // Start batch tracking mode a second time for index 1.
    $index_1->startBatchTracking();
    $entity->save();
    $this->triggerPostRequestIndexing();

    // Index 1 shouldn't have indexed anything.
    $this->assertEquals(2, $tracker_1->getTotalItemsCount());
    $this->assertEquals(0, $tracker_1->getIndexedItemsCount());

    // Make a call to stop batch tracking: because we've started it twice, this
    // shouldn't actually stop batch tracking.
    $index_1->stopBatchTracking();
    $entity->save();
    $this->triggerPostRequestIndexing();

    // Index 1 still shouldn't have indexed the entity because it's in batch
    // tracking mode.
    $this->assertEquals(2, $tracker_1->getTotalItemsCount());
    $this->assertEquals(0, $tracker_1->getIndexedItemsCount());

    // Make a second call to stop batch tracking: this should actually stop
    // batch tracking mode.
    $index_1->stopBatchTracking();
    $entity->save();
    $this->triggerPostRequestIndexing();

    // Index 1 should now have indexed the entity because batch tracking mode's
    // been stopped.
    $this->assertEquals(2, $tracker_1->getTotalItemsCount());
    $this->assertEquals(1, $tracker_1->getIndexedItemsCount());

    // An exception should be thrown if you try to stop batch tracking again.
    $this->expectException(SearchApiException::class);
    $index_1->stopBatchTracking();
  }

  /**
   * Creates a test index.
   *
   * @return \Drupal\search_api\IndexInterface
   *   A test index.
   */
  protected function createIndex(): IndexInterface {
    return Index::create([
      'name' => $this->getRandomGenerator()->string(),
      'id' => $this->getRandomGenerator()->name(),
      'status' => 1,
      'datasource_settings' => [
        'entity:entity_test' => [],
      ],
      'tracker_settings' => [
        'default' => [],
      ],
      'server' => $this->server->id(),
      'options' => ['index_directly' => TRUE],
    ]);
  }

}