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