%PDF- %PDF-
Direktori : /www/varak.net/wiki.varak.net/extensions/CirrusSearch/includes/ |
Current File : /www/varak.net/wiki.varak.net/extensions/CirrusSearch/includes/Connection.php |
<?php namespace CirrusSearch; use ElasticaConnection; use MWNamespace; use CirrusSearch\Maintenance\MetaStoreIndex; /** * Forms and caches connection to Elasticsearch as well as client objects * that contain connection information like \Elastica\Index and \Elastica\Type. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html */ class Connection extends ElasticaConnection { /** * Name of the index that holds content articles. * @var string */ const CONTENT_INDEX_TYPE = 'content'; /** * Name of the index that holds non-content articles. * @var string */ const GENERAL_INDEX_TYPE = 'general'; /** * Name of the index that hosts content title suggestions * @var string */ const TITLE_SUGGEST_TYPE = 'titlesuggest'; /** * Name of the page type. * @var string */ const PAGE_TYPE_NAME = 'page'; /** * Name of the namespace type. * @var string */ const NAMESPACE_TYPE_NAME = 'namespace'; /** * Name of the title suggest type * @var string */ const TITLE_SUGGEST_TYPE_NAME = 'titlesuggest'; /** * @var SearchConfig */ protected $config; /** * @var string */ protected $cluster; /** * @var ClusterSettings|null */ private $clusterSettings; /** * @var Connection[] */ private static $pool = []; /** * @param SearchConfig $config * @param string|null $cluster * @return Connection */ public static function getPool( SearchConfig $config, $cluster = null ) { if ( $cluster === null ) { $cluster = $config->get( 'CirrusSearchDefaultCluster' ); } $wiki = $config->getWikiId(); if ( isset( self::$pool[$wiki][$cluster] ) ) { return self::$pool[$wiki][$cluster]; } else { return new self( $config, $cluster ); } } /** * Pool state must be cleared when forking. Also useful * in tests. */ public static function clearPool() { self::$pool = []; } /** * @param SearchConfig $config * @param string|null $cluster Name of cluster to use, or * null for the default cluster. */ public function __construct( SearchConfig $config, $cluster = null ) { $this->config = $config; if ( $cluster === null ) { $this->cluster = $config->get( 'CirrusSearchDefaultCluster' ); } else { $this->cluster = $cluster; } $this->setConnectTimeout( $this->getSettings()->getConnectTimeout() ); // overwrites previous connection if it exists, but these // seemed more centralized than having the entry points // all call a static method unnecessarily. self::$pool[$config->getWikiId()][$this->cluster] = $this; } public function __sleep() { throw new \RuntimeException( 'Attempting to serialize ES connection' ); } /** * @return string */ public function getClusterName() { return $this->cluster; } /** * @return ClusterSettings */ public function getSettings() { if ( $this->clusterSettings === null ) { $this->clusterSettings = new ClusterSettings( $this->config, $this->cluster ); } return $this->clusterSettings; } /** * @return string[]|array[] Either a list of hostnames, for default * connection configuration or an array of arrays giving full connection * specifications. */ public function getServerList() { // This clause provides backwards compatibility with previous versions // of CirrusSearch. Once this variable is removed cluster configuration // will work as expected. if ( $this->config->has( 'CirrusSearchServers' ) ) { return $this->config->get( 'CirrusSearchServers' ); } $config = $this->config->getElement( 'CirrusSearchClusters', $this->cluster ); if ( $config === null ) { throw new \RuntimeException( "No configuration available for cluster: {$this->cluster}" ); } // Elastica will only create transports from within it's own // namespace. To use the CirrusSearch PooledHttp(s) this // clause is necessary. foreach ( $config as $idx => $server ) { if ( isset( $server['transport'] ) && class_exists( $server['transport'] ) ) { $transportClass = $server['transport']; $config[$idx]['transport'] = new $transportClass; } } return $config; } /** * How many times can we attempt to connect per host? * * @return int */ public function getMaxConnectionAttempts() { return $this->config->get( 'CirrusSearchConnectionAttempts' ); } /** * @return \Elastica\Type */ public function getFrozenIndexNameType() { return MetaStoreIndex::getFrozenType( $this ); } /** * Fetch the Elastica Type for pages. * @param mixed $name basename of index * @param mixed $type type of index (content or general or false to get all) * @return \Elastica\Type */ public function getPageType( $name, $type = false ) { return $this->getIndex( $name, $type )->getType( self::PAGE_TYPE_NAME ); } /** * Fetch the Elastica Type for namespaces. * @param mixed $name basename of index * @return \Elastica\Type */ public function getNamespaceType( $name ) { $type = 'general'; // Namespaces are always stored in the 'general' index. return $this->getIndex( $name, $type )->getType( self::NAMESPACE_TYPE_NAME ); } /** * Get all index types we support, content, general, plus custom ones * * @return string[] */ public function getAllIndexTypes() { return array_merge( array_values( $this->config->get( 'CirrusSearchNamespaceMappings' ) ), [ self::CONTENT_INDEX_TYPE, self::GENERAL_INDEX_TYPE ] ); } /** * @param string $name * @return string * @throws Exception */ public function extractIndexSuffix( $name ) { $matches = []; $possible = implode( '|', array_map( 'preg_quote', $this->getAllIndexTypes() ) ); if ( !preg_match( "/_($possible)_[^_]+$/", $name, $matches ) ) { throw new \Exception( "Can't parse index name: $name" ); } return $matches[1]; } /** * Get the index suffix for a given namespace * @param int $namespace A namespace id * @return string */ public function getIndexSuffixForNamespace( $namespace ) { $mappings = $this->config->get( 'CirrusSearchNamespaceMappings' ); if ( isset( $mappings[$namespace] ) ) { return $mappings[$namespace]; } return MWNamespace::isContent( $namespace ) ? self::CONTENT_INDEX_TYPE : self::GENERAL_INDEX_TYPE; } /** * Is there more then one namespace in the provided index type? * * @param string $indexType an index type * @return false|integer false if the number of indexes is unknown, an integer if it is known */ public function namespacesInIndexType( $indexType ) { if ( $indexType === self::GENERAL_INDEX_TYPE ) { return false; } $mappings = $this->config->get( 'CirrusSearchNamespaceMappings' ); $count = count( array_keys( $mappings, $indexType ) ); if ( $indexType === self::CONTENT_INDEX_TYPE ) { // The content namespace includes everything set in the mappings to content (count right now) // Plus everything in wgContentNamespaces that isn't already in namespace mappings $contentNamespaces = $this->config->get( 'ContentNamespaces' ); $count += count( array_diff( $contentNamespaces, array_keys( $mappings ) ) ); } return $count; } /** * @param int[]|null $namespaces List of namespaces to check * @return string|false The suffix to use (e.g. content or general) to * query the namespaces, or false if both need to be queried. */ public function pickIndexTypeForNamespaces( array $namespaces = null ) { $indexTypes = []; if ( $namespaces ) { foreach ( $namespaces as $namespace ) { $indexTypes[] = $this->getIndexSuffixForNamespace( $namespace ); } $indexTypes = array_unique( $indexTypes ); } if ( count( $indexTypes ) === 1 ) { return $indexTypes[0]; } else { return false; } } /** * @param int[]|null $namespaces List of namespaces to check * @return string[] the list of all index suffixes mathing the namespaces */ public function getAllIndexSuffixesForNamespaces( $namespaces = null ) { if ( $namespaces ) { foreach ( $namespaces as $namespace ) { $indexTypes[] = $this->getIndexSuffixForNamespace( $namespace ); } return array_unique( $indexTypes ); } // If no namespaces provided all indices are needed $mappings = $this->config->get( 'CirrusSearchNamespaceMappings' ); return array_merge( [ self::CONTENT_INDEX_TYPE, self::GENERAL_INDEX_TYPE ], array_values( $mappings ) ); } public function destroyClient() { self::$pool = []; parent::destroyClient(); } /** * @param string[] array of cluter names * @param SearchConfig $config the search config * @return Connection[] array of connection indexed by cluster name */ public static function getClusterConnections( array $clusters, SearchConfig $config ) { $connections = []; foreach ( $clusters as $name ) { $connections[$name] = self::getPool( $config, $name ); } return $connections; } /** * @param SearchConfig $config the search config * @return Connection[] array of connection indexed by cluster name. */ public static function getWritableClusterConnections( SearchConfig $config ) { return self::getClusterConnections( $config->getWritableClusters(), $config ); } /** * @param SearchConfig $config the search config * @return Connection[] array of connection indexed by cluster name. */ public static function getAllClusterConnections( SearchConfig $config ) { return self::getClusterConnections( $config->getAvailableClusters(), $config ); } }