From 54e2b71bd14e0cd160580239356812213a8304ed Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Sat, 5 Apr 2008 18:11:23 +0000 Subject: [PATCH] * Generalised FileRepoStatus, providing a very similar general Status object. * Fixed external storage in LBFactory_Multi, was broken * Useful debugging hack $wgAllDBsAreLocalhost --- includes/AutoLoader.php | 1 + includes/Database.php | 12 +- includes/DefaultSettings.php | 8 ++ includes/LBFactory_Multi.php | 37 +++--- includes/Status.php | 174 +++++++++++++++++++++++++++ includes/filerepo/FileRepoStatus.php | 146 +--------------------- 6 files changed, 212 insertions(+), 166 deletions(-) create mode 100644 includes/Status.php diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index ebf166c21e..0aa929a99d 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -242,6 +242,7 @@ function __autoload($className) { 'SpecialVersion' => 'includes/SpecialVersion.php', 'SqlBagOStuff' => 'includes/BagOStuff.php', 'SquidUpdate' => 'includes/SquidUpdate.php', + 'Status' => 'includes/Status.php', 'StringUtils' => 'includes/StringUtils.php', 'TableDiffFormatter' => 'includes/DifferenceEngine.php', 'TablePager' => 'includes/Pager.php', diff --git a/includes/Database.php b/includes/Database.php index 1e247b4506..486877fae5 100644 --- a/includes/Database.php +++ b/includes/Database.php @@ -295,7 +295,7 @@ class Database { * If the failFunction is set to a non-zero integer, returns success */ function open( $server, $user, $password, $dbName ) { - global $wguname; + global $wguname, $wgAllDBsAreLocalhost; wfProfileIn( __METHOD__ ); # Test for missing mysql.so @@ -310,6 +310,12 @@ class Database { throw new DBConnectionError( $this, "MySQL functions missing, have you compiled PHP with the --with-mysql option?\n" ); } + # Debugging hack -- fake cluster + if ( $wgAllDBsAreLocalhost ) { + $realServer = 'localhost'; + } else { + $realServer = $server; + } $this->close(); $this->mServer = $server; $this->mUser = $user; @@ -330,10 +336,10 @@ class Database { usleep( 1000 ); } if ( $this->mFlags & DBO_PERSISTENT ) { - @/**/$this->mConn = mysql_pconnect( $server, $user, $password ); + @/**/$this->mConn = mysql_pconnect( $realServer, $user, $password ); } else { # Create a new connection... - @/**/$this->mConn = mysql_connect( $server, $user, $password, true ); + @/**/$this->mConn = mysql_connect( $realServer, $user, $password, true ); } if ($this->mConn === false) { #$iplus = $i + 1; diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 4d578a1983..ca8065d102 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -565,6 +565,13 @@ $wgDBprefix = ''; /** MySQL table options to use during installation or update */ $wgDBTableOptions = 'TYPE=InnoDB'; +/** + * Make all database connections secretly go to localhost. Fool the load balancer + * thinking there is an arbitrarily large cluster of servers to connect to. + * Useful for debugging. + */ +$wgAllDBsAreLocalhost = false; + /**#@-*/ @@ -2663,6 +2670,7 @@ $wgExternalStores = false; /** * An array of external mysql servers, e.g. * $wgExternalServers = array( 'cluster1' => array( 'srv28', 'srv29', 'srv30' ) ); + * Used by LBFactory_Simple, may be ignored if $wgLBFactoryConf is set to another class. */ $wgExternalServers = array(); diff --git a/includes/LBFactory_Multi.php b/includes/LBFactory_Multi.php index 788a28c9a3..c0f82898eb 100644 --- a/includes/LBFactory_Multi.php +++ b/includes/LBFactory_Multi.php @@ -5,15 +5,15 @@ * Ignores the old configuration globals * * Configuration: - * sectionsByDB A map of database names to section names + * sectionsByDB A map of database names to section names * * sectionLoads A 2-d map. For each section, gives a map of server names to load ratios. * For example: array( 'section1' => array( 'db1' => 100, 'db2' => 100 ) ) * - * mainTemplate A server info associative array as documented for $wgDBservers. The host, + * serverTemplate A server info associative array as documented for $wgDBservers. The host, * hostName and load entries will be overridden. * - * groupLoadsBySection A 3-d map giving server load ratios for each section and group. For example: + * groupLoadsBySection A 3-d map giving server load ratios for each section and group. For example: * array( 'section1' => array( 'group1' => array( 'db1' => 100, 'db2' => 100 ) ) ) * * groupLoadsByDB A 3-d map giving server load ratios by DB name. @@ -22,23 +22,22 @@ * * externalLoads A map of external storage cluster name to server load map * - * externalTemplate A server info structure used for external storage servers + * externalTemplateOverrides A set of server info keys overriding serverTemplate for external storage * - * templateOverridesByServer A 2-d map overriding mainTemplate or externalTemplate on a - * server-by-server basis. + * templateOverridesByServer A 2-d map overriding serverTemplate and externalTemplateOverrides on a + * server-by-server basis. Applies to both core and external storage. * - * templateOverridesByCluster A 2-d map overriding externalTemplate by cluster + * templateOverridesByCluster A 2-d map overriding the server info by external storage cluster * - * masterTemplateOverrides An override array for mainTemplate and externalTemplate for all - * master servers. + * masterTemplateOverrides An override array for all master servers. * */ class LBFactory_Multi extends LBFactory { // Required settings - var $sectionsByDB, $sectionLoads, $mainTemplate; + var $sectionsByDB, $sectionLoads, $serverTemplate; // Optional settings var $groupLoadsBySection = array(), $groupLoadsByDB = array(), $hostsByName = array(); - var $externalLoads = array(), $externalTemplate, $templateOverridesByServer; + var $externalLoads = array(), $externalTemplateOverrides, $templateOverridesByServer; var $templateOverridesByCluster, $masterTemplateOverrides; // Other stuff var $conf, $mainLBs = array(), $extLBs = array(); @@ -47,9 +46,9 @@ class LBFactory_Multi extends LBFactory { function __construct( $conf ) { $this->chronProt = new ChronologyProtector; $this->conf = $conf; - $required = array( 'sectionsByDB', 'sectionLoads', 'mainTemplate' ); + $required = array( 'sectionsByDB', 'sectionLoads', 'serverTemplate' ); $optional = array( 'groupLoadsBySection', 'groupLoadsByDB', 'hostsByName', - 'externalLoads', 'externalTemplate', 'templateOverridesByServer', + 'externalLoads', 'externalTemplateOverrides', 'templateOverridesByServer', 'templateOverridesByCluster', 'masterTemplateOverrides' ); foreach ( $required as $key ) { @@ -95,7 +94,7 @@ class LBFactory_Multi extends LBFactory { if ( isset( $this->groupLoadsBySection[$section] ) ) { $groupLoads = array_merge_recursive( $groupLoads, $this->groupLoadsBySection[$section] ); } - $this->mainLBs[$section] = $this->newLoadBalancer( $this->mainTemplate, + $this->mainLBs[$section] = $this->newLoadBalancer( $this->serverTemplate, $this->sectionLoads[$section], $groupLoads, "main-$section" ); $this->chronProt->initLB( $this->mainLBs[$section] ); } @@ -107,12 +106,12 @@ class LBFactory_Multi extends LBFactory { if ( !isset( $this->externalLoads[$cluster] ) ) { throw new MWException( __METHOD__.": Unknown cluster \"$cluster\"" ); } + $template = $this->serverTemplate; + if ( isset( $this->externalTemplateOverrides ) ) { + $template = $this->externalTemplateOverrides + $template; + } if ( isset( $this->templateOverridesByCluster[$cluster] ) ) { - $template = $this->templateOverridesByCluster[$cluster]; - } elseif ( isset( $this->externalTemplate ) ) { - $template = $this->externalTemplate; - } else { - $template = $this->mainTemplate; + $template = $this->templateOverridesByCluster[$cluster] + $template; } $this->extLBs[$cluster] = $this->newLoadBalancer( $template, $this->externalLoads[$cluster], array(), "ext-$cluster" ); diff --git a/includes/Status.php b/includes/Status.php new file mode 100644 index 0000000000..12a101af5b --- /dev/null +++ b/includes/Status.php @@ -0,0 +1,174 @@ +ok = false; + return $result; + } + + static function newGood( $value = null ) { + $result = new self; + $result->value = $value; + return $result; + } + + function setResult( $ok, $value = null ) { + $this->ok = $ok; + $this->value = $value; + } + + function isGood() { + return $this->ok && !$this->errors; + } + + function isOK() { + return $this->ok; + } + + function warning( $message /*, parameters... */ ) { + $params = array_slice( func_get_args(), 1 ); + $this->errors[] = array( + 'type' => 'warning', + 'message' => $message, + 'params' => $params ); + } + + /** + * Add an error, do not set fatal flag + * This can be used for non-fatal errors + */ + function error( $message /*, parameters... */ ) { + $params = array_slice( func_get_args(), 1 ); + $this->errors[] = array( + 'type' => 'error', + 'message' => $message, + 'params' => $params ); + } + + /** + * Add an error and set OK to false, indicating that the operation as a whole was fatal + */ + function fatal( $message /*, parameters... */ ) { + $params = array_slice( func_get_args(), 1 ); + $this->errors[] = array( + 'type' => 'error', + 'message' => $message, + 'params' => $params ); + $this->ok = false; + } + + protected function cleanParams( $params ) { + if ( !$this->cleanCallback ) { + return $params; + } + $cleanParams = array(); + foreach ( $params as $i => $param ) { + $cleanParams[$i] = call_user_func( $this->cleanCallback, $param ); + } + return $cleanParams; + } + + protected function getItemXML( $item ) { + $params = $this->cleanParams( $item['params'] ); + $xml = "<{$item['type']}>\n" . + Xml::element( 'message', null, $item['message'] ) . "\n" . + Xml::element( 'text', null, wfMsgReal( $item['message'], $params ) ) ."\n"; + foreach ( $params as $param ) { + $xml .= Xml::element( 'param', null, $param ); + } + $xml .= "type}>\n"; + return $xml; + } + + /** + * Get the error list as XML + */ + function getXML() { + $xml = "\n"; + foreach ( $this->errors as $error ) { + $xml .= $this->getItemXML( $error ); + } + $xml .= "\n"; + return $xml; + } + + /** + * Get the error list as a wikitext formatted list + * @param string $shortContext A short enclosing context message name, to be used + * when there is a single error + * @param string $longContext A long enclosing context message name, for a list + */ + function getWikiText( $shortContext = false, $longContext = false ) { + if ( count( $this->errors ) == 0 ) { + if ( $this->ok ) { + $this->fatal( 'internalerror_info', + __METHOD__." called for a good result, this is incorrect\n" ); + } else { + $this->fatal( 'internalerror_info', + __METHOD__.": Invalid result object: no error text but not OK\n" ); + } + } + if ( count( $this->errors ) == 1 ) { + $params = array_map( 'wfEscapeWikiText', $this->cleanParams( $this->errors[0]['params'] ) ); + $s = wfMsgReal( $this->errors[0]['message'], $params, true, false, false ); + if ( $shortContext ) { + $s = wfMsgNoTrans( $shortContext, $s ); + } elseif ( $longContext ) { + $s = wfMsgNoTrans( $longContext, "* $s\n" ); + } + } else { + $s = ''; + foreach ( $this->errors as $error ) { + $params = array_map( 'wfEscapeWikiText', $this->cleanParams( $error['params'] ) ); + $s .= '* ' . wfMsgReal( $error['message'], $params, true, false, false ) . "\n"; + } + if ( $longContext ) { + $s = wfMsgNoTrans( $longContext, $s ); + } elseif ( $shortContext ) { + $s = wfMsgNoTrans( $shortContext, "\n* $s\n" ); + } + } + return $s; + } + + /** + * Merge another status object into this one + */ + function merge( $other, $overwriteValue = false ) { + $this->errors = array_merge( $this->errors, $other->errors ); + $this->ok = $this->ok && $other->ok; + if ( $overwriteValue ) { + $this->value = $other->value; + } + $this->successCount += $other->successCount; + $this->failCount += $other->failCount; + } +} + diff --git a/includes/filerepo/FileRepoStatus.php b/includes/filerepo/FileRepoStatus.php index 5dd1dbda96..63c6680a45 100644 --- a/includes/filerepo/FileRepoStatus.php +++ b/includes/filerepo/FileRepoStatus.php @@ -1,19 +1,9 @@ cleanCallback = $repo->getErrorCleanupFunction(); } } - - function setResult( $ok, $value = null ) { - $this->ok = $ok; - $this->value = $value; - } - - function isGood() { - return $this->ok && !$this->errors; - } - - function isOK() { - return $this->ok; - } - - function warning( $message /*, parameters... */ ) { - $params = array_slice( func_get_args(), 1 ); - $this->errors[] = array( - 'type' => 'warning', - 'message' => $message, - 'params' => $params ); - } - - /** - * Add an error, do not set fatal flag - * This can be used for non-fatal errors - */ - function error( $message /*, parameters... */ ) { - $params = array_slice( func_get_args(), 1 ); - $this->errors[] = array( - 'type' => 'error', - 'message' => $message, - 'params' => $params ); - } - - /** - * Add an error and set OK to false, indicating that the operation as a whole was fatal - */ - function fatal( $message /*, parameters... */ ) { - $params = array_slice( func_get_args(), 1 ); - $this->errors[] = array( - 'type' => 'error', - 'message' => $message, - 'params' => $params ); - $this->ok = false; - } - - protected function cleanParams( $params ) { - if ( !$this->cleanCallback ) { - return $params; - } - $cleanParams = array(); - foreach ( $params as $i => $param ) { - $cleanParams[$i] = call_user_func( $this->cleanCallback, $param ); - } - return $cleanParams; - } - - protected function getItemXML( $item ) { - $params = $this->cleanParams( $item['params'] ); - $xml = "<{$item['type']}>\n" . - Xml::element( 'message', null, $item['message'] ) . "\n" . - Xml::element( 'text', null, wfMsgReal( $item['message'], $params ) ) ."\n"; - foreach ( $params as $param ) { - $xml .= Xml::element( 'param', null, $param ); - } - $xml .= "type}>\n"; - return $xml; - } - - /** - * Get the error list as XML - */ - function getXML() { - $xml = "\n"; - foreach ( $this->errors as $error ) { - $xml .= $this->getItemXML( $error ); - } - $xml .= "\n"; - return $xml; - } - - /** - * Get the error list as a wikitext formatted list - * @param string $shortContext A short enclosing context message name, to be used - * when there is a single error - * @param string $longContext A long enclosing context message name, for a list - */ - function getWikiText( $shortContext = false, $longContext = false ) { - if ( count( $this->errors ) == 0 ) { - if ( $this->ok ) { - $this->fatal( 'internalerror_info', - __METHOD__." called for a good result, this is incorrect\n" ); - } else { - $this->fatal( 'internalerror_info', - __METHOD__.": Invalid result object: no error text but not OK\n" ); - } - } - if ( count( $this->errors ) == 1 ) { - $params = array_map( 'wfEscapeWikiText', $this->cleanParams( $this->errors[0]['params'] ) ); - $s = wfMsgReal( $this->errors[0]['message'], $params, true, false, false ); - if ( $shortContext ) { - $s = wfMsgNoTrans( $shortContext, $s ); - } elseif ( $longContext ) { - $s = wfMsgNoTrans( $longContext, "* $s\n" ); - } - } else { - $s = ''; - foreach ( $this->errors as $error ) { - $params = array_map( 'wfEscapeWikiText', $this->cleanParams( $error['params'] ) ); - $s .= '* ' . wfMsgReal( $error['message'], $params, true, false, false ) . "\n"; - } - if ( $longContext ) { - $s = wfMsgNoTrans( $longContext, $s ); - } elseif ( $shortContext ) { - $s = wfMsgNoTrans( $shortContext, "\n* $s\n" ); - } - } - return $s; - } - - /** - * Merge another status object into this one - */ - function merge( $other, $overwriteValue = false ) { - $this->errors = array_merge( $this->errors, $other->errors ); - $this->ok = $this->ok && $other->ok; - if ( $overwriteValue ) { - $this->value = $other->value; - } - $this->successCount += $other->successCount; - $this->failCount += $other->failCount; - } } -- 2.20.1