r98842 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r98841‎ | r98842 | r98843 >
Date:00:42, 4 October 2011
Author:nelson
Status:deferred (Comments)
Tags:
Comment:
Do not propagate Swift exceptions up to the user. Fix a few overenthusiastic visibility modifiers.
Modified paths:
  • /trunk/extensions/SwiftMedia/SwiftMedia.body.php (modified) (history)
  • /trunk/extensions/SwiftMedia/TODO (modified) (history)

Diff [purge]

Index: trunk/extensions/SwiftMedia/TODO
@@ -1,5 +1,6 @@
22 Pending:
33
 4+This group all relate to the 404 handler:
45 6) There's no 404 handler to generate missing thumbnails.
56 7) There's no support for remote thumbnailing.
67 7.1) The SpecialUploadStash, when it calls the remote scaler, is actually just relying on the 404 handler on upload.wm.org.
@@ -9,16 +10,11 @@
1011 front-ends forwards the request to a thumb.php running on the scaler cluster. Thumb.php takes care of creating the thumbnail.
1112 6&7) Basically, the code which currently fetches 404 thumbs from upload.wikimedia.org needs to be changed slightly so that it inserts
1213 thumb.php with the appropriate parameters and fetches from the scaler cluster.
13 -8) Test cases (but of course that could be done until the cows come home).
14 -9) Read through the code and look for anything which is insane.
15 -10) Remove directory from $wgLocalFileRepo, to make sure that there's no references to it. Ditto for wgDeletedDirectory and deletedDir.
16 -11) Determine what to do about the one remaining core change needed for Swift.
 14+19) TS: "I suggest you test transform errors throughout your whole system. With our current NFS system, transform errors work by having thumb.php return an HTTP 500 response with an informative HTML error message. The error message is passed through to Squid by the 404 handler, and Squid won't cache it. The user will see a broken image icon in their browser, and choosing "view image" from the context menu of the image will show them the error message from thumb.php."
 15+
1716 12) Why is anybody calling resolveVirtualUrl()? It's defined in the Repo, but getPath() is defined against a file.
1817 Why is UploadStashFile() being called with a virtual URL? Once the file has been stashed() it has an object name. The container name is implicit.
1918 Should UploadStashFile *always* (in our case) be called with a virtual URL?
20 -19) TS: "I suggest you test transform errors throughout your whole system. With our current NFS system, transform errors work by having thumb.php return an HTTP 500 response with an informative HTML error message. The error message is passed through to Squid by the 404 handler, and Squid won't cache it. The user will see a broken image icon in their browser, and choosing "view image" from the context menu of the image will show them the error message from thumb.php."
21 -20) TS: "It's not appropriate to allow CloudFiles exceptions to be propagated back to the callers of File/FileRepo methods such as transform(). Doing this will cause the page to not be displayed at all, with an exceptionally ugly error message in its place. FileRepo has a system for returning user-friendly error messages from pretty much anywhere. For example, SwiftRepo::storeBatch() has a Status object to hold error messages, but your code just sets it to a "good" result, it never sets any errors in it."
22 -"You can throw an MWException in response to configuration errors, or assertion-like unexpected errors, but it's not appropriate to be throwing exceptions in response to network errors or errors generated by the Swift server.
2319 21) TS: "// Check overwriting
2420 if (0) { #FIXME
2521
@@ -26,15 +22,21 @@
2723 22) TS: "I think this [MD65] validation feature in FSRepo is just a hack for NFS. Okay to remove it."
2824 23) TS: "When you get around to implementing SwiftRepo::append(), it will need some sort of concurrency control to avoid having chunks overwrite each other. "
2925 24) TS: "SwiftRepo::swiftcopy() should return a Status object instead of throwing exceptions."
30 -25) TS: In the short term, just copy ForeignDBViaLBRepo to ForeignDBViaSMRepo and change the class parent.
3126
 27+Partially resolved:
3228
 29+20) TS: "It's not appropriate to allow CloudFiles exceptions to be propagated back to the callers of File/FileRepo methods such as transform(). Doing this will cause the page to not be displayed at all, with an exceptionally ugly error message in its place. FileRepo has a system for returning user-friendly error messages from pretty much anywhere. For example, SwiftRepo::storeBatch() has a Status object to hold error messages, but your code just sets it to a "good" result, it never sets any errors in it."
 30+"You can throw an MWException in response to configuration errors, or assertion-like unexpected errors, but it's not appropriate to be throwing exceptions in response to network errors or errors generated by the Swift server.
 31+
