* Introducing bit field for database parameters

** Database constructor calling sequence, and Database::newFromParams()
** Including flags in the server initialisation structs
** Support for setting appropriate flags from legacy globals in Setup.php
** Moved some defines to Define.php so that they can be used in LocalSettings.php, most importantly the bit field constants

* Changes related to post-parse link colouring
** Turn the link cache back on when using it for updating the links table
** No longer need to call preFill() on page view

* Better synchronisation of slave servers
** Rearranged getConnection()
** System for beginning and committing transactions when multiple connections are open
** wfAbruptExit() commits transactions, wfErrorExit() does not. Various functions changed to use wfErrorAbort()

* Allowed reporting of database errors during deferred updates by moving them above output()
This commit is contained in:
Tim Starling 2004-07-24 07:24:04 +00:00
parent a75b7d316f
commit 1773cd1e76
14 changed files with 294 additions and 200 deletions

View file

@ -153,7 +153,7 @@ class Article {
# Try to open, return false on failure
$params = $wgKnownDBServers[$machineId];
$db = Database::newFromParams( $params['server'], $params['user'], $params['password'],
$dbName, 1, false, true, true );
$dbName, 1, DBO_IGNORE );
}
}
if ( $db->isOpen() ) {
@ -711,8 +711,6 @@ class Article {
$pcache = false;
}
$wgLinkCache->preFill( $this->mTitle );
# wrap user css and user js in pre and don't parse
# XXX: use $this->mTitle->usCssJsSubpage() when php is fixed/ a workaround is found
if (
@ -743,7 +741,7 @@ class Article {
/* private */ function insertNewArticle( $text, $summary, $isminor, $watchthis )
{
global $wgOut, $wgUser, $wgLinkCache, $wgMwRedir;
global $wgOut, $wgUser, $wgMwRedir;
global $wgUseSquid, $wgDeferredUpdateList, $wgInternalServer;
$fname = 'Article::insertNewArticle';
@ -888,7 +886,7 @@ class Article {
function updateArticle( $text, $summary, $minor, $watchthis, $forceBot = false, $sectionanchor = '' )
{
global $wgOut, $wgUser, $wgLinkCache;
global $wgOut, $wgUser;
global $wgDBtransactions, $wgMwRedir;
global $wgUseSquid, $wgInternalServer;
@ -1036,7 +1034,11 @@ class Article {
# Get old version of link table to allow incremental link updates
$wgLinkCache->preFill( $this->mTitle );
$wgLinkCache->clear();
# Switch on use of link cache in the skin
$sk =& $wgUser->getSkin();
$sk->postParseLinkColour( false );
# Now update the link cache by parsing the text
$wgOut = new OutputPage();
$wgOut->addWikiText( $text );
@ -1509,7 +1511,7 @@ class Article {
$linkID = $titleObj->getArticleID();
$brokenLinks[] = array( 'bl_from' => $linkID, 'bl_to' => $t );
}
$dbw->insertArray( 'brokenlinks', $brokenLinks, $fname );
$dbw->insert( 'brokenlinks', $brokenLinks, $fname, 'IGNORE' );
# Delete live links
$dbw->delete( 'links', array( 'l_to' => $id ) );

View file

@ -22,43 +22,61 @@ class Database {
# Variables
#------------------------------------------------------------------------------
/* private */ var $mLastQuery = "";
/* private */ var $mBufferResults = true;
/* private */ var $mIgnoreErrors = false;
/* private */ var $mServer, $mUser, $mPassword, $mConn, $mDBname;
/* private */ var $mOut, $mDebug, $mOpened = false;
/* private */ var $mOut, $mOpened = false;
/* private */ var $mFailFunction;
/* private */ var $mTablePrefix;
/* private */ var $mFlags;
/* private */ var $mTrxLevel = 0;
#------------------------------------------------------------------------------
# Accessors
#------------------------------------------------------------------------------
# Set functions
# These set a variable and return the previous state
# These optionally set a variable and return the previous state
# Fail function, takes a Database as a parameter
# Set to false for default, 1 for ignore errors
function setFailFunction( $function ) { return wfSetVar( $this->mFailFunction, $function ); }
function failFunction( $function = NULL ) {
return wfSetVar( $this->mFailFunction, $function );
}
# Output page, used for reporting errors
# FALSE means discard output
function &setOutputPage( &$out ) { $this->mOut =& $out; }
function &setOutputPage( &$out ) {
$this->mOut =& $out;
}
# Boolean, controls output of large amounts of debug information
function setDebug( $debug ) { return wfSetVar( $this->mDebug, $debug ); }
function debug( $debug = NULL ) {
return wfSetBit( $this->mFlags, DBO_DEBUG, $debug );
}
# Turns buffering of SQL result sets on (true) or off (false). Default is
# "on" and it should not be changed without good reasons.
function setBufferResults( $buffer ) { return wfSetVar( $this->mBufferResults, $buffer ); }
function bufferResults( $buffer = NULL ) {
if ( is_null( $buffer ) ) {
return !(bool)( $this->mFlags & DBO_NOBUFFER );
} else {
return !wfSetBit( $this->mFlags, DBO_NOBUFFER, !$buffer );
}
}
# Turns on (false) or off (true) the automatic generation and sending
# of a "we're sorry, but there has been a database error" page on
# database errors. Default is on (false). When turned off, the
# code should use wfLastErrno() and wfLastError() to handle the
# situation as appropriate.
function setIgnoreErrors( $ignoreErrors ) { return wfSetVar( $this->mIgnoreErrors, $ignoreErrors ); }
function ignoreErrors( $ignoreErrors = NULL ) {
return wfSetBit( $this->mFlags, DBO_IGNORE, $ignoreErrors );
}
# The current depth of nested transactions
function trxLevel( $level = NULL ) {
return wfSetVar( $this->mTrxLevel, $level );
}
# Get functions
function lastQuery() { return $this->mLastQuery; }
@ -69,10 +87,9 @@ class Database {
#------------------------------------------------------------------------------
function Database( $server = false, $user = false, $password = false, $dbName = false,
$failFunction = false, $debug = false, $bufferResults = true, $ignoreErrors = false,
$tablePrefix = 'get from global' )
$failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
{
global $wgOut, $wgDBprefix;
global $wgOut, $wgDBprefix, $wgCommandLineMode;
# Can't get a reference if it hasn't been set yet
if ( !isset( $wgOut ) ) {
$wgOut = NULL;
@ -80,9 +97,16 @@ class Database {
$this->mOut =& $wgOut;
$this->mFailFunction = $failFunction;
$this->mIgnoreErrors = $ignoreErrors;
$this->mDebug = $debug;
$this->mBufferResults = $bufferResults;
$this->mFlags = $flags;
if ( $this->mFlags & DBO_DEFAULT ) {
if ( $wgCommandLineMode ) {
$this->mFlags &= ~DBO_TRX;
} else {
$this->mFlags |= DBO_TRX;
}
}
if ( $tablePrefix == 'get from global' ) {
$this->mTablePrefix = $wgDBprefix;
} else {
@ -95,10 +119,9 @@ class Database {
}
/* static */ function newFromParams( $server, $user, $password, $dbName,
$failFunction = false, $debug = false, $bufferResults = true, $ignoreErrors = false )
$failFunction = false, $flags = 0 )
{
return new Database( $server, $user, $password, $dbName, $failFunction, $debug,
$bufferResults, $ignoreErrors );
return new Database( $server, $user, $password, $dbName, $failFunction, $flags );
}
# Usually aborts on failure
@ -146,11 +169,15 @@ class Database {
}
# Closes a database connection, if it is open
# Commits any open transactions
# Returns success, true if already closed
function close()
{
$this->mOpened = false;
if ( $this->mConn ) {
if ( $this->trxLevel() ) {
$this->immediateCommit();
}
return mysql_close( $this->mConn );
} else {
return true;
@ -184,7 +211,7 @@ class Database {
$this->mLastQuery = $sql;
if ( $this->mDebug ) {
if ( $this->debug() ) {
$sqlx = substr( $sql, 0, 500 );
$sqlx = wordwrap(strtr($sqlx,"\t\n"," "));
wfDebug( "SQL: $sqlx\n" );
@ -196,26 +223,37 @@ class Database {
$commentedSql = $sql;
}
if( $this->mBufferResults ) {
$ret = mysql_query( $commentedSql, $this->mConn );
} else {
$ret = mysql_unbuffered_query( $commentedSql, $this->mConn );
}
if ( false === $ret ) {
$this->reportQueryError( mysql_error(), mysql_errno(), $sql, $fname, $tempIgnore );
# If DBO_TRX is set, start a transaction
if ( ( $this->mFlags & DBO_TRX ) && !$this->trxLevel() && $sql != 'BEGIN' ) {
$this->begin();
}
# Do the query and handle errors
$ret = $this->doQuery( $commentedSql );
if ( false === $ret ) {
$this->reportQueryError( $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore );
}
if ( $wgProfiling ) {
wfProfileOut( $profName );
}
return $ret;
}
# The DBMS-dependent part of query()
function doQuery( $sql ) {
if( $this->bufferResults() ) {
$ret = mysql_query( $sql, $this->mConn );
} else {
$ret = mysql_unbuffered_query( $sql, $this->mConn );
}
return $ret;
}
function reportQueryError( $error, $errno, $sql, $fname, $tempIgnore = false ) {
global $wgCommandLineMode, $wgFullyInitialised;
# Ignore errors during error handling to avoid infinite recursion
$ignore = $this->setIgnoreErrors( true );
$ignore = $this->ignoreErrors( true );
if( $ignore || $tempIgnore ) {
wfDebug("SQL ERROR (ignored): " . $error . "\n");
@ -237,7 +275,7 @@ class Database {
$this->mOut->databaseError( $fname, $sql, $error, $errno );
}
}
$this->setIgnoreErrors( $ignore );
$this->ignoreErrors( $ignore );
}
function freeResult( $res ) {
@ -470,10 +508,9 @@ class Database {
function tableExists( $table )
{
$table = $this->tableName( $table );
$old = $this->mIgnoreErrors;
$this->mIgnoreErrors = true;
$old = $this->ignoreErrors( true );
$res = $this->query( "SELECT 1 FROM $table LIMIT 1" );
$this->mIgnoreErrors = $old;
$this->ignoreErrors( $old );
if( $res ) {
$this->freeResult( $res );
return true;
@ -521,6 +558,11 @@ class Database {
# If errors are explicitly ignored, returns success
function insert( $table, $a, $fname = "Database::insert", $options = array() )
{
# No rows to insert, easy just return now
if ( !count( $a ) ) {
return true;
}
$table = $this->tableName( $table );
if ( !is_array( $options ) ) {
$options = array( $options );
@ -532,7 +574,7 @@ class Database {
$multi = false;
$keys = array_keys( $a );
}
$sql = 'INSERT ' . implode( ' ', $options ) .
" INTO $table (" . implode( ',', $keys ) . ') VALUES ';
@ -784,7 +826,7 @@ class Database {
$this->query( "BEGIN", $myFname );
$args = func_get_args();
$function = array_shift( $args );
$oldIgnore = $dbw->setIgnoreErrors( true );
$oldIgnore = $dbw->ignoreErrors( true );
$tries = DEADLOCK_TRIES;
if ( is_array( $function ) ) {
$fname = $function[0];
@ -806,7 +848,7 @@ class Database {
}
}
} while( $dbw->wasDeadlock && --$tries > 0 );
$this->setIgnoreErrors( $oldIgnore );
$this->ignoreErrors( $oldIgnore );
if ( $tries <= 0 ) {
$this->query( "ROLLBACK", $myFname );
$this->reportQueryError( $error, $errno, $sql, $fname );
@ -851,6 +893,43 @@ class Database {
return array( false, false );
}
}
# Begin a transaction, or if a transaction has already started, continue it
function begin( $fname = 'Database::begin' ) {
if ( !$this->mTrxLevel ) {
$this->immediateBegin( $fname );
} else {
$this->mTrxLevel++;
}
}
# End a transaction, or decrement the nest level if transactions are nested
function commit( $fname = 'Database::commit' ) {
if ( $this->mTrxLevel ) {
$this->mTrxLevel--;
}
if ( !$this->mTrxLevel ) {
$this->immediateCommit( $fname );
}
}
# Rollback a transaction
function rollback( $fname = 'Database::rollback' ) {
$this->query( 'ROLLBACK', $fname );
$this->mTrxLevel = 0;
}
# Begin a transaction, committing any previously open transaction
function immediateBegin( $fname = 'Database::immediateBegin' ) {
$this->query( 'BEGIN', $fname );
$this->mTrxLevel = 1;
}
# Commit transaction, if one is open
function immediateCommit( $fname = 'Database::immediateCommit' ) {
$this->query( 'COMMIT', $fname );
$this->mTrxLevel = 0;
}
}
class DatabaseMysql extends Database {
@ -887,7 +966,7 @@ function wfEmergencyAbort( &$conn, $error ) {
$search = $_REQUEST['search'];
echo wfMsgNoDB( "searchdisabled" );
echo wfMsgNoDB( "googlesearch", htmlspecialchars( $search ), $wgInputEncoding );
wfAbruptExit();
wfErrorExit();
} else {
$t = Title::newFromText( wfMsgNoDB( "mainpage" ) );
}
@ -907,7 +986,7 @@ function wfEmergencyAbort( &$conn, $error ) {
}
echo $text;
wfAbruptExit();
wfErrorExit();
}
function wfLimitResult( $limit, $offset ) {

View file

@ -18,17 +18,15 @@ class DatabasePgsql extends Database {
var $mInsertId = NULL;
function DatabasePgsql($server = false, $user = false, $password = false, $dbName = false,
$failFunction = false, $debug = false, $bufferResults = true, $ignoreErrors = false)
$failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
{
Database::Database( $server, $user, $password, $dbName, $failFunction, $debug,
$bufferResults, $ignoreErrors );
Database::Database( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix );
}
/* static */ function newFromParams( $server, $user, $password, $dbName,
$failFunction = false, $debug = false, $bufferResults = true, $ignoreErrors = false )
/* static */ function newFromParams( $server = false, $user = false, $password = false, $dbName = false,
$failFunction = false, $flags = 0, $tablePrefix = 'get from global' )
{
return new DatabasePgsql( $server, $user, $password, $dbName, $failFunction, $debug,
$bufferResults, $ignoreErrors );
return new DatabasePgsql( $server, $user, $password, $dbName, $failFunction, $flags, $tablePrefix );
}
# Usually aborts on failure
@ -74,53 +72,10 @@ class DatabasePgsql extends Database {
}
}
# Usually aborts on failure
# If errors are explicitly ignored, returns success
function query( $sql, $fname = "", $tempIgnore = false )
{
global $wgProfiling;
if ( $wgProfiling ) {
# generalizeSQL will probably cut down the query to reasonable
# logging size most of the time. The substr is really just a sanity check.
$profName = "query: " . substr( Database::generalizeSQL( $sql ), 0, 255 );
wfProfileIn( $profName );
}
$this->mLastQuery = $sql;
if ( $this->mDebug ) {
$sqlx = substr( $sql, 0, 500 );
$sqlx = wordwrap(strtr($sqlx,"\t\n"," "));
wfDebug( "SQL: $sqlx\n" );
}
$ret = pg_query( $this->mConn , $sql);
$this->mLastResult = $ret;
if ( false == $ret ) {
// Ignore errors during error handling to prevent infinite recursion
$ignore = $this->setIgnoreErrors( true );
$error = pg_last_error( $this->mConn );
// TODO FIXME : no error number function in postgre
// $errno = mysql_errno( $this->mConn );
if( $ignore || $tempIgnore ) {
wfDebug("SQL ERROR (ignored): " . $error . "\n");
} else {
wfDebug("SQL ERROR: " . $error . "\n");
if ( $this->mOut ) {
// this calls wfAbruptExit()
$this->mOut->databaseError( $fname, $sql, $error, 0 );
}
}
$this->setIgnoreErrors( $ignore );
}
if ( $wgProfiling ) {
wfProfileOut( $profName );
}
return $ret;
function doQuery( $sql ) {
return pg_query( $this->mConn , $sql);
}
function queryIgnore( $sql, $fname = "" ) {
return $this->query( $sql, $fname, true );
}
@ -168,6 +123,8 @@ class DatabasePgsql extends Database {
function dataSeek( $res, $row ) { return pg_result_seek( $res, $row ); }
function lastError() { return pg_last_error(); }
function lastErrno() { return 1; }
function affectedRows() {
return pg_affected_rows( $this->mLastResult );
}
@ -215,14 +172,14 @@ class DatabasePgsql extends Database {
# IGNORE is performed using single-row inserts, ignoring errors in each
if ( in_array( 'IGNORE', $options ) ) {
# FIXME: need some way to distiguish between key collision and other types of error
$oldIgnore = $this->setIgnoreErrors( true );
$oldIgnore = $this->ignoreErrors( true );
if ( !is_array( reset( $a ) ) ) {
$a = array( $a );
}
foreach ( $a as $row ) {
parent::insertArray( $table, $row, $fname, array() );
}
$this->setIgnoreErrors( $oldIgnore );
$this->ignoreErrors( $oldIgnore );
$retVal = true;
} else {
$retVal = parent::insertArray( $table, $a, $fname, array() );

View file

@ -70,6 +70,13 @@ $wgDBprefix = ''; # Table name prefix
# password: DB password
# type: "mysql" or "pgsql"
# load: ratio of DB_SLAVE load, must be >=0, the sum of all loads must be >0
# flags: bit field
# DBO_DEFAULT -- turns on DBO_TRX only if !$wgCommandLineMode (recommended)
# DBO_DEBUG -- equivalent of $wgDebugDumpSql
# DBO_TRX -- wrap entire request in a transaction
# DBO_IGNORE -- ignore errors (not useful in LocalSettings.php)
# DBO_NOBUFFER -- turn off buffering (not useful in LocalSettings.php)
#
# Leave at false to use the single-server variables above
$wgDBservers = false;
@ -139,6 +146,7 @@ $wgReadOnlyFile = "{$wgUploadDirectory}/lock_yBgMBwiR";
# used, as it may contain private data.
$wgDebugLogFile = '';
$wgDebugRedirects = false;
$wgDebugRawPage = false; # Avoid overlapping debug entries by leaving out CSS
$wgDebugComments = false;
$wgReadOnly = false;
@ -160,7 +168,7 @@ $wgUseCategoryMagic = true;
# FIXME: need fixing
$wgUseCategoryBrowser = false;
$wgEnablePersistentLC = false; # Persistent link cache in linkscc table; FAILS on MySQL 3.x
$wgEnablePersistentLC = false; # Obsolete, do not use
$wgCompressedPersistentLC = true; # use gzcompressed blobs
$wgEnableParserCache = false; # requires that php was compiled --with-zlib
@ -445,4 +453,8 @@ $wgAllowPageInfo = false;
# Maximum indent level of toc.
$wgMaxTocLevel = 999;
# Recognise longitude/latitude coordinates
$wgUseGeoMode = false;
?>

View file

@ -219,8 +219,13 @@ function wfUtf8ToHTML($string) {
function wfDebug( $text, $logonly = false )
{
global $wgOut, $wgDebugLogFile, $wgDebugComments, $wgProfileOnly;
global $wgOut, $wgDebugLogFile, $wgDebugComments, $wgProfileOnly, $wgDebugRawPage;
# Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet
if ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' && !$wgDebugRawPage ) {
return;
}
if ( isset( $wgOut ) && $wgDebugComments && !$logonly ) {
$wgOut->debug( $text );
}
@ -240,7 +245,7 @@ function wfLogDBError( $text ) {
function logProfilingData()
{
global $wgRequestTime, $wgDebugLogFile;
global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest;
global $wgProfiling, $wgProfileStack, $wgProfileLimit, $wgUser;
$now = wfTime();
@ -263,7 +268,7 @@ function logProfilingData()
$log = sprintf( "%s\t%04.3f\t%s\n",
gmdate( 'YmdHis' ), $elapsed,
urldecode( $_SERVER['REQUEST_URI'] . $forward ) );
if ( '' != $wgDebugLogFile ) {
if ( '' != $wgDebugLogFile && ( $wgRequest->getVal('action') != 'raw' || $wgDebugRawPage ) ) {
error_log( $log . $prof, 3, $wgDebugLogFile );
}
}
@ -360,7 +365,9 @@ function wfGo( $s )
}
# Just like exit() but makes a note of it.
function wfAbruptExit(){
# Commits open transactions except if the error parameter is set
function wfAbruptExit( $error = false ){
global $wgLoadBalancer;
static $called = false;
if ( $called ){
exit();
@ -377,9 +384,16 @@ function wfAbruptExit(){
} else {
wfDebug('WARNING: Abrupt exit\n');
}
if ( !$error ) {
$wgLoadBalancer->closeAll();
}
exit();
}
function wfErrorExit() {
wfAbruptExit( true );
}
function wfDebugDieBacktrace( $msg = '' ) {
global $wgCommandLineMode;
@ -773,11 +787,17 @@ function wfSetVar( &$dest, $source )
return $temp;
}
# Sets dest to a reference to source and returns the original dest
# Pity that doesn't work in PHP
function &wfSetRef( &$dest, &$source )
{
die( "You can't rebind a variable in the caller's scope" );
# As for wfSetVar except setting a bit
function wfSetBit( &$dest, $bit, $state = true ) {
$temp = (bool)($dest & $bit );
if ( !is_null( $state ) ) {
if ( $state ) {
$dest |= $bit;
} else {
$dest &= ~$bit;
}
}
return $temp;
}
# This function takes two arrays as input, and returns a CGI-style string, e.g.

View file

@ -85,6 +85,7 @@ class LinksUpdate {
}
$sql .= $dbw->addQuotes( $badTitle );
}
$sql .= ")";
$dbw->query( $sql, $fname );
}
} else {

View file

@ -29,7 +29,7 @@ define( "MASTER_WAIT_TIMEOUT", 15 ); # Time to wait for a slave to synchronise
class LoadBalancer {
/* private */ var $mServers, $mConnections, $mLoads;
/* private */ var $mFailFunction;
/* private */ var $mForce, $mReadIndex, $mLastConn;
/* private */ var $mForce, $mReadIndex, $mLastIndex;
/* private */ var $mWaitForFile, $mWaitForPos;
function LoadBalancer()
@ -39,7 +39,7 @@ class LoadBalancer {
$this->mFailFunction = false;
$this->mReadIndex = -1;
$this->mForce = -1;
$this->mLastConn = false;
$this->mLastIndex = -1;
}
function newFromParams( $servers, $failFunction = false )
@ -57,7 +57,7 @@ class LoadBalancer {
$this->mWriteIndex = -1;
$this->mForce = -1;
$this->mConnections = array();
$this->mLastConn = false;
$this->mLastIndex = 1;
$this->mLoads = array();
$this->mWaitForFile = false;
$this->mWaitForPos = false;
@ -92,13 +92,14 @@ class LoadBalancer {
return $i;
}
function &getReader()
function getReaderIndex()
{
$i = false;
if ( $this->mForce >= 0 ) {
$conn =& $this->getConnection( $this->mForce );
$i = $this->mForce;
} else {
if ( $this->mReadIndex >= 0 ) {
$conn =& $this->getConnection( $this->mReadIndex );
$i = $this->mReadIndex;
} else {
# $loads is $this->mLoads except with elements knocked out if they
# don't work
@ -109,6 +110,8 @@ class LoadBalancer {
wfDebug( "Using reader #$i: {$this->mServers[$i]['host']}\n" );
$conn =& $this->getConnection( $i );
$this->mConnections[$i] =& $conn;
if ( !$conn->isOpen() ) {
unset( $loads[$i] );
}
@ -116,14 +119,12 @@ class LoadBalancer {
} while ( $i !== false && !$conn->isOpen() );
if ( $conn->isOpen() ) {
$this->mReadIndex = $i;
} else {
$i = false;
}
}
}
if ( $conn === false || !$conn->isOpen() ) {
$this->reportConnectionError( $conn );
$conn = false;
}
return $conn;
return $i;
}
# Set the master wait position
@ -142,7 +143,10 @@ class LoadBalancer {
$this->mWaitForPos = $pos;
if ( $this->mReadIndex > 0 ) {
$this->doWait( $this->mReadIndex );
if ( !$this->doWait( $this->mReadIndex ) ) {
# Use master instead
$this->mReadIndex = 0;
}
}
}
@ -156,7 +160,7 @@ class LoadBalancer {
list( $file, $pos ) = explode( ' ', $memcPos );
# If the saved position is later than the requested position, return now
if ( $file == $this->mWaitForFile && $this->mWaitForPos <= $pos ) {
return;
return true;
}
}
@ -166,16 +170,16 @@ class LoadBalancer {
if ( $result == -1 || is_null( $result ) ) {
# Timed out waiting for slave, use master instead
# This is not the ideal solution. If there are a large number of slaves, a slow
# replicated write query will cause the master to be swamped with reads. However
# that's a relatively graceful failure mode, so it will do for now.
wfDebug( "Timed out waiting for slave #$index pos {$this->mWaitForFile} {$this->mWaitForPos}\n" );
$this->mReadIndex = 0;
$retVal = false;
} else {
$retVal = true;
wfDebug( "Done\n" );
}
return $retVal;
}
# Get a connection by index
function &getConnection( $i, $fail = false )
{
/*
@ -191,37 +195,55 @@ class LoadBalancer {
}*/
# Operation-based index
# Note, getReader() and getWriter() will re-enter this function
if ( $i == DB_SLAVE ) {
$this->mLastConn =& $this->getReader();
if ( $i == DB_SLAVE ) {
# Note: re-entrant
$i = $this->getReaderIndex();
} elseif ( $i == DB_MASTER ) {
$this->mLastConn =& $this->getWriter();
$i = $this->getWriterIndex();
} elseif ( $i == DB_LAST ) {
# Just use $this->mLastConn, which should already be set
if ( $this->mLastConn === false ) {
# Just use $this->mLastIndex, which should already be set
$i = $this->mLastIndex;
if ( $i === -1 ) {
# Oh dear, not set, best to use the writer for safety
$this->mLastConn =& $this->getWriter();
$i = $this->getWriterIndex();
}
} else {
# Explicit index
if ( !array_key_exists( $i, $this->mConnections ) || !$this->mConnections[$i]->isOpen() ) {
$this->mConnections[$i] = $this->makeConnection( $this->mServers[$i] );
if ( $i != 0 && $this->mWaitForFile ) {
$this->doWait( $i );
}
# Now we have an explicit index into the servers array
if ( !$this->isOpen( $i ) ) {
$this->mConnections[$i] = $this->makeConnection( $this->mServers[$i] );
if ( $i != 0 && $this->mWaitForFile ) {
if ( !$this->doWait( $i ) ) {
# Error waiting for this slave, use master instead
$this->mReadIndex = 0;
$i = 0;
if ( !$this->isOpen( 0 ) ) {
$this->mConnections[0] = $this->makeConnection( $this->mServers[0] );
}
wfDebug( "Failed over to {$this->mConnections[0]->mServer}\n" );
}
}
if ( !$this->mConnections[$i]->isOpen() ) {
wfDebug( "Failed to connect to database $i at {$this->mServers[$i]['host']}\n" );
if ( $fail ) {
$this->reportConnectionError( $this->mConnections[$i] );
}
$this->mConnections[$i] = false;
}
$this->mLastConn =& $this->mConnections[$i];
}
return $this->mLastConn;
if ( !$this->isOpen( $i ) ) {
wfDebug( "Failed to connect to database $i at {$this->mServers[$i]['host']}\n" );
if ( $fail ) {
$this->reportConnectionError( $this->mConnections[$i] );
}
$this->mConnections[$i] = false;
}
$this->mLastIndex = $i;
return $this->mConnections[$i];
}
/* private */ function isOpen( $index ) {
if ( array_key_exists( $index, $this->mConnections ) && $this->mConnections[$index]->isOpen() ) {
return true;
} else {
return false;
}
}
/* private */ function makeConnection( &$server ) {
extract( $server );
# Get class for this database type
@ -231,7 +253,7 @@ class LoadBalancer {
}
# Create object
return new $class( $host, $user, $password, $dbname, 1 );
return new $class( $host, $user, $password, $dbname, 1, $flags );
}
function reportConnectionError( &$conn )
@ -247,14 +269,9 @@ class LoadBalancer {
$conn->reportConnectionError();
}
function &getWriter()
function getWriterIndex()
{
$c =& $this->getConnection( 0 );
if ( $c === false || !$c->isOpen() ) {
$this->reportConnectionError( $c );
$c = false;
}
return $c;
return 0;
}
function force( $i )
@ -300,4 +317,21 @@ class LoadBalancer {
$this->waitFor( $_SESSION['master_log_file'], $_SESSION['master_pos'] );
}
}
# Close all open connections
function closeAll() {
foreach( $this->mConnections as $i => $conn ) {
if ( $this->isOpen( $i ) ) {
$conn->close();
}
}
}
function commitAll() {
foreach( $this->mConnections as $i => $conn ) {
if ( $this->isOpen( $i ) ) {
$conn->immediateCommit();
}
}
}
}

View file

@ -4,29 +4,7 @@
# "magic" behaviors of them based on index. The textual
# names of the namespaces are handled by Language.php.
# Virtual namespaces; these don't appear in the page database:
define("NS_MEDIA", -2);
define("NS_SPECIAL", -1);
# Real namespaces:
define("NS_MAIN", 0);
define("NS_TALK", 1);
define("NS_USER", 2);
define("NS_USER_TALK", 3);
define("NS_WP", 4);
define("NS_WIKIPEDIA", 4);
define("NS_WP_TALK", 5);
define("NS_WIKIPEDIA_TALK", 5);
define("NS_IMAGE", 6);
define("NS_IMAGE_TALK", 7);
define("NS_MEDIAWIKI", 8);
define("NS_MEDIAWIKI_TALK", 9);
define("NS_TEMPLATE", 10);
define("NS_TEMPLATE_TALK", 11);
define("NS_HELP", 12);
define("NS_HELP_TALK", 13);
define("NS_CATEGORY", 14);
define("NS_CATEGORY_TALK", 15);
# Definitions of the NS_ constants are in Defines.php
# These are synonyms for the names given in the language file
# Users and translators should not change them

View file

@ -465,13 +465,14 @@ class OutputPage {
$this->setRobotpolicy( "noindex,nofollow" );
$this->setArticleRelated( false );
$this->enableClientCache( false );
$this->mRedirect = "";
$this->mBodytext = "";
$this->addHTML( "<p>" . wfMsg( $msg ) . "</p>\n" );
$this->returnToMain( false );
$this->output();
wfAbruptExit();
wfErrorExit();
}
function sysopRequired()
@ -534,6 +535,7 @@ class OutputPage {
$this->setRobotpolicy( "noindex,nofollow" );
$this->setArticleRelated( false );
$this->enableClientCache( false );
$this->mRedirect = "";
if ( $wgCommandLineMode ) {
$msg = wfMsgNoDB( "dberrortextcl" );
@ -548,7 +550,7 @@ class OutputPage {
if ( $wgCommandLineMode || !is_object( $wgUser )) {
print "$msg\n";
wfAbruptExit();
wfErrorExit();
}
$sk = $wgUser->getSkin();
$shlink = $sk->makeKnownLink( wfMsgNoDB( "searchhelppage" ),
@ -556,7 +558,7 @@ class OutputPage {
$msg = str_replace( "$5", $shlink, $msg );
$this->mBodytext = $msg;
$this->output();
wfAbruptExit();
wfErrorExit();
}
function readOnlyPage( $source = null, $protected = false )
@ -595,10 +597,11 @@ class OutputPage {
$this->setRobotpolicy( "noindex,nofollow" );
$this->setArticleRelated( false );
$this->enableClientCache( false );
$this->mRedirect = "";
$this->mBodytext = $message;
$this->output();
wfAbruptExit();
wfErrorExit();
}
function unexpectedValueError( $name, $val )

View file

@ -72,7 +72,7 @@ global $wgMemc, $wgMagicWords, $wgMwRedir, $wgDebugLogFile;
global $wgMessageCache, $wgUseMemCached, $wgUseDatabaseMessages;
global $wgMsgCacheExpiry, $wgCommandLineMode;
global $wgBlockCache, $wgParserCache, $wgParser, $wgDBConnections;
global $wgLoadBalancer, $wgDBservers;
global $wgLoadBalancer, $wgDBservers, $wgDebugDumpSql;
global $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, $wgDBtype;
global $wgFullyInitialised;
@ -157,7 +157,8 @@ if ( !$wgDBservers ) {
'password' => $wgDBpassword,
'dbname' => $wgDBname,
'type' => $wgDBtype,
'load' => 1
'load' => 1,
'flags' => ($wgDebugDumpSql ? DBO_DEBUG : 0) | DBO_DEFAULT
));
}
$wgLoadBalancer = LoadBalancer::newFromParams( $wgDBservers );

View file

@ -37,8 +37,8 @@ $wgSpecialPages = array_merge($wgSpecialPages, array (
"Recentchangeslinked" => new UnlistedSpecialPage( "Recentchangeslinked" ),
"Movepage" => new UnlistedSpecialPage( "Movepage" ),
"Blockme" => new UnlistedSpecialPage( "Blockme" ),
"Geo" => new SpecialPage( "Geo" ),
"Validate" => new SpecialPage( "Validate" ),
"Geo" => new UnlistedSpecialPage( "Geo" ),
"Validate" => new UnlistedSpecialPage( "Validate" ),
"Booksources" => new SpecialPage( "Booksources" ),
"Categories" => new SpecialPage( "Categories" ),
"Export" => new SpecialPage( "Export" ),
@ -49,7 +49,7 @@ $wgSpecialPages = array_merge($wgSpecialPages, array (
"Asksql" => new SpecialPage( "Asksql", "sysop" ),
"Undelete" => new SpecialPage( "Undelete", "sysop" ),
"Makesysop" => new SpecialPage( "Makesysop", "sysop" ),
"Import" => new SpecialPage( "Import", "sysop" ),
# "Import" => new SpecialPage( "Import", "sysop" ),
"Lockdb" => new SpecialPage( "Lockdb", "developer" ),
"Unlockdb" => new SpecialPage( "Unlockdb", "developer" )
));

View file

@ -11,6 +11,7 @@ if(!file_exists("LocalSettings.php")) {
}
define( "MEDIAWIKI", true );
require_once( "./includes/Defines.php" );
require_once( "./LocalSettings.php" );
require_once( "includes/Setup.php" );
@ -54,8 +55,6 @@ if ( !is_null( $wgTitle ) && !$wgTitle->userCanRead() ) {
exit;
}
$db =& wfGetDB( DB_MASTER );
if ( $search = $wgRequest->getText( 'search' ) ) {
$wgTitle = Title::makeTitle( NS_SPECIAL, "Search" );
if( $wgRequest->getVal( 'fulltext' ) || !is_null( $wgRequest->getVal( 'offset' ) ) ) {
@ -97,7 +96,6 @@ if ( $search = $wgRequest->getText( 'search' ) ) {
$wgArticle = new Article( $wgTitle );
}
$db->query("BEGIN");
switch( $action ) {
case "view":
$wgOut->setSquidMaxage( $wgSquidMaxage );
@ -168,17 +166,23 @@ if ( $search = $wgRequest->getText( 'search' ) ) {
default:
$wgOut->errorpage( "nosuchaction", "nosuchactiontext" );
}
$db->query("COMMIT");
}
# Deferred updates aren't really deferred anymore. It's important to report errors to the
# user, and that means doing this before OutputPage::output(). Note that for page saves,
# the client will wait until the script exits anyway before following the redirect.
foreach ( $wgDeferredUpdateList as $up ) {
$up->doUpdate();
}
$wgLoadBalancer->saveMasterPos();
# Now commit any transactions, so that unreported errors after output() don't roll back the whole thing
$wgLoadBalancer->commitAll();
$wgOut->output();
foreach ( $wgDeferredUpdateList as $up ) {
$db->query("BEGIN");
$up->doUpdate();
$db->query("COMMIT");
}
logProfilingData();
$wgLoadBalancer->closeAll();
wfDebug( "Request ended normally\n" );
?>

View file

@ -14,6 +14,10 @@ function refreshLinks( $start ) {
# Don't generate TeX PNGs (lack of a sensible current directory causes errors anyway)
$wgUser->setOption("math", 3);
# Turn on link cache in skin
$sk =& $wgUser->getSkin();
$sk->postParseLinkColour( false );
for ($id = $start; $id <= $end; $id++) {
if ( !($id % REPORTING_INTERVAL) ) {

View file

@ -50,8 +50,7 @@ $wgTitle = Title::newFromText( "Update script" );
#
print "Checking database for necessary updates...\n";
$wgDatabase = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname,
1, false, true, false);
$wgDatabase = Database::newFromParams( $wgDBserver, $wgDBadminuser, $wgDBadminpassword, $wgDBname, 1 );
if ( !$wgDatabase->isOpen() ) {
print "Unable to connect to database: " . $wgDatabase->lastError() . "\n";
exit();