&& in_array( 'bot', $this->getUser()->getGroups() )
&& wfGetLB()->getServerCount() > 1
) {
- // Figure out how many servers have passed the lag threshold
- $numLagged = 0;
- $lagLimit = $this->getConfig()->get( 'APIMaxLagThreshold' );
- foreach ( wfGetLB()->getLagTimes() as $lag ) {
- if ( $lag > $lagLimit ) {
- ++$numLagged;
- }
- }
- // If a majority of slaves are too lagged then disallow writes
- $slaveCount = wfGetLB()->getServerCount() - 1;
- if ( $numLagged >= ceil( $slaveCount / 2 ) ) {
- $parsed = $this->parseMsg( array( 'readonlytext' ) );
- $this->dieUsage(
- $parsed['info'],
- $parsed['code'],
- /* http error */
- 0,
- array( 'readonlyreason' => "Waiting for $numLagged lagged database(s)" )
- );
+ $this->checkBotReadOnly();
+ }
+ }
+
+ /**
+ * Check whether we are readonly for bots
+ */
+ private function checkBotReadOnly() {
+ // Figure out how many servers have passed the lag threshold
+ $numLagged = 0;
+ $lagLimit = $this->getConfig()->get( 'APIMaxLagThreshold' );
+ $laggedServers = array();
+ $loadBalancer = wfGetLB();
+ foreach ( $loadBalancer->getLagTimes() as $serverIndex => $lag ) {
+ if ( $lag > $lagLimit ) {
+ ++$numLagged;
+ $laggedServers[] = $loadBalancer->getServerName( $serverIndex ) . " ({$lag}s)";
}
}
+
+ // If a majority of slaves are too lagged then disallow writes
+ $slaveCount = wfGetLB()->getServerCount() - 1;
+ if ( $numLagged >= ceil( $slaveCount / 2 ) ) {
+ $laggedServers = join( ', ', $laggedServers );
+ wfDebugLog(
+ 'api-readonly',
+ "Api request failed as read only because the following DBs are lagged: $laggedServers"
+ );
+
+ $parsed = $this->parseMsg( array( 'readonlytext' ) );
+ $this->dieUsage(
+ $parsed['info'],
+ $parsed['code'],
+ /* http error */
+ 0,
+ array( 'readonlyreason' => "Waiting for $numLagged lagged database(s)" )
+ );
+ }
}
/**
* @param string $index
* @return string
*/
- public function indexName( $index ) {
- // @FIXME: Make this protected once we move away from PHP 5.3
- // Needs to be public because of usage in closure (in DatabaseBase::replaceVars)
-
+ protected function indexName( $index ) {
// Backwards-compatibility hack
$renamed = array(
'ar_usertext_timestamp' => 'usertext_timestamp',
* @return string The new SQL statement with variables replaced
*/
protected function replaceVars( $ins ) {
- $that = $this;
$vars = $this->getSchemaVars();
return preg_replace_callback(
'!
`\{\$ (\w+) }` | # 4. addIdentifierQuotes
/\*\$ (\w+) \*/ # 5. leave unencoded
!x',
- function ( $m ) use ( $that, $vars ) {
+ function ( $m ) use ( $vars ) {
// Note: Because of <https://bugs.php.net/bug.php?id=51881>,
// check for both nonexistent keys *and* the empty string.
if ( isset( $m[1] ) && $m[1] !== '' ) {
if ( $m[1] === 'i' ) {
- return $that->indexName( $m[2] );
+ return $this->indexName( $m[2] );
} else {
- return $that->tableName( $m[2] );
+ return $this->tableName( $m[2] );
}
} elseif ( isset( $m[3] ) && $m[3] !== '' && array_key_exists( $m[3], $vars ) ) {
- return $that->addQuotes( $vars[$m[3]] );
+ return $this->addQuotes( $vars[$m[3]] );
} elseif ( isset( $m[4] ) && $m[4] !== '' && array_key_exists( $m[4], $vars ) ) {
- return $that->addIdentifierQuotes( $vars[$m[4]] );
+ return $this->addIdentifierQuotes( $vars[$m[4]] );
} elseif ( isset( $m[5] ) && $m[5] !== '' && array_key_exists( $m[5], $vars ) ) {
return $vars[$m[5]];
} else {
return null;
}
- $that = $this;
- $unlocker = new ScopedCallback( function () use ( $that, $lockKey, $fname ) {
- $that->commit( __METHOD__, 'flush' );
- $that->unlock( $lockKey, $fname );
+ $unlocker = new ScopedCallback( function () use ( $lockKey, $fname ) {
+ $this->commit( __METHOD__, 'flush' );
+ $this->unlock( $lockKey, $fname );
} );
$this->commit( __METHOD__, 'flush' );
$this->getLBInfo( 'clusterMasterHost' ) ?: $this->getServer()
);
- $that = $this;
return $cache->getWithSetCallback(
$key,
$cache::TTL_INDEFINITE,
- function () use ( $that, $cache, $key ) {
+ function () use ( $cache, $key ) {
// Get and leave a lock key in place for a short period
if ( !$cache->lock( $key, 0, 10 ) ) {
return false; // avoid master connection spike slams
}
- $conn = $that->getLazyMasterHandle();
+ $conn = $this->getLazyMasterHandle();
if ( !$conn ) {
return false; // something is misconfigured
}
Hooks::run( 'LinksUpdate', array( &$this ) );
$this->doIncrementalUpdate();
- $that = $this;
- $this->mDb->onTransactionIdle( function() use ( $that ) {
- Hooks::run( 'LinksUpdateComplete', array( &$that ) );
+ $this->mDb->onTransactionIdle( function() {
+ Hooks::run( 'LinksUpdateComplete', array( &$this ) );
} );
}
'body' => $params['content']
) );
- $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
} elseif ( $rcode === 412 ) {
$status->fatal( 'backend-fail-contenttype', $params['dst'] );
} else {
- $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $this->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
'body' => $handle // resource
) );
- $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
} elseif ( $rcode === 412 ) {
$status->fatal( 'backend-fail-contenttype', $params['dst'] );
} else {
- $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $this->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
) + $this->sanitizeHdrs( $params ), // extra headers merged into object
) );
- $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 201 ) {
// good
} elseif ( $rcode === 404 ) {
$status->fatal( 'backend-fail-copy', $params['src'], $params['dst'] );
} else {
- $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $this->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
);
}
- $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $request['method'] === 'PUT' && $rcode === 201 ) {
// good
} elseif ( $rcode === 404 ) {
$status->fatal( 'backend-fail-move', $params['src'], $params['dst'] );
} else {
- $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $this->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
'headers' => array()
) );
- $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 204 ) {
// good
$status->fatal( 'backend-fail-delete', $params['src'] );
}
} else {
- $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $this->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
'headers' => $metaHdrs + $customHdrs
) );
- $that = $this;
$method = __METHOD__;
- $handler = function ( array $request, Status $status ) use ( $that, $method, $params ) {
+ $handler = function ( array $request, Status $status ) use ( $method, $params ) {
list( $rcode, $rdesc, $rhdrs, $rbody, $rerr ) = $request['response'];
if ( $rcode === 202 ) {
// good
} elseif ( $rcode === 404 ) {
$status->fatal( 'backend-fail-describe', $params['src'] );
} else {
- $that->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
+ $this->onError( $status, $method, $params, $rerr, $rcode, $rdesc );
}
};
protected function doBatchPush( array $jobs, $flags ) {
$dbw = $this->getMasterDB();
- $that = $this;
$method = __METHOD__;
$dbw->onTransactionIdle(
- function () use ( $dbw, $that, $jobs, $flags, $method ) {
- $that->doBatchPushInternal( $dbw, $jobs, $flags, $method );
+ function () use ( $dbw, $jobs, $flags, $method ) {
+ $this->doBatchPushInternal( $dbw, $jobs, $flags, $method );
}
);
}
return new ArrayIterator( array() );
}
- $that = $this;
return new MappedIterator(
$unclaimed,
- function ( $value ) use ( $that ) {
- $that->jobFromSpecInternal( $value );
+ function ( $value ) {
+ $this->jobFromSpecInternal( $value );
}
);
}
return new ArrayIterator( array() );
}
- $that = $this;
return new MappedIterator(
$claimed,
- function ( $value ) use ( $that ) {
- $that->jobFromSpecInternal( $value );
+ function ( $value ) {
+ $this->jobFromSpecInternal( $value );
}
);
}
* @return MappedIterator
*/
protected function getJobIterator( RedisConnRef $conn, array $uids ) {
- $that = $this;
-
return new MappedIterator(
$uids,
- function ( $uid ) use ( $that, $conn ) {
- return $that->getJobFromUidInternal( $uid, $conn );
+ function ( $uid ) use ( $conn ) {
+ return $this->getJobFromUidInternal( $uid, $conn );
},
array( 'accept' => function ( $job ) {
return is_object( $job );
}
$lSince = microtime( true ); // lock timestamp
- // PHP 5.3: Can't use $this in a closure
- $that = $this;
- $logger = $this->logger;
- return new ScopedCallback( function() use ( $that, $logger, $key, $lSince, $expiry ) {
+ return new ScopedCallback( function() use ( $key, $lSince, $expiry ) {
$latency = .050; // latency skew (err towards keeping lock present)
$age = ( microtime( true ) - $lSince + $latency );
if ( ( $age + $latency ) >= $expiry ) {
- $logger->warning( "Lock for $key held too long ($age sec)." );
+ $this->logger->warning( "Lock for $key held too long ($age sec)." );
return; // expired; it's not "safe" to delete the key
}
- $that->unlock( $key );
+ $this->unlock( $key );
} );
}
* @return \ScopedCallback When this goes out of scope, a save will be triggered
*/
public function delaySave() {
- $that = $this;
$this->delaySave++;
- $ref = &$this->delaySave;
- return new \ScopedCallback( function () use ( $that, &$ref ) {
- if ( --$ref <= 0 ) {
- $ref = 0;
- $that->save();
+ return new \ScopedCallback( function () {
+ if ( --$this->delaySave <= 0 ) {
+ $this->delaySave = 0;
+ $this->save();
}
} );
}
private function checkPHPSession() {
if ( !$this->checkPHPSessionRecursionGuard ) {
$this->checkPHPSessionRecursionGuard = true;
- $ref = &$this->checkPHPSessionRecursionGuard;
- $reset = new \ScopedCallback( function () use ( &$ref ) {
- $ref = false;
+ $reset = new \ScopedCallback( function () {
+ $this->checkPHPSessionRecursionGuard = false;
} );
if ( $this->usePhpSessionHandling && session_id() === '' && PHPSessionHandler::isEnabled() &&
// ip-based limits
if ( isset( $limits['ip'] ) ) {
$ip = $this->getRequest()->getIP();
- $keys[wfMemcKey( 'limiter', $action, 'ip', $ip )] = $limits['ip'];
+ $keys["mediawiki:limiter:$action:ip:$ip"] = $limits['ip'];
}
// subnet-based limits
if ( isset( $limits['subnet'] ) ) {
$ip = $this->getRequest()->getIP();
$subnet = IP::getSubnet( $ip );
if ( $subnet !== false ) {
- $keys[wfMemcKey( 'limiter', $action, 'subnet', $subnet )] = $limits['subnet'];
+ $keys["mediawiki:limiter:$action:subnet:$subnet"] = $limits['subnet'];
}
}
}
case T_NAMESPACE:
case T_CLASS:
case T_INTERFACE:
+ case T_TRAIT:
$this->startToken = $token;
}
}
case T_CLASS:
case T_INTERFACE:
+ case T_TRAIT:
$this->tokens[] = $token;
if ( is_array( $token ) && $token[0] === T_STRING ) {
$this->classes[] = $this->namespace . $this->implodeTokens();
}
public function testPersistSessionWithHook() {
- $that = $this;
-
$provider = new CookieSessionProvider( array(
'priority' => 1,
'sessionName' => 'MySessionName',
// Logged-in user, no remember
$mock = $this->getMock( __CLASS__, array( 'onUserSetCookies' ) );
$mock->expects( $this->once() )->method( 'onUserSetCookies' )
- ->will( $this->returnCallback( function ( $u, &$sessionData, &$cookies ) use ( $that, $user ) {
- $that->assertSame( $user, $u );
- $that->assertEquals( array(
+ ->will( $this->returnCallback( function ( $u, &$sessionData, &$cookies ) use ( $user ) {
+ $this->assertSame( $user, $u );
+ $this->assertEquals( array(
'wsUserID' => $user->getId(),
'wsUserName' => $user->getName(),
'wsToken' => $user->getToken(),
), $sessionData );
- $that->assertEquals( array(
+ $this->assertEquals( array(
'UserID' => $user->getId(),
'UserName' => $user->getName(),
'Token' => false,
// Logged-in user, remember
$mock = $this->getMock( __CLASS__, array( 'onUserSetCookies' ) );
$mock->expects( $this->once() )->method( 'onUserSetCookies' )
- ->will( $this->returnCallback( function ( $u, &$sessionData, &$cookies ) use ( $that, $user ) {
- $that->assertSame( $user, $u );
- $that->assertEquals( array(
+ ->will( $this->returnCallback( function ( $u, &$sessionData, &$cookies ) use ( $user ) {
+ $this->assertSame( $user, $u );
+ $this->assertEquals( array(
'wsUserID' => $user->getId(),
'wsUserName' => $user->getName(),
'wsToken' => $user->getToken(),
), $sessionData );
- $that->assertEquals( array(
+ $this->assertEquals( array(
'UserID' => $user->getId(),
'UserName' => $user->getName(),
'Token' => $user->getToken(),
public function testAutoCreateUser() {
global $wgGroupPermissions;
- $that = $this;
-
\ObjectCache::$instances[__METHOD__] = new TestBagOStuff();
$this->setMwGlobals( array( 'wgMainCacheType' => __METHOD__ ) );
$this->setMWGlobals( array(
$logger->clearBuffer();
// Sanity check that creation still works, and test completion hook
- $cb = $this->callback( function ( User $user ) use ( $that ) {
- $that->assertNotEquals( 0, $user->getId() );
- $that->assertSame( 'UTSessionAutoCreate4', $user->getName() );
- $that->assertEquals(
+ $cb = $this->callback( function ( User $user ) {
+ $this->assertNotEquals( 0, $user->getId() );
+ $this->assertSame( 'UTSessionAutoCreate4', $user->getName() );
+ $this->assertEquals(
$user->getId(), User::idFromName( 'UTSessionAutoCreate4', User::READ_LATEST )
);
return true;
$this->assertSame( array(), $logger->getBuffer() );
// Hook
- $that = $this;
$called = false;
$data = array( 'foo' => 1 );
$this->store->setSession( $id, array( 'metadata' => $metadata, 'data' => $data ) );
) );
$this->mergeMwGlobalArrayValue( 'wgHooks', array(
'SessionCheckInfo' => array( function ( &$reason, $i, $r, $m, $d ) use (
- $that, $info, $metadata, $data, $request, &$called
+ $info, $metadata, $data, $request, &$called
) {
- $that->assertSame( $info->getId(), $i->getId() );
- $that->assertSame( $info->getProvider(), $i->getProvider() );
- $that->assertSame( $info->getUserInfo(), $i->getUserInfo() );
- $that->assertSame( $request, $r );
- $that->assertEquals( $metadata, $m );
- $that->assertEquals( $data, $d );
+ $this->assertSame( $info->getId(), $i->getId() );
+ $this->assertSame( $info->getProvider(), $i->getProvider() );
+ $this->assertSame( $info->getUserInfo(), $i->getUserInfo() );
+ $this->assertSame( $request, $r );
+ $this->assertEquals( $metadata, $m );
+ $this->assertEquals( $data, $d );
$called = true;
return false;
} )