Index: trunk/phase3/maintenance/storage/fixBug20757.php |
— | — | @@ -12,6 +12,7 @@ |
13 | 13 | parent::__construct(); |
14 | 14 | $this->mDescription = 'Script to fix bug 20757 assuming that blob_tracking is intact'; |
15 | 15 | $this->addOption( 'dry-run', 'Report only' ); |
| 16 | + $this->addOption( 'start', 'old_id to start at', false, true ); |
16 | 17 | } |
17 | 18 | |
18 | 19 | function execute() { |
— | — | @@ -23,7 +24,7 @@ |
24 | 25 | print "Dry run only.\n"; |
25 | 26 | } |
26 | 27 | |
27 | | - $startId = 0; |
| 28 | + $startId = $this->getOption( 'start', 0 ); |
28 | 29 | $numGood = 0; |
29 | 30 | $numFixed = 0; |
30 | 31 | $numBad = 0; |
— | — | @@ -38,7 +39,7 @@ |
39 | 40 | array( 'old_id', 'old_flags', 'old_text' ), |
40 | 41 | array( |
41 | 42 | 'old_id > ' . intval( $startId ), |
42 | | - 'old_flags' => 'object' |
| 43 | + 'old_flags ' . $dbr->buildLike( $dbr->anyString(), 'object', $dbr->anyString ) |
43 | 44 | ), |
44 | 45 | __METHOD__, |
45 | 46 | array( |
— | — | @@ -72,14 +73,6 @@ |
73 | 74 | continue; |
74 | 75 | } |
75 | 76 | |
76 | | - // Check if it really is broken |
77 | | - $text = Revision::getRevisionText( $row ); |
78 | | - if ( $text !== false ) { |
79 | | - // Not broken yet |
80 | | - ++$numGood; |
81 | | - continue; |
82 | | - } |
83 | | - |
84 | 77 | if ( strtolower( get_class( $obj ) ) !== 'historyblobstub' ) { |
85 | 78 | print "{$row->old_id}: unrecoverable: unexpected object class " . |
86 | 79 | get_class( $obj ) . "\n"; |
— | — | @@ -122,6 +115,7 @@ |
123 | 116 | foreach ( $stubs as $primaryId => $stub ) { |
124 | 117 | $secondaryId = $stub['secondaryId']; |
125 | 118 | if ( !isset( $trackedBlobs[$secondaryId] ) ) { |
| 119 | + // No tracked blob. Work out what went wrong |
126 | 120 | $secondaryRow = $dbr->selectRow( |
127 | 121 | 'text', |
128 | 122 | array( 'old_flags', 'old_text' ), |
— | — | @@ -130,12 +124,18 @@ |
131 | 125 | ); |
132 | 126 | if ( !$secondaryRow ) { |
133 | 127 | print "$primaryId: unrecoverable: secondary row is missing\n"; |
| 128 | + ++$numBad; |
| 129 | + } elseif ( $this->isUnbrokenStub( $stub, $secondaryRow ) ) { |
| 130 | + // Not broken yet, and not in the tracked clusters so it won't get |
| 131 | + // broken by the current RCT run. |
| 132 | + ++$numGood; |
134 | 133 | } elseif ( strpos( $secondaryRow->old_flags, 'external' ) !== false ) { |
135 | 134 | print "$primaryId: unrecoverable: secondary gone to {$secondaryRow->old_text}\n"; |
| 135 | + ++$numBad; |
136 | 136 | } else { |
137 | 137 | print "$primaryId: unrecoverable: miscellaneous corruption of secondary row\n"; |
| 138 | + ++$numBad; |
138 | 139 | } |
139 | | - ++$numBad; |
140 | 140 | unset( $stubs[$primaryId] ); |
141 | 141 | continue; |
142 | 142 | } |
— | — | @@ -212,7 +212,7 @@ |
213 | 213 | print "\n"; |
214 | 214 | print "Fixed: $numFixed\n"; |
215 | 215 | print "Unrecoverable: $numBad\n"; |
216 | | - print "Not yet broken: $numGood\n"; |
| 216 | + print "Good stubs: $numGood\n"; |
217 | 217 | } |
218 | 218 | |
219 | 219 | function waitForSlaves() { |
— | — | @@ -258,6 +258,43 @@ |
259 | 259 | return $this->mapCache[$pageId]; |
260 | 260 | } |
261 | 261 | |
| 262 | + /** |
| 263 | + * This is based on part of HistoryBlobStub::getText(). |
| 264 | + * Determine if the text can be retrieved from the row in the normal way. |
| 265 | + */ |
| 266 | + function isUnbrokenStub( $stub, $secondaryRow ) { |
| 267 | + $flags = explode( ',', $secondaryRow->old_flags ); |
| 268 | + if( in_array( 'external', $flags ) ) { |
| 269 | + $url = $secondaryRow->old_text; |
| 270 | + @list( /* $proto */ , $path ) = explode( '://', $url, 2 ); |
| 271 | + if ( $path == "" ) { |
| 272 | + return false; |
| 273 | + } |
| 274 | + $secondaryRow->old_text = ExternalStore::fetchFromUrl( $url ); |
| 275 | + } |
| 276 | + if( !in_array( 'object', $flags ) ) { |
| 277 | + return false; |
| 278 | + } |
| 279 | + |
| 280 | + if( in_array( 'gzip', $flags ) ) { |
| 281 | + $obj = unserialize( gzinflate( $secondaryRow->old_text ) ); |
| 282 | + } else { |
| 283 | + $obj = unserialize( $secondaryRow->old_text ); |
| 284 | + } |
| 285 | + |
| 286 | + if( !is_object( $obj ) ) { |
| 287 | + // Correct for old double-serialization bug. |
| 288 | + $obj = unserialize( $obj ); |
| 289 | + } |
| 290 | + |
| 291 | + if ( !is_object( $obj ) ) { |
| 292 | + return false; |
| 293 | + } |
| 294 | + |
| 295 | + $obj->uncompress(); |
| 296 | + $text = $obj->getItem( $stub['hash'] ); |
| 297 | + return $text !== false; |
| 298 | + } |
262 | 299 | } |
263 | 300 | |
264 | 301 | $maintClass = 'FixBug20757'; |