diff --git a/resources/sql/autopatches/20160711.files.01.builtin.sql b/resources/sql/autopatches/20160711.files.01.builtin.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20160711.files.01.builtin.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_file.file + ADD builtinKey VARCHAR(64) COLLATE {$COLLATE_TEXT}; diff --git a/resources/sql/autopatches/20160711.files.02.builtinkey.sql b/resources/sql/autopatches/20160711.files.02.builtinkey.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20160711.files.02.builtinkey.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_file.file + ADD UNIQUE KEY `key_builtin` (builtinKey); diff --git a/src/applications/files/query/PhabricatorFileQuery.php b/src/applications/files/query/PhabricatorFileQuery.php --- a/src/applications/files/query/PhabricatorFileQuery.php +++ b/src/applications/files/query/PhabricatorFileQuery.php @@ -16,6 +16,7 @@ private $names; private $isPartial; private $needTransforms; + private $builtinKeys; public function withIDs(array $ids) { $this->ids = $ids; @@ -47,6 +48,11 @@ return $this; } + public function withBuiltinKeys(array $keys) { + $this->builtinKeys = $keys; + return $this; + } + /** * Select files which are transformations of some other file. For example, * you can use this query to find previously generated thumbnails of an image @@ -384,6 +390,13 @@ (int)$this->isPartial); } + if ($this->builtinKeys !== null) { + $where[] = qsprintf( + $conn, + 'builtinKey IN (%Ls)', + $this->builtinKeys); + } + return $where; } diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -42,6 +42,7 @@ protected $contentHash; protected $metadata = array(); protected $mailKey; + protected $builtinKey; protected $storageEngine; protected $storageFormat; @@ -94,6 +95,7 @@ 'isExplicitUpload' => 'bool?', 'mailKey' => 'bytes20', 'isPartial' => 'bool', + 'builtinKey' => 'text64?', ), self::CONFIG_KEY_SCHEMA => array( 'key_phid' => null, @@ -116,6 +118,10 @@ 'key_partial' => array( 'columns' => array('authorPHID', 'isPartial'), ), + 'key_builtin' => array( + 'columns' => array('builtinKey'), + 'unique' => true, + ), ), ) + parent::getConfiguration(); } @@ -1070,19 +1076,11 @@ public static function loadBuiltins(PhabricatorUser $user, array $builtins) { $builtins = mpull($builtins, null, 'getBuiltinFileKey'); - $specs = array(); - foreach ($builtins as $key => $buitin) { - $specs[] = array( - 'originalPHID' => PhabricatorPHIDConstants::PHID_VOID, - 'transform' => $key, - ); - } - // NOTE: Anyone is allowed to access builtin files. $files = id(new PhabricatorFileQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) - ->withTransforms($specs) + ->withBuiltinKeys(array_keys($builtins)) ->execute(); $results = array(); @@ -1109,12 +1107,21 @@ ); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $file = self::newFromFileData($data, $params); - $xform = id(new PhabricatorTransformedFile()) - ->setOriginalPHID(PhabricatorPHIDConstants::PHID_VOID) - ->setTransform($key) - ->setTransformedPHID($file->getPHID()) - ->save(); + try { + $file = self::newFromFileData($data, $params); + } catch (AphrontDuplicateKeyQueryException $ex) { + $file = id(new PhabricatorFileQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withBuiltinKeys(array($key)) + ->executeOne(); + if (!$file) { + throw new Exception( + pht( + 'Collided mid-air when generating builtin file "%s", but '. + 'then failed to load the object we collided with.', + $key)); + } + } unset($unguarded); $file->attachObjectPHIDs(array()); @@ -1289,6 +1296,7 @@ $builtin = idx($params, 'builtin'); if ($builtin) { $this->setBuiltinName($builtin); + $this->setBuiltinKey($builtin); } $profile = idx($params, 'profile');