]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - maintenance/fixSlaveDesync.php
MediaWiki 1.14.0
[autoinstallsdev/mediawiki.git] / maintenance / fixSlaveDesync.php
1 <?php
2 /**
3  * @file
4  * @ingroup Maintenance
5  */
6
7 $wgUseRootUser = true;
8 require_once( 'commandLine.inc' );
9
10 //$wgDebugLogFile = '/dev/stdout';
11
12 $slaveIndexes = array();
13 for ( $i = 1; $i < count( $wgDBservers ); $i++ ) {
14         if ( wfGetLB()->isNonZeroLoad( $i ) ) {
15                 $slaveIndexes[] = $i;
16         }
17 }
18 /*
19 foreach ( wfGetLB()->mServers as $i => $server ) {
20         wfGetLB()->mServers[$i]['flags'] |= DBO_DEBUG;
21 }*/
22 $reportingInterval = 1000;
23
24 if ( isset( $args[0] ) ) {
25         desyncFixPage( $args[0] );
26 } else {
27         $dbw = wfGetDB( DB_MASTER );
28         $maxPage = $dbw->selectField( 'page', 'MAX(page_id)', false, 'fixDesync.php' );
29         $corrupt = findPageLatestCorruption();
30         foreach ( $corrupt as $id => $dummy ) {
31                 desyncFixPage( $id );
32         }
33                 /*
34         for ( $i=1; $i <= $maxPage; $i++ ) {
35                 desyncFixPage( $i );
36                 if ( !($i % $reportingInterval) ) {
37                         print "$i\n";
38                 }
39         }*/
40 }
41
42 function findPageLatestCorruption() {
43         $desync = array();
44         $n = 0;
45         $dbw = wfGetDB( DB_MASTER );
46         $masterIDs = array();
47         $res = $dbw->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
48         print "Number of pages: " . $dbw->numRows( $res ) . "\n";
49         while ( $row = $dbw->fetchObject( $res ) ) {
50                 $masterIDs[$row->page_id] = $row->page_latest;
51                 if ( !( ++$n % 10000 ) ) {
52                         print "$n\r";
53                 }
54         }
55         print "\n";
56         $dbw->freeResult( $res );
57         
58         global $slaveIndexes;
59         foreach ( $slaveIndexes as $i ) {
60                 $db = wfGetDB( $i );
61                 $res = $db->select( 'page', array( 'page_id', 'page_latest' ), array( 'page_id<6054123' ), __METHOD__ );
62                 while ( $row = $db->fetchObject( $res ) ) {
63                         if ( isset( $masterIDs[$row->page_id] ) && $masterIDs[$row->page_id] != $row->page_latest ) {
64                                 $desync[$row->page_id] = true;
65                                 print $row->page_id . "\t";
66                         }
67                 }
68                 $db->freeResult( $res );
69         }
70         print "\n";
71         return $desync;
72 }
73
74 function desyncFixPage( $pageID ) {
75         global $slaveIndexes;
76         $fname = 'desyncFixPage';
77
78         # Check for a corrupted page_latest
79         $dbw = wfGetDB( DB_MASTER );
80         $dbw->begin();
81         $realLatest = $dbw->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), 
82                 $fname, 'FOR UPDATE' );
83         #list( $masterFile, $masterPos ) = $dbw->getMasterPos();
84         $found = false;
85         foreach ( $slaveIndexes as $i ) {
86                 $db = wfGetDB( $i );
87                 /*
88                 if ( !$db->masterPosWait( $masterFile, $masterPos, 10 ) ) {
89                        echo "Slave is too lagged, aborting\n";
90                        $dbw->commit();
91                        sleep(10);
92                        return;
93                 }*/            
94                 $latest = $db->selectField( 'page', 'page_latest', array( 'page_id' => $pageID ), $fname );
95                 $max = $db->selectField( 'revision', 'MAX(rev_id)', false, $fname );
96                 if ( $latest != $realLatest && $realLatest < $max ) {
97                         print "page_latest corrupted in page $pageID, server $i\n";
98                         $found = true;
99                         break;
100                 }
101         }
102         if ( !$found ) {
103                 print "page_id $pageID seems fine\n";
104                 $dbw->commit();
105                 return;
106         }
107
108         # Find the missing revisions
109         $res = $dbw->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), 
110                 $fname, 'FOR UPDATE' );
111         $masterIDs = array();
112         while ( $row = $dbw->fetchObject( $res ) ) {
113                 $masterIDs[] = $row->rev_id;
114         }
115         $dbw->freeResult( $res );
116
117         $res = $db->select( 'revision', array( 'rev_id' ), array( 'rev_page' => $pageID ), $fname );
118         $slaveIDs = array();
119         while ( $row = $db->fetchObject( $res ) ) {
120                 $slaveIDs[] = $row->rev_id;
121         }
122         $db->freeResult( $res );
123         if ( count( $masterIDs ) < count( $slaveIDs ) ) {
124                 $missingIDs = array_diff( $slaveIDs, $masterIDs );
125                 if ( count( $missingIDs ) ) {
126                         print "Found " . count( $missingIDs ) . " lost in master, copying from slave... ";
127                         $dbFrom = $db;
128                         $found = true;
129                         $toMaster = true;
130                 } else {
131                         $found = false;
132                 }
133         } else {
134                 $missingIDs = array_diff( $masterIDs, $slaveIDs );
135                 if ( count( $missingIDs ) ) {
136                         print "Found " . count( $missingIDs ) . " missing revision(s), copying from master... ";
137                         $dbFrom = $dbw;
138                         $found = true;
139                         $toMaster = false;
140                 } else {
141                         $found = false;
142                 }
143         }
144
145         if ( $found ) {
146                 foreach ( $missingIDs as $rid ) {
147                         print "$rid ";
148                         # Revision
149                         $row = $dbFrom->selectRow( 'revision', '*', array( 'rev_id' => $rid ), $fname );
150                         if ( $toMaster ) {
151                                 $id = $dbw->selectField( 'revision', 'rev_id', array( 'rev_id' => $rid ), 
152                                         $fname, 'FOR UPDATE' );
153                                 if ( $id ) {
154                                         echo "Revision already exists\n";
155                                         $found = false;
156                                         break;
157                                 } else {
158                                         $dbw->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' );
159                                 }
160                         } else {
161                                 foreach ( $slaveIndexes as $i ) {
162                                         $db = wfGetDB( $i );
163                                         $db->insert( 'revision', get_object_vars( $row ), $fname, 'IGNORE' );
164                                 }
165                         }
166
167                         # Text
168                         $row = $dbFrom->selectRow( 'text', '*', array( 'old_id' => $row->rev_text_id ), $fname );
169                         if ( $toMaster ) {
170                                 $dbw->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' );
171                         } else {
172                                 foreach ( $slaveIndexes as $i ) {
173                                         $db = wfGetDB( $i );
174                                         $db->insert( 'text', get_object_vars( $row ), $fname, 'IGNORE' );
175                                 }
176                         }
177                 }
178                 print "done\n";
179         }
180
181         if ( $found ) {
182                 print "Fixing page_latest... ";
183                 if ( $toMaster ) {
184                         #$dbw->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname );
185                 } else {
186                         foreach ( $slaveIndexes as $i ) {
187                                 $db = wfGetDB( $i );
188                                 $db->update( 'page', array( 'page_latest' => $realLatest ), array( 'page_id' => $pageID ), $fname );
189                         }
190                 }
191                 print "done\n";
192         }
193         $dbw->commit();
194 }
195
196