3332 Resolved:
3433
3534 5) The Upload seems to take more time than I expect, but that could be a function of generating the six thumbnails.
3635 It *is* a function of generating the seven (we generate 800x600 twice) thumbnails. Each one takes 1/2 second.
 36+8) Test cases (but of course that could be done until the cows come home).
 37+9) Read through the code and look for anything which is insane.
3738 10) Remove directory from $wgLocalFileRepo, to make sure that there's no references to it. Ditto for wgDeletedDirectory and deletedDir.
3839 wgDeletedDirectory and deletedDir can be removed.
 40+11) Determine what to do about the one remaining core change needed for Swift.
3941 12) Implement repo->freeTemp() - needed by several extensions and UploadFromStash.
4042 13) Do we need $wgLocalRepo->ThumbUrl to be configurable given that the Python middleware presumes it?
4143 We currently have no need for it to be configurable in Swift. I'll just hard-code it to .../thumb with a note saying
@@ -46,6 +48,7 @@
4749 18) TS: "You need to handle errors from MediaHandler::doTransform() correctly. "
4850 20) TS: "SwiftMedia::migrateThumbFile() should just do nothing,"
4951 21) TS: "[$wgExcludeFromThumbnailPurge] looks pretty trivial to implement to me." (RN: It was!)
 52+25) TS: In the short term, just copy ForeignDBViaLBRepo to ForeignDBViaSMRepo and change the class parent.
