includes/Maintenance/Validators/SpecificAliasValidator.php
<?php
namespace CirrusSearch\Maintenance\Validators;
use CirrusSearch\Maintenance\Printer;
use CirrusSearch\Maintenance\Reindexer;
use Elastica\Client;
use MediaWiki\Language\RawMessage;
use MediaWiki\Status\Status;
class SpecificAliasValidator extends IndexAliasValidator {
/**
* @var Reindexer
*/
private $reindexer;
/**
* @var array
*/
private $reindexParams;
/**
* @var Validator[]
*/
private $reindexValidators;
/**
* @var bool
*/
private $reindexAndRemoveOk;
/**
* @param Client $client
* @param string $aliasName
* @param string $specificIndexName
* @param bool $startOver
* @param Reindexer $reindexer
* @param array $reindexParams
* @param Validator[] $reindexValidators
* @param bool $reindexAndRemoveOk
* @param Printer|null $out
*/
public function __construct(
Client $client,
$aliasName,
$specificIndexName,
$startOver,
Reindexer $reindexer,
array $reindexParams,
array $reindexValidators,
$reindexAndRemoveOk,
Printer $out = null
) {
// @todo: this constructor takes too many arguments - refactor!
parent::__construct( $client, $aliasName, $specificIndexName, $startOver, $out );
$this->reindexer = $reindexer;
$this->reindexParams = $reindexParams;
$this->reindexValidators = $reindexValidators;
$this->reindexAndRemoveOk = $reindexAndRemoveOk;
}
/**
* @param string[] $add
* @param string[] $remove
* @return Status
*/
protected function updateIndices( array $add, array $remove ) {
if ( !$remove ) {
return $this->updateFreeIndices( $add );
}
if ( !$this->reindexAndRemoveOk ) {
$this->output( "cannot correct!\n" );
return Status::newFatal( new RawMessage(
"The alias is held by another index which means it might be actively serving\n" .
"queries. You can solve this problem by running this program again with\n" .
"--reindexAndRemoveOk. Make sure you understand the consequences of either\n" .
"choice." ) );
}
try {
$this->output( "is taken...\n" );
$this->outputIndented( "\tReindexing...\n" );
$this->reindexer->reindex( ...$this->reindexParams );
# Expecting this to usually be a noop, index should have been created with
# appropriate settings and reindexer should restore all the settings it
# changed, but it couldn't hurt to check again.
foreach ( $this->reindexValidators as $validator ) {
$status = $validator->validate();
if ( !$status->isOK() ) {
return $status;
}
}
// Validators might have changed replica counts, wait for everything to
// get to green.
$this->reindexer->waitForGreen();
} catch ( \Exception $e ) {
return Status::newFatal( new RawMessage( $e->getMessage() ) );
}
// now add alias & remove indices for real
$status = Status::newGood();
$status->merge( $this->swapAliases( $add ) );
$toRemove = [];
foreach ( $remove as $indexToRemove ) {
$resp = $this->client->request( $indexToRemove . '/_alias', 'GET' );
if ( !$resp->isOk() ) {
return Status::newFatal( "Cannot fetch aliases of the old index $indexToRemove" );
}
if ( count( $resp->getData()[$indexToRemove]['aliases'] ?? [] ) > 0 ) {
$this->outputIndented( "\t$indexToRemove still have active aliases, cannot remove.\n" );
} else {
$toRemove[] = $indexToRemove;
}
}
$status->merge( parent::updateIndices( [], $toRemove ) );
return $status;
}
/**
* @param string[] $add
* @return Status
*/
public function updateFreeIndices( array $add ) {
$this->output( "alias is free..." );
foreach ( $add as $indexName ) {
$index = $this->client->getIndex( $indexName );
$index->addAlias( $this->aliasName, false );
}
$this->output( "corrected\n" );
return Status::newGood();
}
/**
* @param array $add
* @return Status
*/
public function swapAliases( array $add ) {
$this->outputIndented( "\tSwapping alias..." );
foreach ( $add as $indexName ) {
$index = $this->client->getIndex( $indexName );
$index->addAlias( $this->aliasName, true );
}
$this->output( "done\n" );
return Status::newGood();
}
/**
* @param string $name
* @return bool
*/
protected function shouldRemoveFromAlias( $name ) {
return true;
}
}