'ListredirectsPage' => __DIR__ . '/includes/specials/SpecialListredirects.php',
'LoadBalancer' => __DIR__ . '/includes/db/loadbalancer/LoadBalancer.php',
'LoadBalancerSingle' => __DIR__ . '/includes/db/loadbalancer/LBFactorySingle.php',
- 'LoadMonitor' => __DIR__ . '/includes/db/loadbalancer/LoadMonitor.php',
- 'LoadMonitorMySQL' => __DIR__ . '/includes/db/loadbalancer/LoadMonitorMySQL.php',
- 'LoadMonitorNull' => __DIR__ . '/includes/db/loadbalancer/LoadMonitor.php',
+ 'LoadMonitor' => __DIR__ . '/includes/libs/rdbms/loadmonitor/LoadMonitor.php',
+ 'LoadMonitorMySQL' => __DIR__ . '/includes/libs/rdbms/loadmonitor/LoadMonitorMySQL.php',
+ 'LoadMonitorNull' => __DIR__ . '/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php',
'LocalFile' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
'LocalFileDeleteBatch' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
'LocalFileLockError' => __DIR__ . '/includes/filerepo/file/LocalFile.php',
protected $replLogger;
/** @var BagOStuff */
protected $srvCache;
+ /** @var BagOStuff */
+ protected $memCache;
/** @var WANObjectCache */
protected $wanCache;
$this->chronProt = $this->newChronologyProtector();
$this->trxProfiler = Profiler::instance()->getTransactionProfiler();
// Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
- $cache = ObjectCache::getLocalServerInstance();
- if ( $cache->getQoS( $cache::ATTR_EMULATION ) > $cache::QOS_EMULATION_SQL ) {
- $this->srvCache = $cache;
+ $sCache = ObjectCache::getLocalServerInstance();
+ if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) {
+ $this->srvCache = $sCache;
} else {
$this->srvCache = new EmptyBagOStuff();
}
+ $cCache = ObjectCache::getLocalClusterInstance();
+ if ( $cCache->getQoS( $cCache::ATTR_EMULATION ) > $cCache::QOS_EMULATION_SQL ) {
+ $this->memCache = $cCache;
+ } else {
+ $this->memCache = new EmptyBagOStuff();
+ }
$wCache = ObjectCache::getMainWANInstance();
if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) {
$this->wanCache = $wCache;
'localDomain' => wfWikiID(),
'readOnlyReason' => $this->readOnlyReason,
'srvCache' => $this->srvCache,
+ 'memCache' => $this->memCache,
'wanCache' => $this->wanCache,
'trxProfiler' => $this->trxProfiler,
'queryLogger' => LoggerFactory::getInstance( 'DBQuery' ),
private $mLoadMonitor;
/** @var BagOStuff */
private $srvCache;
+ /** @var BagOStuff */
+ private $memCache;
/** @var WANObjectCache */
private $wanCache;
/** @var TransactionProfiler */
} else {
$this->srvCache = new EmptyBagOStuff();
}
+ if ( isset( $params['memCache'] ) ) {
+ $this->memCache = $params['memCache'];
+ } else {
+ $this->memCache = new EmptyBagOStuff();
+ }
if ( isset( $params['wanCache'] ) ) {
$this->wanCache = $params['wanCache'];
} else {
private function getLoadMonitor() {
if ( !isset( $this->mLoadMonitor ) ) {
$class = $this->mLoadMonitorClass;
- $this->mLoadMonitor = new $class( $this );
+ $this->mLoadMonitor = new $class( $this, $this->srvCache, $this->memCache );
$this->mLoadMonitor->setLogger( $this->replLogger );
}
+++ /dev/null
-<?php
-/**
- * Database load monitoring.
- *
- * 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
- *
- * @file
- * @ingroup Database
- */
-use Psr\Log\LoggerAwareInterface;
-use Psr\Log\LoggerInterface;
-
-/**
- * An interface for database load monitoring
- *
- * @ingroup Database
- */
-interface LoadMonitor extends LoggerAwareInterface {
- /**
- * Construct a new LoadMonitor with a given LoadBalancer parent
- *
- * @param LoadBalancer $parent
- */
- public function __construct( LoadBalancer $parent );
-
- /**
- * Perform pre-connection load ratio adjustment.
- * @param array &$loads
- * @param string|bool $group The selected query group. Default: false
- * @param string|bool $wiki Default: false
- */
- public function scaleLoads( &$loads, $group = false, $wiki = false );
-
- /**
- * Get an estimate of replication lag (in seconds) for each server
- *
- * Values may be "false" if replication is too broken to estimate
- *
- * @param array $serverIndexes
- * @param string $wiki
- *
- * @return array Map of (server index => float|int|bool)
- */
- public function getLagTimes( $serverIndexes, $wiki );
-
- /**
- * Clear any process and persistent cache of lag times
- * @since 1.27
- */
- public function clearCaches();
-}
-
-class LoadMonitorNull implements LoadMonitor {
- public function __construct( LoadBalancer $parent ) {
- }
-
- public function setLogger( LoggerInterface $logger ) {
- }
-
- public function scaleLoads( &$loads, $group = false, $wiki = false ) {
- }
-
- public function getLagTimes( $serverIndexes, $wiki ) {
- return array_fill_keys( $serverIndexes, 0 );
- }
-
- public function clearCaches() {
-
- }
-}
+++ /dev/null
-<?php
-/**
- * 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
- *
- * @file
- * @ingroup Database
- */
-
-use Psr\Log\LoggerInterface;
-
-/**
- * Basic MySQL load monitor with no external dependencies
- * Uses memcached to cache the replication lag for a short time
- *
- * @ingroup Database
- */
-class LoadMonitorMySQL implements LoadMonitor {
- /** @var LoadBalancer */
- public $parent;
- /** @var BagOStuff */
- protected $srvCache;
- /** @var BagOStuff */
- protected $mainCache;
- /** @var LoggerInterface */
- protected $replLogger;
-
- public function __construct( LoadBalancer $parent ) {
- $this->parent = $parent;
- $this->srvCache = ObjectCache::getLocalServerInstance( 'hash' );
- $this->mainCache = ObjectCache::getLocalClusterInstance();
- $this->replLogger = new \Psr\Log\NullLogger();
- }
-
- public function setLogger( LoggerInterface $logger ) {
- $this->replLogger = $logger;
- }
-
- public function scaleLoads( &$loads, $group = false, $wiki = false ) {
- }
-
- public function getLagTimes( $serverIndexes, $wiki ) {
- if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
- # Single server only, just return zero without caching
- return [ 0 => 0 ];
- }
-
- $key = $this->getLagTimeCacheKey();
- # Randomize TTLs to reduce stampedes (4.0 - 5.0 sec)
- $ttl = mt_rand( 4e6, 5e6 ) / 1e6;
- # Keep keys around longer as fallbacks
- $staleTTL = 60;
-
- # (a) Check the local APC cache
- $value = $this->srvCache->get( $key );
- if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
- $this->replLogger->debug( __METHOD__ . ": got lag times ($key) from local cache" );
- return $value['lagTimes']; // cache hit
- }
- $staleValue = $value ?: false;
-
- # (b) Check the shared cache and backfill APC
- $value = $this->mainCache->get( $key );
- if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
- $this->srvCache->set( $key, $value, $staleTTL );
- $this->replLogger->debug( __METHOD__ . ": got lag times ($key) from main cache" );
-
- return $value['lagTimes']; // cache hit
- }
- $staleValue = $value ?: $staleValue;
-
- # (c) Cache key missing or expired; regenerate and backfill
- if ( $this->mainCache->lock( $key, 0, 10 ) ) {
- # Let this process alone update the cache value
- $cache = $this->mainCache;
- /** @noinspection PhpUnusedLocalVariableInspection */
- $unlocker = new ScopedCallback( function () use ( $cache, $key ) {
- $cache->unlock( $key );
- } );
- } elseif ( $staleValue ) {
- # Could not acquire lock but an old cache exists, so use it
- return $staleValue['lagTimes'];
- }
-
- $lagTimes = [];
- foreach ( $serverIndexes as $i ) {
- if ( $i == $this->parent->getWriterIndex() ) {
- $lagTimes[$i] = 0; // master always has no lag
- continue;
- }
-
- $conn = $this->parent->getAnyOpenConnection( $i );
- if ( $conn ) {
- $close = false; // already open
- } else {
- $conn = $this->parent->openConnection( $i, $wiki );
- $close = true; // new connection
- }
-
- if ( !$conn ) {
- $lagTimes[$i] = false;
- $host = $this->parent->getServerName( $i );
- $this->replLogger->error( __METHOD__ . ": host $host (#$i) is unreachable" );
- continue;
- }
-
- $lagTimes[$i] = $conn->getLag();
- if ( $lagTimes[$i] === false ) {
- $host = $this->parent->getServerName( $i );
- $this->replLogger->error( __METHOD__ . ": host $host (#$i) is not replicating?" );
- }
-
- if ( $close ) {
- # Close the connection to avoid sleeper connections piling up.
- # Note that the caller will pick one of these DBs and reconnect,
- # which is slightly inefficient, but this only matters for the lag
- # time cache miss cache, which is far less common that cache hits.
- $this->parent->closeConnection( $conn );
- }
- }
-
- # Add a timestamp key so we know when it was cached
- $value = [ 'lagTimes' => $lagTimes, 'timestamp' => microtime( true ) ];
- $this->mainCache->set( $key, $value, $staleTTL );
- $this->srvCache->set( $key, $value, $staleTTL );
- $this->replLogger->info( __METHOD__ . ": re-calculated lag times ($key)" );
-
- return $value['lagTimes'];
- }
-
- public function clearCaches() {
- $key = $this->getLagTimeCacheKey();
- $this->srvCache->delete( $key );
- $this->mainCache->delete( $key );
- }
-
- private function getLagTimeCacheKey() {
- $writerIndex = $this->parent->getWriterIndex();
- // Lag is per-server, not per-DB, so key on the master DB name
- return $this->srvCache->makeGlobalKey(
- 'lag-times', $this->parent->getServerName( $writerIndex )
- );
- }
-}
--- /dev/null
+<?php
+/**
+ * Database load monitoring.
+ *
+ * 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
+ *
+ * @file
+ * @ingroup Database
+ */
+use Psr\Log\LoggerAwareInterface;
+
+/**
+ * An interface for database load monitoring
+ *
+ * @ingroup Database
+ */
+interface LoadMonitor extends LoggerAwareInterface {
+ /**
+ * Construct a new LoadMonitor with a given LoadBalancer parent
+ *
+ * @param BagOStuff $sCache Server local memory cache
+ * @param BagOStuff $cCache Server local memory cache
+ * @param ILoadBalancer $parent LoadBalancer this instance serves
+ */
+ public function __construct( ILoadBalancer $parent, BagOStuff $sCache, BagOStuff $cCache );
+
+ /**
+ * Perform pre-connection load ratio adjustment.
+ * @param int[] &$loads
+ * @param string|bool $group The selected query group. Default: false
+ * @param string|bool $domain Default: false
+ */
+ public function scaleLoads( &$loads, $group = false, $domain = false );
+
+ /**
+ * Get an estimate of replication lag (in seconds) for each server
+ *
+ * Values may be "false" if replication is too broken to estimate
+ *
+ * @param integer[] $serverIndexes
+ * @param string $domain
+ *
+ * @return array Map of (server index => float|int|bool)
+ */
+ public function getLagTimes( $serverIndexes, $domain );
+
+ /**
+ * Clear any process and persistent cache of lag times
+ * @since 1.27
+ */
+ public function clearCaches();
+}
--- /dev/null
+<?php
+/**
+ * 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
+ *
+ * @file
+ * @ingroup Database
+ */
+
+use Psr\Log\LoggerInterface;
+
+/**
+ * Basic MySQL load monitor with no external dependencies
+ * Uses memcached to cache the replication lag for a short time
+ *
+ * @ingroup Database
+ */
+class LoadMonitorMySQL implements LoadMonitor {
+ /** @var ILoadBalancer */
+ protected $parent;
+ /** @var BagOStuff */
+ protected $srvCache;
+ /** @var BagOStuff */
+ protected $mainCache;
+ /** @var LoggerInterface */
+ protected $replLogger;
+
+ public function __construct( ILoadBalancer $parent, BagOStuff $sCache, BagOStuff $cCache ) {
+ $this->parent = $parent;
+ $this->srvCache = $sCache;
+ $this->mainCache = $cCache;
+ $this->replLogger = new \Psr\Log\NullLogger();
+ }
+
+ public function setLogger( LoggerInterface $logger ) {
+ $this->replLogger = $logger;
+ }
+
+ public function scaleLoads( &$loads, $group = false, $wiki = false ) {
+ }
+
+ public function getLagTimes( $serverIndexes, $wiki ) {
+ if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
+ # Single server only, just return zero without caching
+ return [ 0 => 0 ];
+ }
+
+ $key = $this->getLagTimeCacheKey();
+ # Randomize TTLs to reduce stampedes (4.0 - 5.0 sec)
+ $ttl = mt_rand( 4e6, 5e6 ) / 1e6;
+ # Keep keys around longer as fallbacks
+ $staleTTL = 60;
+
+ # (a) Check the local APC cache
+ $value = $this->srvCache->get( $key );
+ if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
+ $this->replLogger->debug( __METHOD__ . ": got lag times ($key) from local cache" );
+ return $value['lagTimes']; // cache hit
+ }
+ $staleValue = $value ?: false;
+
+ # (b) Check the shared cache and backfill APC
+ $value = $this->mainCache->get( $key );
+ if ( $value && $value['timestamp'] > ( microtime( true ) - $ttl ) ) {
+ $this->srvCache->set( $key, $value, $staleTTL );
+ $this->replLogger->debug( __METHOD__ . ": got lag times ($key) from main cache" );
+
+ return $value['lagTimes']; // cache hit
+ }
+ $staleValue = $value ?: $staleValue;
+
+ # (c) Cache key missing or expired; regenerate and backfill
+ if ( $this->mainCache->lock( $key, 0, 10 ) ) {
+ # Let this process alone update the cache value
+ $cache = $this->mainCache;
+ /** @noinspection PhpUnusedLocalVariableInspection */
+ $unlocker = new ScopedCallback( function () use ( $cache, $key ) {
+ $cache->unlock( $key );
+ } );
+ } elseif ( $staleValue ) {
+ # Could not acquire lock but an old cache exists, so use it
+ return $staleValue['lagTimes'];
+ }
+
+ $lagTimes = [];
+ foreach ( $serverIndexes as $i ) {
+ if ( $i == $this->parent->getWriterIndex() ) {
+ $lagTimes[$i] = 0; // master always has no lag
+ continue;
+ }
+
+ $conn = $this->parent->getAnyOpenConnection( $i );
+ if ( $conn ) {
+ $close = false; // already open
+ } else {
+ $conn = $this->parent->openConnection( $i, $wiki );
+ $close = true; // new connection
+ }
+
+ if ( !$conn ) {
+ $lagTimes[$i] = false;
+ $host = $this->parent->getServerName( $i );
+ $this->replLogger->error( __METHOD__ . ": host $host (#$i) is unreachable" );
+ continue;
+ }
+
+ $lagTimes[$i] = $conn->getLag();
+ if ( $lagTimes[$i] === false ) {
+ $host = $this->parent->getServerName( $i );
+ $this->replLogger->error( __METHOD__ . ": host $host (#$i) is not replicating?" );
+ }
+
+ if ( $close ) {
+ # Close the connection to avoid sleeper connections piling up.
+ # Note that the caller will pick one of these DBs and reconnect,
+ # which is slightly inefficient, but this only matters for the lag
+ # time cache miss cache, which is far less common that cache hits.
+ $this->parent->closeConnection( $conn );
+ }
+ }
+
+ # Add a timestamp key so we know when it was cached
+ $value = [ 'lagTimes' => $lagTimes, 'timestamp' => microtime( true ) ];
+ $this->mainCache->set( $key, $value, $staleTTL );
+ $this->srvCache->set( $key, $value, $staleTTL );
+ $this->replLogger->info( __METHOD__ . ": re-calculated lag times ($key)" );
+
+ return $value['lagTimes'];
+ }
+
+ public function clearCaches() {
+ $key = $this->getLagTimeCacheKey();
+ $this->srvCache->delete( $key );
+ $this->mainCache->delete( $key );
+ }
+
+ private function getLagTimeCacheKey() {
+ $writerIndex = $this->parent->getWriterIndex();
+ // Lag is per-server, not per-DB, so key on the master DB name
+ return $this->srvCache->makeGlobalKey(
+ 'lag-times',
+ $this->parent->getServerName( $writerIndex )
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * 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
+ *
+ * @file
+ * @ingroup Database
+ */
+use Psr\Log\LoggerInterface;
+
+class LoadMonitorNull implements LoadMonitor {
+ public function __construct( ILoadBalancer $parent, BagOStuff $sCache, BagOStuff $cCache ) {
+ }
+
+ public function setLogger( LoggerInterface $logger ) {
+ }
+
+ public function scaleLoads( &$loads, $group = false, $wiki = false ) {
+ }
+
+ public function getLagTimes( $serverIndexes, $wiki ) {
+ return array_fill_keys( $serverIndexes, 0 );
+ }
+
+ public function clearCaches() {
+
+ }
+}