[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Fix erroneous page_latest values due to slave desynchronisation. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup Maintenance 22 */ 23 24 require_once __DIR__ . '/Maintenance.php'; 25 26 /** 27 * Maintenance script that fixes erroneous page_latest values 28 * due to slave desynchronisation. 29 * 30 * @ingroup Maintenance 31 */ 32 class FixSlaveDesync extends Maintenance { 33 /** @var array */ 34 private $slaveIndexes; 35 36 public function __construct() { 37 parent::__construct(); 38 $this->mDescription = ""; 39 } 40 41 public function getDbType() { 42 return Maintenance::DB_ADMIN; 43 } 44 45 public function execute() { 46 $this->slaveIndexes = array(); 47 $serverCount = wfGetLB()->getServerCount(); 48 for ( $i = 1; $i < $serverCount; $i++ ) { 49 if ( wfGetLB()->isNonZeroLoad( $i ) ) { 50 $this->slaveIndexes[] = $i; 51 } 52 } 53 54 if ( $this->hasArg() ) { 55 $this->desyncFixPage( $this->getArg() ); 56 } else { 57 $corrupt = $this->findPageLatestCorruption(); 58 foreach ( $corrupt as $id => $dummy ) { 59 $this->desyncFixPage( $id ); 60 } 61 } 62 } 63 64 /** 65 * Find all pages that have a corrupted page_latest 66 * @return array 67 */ 68 private function findPageLatestCorruption() { 69 $desync = array(); 70 $n = 0; 71 $dbw = wfGetDB( DB_MASTER ); 72 $masterIDs = array(); 73 $res = $dbw->select( 74 'page', 75 array( 'page_id', 'page_latest' ), 76 array( 'page_id<6054123' ), 77 __METHOD__ 78 ); 79 $this->output( "Number of pages: " . $res->numRows() . "\n" ); 80 foreach ( $res as $row ) { 81 $masterIDs[$row->page_id] = $row->page_latest; 82 if ( !( ++$n % 10000 ) ) { 83 $this->output( "$n\r" ); 84 } 85 } 86 $this->output( "\n" ); 87 88 foreach ( $this->slaveIndexes as $i ) { 89 $db = wfGetDB( $i ); 90 $res = $db->select( 91 'page', 92 array( 'page_id', 'page_latest' ), 93 array( 'page_id<6054123' ), 94 __METHOD__ 95 ); 96 foreach ( $res as $row ) { 97 if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) { 98 $desync[$row->page_id] = true; 99 $this->output( $row->page_id . "\t" ); 100 } 101 } 102 } 103 $this->output( "\n" ); 104 105 return $desync; 106 } 107 108 /** 109 * Fix a broken page entry 110 * @param int $pageID The page_id to fix 111 */ 112 private function desyncFixPage( $pageID ) { 113 # Check for a corrupted page_latest 114 $dbw = wfGetDB( DB_MASTER ); 115 $dbw->begin( __METHOD__ ); 116 $realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), 117 __METHOD__, 'FOR UPDATE' ); 118 # list( $masterFile, $masterPos ) = $dbw->getMasterPos(); 119 $found = false; 120 foreach ( $this->slaveIndexes as $i ) { 121 $db = wfGetDB( $i ); 122 /* 123 if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) { 124 $this->output( "Slave is too lagged, aborting\n" ); 125 $dbw->commit( __METHOD__ ); 126 sleep(10); 127 return; 128 }*/ 129 $latest = $db->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), __METHOD__ ); 130 $max = $db->selectField( 'revision', 'MAX(rev_id)', false, __METHOD__ ); 131 if ( $latest != $realLatest && $realLatest < $max ) { 132 $this->output( "page_latest corrupted in page $pageID, server $i\n" ); 133 $found = true; 134 break; 135 } 136 } 137 if ( !$found ) { 138 $this->output( "page_id $pageID seems fine\n" ); 139 $dbw->commit( __METHOD__ ); 140 141 return; 142 } 143 144 # Find the missing revisions 145 $res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), 146 __METHOD__, 'FOR UPDATE' ); 147 $masterIDs = array(); 148 foreach ( $res as $row ) { 149 $masterIDs[] = $row->rev_id; 150 } 151 152 $res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), __METHOD__ ); 153 $slaveIDs = array(); 154 foreach ( $res as $row ) { 155 $slaveIDs[] = $row->rev_id; 156 } 157 if ( count( $masterIDs ) < count( $slaveIDs ) ) { 158 $missingIDs = array_diff( $slaveIDs, $masterIDs ); 159 if ( count( $missingIDs ) ) { 160 $this->output( "Found " . count( $missingIDs ) 161 . " lost in master, copying from slave... " ); 162 $dbFrom = $dbw; 163 $found = true; 164 $toMaster = true; 165 } else { 166 $found = false; 167 } 168 } else { 169 $missingIDs = array_diff( $masterIDs, $slaveIDs ); 170 if ( count( $missingIDs ) ) { 171 $this->output( "Found " . count( $missingIDs ) 172 . " missing revision(s), copying from master... " ); 173 $dbFrom = $dbw; 174 $found = true; 175 $toMaster = false; 176 } else { 177 $found = false; 178 } 179 } 180 181 if ( $found ) { 182 foreach ( $missingIDs as $rid ) { 183 $this->output( "$rid " ); 184 # Revision 185 $row = $dbFrom->selectRow( 'revision', '*', array( 'rev_id' => $rid ), __METHOD__ ); 186 if ( $toMaster ) { 187 $id = $dbw->selectField( 'revision', 'rev_id', array( 'rev_id' => $rid ), 188 __METHOD__, 'FOR UPDATE' ); 189 if ( $id ) { 190 $this->output( "Revision already exists\n" ); 191 $found = false; 192 break; 193 } else { 194 $dbw->insert( 'revision', get_object_vars( $row ), __METHOD__, 'IGNORE' ); 195 } 196 } else { 197 foreach ( $this->slaveIndexes as $i ) { 198 $db = wfGetDB( $i ); 199 $db->insert( 'revision', get_object_vars( $row ), __METHOD__, 'IGNORE' ); 200 } 201 } 202 203 # Text 204 $row = $dbFrom->selectRow( 'text', '*', array( 'old_id' => $row->rev_text_id ), __METHOD__ ); 205 if ( $toMaster ) { 206 $dbw->insert( 'text', get_object_vars( $row ), __METHOD__, 'IGNORE' ); 207 } else { 208 foreach ( $this->slaveIndexes as $i ) { 209 $db = wfGetDB( $i ); 210 $db->insert( 'text', get_object_vars( $row ), __METHOD__, 'IGNORE' ); 211 } 212 } 213 } 214 $this->output( "done\n" ); 215 } 216 217 if ( $found ) { 218 $this->output( "Fixing page_latest... " ); 219 if ( $toMaster ) { 220 /* 221 $dbw->update( 222 'page', 223 array( 'page_latest' => $realLatest ), 224 array( 'page_id' => $pageID ), 225 __METHOD__ 226 ); 227 */ 228 } else { 229 foreach ( $this->slaveIndexes as $i ) { 230 $db = wfGetDB( $i ); 231 $db->update( 232 'page', 233 array( 'page_latest' => $realLatest ), 234 array( 'page_id' => $pageID ), 235 __METHOD__ 236 ); 237 } 238 } 239 $this->output( "done\n" ); 240 } 241 $dbw->commit( __METHOD__ ); 242 } 243 } 244 245 $maintClass = "FixSlaveDesync"; 246 require_once RUN_MAINTENANCE_IF_MAIN;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |