diff --git a/src/applications/files/controller/PhabricatorFileTransformController.php b/src/applications/files/controller/PhabricatorFileTransformController.php --- a/src/applications/files/controller/PhabricatorFileTransformController.php +++ b/src/applications/files/controller/PhabricatorFileTransformController.php @@ -30,11 +30,7 @@ } $transform = $request->getURIData('transform'); - $xform = id(new PhabricatorTransformedFile()) - ->loadOneWhere( - 'originalPHID = %s AND transform = %s', - $source_phid, - $transform); + $xform = $this->loadTransform($source_phid, $transform); if ($xform) { if ($is_regenerate) { @@ -80,8 +76,20 @@ $xform = id(new PhabricatorTransformedFile()) ->setOriginalPHID($source_phid) ->setTransform($transform) - ->setTransformedPHID($xformed_file->getPHID()) - ->save(); + ->setTransformedPHID($xformed_file->getPHID()); + + try { + $xform->save(); + } catch (AphrontDuplicateKeyQueryException $ex) { + // If we collide when saving, we've raced another endpoint which was + // transforming the same file. Just throw our work away and use that + // transform instead. + $this->destroyTransform($xform); + $xform = $this->loadTransform($source_phid, $transform); + if (!$xform) { + return new Aphront404Response(); + } + } return $this->buildTransformedFileResponse($xform); } @@ -113,7 +121,9 @@ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); if (!$file) { - $xform->delete(); + if ($xform->getID()) { + $xform->delete(); + } } else { $engine->destroyObject($file); } @@ -121,4 +131,11 @@ unset($unguarded); } + private function loadTransform($source_phid, $transform) { + return id(new PhabricatorTransformedFile())->loadOneWhere( + 'originalPHID = %s AND transform = %s', + $source_phid, + $transform); + } + }