Index: trunk/phase3/includes/db/Database.php |
— | — | @@ -257,11 +257,9 @@ |
258 | 258 | * @param failFunction |
259 | 259 | * @param $flags |
260 | 260 | * @param $tablePrefix String: database table prefixes. By default use the prefix gave in LocalSettings.php |
261 | | - * @param int $max, max connection attempts |
262 | | - ** After the first retry (second attempt), each retry waits 1 second |
263 | 261 | */ |
264 | 262 | function __construct( $server = false, $user = false, $password = false, $dbName = false, |
265 | | - $failFunction = false, $flags = 0, $tablePrefix = 'get from global', $max = false ) { |
| 263 | + $failFunction = false, $flags = 0, $tablePrefix = 'get from global' ) { |
266 | 264 | |
267 | 265 | global $wgOut, $wgDBprefix, $wgCommandLineMode; |
268 | 266 | # Can't get a reference if it hasn't been set yet |
— | — | @@ -295,7 +293,7 @@ |
296 | 294 | } |
297 | 295 | |
298 | 296 | if ( $server ) { |
299 | | - $this->open( $server, $user, $password, $dbName, $max ); |
| 297 | + $this->open( $server, $user, $password, $dbName ); |
300 | 298 | } |
301 | 299 | } |
302 | 300 | |
— | — | @@ -313,7 +311,7 @@ |
314 | 312 | * Usually aborts on failure |
315 | 313 | * If the failFunction is set to a non-zero integer, returns success |
316 | 314 | */ |
317 | | - function open( $server, $user, $password, $dbName, $max = false ) { |
| 315 | + function open( $server, $user, $password, $dbName ) { |
318 | 316 | global $wguname, $wgAllDBsAreLocalhost; |
319 | 317 | wfProfileIn( __METHOD__ ); |
320 | 318 | |
— | — | @@ -345,13 +343,17 @@ |
346 | 344 | |
347 | 345 | wfProfileIn("dbconnect-$server"); |
348 | 346 | |
349 | | - if( !$max ) { $max = 3; } |
350 | | - # Try to connect up to three times (by default) |
351 | 347 | # The kernel's default SYN retransmission period is far too slow for us, |
352 | | - # so we use a short timeout plus a manual retry. |
| 348 | + # so we use a short timeout plus a manual retry. Retrying means that a small |
| 349 | + # but finite rate of SYN packet loss won't cause user-visible errors. |
353 | 350 | $this->mConn = false; |
| 351 | + if ( ini_get( 'mysql.connect_timeout' ) <= 3 ) { |
| 352 | + $numAttempts = 2; |
| 353 | + } else { |
| 354 | + $numAttempts = 1; |
| 355 | + } |
354 | 356 | $this->installErrorHandler(); |
355 | | - for ( $i = 0; $i < $max && !$this->mConn; $i++ ) { |
| 357 | + for ( $i = 0; $i < $numAttempts && !$this->mConn; $i++ ) { |
356 | 358 | if ( $i > 1 ) { |
357 | 359 | usleep( 1000 ); |
358 | 360 | } |
— | — | @@ -367,6 +369,7 @@ |
368 | 370 | } |
369 | 371 | } |
370 | 372 | $phpError = $this->restoreErrorHandler(); |
| 373 | + # Always log connection errors |
371 | 374 | if ( !$this->mConn ) { |
372 | 375 | $error = $this->lastError(); |
373 | 376 | if ( !$error ) { |
— | — | @@ -2507,6 +2510,13 @@ |
2508 | 2511 | |
2509 | 2512 | $text = str_replace( '$1', $this->error, $noconnect ); |
2510 | 2513 | |
| 2514 | + global $wgShowExceptionDetails; |
| 2515 | + if ( $GLOBALS['wgShowExceptionDetails'] ) { |
| 2516 | + $text .= '</p><p>Backtrace:</p><p>' . |
| 2517 | + nl2br( htmlspecialchars( $this->getTraceAsString() ) ) . |
| 2518 | + "</p>\n"; |
| 2519 | + } |
| 2520 | + |
2511 | 2521 | if($wgUseFileCache) { |
2512 | 2522 | if($wgTitle) { |
2513 | 2523 | $t =& $wgTitle; |
Index: trunk/phase3/includes/db/LoadBalancer.php |
— | — | @@ -11,8 +11,6 @@ |
12 | 12 | * @ingroup Database |
13 | 13 | */ |
14 | 14 | class LoadBalancer { |
15 | | - const GRACEFUL = 1; |
16 | | - |
17 | 15 | /* private */ var $mServers, $mConns, $mLoads, $mGroupLoads; |
18 | 16 | /* private */ var $mFailFunction, $mErrorConnection; |
19 | 17 | /* private */ var $mReadIndex, $mAllowLagged; |
— | — | @@ -172,7 +170,7 @@ |
173 | 171 | * |
174 | 172 | * Side effect: opens connections to databases |
175 | 173 | */ |
176 | | - function getReaderIndex( $group = false, $wiki = false, $attempts = false ) { |
| 174 | + function getReaderIndex( $group = false, $wiki = false ) { |
177 | 175 | global $wgReadOnly, $wgDBClusterTimeout, $wgDBAvgStatusPoll, $wgDBtype; |
178 | 176 | |
179 | 177 | # FIXME: For now, only go through all this for mysql databases |
— | — | @@ -249,7 +247,7 @@ |
250 | 248 | } |
251 | 249 | |
252 | 250 | wfDebugLog( 'connect', __METHOD__.": Using reader #$i: {$this->mServers[$i]['host']}...\n" ); |
253 | | - $conn = $this->openConnection( $i, $wiki, $attempts ); |
| 251 | + $conn = $this->openConnection( $i, $wiki ); |
254 | 252 | |
255 | 253 | if ( !$conn ) { |
256 | 254 | wfDebugLog( 'connect', __METHOD__.": Failed connecting to $i/$wiki\n" ); |
— | — | @@ -403,10 +401,8 @@ |
404 | 402 | * @param int $i Database |
405 | 403 | * @param array $groups Query groups |
406 | 404 | * @param string $wiki Wiki ID |
407 | | - * @param int $attempts Max DB connect attempts |
408 | | - * @param int $flags |
409 | 405 | */ |
410 | | - public function &getConnection( $i, $groups = array(), $wiki = false, $attempts = false, $flags = 0 ) { |
| 406 | + public function &getConnection( $i, $groups = array(), $wiki = false ) { |
411 | 407 | global $wgDBtype; |
412 | 408 | wfProfileIn( __METHOD__ ); |
413 | 409 | |
— | — | @@ -438,21 +434,18 @@ |
439 | 435 | |
440 | 436 | # Operation-based index |
441 | 437 | if ( $i == DB_SLAVE ) { |
442 | | - $i = $this->getReaderIndex( false, $wiki, $attempts ); |
| 438 | + $i = $this->getReaderIndex( false, $wiki ); |
443 | 439 | } elseif ( $i == DB_LAST ) { |
444 | 440 | throw new MWException( 'Attempt to call ' . __METHOD__ . ' with deprecated server index DB_LAST' ); |
445 | 441 | } |
446 | 442 | # Couldn't find a working server in getReaderIndex()? |
447 | 443 | if ( $i === false ) { |
448 | | - if( $flags && self::GRACEFUL ) { |
449 | | - return false; |
450 | | - } |
451 | 444 | $this->reportConnectionError( $this->mErrorConnection ); |
452 | 445 | } |
453 | 446 | |
454 | 447 | # Now we have an explicit index into the servers array |
455 | | - $conn = $this->openConnection( $i, $wiki, $attempts ); |
456 | | - if ( !$conn && !($flags & self::GRACEFUL) ) { |
| 448 | + $conn = $this->openConnection( $i, $wiki ); |
| 449 | + if ( !$conn ) { |
457 | 450 | $this->reportConnectionError( $this->mErrorConnection ); |
458 | 451 | } |
459 | 452 | |
— | — | @@ -512,12 +505,11 @@ |
513 | 506 | * |
514 | 507 | * @param integer $i Server index |
515 | 508 | * @param string $wiki Wiki ID to open |
516 | | - * @param int $attempts Maximum connection attempts |
517 | 509 | * @return Database |
518 | 510 | * |
519 | 511 | * @access private |
520 | 512 | */ |
521 | | - function openConnection( $i, $wiki = false, $attempts = false ) { |
| 513 | + function openConnection( $i, $wiki = false ) { |
522 | 514 | wfProfileIn( __METHOD__ ); |
523 | 515 | if ( $wiki !== false ) { |
524 | 516 | $conn = $this->openForeignConnection( $i, $wiki ); |
— | — | @@ -529,7 +521,7 @@ |
530 | 522 | } else { |
531 | 523 | $server = $this->mServers[$i]; |
532 | 524 | $server['serverIndex'] = $i; |
533 | | - $conn = $this->reallyOpenConnection( $server, false, $attempts ); |
| 525 | + $conn = $this->reallyOpenConnection( $server, false ); |
534 | 526 | if ( $conn->isOpen() ) { |
535 | 527 | $this->mConns['local'][$i][0] = $conn; |
536 | 528 | } else { |
— | — | @@ -631,7 +623,7 @@ |
632 | 624 | * Returns a Database object whether or not the connection was successful. |
633 | 625 | * @access private |
634 | 626 | */ |
635 | | - function reallyOpenConnection( $server, $dbNameOverride = false, $attempts = false ) { |
| 627 | + function reallyOpenConnection( $server, $dbNameOverride = false ) { |
636 | 628 | if( !is_array( $server ) ) { |
637 | 629 | throw new MWException( 'You must update your load-balancing configuration. See DefaultSettings.php entry for $wgDBservers.' ); |
638 | 630 | } |
— | — | @@ -646,7 +638,7 @@ |
647 | 639 | |
648 | 640 | # Create object |
649 | 641 | wfDebug( "Connecting to $host $dbname...\n" ); |
650 | | - $db = new $class( $host, $user, $password, $dbname, 1, $flags, 'get from global', $attempts ); |
| 642 | + $db = new $class( $host, $user, $password, $dbname, 1, $flags ); |
651 | 643 | if ( $db->isOpen() ) { |
652 | 644 | wfDebug( "Connected\n" ); |
653 | 645 | } else { |
Index: trunk/phase3/includes/ExternalStore.php |
— | — | @@ -77,30 +77,36 @@ |
78 | 78 | */ |
79 | 79 | public static function randomInsert( $data ) { |
80 | 80 | global $wgDefaultExternalStore; |
81 | | - $tryStorages = (array)$wgDefaultExternalStore; |
82 | | - // Do not wait and do second retry per master if we |
83 | | - // have other active cluster masters to try instead. |
84 | | - $retry = count($tryStorages) > 1 ? false : true; |
85 | | - while ( count($tryStorages) > 0 ) { |
86 | | - $index = mt_rand(0, count( $tryStorages ) - 1); |
87 | | - $storeUrl = $tryStorages[$index]; |
| 81 | + $tryStores = (array)$wgDefaultExternalStore; |
| 82 | + $error = false; |
| 83 | + while ( count( $tryStores ) > 0 ) { |
| 84 | + $index = mt_rand(0, count( $tryStores ) - 1); |
| 85 | + $storeUrl = $tryStores[$index]; |
| 86 | + wfDebug( __METHOD__.": trying $storeUrl\n" ); |
88 | 87 | list( $proto, $params ) = explode( '://', $storeUrl, 2 ); |
89 | 88 | $store = self::getStoreObject( $proto ); |
90 | 89 | if ( $store === false ) { |
91 | 90 | throw new MWException( "Invalid external storage protocol - $storeUrl" ); |
92 | | - return false; |
| 91 | + } |
| 92 | + try { |
| 93 | + $url = $store->store( $params, $data ); // Try to save the object |
| 94 | + } catch ( DBConnectionError $error ) { |
| 95 | + $url = false; |
| 96 | + unset( $tryStores[$index] ); // Don't try this one again! |
| 97 | + $tryStores = array_values( $tryStores ); // Must have consecutive keys |
| 98 | + } |
| 99 | + if ( $url ) { |
| 100 | + return $url; // Done! |
93 | 101 | } else { |
94 | | - $url = $store->store( $params, $data, $retry ); // Try to save the object |
95 | | - if ( $url ) { |
96 | | - return $url; // Done! |
97 | | - } else { |
98 | | - unset( $tryStorages[$index] ); // Don't try this one again! |
99 | | - sort( $tryStorages ); // Must have consecutive keys |
100 | | - wfDebugLog( 'ExternalStorage', "Unable to store text to external storage $storeUrl" ); |
101 | | - } |
| 102 | + wfDebugLog( 'ExternalStorage', "Unable to store text to external storage $storeUrl" ); |
102 | 103 | } |
103 | 104 | } |
104 | | - throw new MWException( "Unable to store text to external storage" ); |
105 | | - return false; // All cluster masters dead :( |
| 105 | + // All stores failed |
| 106 | + if ( $error ) { |
| 107 | + // Rethrow the last connection error |
| 108 | + throw $error; |
| 109 | + } else { |
| 110 | + throw new MWException( "Unable to store text to external storage" ); |
| 111 | + } |
106 | 112 | } |
107 | 113 | } |
Index: trunk/phase3/includes/ExternalStoreDB.php |
— | — | @@ -34,14 +34,13 @@ |
35 | 35 | /** @todo Document.*/ |
36 | 36 | function &getSlave( $cluster ) { |
37 | 37 | $lb =& $this->getLoadBalancer( $cluster ); |
38 | | - // Make only two connection attempts, since we still have the master to try |
39 | | - return $lb->getConnection( DB_SLAVE, array(), false, 2 ); |
| 38 | + return $lb->getConnection( DB_SLAVE ); |
40 | 39 | } |
41 | 40 | |
42 | 41 | /** @todo Document.*/ |
43 | | - function &getMaster( $cluster, $retry = true ) { |
| 42 | + function &getMaster( $cluster ) { |
44 | 43 | $lb =& $this->getLoadBalancer( $cluster ); |
45 | | - return $lb->getConnection( DB_MASTER, array(), false, false, LoadBalancer::GRACEFUL ); |
| 44 | + return $lb->getConnection( DB_MASTER, array() ); |
46 | 45 | } |
47 | 46 | |
48 | 47 | /** @todo Document.*/ |
— | — | @@ -120,13 +119,11 @@ |
121 | 120 | * |
122 | 121 | * @param $cluster String: the cluster name |
123 | 122 | * @param $data String: the data item |
124 | | - * @param $retry bool: allows an extra DB connection retry after 1 second |
125 | 123 | * @return string URL |
126 | 124 | */ |
127 | | - function store( $cluster, $data, $retry = true ) { |
128 | | - if( !$dbw = $this->getMaster( $cluster, $retry ) ) { |
129 | | - return false; // failed, maybe another cluster is up... |
130 | | - } |
| 125 | + function store( $cluster, $data ) { |
| 126 | + $dbw = $this->getMaster( $cluster ); |
| 127 | + |
131 | 128 | $id = $dbw->nextSequenceValue( 'blob_blob_id_seq' ); |
132 | 129 | $dbw->insert( $this->getTable( $dbw ), |
133 | 130 | array( 'blob_id' => $id, 'blob_text' => $data ), |