wiki.techinc.nl/maintenance/fixSlaveDesync.php
Nick Jenkins f88c771756 The war on redundant ampersand usage!
* Convert "$dbw =& wfGetDB( DB_MASTER );" --> "$dbw = wfGetDB( DB_MASTER );"
* convert "$skin =& $wgUser->getSkin();" --> "$skin = $wgUser->getSkin();"

For the time being have not changed the function definitions of wfGetDB() or User::getSkin() [i.e. they are still both return-by-ref], so as to ensure the interface does not change for extensions [some of which may still be trying to run on PHP4 environments]. However presumably at some point this can be changed too.

Also includes tiny tweak to newlines in parserTests - will show 1 rather than 2 newlines between the "Reading tests from" strings when in quiet mode.
2007-01-22 23:50:42 +00:00

192 lines
5.2 KiB
PHP

<?php
$wgUseRootUser = true;
require_once( 'commandLine.inc' );
//$wgDebugLogFile = '/dev/stdout';
$slaveIndexes = array();
for ( $i = 1; $i < count( $wgDBservers ); $i++ ) {
if ( $wgLoadBalancer->isNonZeroLoad( $i ) ) {
$slaveIndexes[] = $i;
}
}
/*
foreach ( $wgLoadBalancer->mServers as $i => $server ) {
$wgLoadBalancer->mServers[$i]['flags'] |= DBO_DEBUG;
}*/
$reportingInterval = 1000;
if ( isset( $args[0] ) ) {
desyncFixPage( $args[0] );
} else {
$dbw = wfGetDB( DB_MASTER );
$maxPage = $dbw->selectField( 'page', 'MAX(page_id)', false, 'fixDesync.php' );
$corrupt = findPageLatestCorruption();
foreach ( $corrupt as $id => $dummy ) {
desyncFixPage( $id );
}
/*
for ( $i=1; $i <= $maxPage; $i++ ) {
desyncFixPage( $i );
if ( !($i % $reportingInterval) ) {
print "$i\n";
}
}*/
}
function findPageLatestCorruption() {
$desync = array();
$n = 0;
$dbw = wfGetDB( DB_MASTER );
$masterIDs = array();
$res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
print "Number of pages: " . $dbw->numRows( $res ) . "\n";
while ( $row = $dbw->fetchObject( $res ) ) {
$masterIDs[$row->page_id] = $row->page_latest;
if ( !( ++$n % 10000 ) ) {
print "$n\r";
}
}
print "\n";
$dbw->freeResult( $res );
global $slaveIndexes;
foreach ( $slaveIndexes as $i ) {
$db = wfGetDB( $i );
$res = $db->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
while ( $row = $db->fetchObject( $res ) ) {
if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) {
$desync[$row->page_id] = true;
print $row->page_id . "\t";
}
}
$db->freeResult( $res );
}
print "\n";
return $desync;
}
function desyncFixPage( $pageID ) {
global $slaveIndexes;
$fname = 'desyncFixPage';
# Check for a corrupted page_latest
$dbw = wfGetDB( DB_MASTER );
$dbw->begin();
$realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ),
$fname, 'FOR UPDATE' );
#list( $masterFile, $masterPos ) = $dbw->getMasterPos();
$found = false;
foreach ( $slaveIndexes as $i ) {
$db = wfGetDB( $i );
/*
if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) {
echo "Slave is too lagged, aborting\n";
$dbw->commit();
sleep(10);
return;
}*/
$latest = $db->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), $fname );
$max = $db->selectField( 'revision', 'MAX(rev_id)', false, $fname );
if ( $latest != $realLatest && $realLatest < $max ) {
print "page_latest corrupted in page $pageID, server $i\n";
$found = true;
break;
}
}
if ( !$found ) {
print "page_id $pageID seems fine\n";
$dbw->commit();
return;
}
# Find the missing revisions
$res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ),
$fname, 'FOR UPDATE' );
$masterIDs = array();
while ( $row = $dbw->fetchObject( $res ) ) {
$masterIDs[] = $row->rev_id;
}
$dbw->freeResult( $res );
$res = $db->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), $fname );
$slaveIDs = array();
while ( $row = $db->fetchObject( $res ) ) {
$slaveIDs[] = $row->rev_id;
}
$db->freeResult( $res );
if ( count( $masterIDs ) < count( $slaveIDs ) ) {
$missingIDs = array_diff( $slaveIDs, $masterIDs );
if ( count( $missingIDs ) ) {
print "Found " . count( $missingIDs ) . " lost in master, copying from slave... ";
$dbFrom = $db;
$found = true;
$toMaster = true;
} else {
$found = false;
}
} else {
$missingIDs = array_diff( $masterIDs, $slaveIDs );
if ( count( $missingIDs ) ) {
print "Found " . count( $missingIDs ) . " missing revision(s), copying from master... ";
$dbFrom = $dbw;
$found = true;
$toMaster = false;
} else {
$found = false;
}
}
if ( $found ) {
foreach ( $missingIDs as $rid ) {
print "$rid ";
# Revision
$row = $dbFrom->selectRow( 'revision', '*', array( 'rev_id' => $rid ), $fname );
if ( $toMaster ) {
$id = $dbw->selectField( 'revision', 'rev_id', array( 'rev_id' => $rid ),
$fname, 'FOR UPDATE' );
if ( $id ) {
echo "Revision already exists\n";
$found = false;
break;
} else {
$dbw->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' );
}
} else {
foreach ( $slaveIndexes as $i ) {
$db = wfGetDB( $i );
$db->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' );
}
}
# Text
$row = $dbFrom->selectRow( 'text', '*', array( 'old_id' => $row->rev_text_id ), $fname );
if ( $toMaster ) {
$dbw->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' );
} else {
foreach ( $slaveIndexes as $i ) {
$db = wfGetDB( $i );
$db->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' );
}
}
}
print "done\n";
}
if ( $found ) {
print "Fixing page_latest... ";
if ( $toMaster ) {
#$dbw->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname );
} else {
foreach ( $slaveIndexes as $i ) {
$db = wfGetDB( $i );
$db->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname );
}
}
print "done\n";
}
$dbw->commit();
}
?>