Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -242,6 +242,7 @@ |
243 | 243 | 'SpecialVersion' => 'includes/SpecialVersion.php', |
244 | 244 | 'SqlBagOStuff' => 'includes/BagOStuff.php', |
245 | 245 | 'SquidUpdate' => 'includes/SquidUpdate.php', |
| 246 | + 'Status' => 'includes/Status.php', |
246 | 247 | 'StringUtils' => 'includes/StringUtils.php', |
247 | 248 | 'TableDiffFormatter' => 'includes/DifferenceEngine.php', |
248 | 249 | 'TablePager' => 'includes/Pager.php', |
Index: trunk/phase3/includes/filerepo/FileRepoStatus.php |
— | — | @@ -1,19 +1,9 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | 4 | /** |
5 | | - * Generic operation result class |
6 | | - * Has warning/error list, boolean status and arbitrary value |
| 5 | + * Generic operation result class for FileRepo-related operations |
7 | 6 | */ |
8 | | -class FileRepoStatus { |
9 | | - var $ok = true; |
10 | | - var $value; |
11 | | - |
12 | | - /** Counters for batch operations */ |
13 | | - var $successCount = 0, $failCount = 0; |
14 | | - |
15 | | - /*semi-private*/ var $errors = array(); |
16 | | - /*semi-private*/ var $cleanCallback = false; |
17 | | - |
| 7 | +class FileRepoStatus extends Status { |
18 | 8 | /** |
19 | 9 | * Factory function for fatal errors |
20 | 10 | */ |
— | — | @@ -36,136 +26,4 @@ |
37 | 27 | $this->cleanCallback = $repo->getErrorCleanupFunction(); |
38 | 28 | } |
39 | 29 | } |
40 | | - |
41 | | - function setResult( $ok, $value = null ) { |
42 | | - $this->ok = $ok; |
43 | | - $this->value = $value; |
44 | | - } |
45 | | - |
46 | | - function isGood() { |
47 | | - return $this->ok && !$this->errors; |
48 | | - } |
49 | | - |
50 | | - function isOK() { |
51 | | - return $this->ok; |
52 | | - } |
53 | | - |
54 | | - function warning( $message /*, parameters... */ ) { |
55 | | - $params = array_slice( func_get_args(), 1 ); |
56 | | - $this->errors[] = array( |
57 | | - 'type' => 'warning', |
58 | | - 'message' => $message, |
59 | | - 'params' => $params ); |
60 | | - } |
61 | | - |
62 | | - /** |
63 | | - * Add an error, do not set fatal flag |
64 | | - * This can be used for non-fatal errors |
65 | | - */ |
66 | | - function error( $message /*, parameters... */ ) { |
67 | | - $params = array_slice( func_get_args(), 1 ); |
68 | | - $this->errors[] = array( |
69 | | - 'type' => 'error', |
70 | | - 'message' => $message, |
71 | | - 'params' => $params ); |
72 | | - } |
73 | | - |
74 | | - /** |
75 | | - * Add an error and set OK to false, indicating that the operation as a whole was fatal |
76 | | - */ |
77 | | - function fatal( $message /*, parameters... */ ) { |
78 | | - $params = array_slice( func_get_args(), 1 ); |
79 | | - $this->errors[] = array( |
80 | | - 'type' => 'error', |
81 | | - 'message' => $message, |
82 | | - 'params' => $params ); |
83 | | - $this->ok = false; |
84 | | - } |
85 | | - |
86 | | - protected function cleanParams( $params ) { |
87 | | - if ( !$this->cleanCallback ) { |
88 | | - return $params; |
89 | | - } |
90 | | - $cleanParams = array(); |
91 | | - foreach ( $params as $i => $param ) { |
92 | | - $cleanParams[$i] = call_user_func( $this->cleanCallback, $param ); |
93 | | - } |
94 | | - return $cleanParams; |
95 | | - } |
96 | | - |
97 | | - protected function getItemXML( $item ) { |
98 | | - $params = $this->cleanParams( $item['params'] ); |
99 | | - $xml = "<{$item['type']}>\n" . |
100 | | - Xml::element( 'message', null, $item['message'] ) . "\n" . |
101 | | - Xml::element( 'text', null, wfMsgReal( $item['message'], $params ) ) ."\n"; |
102 | | - foreach ( $params as $param ) { |
103 | | - $xml .= Xml::element( 'param', null, $param ); |
104 | | - } |
105 | | - $xml .= "</{$this->type}>\n"; |
106 | | - return $xml; |
107 | | - } |
108 | | - |
109 | | - /** |
110 | | - * Get the error list as XML |
111 | | - */ |
112 | | - function getXML() { |
113 | | - $xml = "<errors>\n"; |
114 | | - foreach ( $this->errors as $error ) { |
115 | | - $xml .= $this->getItemXML( $error ); |
116 | | - } |
117 | | - $xml .= "</errors>\n"; |
118 | | - return $xml; |
119 | | - } |
120 | | - |
121 | | - /** |
122 | | - * Get the error list as a wikitext formatted list |
123 | | - * @param string $shortContext A short enclosing context message name, to be used |
124 | | - * when there is a single error |
125 | | - * @param string $longContext A long enclosing context message name, for a list |
126 | | - */ |
127 | | - function getWikiText( $shortContext = false, $longContext = false ) { |
128 | | - if ( count( $this->errors ) == 0 ) { |
129 | | - if ( $this->ok ) { |
130 | | - $this->fatal( 'internalerror_info', |
131 | | - __METHOD__." called for a good result, this is incorrect\n" ); |
132 | | - } else { |
133 | | - $this->fatal( 'internalerror_info', |
134 | | - __METHOD__.": Invalid result object: no error text but not OK\n" ); |
135 | | - } |
136 | | - } |
137 | | - if ( count( $this->errors ) == 1 ) { |
138 | | - $params = array_map( 'wfEscapeWikiText', $this->cleanParams( $this->errors[0]['params'] ) ); |
139 | | - $s = wfMsgReal( $this->errors[0]['message'], $params, true, false, false ); |
140 | | - if ( $shortContext ) { |
141 | | - $s = wfMsgNoTrans( $shortContext, $s ); |
142 | | - } elseif ( $longContext ) { |
143 | | - $s = wfMsgNoTrans( $longContext, "* $s\n" ); |
144 | | - } |
145 | | - } else { |
146 | | - $s = ''; |
147 | | - foreach ( $this->errors as $error ) { |
148 | | - $params = array_map( 'wfEscapeWikiText', $this->cleanParams( $error['params'] ) ); |
149 | | - $s .= '* ' . wfMsgReal( $error['message'], $params, true, false, false ) . "\n"; |
150 | | - } |
151 | | - if ( $longContext ) { |
152 | | - $s = wfMsgNoTrans( $longContext, $s ); |
153 | | - } elseif ( $shortContext ) { |
154 | | - $s = wfMsgNoTrans( $shortContext, "\n* $s\n" ); |
155 | | - } |
156 | | - } |
157 | | - return $s; |
158 | | - } |
159 | | - |
160 | | - /** |
161 | | - * Merge another status object into this one |
162 | | - */ |
163 | | - function merge( $other, $overwriteValue = false ) { |
164 | | - $this->errors = array_merge( $this->errors, $other->errors ); |
165 | | - $this->ok = $this->ok && $other->ok; |
166 | | - if ( $overwriteValue ) { |
167 | | - $this->value = $other->value; |
168 | | - } |
169 | | - $this->successCount += $other->successCount; |
170 | | - $this->failCount += $other->failCount; |
171 | | - } |
172 | 30 | } |
Index: trunk/phase3/includes/Status.php |
— | — | @@ -0,0 +1,174 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Generic operation result class |
| 6 | + * Has warning/error list, boolean status and arbitrary value |
| 7 | + * |
| 8 | + * "Good" means the operation was completed with no warnings or errors. |
| 9 | + * |
| 10 | + * "OK" means the operation was partially or wholly completed. |
| 11 | + * |
| 12 | + * An operation which is not OK should have errors so that the user can be |
| 13 | + * informed as to what went wrong. Calling the fatal() function sets an error |
| 14 | + * message and simultaneously switches off the OK flag. |
| 15 | + */ |
| 16 | +class Status { |
| 17 | + var $ok = true; |
| 18 | + var $value; |
| 19 | + |
| 20 | + /** Counters for batch operations */ |
| 21 | + var $successCount = 0, $failCount = 0; |
| 22 | + |
| 23 | + /*semi-private*/ var $errors = array(); |
| 24 | + /*semi-private*/ var $cleanCallback = false; |
| 25 | + |
| 26 | + /** |
| 27 | + * Factory function for fatal errors |
| 28 | + */ |
| 29 | + static function newFatal( $message /*, parameters...*/ ) { |
| 30 | + $params = func_get_args(); |
| 31 | + $result = new self; |
| 32 | + call_user_func_array( array( &$result, 'error' ), $params ); |
| 33 | + $result->ok = false; |
| 34 | + return $result; |
| 35 | + } |
| 36 | + |
| 37 | + static function newGood( $value = null ) { |
| 38 | + $result = new self; |
| 39 | + $result->value = $value; |
| 40 | + return $result; |
| 41 | + } |
| 42 | + |
| 43 | + function setResult( $ok, $value = null ) { |
| 44 | + $this->ok = $ok; |
| 45 | + $this->value = $value; |
| 46 | + } |
| 47 | + |
| 48 | + function isGood() { |
| 49 | + return $this->ok && !$this->errors; |
| 50 | + } |
| 51 | + |
| 52 | + function isOK() { |
| 53 | + return $this->ok; |
| 54 | + } |
| 55 | + |
| 56 | + function warning( $message /*, parameters... */ ) { |
| 57 | + $params = array_slice( func_get_args(), 1 ); |
| 58 | + $this->errors[] = array( |
| 59 | + 'type' => 'warning', |
| 60 | + 'message' => $message, |
| 61 | + 'params' => $params ); |
| 62 | + } |
| 63 | + |
| 64 | + /** |
| 65 | + * Add an error, do not set fatal flag |
| 66 | + * This can be used for non-fatal errors |
| 67 | + */ |
| 68 | + function error( $message /*, parameters... */ ) { |
| 69 | + $params = array_slice( func_get_args(), 1 ); |
| 70 | + $this->errors[] = array( |
| 71 | + 'type' => 'error', |
| 72 | + 'message' => $message, |
| 73 | + 'params' => $params ); |
| 74 | + } |
| 75 | + |
| 76 | + /** |
| 77 | + * Add an error and set OK to false, indicating that the operation as a whole was fatal |
| 78 | + */ |
| 79 | + function fatal( $message /*, parameters... */ ) { |
| 80 | + $params = array_slice( func_get_args(), 1 ); |
| 81 | + $this->errors[] = array( |
| 82 | + 'type' => 'error', |
| 83 | + 'message' => $message, |
| 84 | + 'params' => $params ); |
| 85 | + $this->ok = false; |
| 86 | + } |
| 87 | + |
| 88 | + protected function cleanParams( $params ) { |
| 89 | + if ( !$this->cleanCallback ) { |
| 90 | + return $params; |
| 91 | + } |
| 92 | + $cleanParams = array(); |
| 93 | + foreach ( $params as $i => $param ) { |
| 94 | + $cleanParams[$i] = call_user_func( $this->cleanCallback, $param ); |
| 95 | + } |
| 96 | + return $cleanParams; |
| 97 | + } |
| 98 | + |
| 99 | + protected function getItemXML( $item ) { |
| 100 | + $params = $this->cleanParams( $item['params'] ); |
| 101 | + $xml = "<{$item['type']}>\n" . |
| 102 | + Xml::element( 'message', null, $item['message'] ) . "\n" . |
| 103 | + Xml::element( 'text', null, wfMsgReal( $item['message'], $params ) ) ."\n"; |
| 104 | + foreach ( $params as $param ) { |
| 105 | + $xml .= Xml::element( 'param', null, $param ); |
| 106 | + } |
| 107 | + $xml .= "</{$this->type}>\n"; |
| 108 | + return $xml; |
| 109 | + } |
| 110 | + |
| 111 | + /** |
| 112 | + * Get the error list as XML |
| 113 | + */ |
| 114 | + function getXML() { |
| 115 | + $xml = "<errors>\n"; |
| 116 | + foreach ( $this->errors as $error ) { |
| 117 | + $xml .= $this->getItemXML( $error ); |
| 118 | + } |
| 119 | + $xml .= "</errors>\n"; |
| 120 | + return $xml; |
| 121 | + } |
| 122 | + |
| 123 | + /** |
| 124 | + * Get the error list as a wikitext formatted list |
| 125 | + * @param string $shortContext A short enclosing context message name, to be used |
| 126 | + * when there is a single error |
| 127 | + * @param string $longContext A long enclosing context message name, for a list |
| 128 | + */ |
| 129 | + function getWikiText( $shortContext = false, $longContext = false ) { |
| 130 | + if ( count( $this->errors ) == 0 ) { |
| 131 | + if ( $this->ok ) { |
| 132 | + $this->fatal( 'internalerror_info', |
| 133 | + __METHOD__." called for a good result, this is incorrect\n" ); |
| 134 | + } else { |
| 135 | + $this->fatal( 'internalerror_info', |
| 136 | + __METHOD__.": Invalid result object: no error text but not OK\n" ); |
| 137 | + } |
| 138 | + } |
| 139 | + if ( count( $this->errors ) == 1 ) { |
| 140 | + $params = array_map( 'wfEscapeWikiText', $this->cleanParams( $this->errors[0]['params'] ) ); |
| 141 | + $s = wfMsgReal( $this->errors[0]['message'], $params, true, false, false ); |
| 142 | + if ( $shortContext ) { |
| 143 | + $s = wfMsgNoTrans( $shortContext, $s ); |
| 144 | + } elseif ( $longContext ) { |
| 145 | + $s = wfMsgNoTrans( $longContext, "* $s\n" ); |
| 146 | + } |
| 147 | + } else { |
| 148 | + $s = ''; |
| 149 | + foreach ( $this->errors as $error ) { |
| 150 | + $params = array_map( 'wfEscapeWikiText', $this->cleanParams( $error['params'] ) ); |
| 151 | + $s .= '* ' . wfMsgReal( $error['message'], $params, true, false, false ) . "\n"; |
| 152 | + } |
| 153 | + if ( $longContext ) { |
| 154 | + $s = wfMsgNoTrans( $longContext, $s ); |
| 155 | + } elseif ( $shortContext ) { |
| 156 | + $s = wfMsgNoTrans( $shortContext, "\n* $s\n" ); |
| 157 | + } |
| 158 | + } |
| 159 | + return $s; |
| 160 | + } |
| 161 | + |
| 162 | + /** |
| 163 | + * Merge another status object into this one |
| 164 | + */ |
| 165 | + function merge( $other, $overwriteValue = false ) { |
| 166 | + $this->errors = array_merge( $this->errors, $other->errors ); |
| 167 | + $this->ok = $this->ok && $other->ok; |
| 168 | + if ( $overwriteValue ) { |
| 169 | + $this->value = $other->value; |
| 170 | + } |
| 171 | + $this->successCount += $other->successCount; |
| 172 | + $this->failCount += $other->failCount; |
| 173 | + } |
| 174 | +} |
| 175 | + |
Index: trunk/phase3/includes/Database.php |
— | — | @@ -295,7 +295,7 @@ |
296 | 296 | * If the failFunction is set to a non-zero integer, returns success |
297 | 297 | */ |
298 | 298 | function open( $server, $user, $password, $dbName ) { |
299 | | - global $wguname; |
| 299 | + global $wguname, $wgAllDBsAreLocalhost; |
300 | 300 | wfProfileIn( __METHOD__ ); |
301 | 301 | |
302 | 302 | # Test for missing mysql.so |
— | — | @@ -310,6 +310,12 @@ |
311 | 311 | throw new DBConnectionError( $this, "MySQL functions missing, have you compiled PHP with the --with-mysql option?\n" ); |
312 | 312 | } |
313 | 313 | |
| 314 | + # Debugging hack -- fake cluster |
| 315 | + if ( $wgAllDBsAreLocalhost ) { |
| 316 | + $realServer = 'localhost'; |
| 317 | + } else { |
| 318 | + $realServer = $server; |
| 319 | + } |
314 | 320 | $this->close(); |
315 | 321 | $this->mServer = $server; |
316 | 322 | $this->mUser = $user; |
— | — | @@ -330,10 +336,10 @@ |
331 | 337 | usleep( 1000 ); |
332 | 338 | } |
333 | 339 | if ( $this->mFlags & DBO_PERSISTENT ) { |
334 | | - @/**/$this->mConn = mysql_pconnect( $server, $user, $password ); |
| 340 | + @/**/$this->mConn = mysql_pconnect( $realServer, $user, $password ); |
335 | 341 | } else { |
336 | 342 | # Create a new connection... |
337 | | - @/**/$this->mConn = mysql_connect( $server, $user, $password, true ); |
| 343 | + @/**/$this->mConn = mysql_connect( $realServer, $user, $password, true ); |
338 | 344 | } |
339 | 345 | if ($this->mConn === false) { |
340 | 346 | #$iplus = $i + 1; |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -565,6 +565,13 @@ |
566 | 566 | /** MySQL table options to use during installation or update */ |
567 | 567 | $wgDBTableOptions = 'TYPE=InnoDB'; |
568 | 568 | |
| 569 | +/** |
| 570 | + * Make all database connections secretly go to localhost. Fool the load balancer |
| 571 | + * thinking there is an arbitrarily large cluster of servers to connect to. |
| 572 | + * Useful for debugging. |
| 573 | + */ |
| 574 | +$wgAllDBsAreLocalhost = false; |
| 575 | + |
569 | 576 | /**#@-*/ |
570 | 577 | |
571 | 578 | |
— | — | @@ -2663,6 +2670,7 @@ |
2664 | 2671 | /** |
2665 | 2672 | * An array of external mysql servers, e.g. |
2666 | 2673 | * $wgExternalServers = array( 'cluster1' => array( 'srv28', 'srv29', 'srv30' ) ); |
| 2674 | + * Used by LBFactory_Simple, may be ignored if $wgLBFactoryConf is set to another class. |
2667 | 2675 | */ |
2668 | 2676 | $wgExternalServers = array(); |
2669 | 2677 | |
Index: trunk/phase3/includes/LBFactory_Multi.php |
— | — | @@ -5,15 +5,15 @@ |
6 | 6 | * Ignores the old configuration globals |
7 | 7 | * |
8 | 8 | * Configuration: |
9 | | - * sectionsByDB A map of database names to section names |
| 9 | + * sectionsByDB A map of database names to section names |
10 | 10 | * |
11 | 11 | * sectionLoads A 2-d map. For each section, gives a map of server names to load ratios. |
12 | 12 | * For example: array( 'section1' => array( 'db1' => 100, 'db2' => 100 ) ) |
13 | 13 | * |
14 | | - * mainTemplate A server info associative array as documented for $wgDBservers. The host, |
| 14 | + * serverTemplate A server info associative array as documented for $wgDBservers. The host, |
15 | 15 | * hostName and load entries will be overridden. |
16 | 16 | * |
17 | | - * groupLoadsBySection A 3-d map giving server load ratios for each section and group. For example: |
| 17 | + * groupLoadsBySection A 3-d map giving server load ratios for each section and group. For example: |
18 | 18 | * array( 'section1' => array( 'group1' => array( 'db1' => 100, 'db2' => 100 ) ) ) |
19 | 19 | * |
20 | 20 | * groupLoadsByDB A 3-d map giving server load ratios by DB name. |
— | — | @@ -22,23 +22,22 @@ |
23 | 23 | * |
24 | 24 | * externalLoads A map of external storage cluster name to server load map |
25 | 25 | * |
26 | | - * externalTemplate A server info structure used for external storage servers |
| 26 | + * externalTemplateOverrides A set of server info keys overriding serverTemplate for external storage |
27 | 27 | * |
28 | | - * templateOverridesByServer A 2-d map overriding mainTemplate or externalTemplate on a |
29 | | - * server-by-server basis. |
| 28 | + * templateOverridesByServer A 2-d map overriding serverTemplate and externalTemplateOverrides on a |
| 29 | + * server-by-server basis. Applies to both core and external storage. |
30 | 30 | * |
31 | | - * templateOverridesByCluster A 2-d map overriding externalTemplate by cluster |
| 31 | + * templateOverridesByCluster A 2-d map overriding the server info by external storage cluster |
32 | 32 | * |
33 | | - * masterTemplateOverrides An override array for mainTemplate and externalTemplate for all |
34 | | - * master servers. |
| 33 | + * masterTemplateOverrides An override array for all master servers. |
35 | 34 | * |
36 | 35 | */ |
37 | 36 | class LBFactory_Multi extends LBFactory { |
38 | 37 | // Required settings |
39 | | - var $sectionsByDB, $sectionLoads, $mainTemplate; |
| 38 | + var $sectionsByDB, $sectionLoads, $serverTemplate; |
40 | 39 | // Optional settings |
41 | 40 | var $groupLoadsBySection = array(), $groupLoadsByDB = array(), $hostsByName = array(); |
42 | | - var $externalLoads = array(), $externalTemplate, $templateOverridesByServer; |
| 41 | + var $externalLoads = array(), $externalTemplateOverrides, $templateOverridesByServer; |
43 | 42 | var $templateOverridesByCluster, $masterTemplateOverrides; |
44 | 43 | // Other stuff |
45 | 44 | var $conf, $mainLBs = array(), $extLBs = array(); |
— | — | @@ -47,9 +46,9 @@ |
48 | 47 | function __construct( $conf ) { |
49 | 48 | $this->chronProt = new ChronologyProtector; |
50 | 49 | $this->conf = $conf; |
51 | | - $required = array( 'sectionsByDB', 'sectionLoads', 'mainTemplate' ); |
| 50 | + $required = array( 'sectionsByDB', 'sectionLoads', 'serverTemplate' ); |
52 | 51 | $optional = array( 'groupLoadsBySection', 'groupLoadsByDB', 'hostsByName', |
53 | | - 'externalLoads', 'externalTemplate', 'templateOverridesByServer', |
| 52 | + 'externalLoads', 'externalTemplateOverrides', 'templateOverridesByServer', |
54 | 53 | 'templateOverridesByCluster', 'masterTemplateOverrides' ); |
55 | 54 | |
56 | 55 | foreach ( $required as $key ) { |
— | — | @@ -95,7 +94,7 @@ |
96 | 95 | if ( isset( $this->groupLoadsBySection[$section] ) ) { |
97 | 96 | $groupLoads = array_merge_recursive( $groupLoads, $this->groupLoadsBySection[$section] ); |
98 | 97 | } |
99 | | - $this->mainLBs[$section] = $this->newLoadBalancer( $this->mainTemplate, |
| 98 | + $this->mainLBs[$section] = $this->newLoadBalancer( $this->serverTemplate, |
100 | 99 | $this->sectionLoads[$section], $groupLoads, "main-$section" ); |
101 | 100 | $this->chronProt->initLB( $this->mainLBs[$section] ); |
102 | 101 | } |
— | — | @@ -107,12 +106,12 @@ |
108 | 107 | if ( !isset( $this->externalLoads[$cluster] ) ) { |
109 | 108 | throw new MWException( __METHOD__.": Unknown cluster \"$cluster\"" ); |
110 | 109 | } |
| 110 | + $template = $this->serverTemplate; |
| 111 | + if ( isset( $this->externalTemplateOverrides ) ) { |
| 112 | + $template = $this->externalTemplateOverrides + $template; |
| 113 | + } |
111 | 114 | if ( isset( $this->templateOverridesByCluster[$cluster] ) ) { |
112 | | - $template = $this->templateOverridesByCluster[$cluster]; |
113 | | - } elseif ( isset( $this->externalTemplate ) ) { |
114 | | - $template = $this->externalTemplate; |
115 | | - } else { |
116 | | - $template = $this->mainTemplate; |
| 115 | + $template = $this->templateOverridesByCluster[$cluster] + $template; |
117 | 116 | } |
118 | 117 | $this->extLBs[$cluster] = $this->newLoadBalancer( $template, |
119 | 118 | $this->externalLoads[$cluster], array(), "ext-$cluster" ); |