00001 <?php
00007 $wgUseRootUser = true;
00008 require_once( 'commandLine.inc' );
00009
00010
00011
00012 $slaveIndexes = array();
00013 for ( $i = 1; $i < count( $wgDBservers ); $i++ ) {
00014 if ( wfGetLB()->isNonZeroLoad( $i ) ) {
00015 $slaveIndexes[] = $i;
00016 }
00017 }
00018
00019
00020
00021
00022 $reportingInterval = 1000;
00023
00024 if ( isset( $args[0] ) ) {
00025 desyncFixPage( $args[0] );
00026 } else {
00027 $dbw = wfGetDB( DB_MASTER );
00028 $maxPage = $dbw->selectField( 'page', 'MAX(page_id)', false, 'fixDesync.php' );
00029 $corrupt = findPageLatestCorruption();
00030 foreach ( $corrupt as $id => $dummy ) {
00031 desyncFixPage( $id );
00032 }
00033
00034
00035
00036
00037
00038
00039
00040 }
00041
00042 function findPageLatestCorruption() {
00043 $desync = array();
00044 $n = 0;
00045 $dbw = wfGetDB( DB_MASTER );
00046 $masterIDs = array();
00047 $res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
00048 print "Number of pages: " . $dbw->numRows( $res ) . "\n";
00049 while ( $row = $dbw->fetchObject( $res ) ) {
00050 $masterIDs[$row->page_id] = $row->page_latest;
00051 if ( !( ++$n % 10000 ) ) {
00052 print "$n\r";
00053 }
00054 }
00055 print "\n";
00056 $dbw->freeResult( $res );
00057
00058 global $slaveIndexes;
00059 foreach ( $slaveIndexes as $i ) {
00060 $db = wfGetDB( $i );
00061 $res = $db->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
00062 while ( $row = $db->fetchObject( $res ) ) {
00063 if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) {
00064 $desync[$row->page_id] = true;
00065 print $row->page_id . "\t";
00066 }
00067 }
00068 $db->freeResult( $res );
00069 }
00070 print "\n";
00071 return $desync;
00072 }
00073
00074 function desyncFixPage( $pageID ) {
00075 global $slaveIndexes;
00076 $fname = 'desyncFixPage';
00077
00078 # Check for a corrupted page_latest
00079 $dbw = wfGetDB( DB_MASTER );
00080 $dbw->begin();
00081 $realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ),
00082 $fname, 'FOR UPDATE' );
00083 #list( $masterFile, $masterPos ) = $dbw->getMasterPos();
00084 $found = false;
00085 foreach ( $slaveIndexes as $i ) {
00086 $db = wfGetDB( $i );
00087
00088
00089
00090
00091
00092
00093
00094 $latest = $db->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), $fname );
00095 $max = $db->selectField( 'revision', 'MAX(rev_id)', false, $fname );
00096 if ( $latest != $realLatest && $realLatest < $max ) {
00097 print "page_latest corrupted in page $pageID, server $i\n";
00098 $found = true;
00099 break;
00100 }
00101 }
00102 if ( !$found ) {
00103 print "page_id $pageID seems fine\n";
00104 $dbw->commit();
00105 return;
00106 }
00107
00108 # Find the missing revisions
00109 $res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ),
00110 $fname, 'FOR UPDATE' );
00111 $masterIDs = array();
00112 while ( $row = $dbw->fetchObject( $res ) ) {
00113 $masterIDs[] = $row->rev_id;
00114 }
00115 $dbw->freeResult( $res );
00116
00117 $res = $db->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), $fname );
00118 $slaveIDs = array();
00119 while ( $row = $db->fetchObject( $res ) ) {
00120 $slaveIDs[] = $row->rev_id;
00121 }
00122 $db->freeResult( $res );
00123 if ( count( $masterIDs ) < count( $slaveIDs ) ) {
00124 $missingIDs = array_diff( $slaveIDs, $masterIDs );
00125 if ( count( $missingIDs ) ) {
00126 print "Found " . count( $missingIDs ) . " lost in master, copying from slave... ";
00127 $dbFrom = $db;
00128 $found = true;
00129 $toMaster = true;
00130 } else {
00131 $found = false;
00132 }
00133 } else {
00134 $missingIDs = array_diff( $masterIDs, $slaveIDs );
00135 if ( count( $missingIDs ) ) {
00136 print "Found " . count( $missingIDs ) . " missing revision(s), copying from master... ";
00137 $dbFrom = $dbw;
00138 $found = true;
00139 $toMaster = false;
00140 } else {
00141 $found = false;
00142 }
00143 }
00144
00145 if ( $found ) {
00146 foreach ( $missingIDs as $rid ) {
00147 print "$rid ";
00148 # Revision
00149 $row = $dbFrom->selectRow( 'revision', '*', array( 'rev_id' => $rid ), $fname );
00150 if ( $toMaster ) {
00151 $id = $dbw->selectField( 'revision', 'rev_id', array( 'rev_id' => $rid ),
00152 $fname, 'FOR UPDATE' );
00153 if ( $id ) {
00154 echo "Revision already exists\n";
00155 $found = false;
00156 break;
00157 } else {
00158 $dbw->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' );
00159 }
00160 } else {
00161 foreach ( $slaveIndexes as $i ) {
00162 $db = wfGetDB( $i );
00163 $db->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' );
00164 }
00165 }
00166
00167 # Text
00168 $row = $dbFrom->selectRow( 'text', '*', array( 'old_id' => $row->rev_text_id ), $fname );
00169 if ( $toMaster ) {
00170 $dbw->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' );
00171 } else {
00172 foreach ( $slaveIndexes as $i ) {
00173 $db = wfGetDB( $i );
00174 $db->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' );
00175 }
00176 }
00177 }
00178 print "done\n";
00179 }
00180
00181 if ( $found ) {
00182 print "Fixing page_latest... ";
00183 if ( $toMaster ) {
00184 #$dbw->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname );
00185 } else {
00186 foreach ( $slaveIndexes as $i ) {
00187 $db = wfGetDB( $i );
00188 $db->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname );
00189 }
00190 }
00191 print "done\n";
00192 }
00193 $dbw->commit();
00194 }
00195
00196