5053
5154
5255
Index: trunk/extensions/SwiftMedia/SwiftMedia.body.php
@@ -140,7 +140,7 @@
141141 *
142142 * @return MediaTransformOutput | false
143143 */
144 - private function maybeDoTransform( $thumbName, $thumbUrl, $params, $flags ) {
 144+ function maybeDoTransform( $thumbName, $thumbUrl, $params, $flags ) {
145145 global $wgIgnoreImageErrors, $wgThumbnailEpoch, $wgTmpDirectory;
146146
147147 // get a temporary place to put the original.
@@ -203,7 +203,7 @@
204204 /**
205205 * We have nothing to do here.
206206 */
207 - protected function migrateThumbFile( $thumbName ) {
 207+ function migrateThumbFile( $thumbName ) {
208208 return;
209209 }
210210 /**
@@ -316,14 +316,14 @@
317317 *
318318 * @return CF_Connection
319319 */
320 - protected function connect() {
 320+ function connect() {
321321 $auth = new CF_Authentication($this->swiftuser, $this->swiftkey, NULL, $this->authurl);
322322 try {
323323 $auth->authenticate();
324324 } catch (AuthenticationException $e) {
325 - throw new MWException( 'We can't authenticate ourselves.' );
326 - } catch (InvalidResponseException $e) {
327 - throw new MWException( __METHOD__ . "unexpected response '$e'" );
 325+ throw new MWException( "We can't authenticate ourselves." );
 326+ #} catch (InvalidResponseException $e) {
 327+ # throw new MWException( __METHOD__ . "unexpected response '$e'" );
328328 }
329329 return new CF_Connection($auth);
330330 }
@@ -334,13 +334,13 @@
335335 *
336336 * @return CF_Container
337337 */
338 - protected function get_container($conn, $cont) {
 338+ function get_container($conn, $cont) {
339339 try {
340340 return $conn->get_container($cont);
341341 } catch (NoSuchContainerException $e) {
342342 throw new MWException( "A container we thought existed, doesn't." );
343 - } catch (InvalidResponseException $e) {
344 - throw new MWException( __METHOD__ . "unexpected response '$e'" );
 343+ #} catch (InvalidResponseException $e) {
 344+ # throw new MWException( __METHOD__ . "unexpected response '$e'" );
345345 }
346346 }
347347
@@ -351,7 +351,7 @@
352352 *
353353 * @return CF_Container
354354 */
355 - protected function write_swift_object( $srcPath, $dstc, $dstRel) {
 355+ function write_swift_object( $srcPath, $dstc, $dstRel) {
356356 try {
357357 $obj = $dstc->create_object($dstRel);
358358 $obj->load_from_filename( $srcPath, True);
@@ -359,8 +359,8 @@
360360 throw new MWException( 'missing required parameters' );
361361 } catch (BadContentTypeException $e) {
362362 throw new MWException( 'No Content-Type was/could be set' );
363 - } catch (InvalidResponseException $e) {
364 - throw new MWException( __METHOD__ . "unexpected response '$e'" );
 363+ #} catch (InvalidResponseException $e) {
 364+ # throw new MWException( __METHOD__ . "unexpected response '$e'" );
365365 } catch (IOException $e) {
366366 throw new MWException( "error opening file '$e'" );
367367 }
@@ -372,15 +372,15 @@
373373 * an Internal Error on them.
374374 *
375375 */
376 - protected function swift_delete( $container, $rel ) {
 376+ function swift_delete( $container, $rel ) {
377377 try {
378378 $container->delete_object($rel);
379379 } catch (SyntaxException $e) {
380380 throw new MWException( "Swift object name not well-formed: '$e'" );
381381 } catch (NoSuchObjectException $e) {
382382 throw new MWException( "Swift object we are trying to delete does not exist: '$e'" );
383 - } catch (InvalidResponseException $e) {
384 - throw new MWException( "unexpected response '$e'" );
 383+ #} catch (InvalidResponseException $e) {
 384+ # throw new MWException( "unexpected response '$e'" );
385385 }
386386 }
387387
@@ -458,16 +458,9 @@
459459 unlink ( $srcPath );
460460 }
461461 }
462 -
463 - if ( !( $flags & self::SKIP_VALIDATION ) ) {
464 - // FIXME: Swift will return the MD5 of the data written.
465 - if (0) { // ( $hashDest === false || $hashSource !== $hashDest )
466 - wfDebug( __METHOD__ . ': File copy validation failed: ' .
467 - "$srcPath ($hashSource) to $dstPath ($hashDest)\n" );
468 -
469 - $status->error( 'filecopyerror', $srcPath, $dstPath );
470 - $good = false;
471 - }
 462+ if (0) {
 463+ $status->error( 'filecopyerror', $srcPath, $dstPath );
 464+ $good = false;
472465 }
473466 if ( $good ) {
474467 $status->successCount++;
@@ -630,8 +623,8 @@
631624 throw new MWException( "Missing Content-Type: $e" );
632625 } catch (MisMatchedChecksumException $e ) {
633626 throw new MWException( __METHOD__ . "should not happen: '$e'" );
634 - } catch (InvalidResponseException $e ) {
635 - throw new MWException( __METHOD__ . "unexpected response '$e'" );
 627+ #} catch (InvalidResponseException $e ) {
 628+ # throw new MWException( __METHOD__ . "unexpected response '$e'" );
636629 }
637630
638631 try {
@@ -648,8 +641,8 @@
649642 throw new MWException( 'Source file does not exist: ' . $srcContainer->name . "/$srcRel: $e" );
650643 } catch (MisMatchedChecksumException $e ) {
651644 throw new MWException( "Checksums do not match: $e" );
652 - } catch (InvalidResponseException $e ) {
653 - throw new MWException( __METHOD__ . "unexpected response '$e'" );
 645+ #} catch (InvalidResponseException $e ) {
 646+ # throw new MWException( __METHOD__ . "unexpected response '$e'" );
654647 }
655648 }
656649
@@ -678,18 +671,31 @@
679672 return $status;
680673 }
681674
682 - $conn = $this->connect();
683 - $container = $this->get_container($conn,$this->container);
 675+ try {
 676+ $conn = $this->connect();
 677+ $container = $this->get_container($conn,$this->container);
 678+ } catch (InvalidResponseException $e) {
 679+ $status->fatal("Unexpected Swift response: '$e'");
 680+ }
684681
 682+ if ( !$status->ok ) {
 683+ return $status;
 684+ }
 685+
685686 foreach ( $triplets as $i => $triplet ) {
686687 list( $srcPath, $dstRel, $archiveRel ) = $triplet;
687688
688689 // Archive destination file if it exists
689690 try {
690691 $pic = $container->get_object($dstRel);
 692+ } catch (InvalidResponseException $e) {
 693+ $status->error("Unexpected Swift response: '$e'");
 694+ $status->failCount++;
 695+ continue;
691696 } catch (NoSuchObjectException $e) {
692697 $pic = NULL;
693698 }
 699+
694700 if( $pic ) {
695701 $this->swiftcopy($container, $dstRel, $container, $archiveRel );
696702 wfDebug(__METHOD__.": moved file $dstRel to $archiveRel\n");
@@ -698,26 +704,30 @@
699705 $status->value[$i] = 'new';
700706 }
701707
702 - // Where are we copying this from?
703 - if (self::isVirtualUrl( $srcPath )) {
704 - $src = $this->getContainerRel( $srcPath );
705 - list ($srcContainer, $srcRel) = $src;
706 - $srcc = $this->get_container($conn, $srcContainer);
 708+ $good = true;
 709+ try {
 710+ // Where are we copying this from?
 711+ if (self::isVirtualUrl( $srcPath )) {
 712+ $src = $this->getContainerRel( $srcPath );
 713+ list ($srcContainer, $srcRel) = $src;
 714+ $srcc = $this->get_container($conn, $srcContainer);
707715
708 - $this->swiftcopy($srcc, $srcRel, $container, $dstRel);
709 - if ( $flags & self::DELETE_SOURCE ) {
710 - $this->swift_delete( $srcc, $srcRel );
 716+ $this->swiftcopy($srcc, $srcRel, $container, $dstRel);
 717+ if ( $flags & self::DELETE_SOURCE ) {
 718+ $this->swift_delete( $srcc, $srcRel );
 719+ }
 720+ } else {
 721+ $this->write_swift_object( $srcPath, $container, $dstRel);
 722+ // php-cloudfiles throws exceptions, so failure never gets here.
 723+ if ( $flags & self::DELETE_SOURCE ) {
 724+ unlink ( $srcPath );
 725+ }
711726 }
712 - } else {
713 - $this->write_swift_object( $srcPath, $container, $dstRel);
714 - // php-cloudfiles throws exceptions, so failure never gets here.
715 - if ( $flags & self::DELETE_SOURCE ) {
716 - unlink ( $srcPath );
717 - }
 727+ } catch (InvalidResponseException $e) {
 728+ $status->error("Unexpected Swift response: '$e'");
 729+ $good = false;
718730 }
719731
720 - $good = true;
721 -
722732 if ( $good ) {
723733 $status->successCount++;
724734 wfDebug(__METHOD__.": wrote tempfile $srcPath to $dstRel\n");
@@ -884,8 +894,9 @@
885895 * copy of the file MUST delete the produced file, or else store it in
886896 * SwiftFile->tempPath so it will be deleted when the object goes out of
887897 * scope.
 898+ * FIXME: how do we return a fatal error from Swift?
888899 */
889 - protected function getLocalCopy($container, $rel) {
 900+ function getLocalCopy($container, $rel) {
890901
891902 // get a temporary place to put the original.
892903 $tempPath = tempnam( wfTempDir(), 'swift_in_' ) . '.' . pathinfo( $rel, PATHINFO_EXTENSION );
@@ -1270,15 +1281,16 @@
12711282 }
12721283
12731284 function getMasterDB() {
 1285+ wfDebug( __METHOD__.": {$this->dbServer}\n" );
12741286 if ( !isset( $this->dbConn ) ) {
1275 - $this->dbConn = DatabaseBase::newFromType( $this->dbType,
 1287+ $this->dbConn = DatabaseBase::factory( $this->dbType,
12761288 array(
1277 - 'server' => $this->dbServer,
 1289+ 'host' => $this->dbServer,
12781290 'user' => $this->dbUser,
12791291 'password' => $this->dbPassword,
12801292 'dbname' => $this->dbName,
12811293 'flags' => $this->dbFlags,
1282 - 'tableprefix' => $this->tablePrefix
 1294+ 'tablePrefix' => $this->tablePrefix
12831295 )
12841296 );
12851297 }
@@ -1331,7 +1343,7 @@
13321344 *
13331345 * @ingroup FileRepo
13341346 */
1335 -class SwiftForeignDBViaLBRepo extends LocalRepo {
 1347+class SwiftForeignDBViaLBRepo extends SwiftRepo{
13361348 var $wiki, $dbName, $tablePrefix;
13371349 var $fileFactory = array( 'SwiftForeignDBFile', 'newFromTitle' );
13381350 var $fileFromRowFactory = array( 'SwiftForeignDBFile', 'newFromRow' );

Comments

#Comment by 😂 (talk | contribs)   22:01, 4 October 2011

This doesn't look right:

+ if (0) {

Also, if you're making stuff public please mark it as such.

#Comment by RussNelson (talk | contribs)   01:06, 5 October 2011

It's not right. Well, it's not wrong either. I need to figure out how to test this code before I enable it. So far I can't see a clean test case, but will keep looking for a few hours. May need to knuckle down and test php unit tests. I prefer end-to-end tests, but if there's no clean way to get to the end, better a unit test.

Not making things public that weren't already (but not marked as such). I had over-hidden a few functions in my enthusiasm to mark things as private and protected.

#Comment by RussNelson (talk | contribs)   03:51, 19 October 2011

I wrote include/filerepo/StoreBatchTest.php to fix this.

#Comment by RussNelson (talk | contribs)   03:55, 19 October 2011

Fixed in r99590

#Comment by RussNelson (talk | contribs)   03:56, 19 October 2011

Trying to mark this as resolved ...

#Comment by 😂 (talk | contribs)   04:05, 19 October 2011

You can't mark your own code as "ok" or "resolved." Set it back to new and someone will re-review.

#Comment by RussNelson (talk | contribs)   12:44, 19 October 2011

I want to know why I can't mark my code "fabulous". That's what I want to know, yeah.

#Comment by RussNelson (talk | contribs)   12:45, 19 October 2011

Marking as 'new', although that seems wrong, since I'm claiming that it's fixed.

Status & tagging log