mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 19:40:55 +01:00
Simplify "builtin file" management and recover from races
Summary: Fixes T11307. Fixes T8124. Currently, builtin files are tracked by using a special transform with an invalid source ID. Just use a dedicated column instead. The transform thing is too clever/weird/hacky and exposes us to issues with the "file" and "transform" tables getting out of sync (possibly the issue in T11307?) and with race conditions. Test Plan: - Loaded profile "edit picture" page, saw builtins. - Deleted all builtin files, put 3 second sleep in the storage engine write, loaded profile page in two windows. - Before patch: one of them failed with a race. - After patch: both of them loaded. Reviewers: chad Reviewed By: chad Maniphest Tasks: T8124, T11307 Differential Revision: https://secure.phabricator.com/D16271
This commit is contained in:
parent
830f3eb8f8
commit
8ad61d0150
4 changed files with 40 additions and 15 deletions
2
resources/sql/autopatches/20160711.files.01.builtin.sql
Normal file
2
resources/sql/autopatches/20160711.files.01.builtin.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_file.file
|
||||
ADD builtinKey VARCHAR(64) COLLATE {$COLLATE_TEXT};
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_file.file
|
||||
ADD UNIQUE KEY `key_builtin` (builtinKey);
|
|
@ -16,6 +16,7 @@ final class PhabricatorFileQuery
|
|||
private $names;
|
||||
private $isPartial;
|
||||
private $needTransforms;
|
||||
private $builtinKeys;
|
||||
|
||||
public function withIDs(array $ids) {
|
||||
$this->ids = $ids;
|
||||
|
@ -47,6 +48,11 @@ final class PhabricatorFileQuery
|
|||
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 @@ final class PhabricatorFileQuery
|
|||
(int)$this->isPartial);
|
||||
}
|
||||
|
||||
if ($this->builtinKeys !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'builtinKey IN (%Ls)',
|
||||
$this->builtinKeys);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
protected $contentHash;
|
||||
protected $metadata = array();
|
||||
protected $mailKey;
|
||||
protected $builtinKey;
|
||||
|
||||
protected $storageEngine;
|
||||
protected $storageFormat;
|
||||
|
@ -94,6 +95,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
'isExplicitUpload' => 'bool?',
|
||||
'mailKey' => 'bytes20',
|
||||
'isPartial' => 'bool',
|
||||
'builtinKey' => 'text64?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_phid' => null,
|
||||
|
@ -116,6 +118,10 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
'key_partial' => array(
|
||||
'columns' => array('authorPHID', 'isPartial'),
|
||||
),
|
||||
'key_builtin' => array(
|
||||
'columns' => array('builtinKey'),
|
||||
'unique' => true,
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
@ -1070,19 +1076,11 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
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 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
);
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
try {
|
||||
$file = self::newFromFileData($data, $params);
|
||||
$xform = id(new PhabricatorTransformedFile())
|
||||
->setOriginalPHID(PhabricatorPHIDConstants::PHID_VOID)
|
||||
->setTransform($key)
|
||||
->setTransformedPHID($file->getPHID())
|
||||
->save();
|
||||
} 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 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
$builtin = idx($params, 'builtin');
|
||||
if ($builtin) {
|
||||
$this->setBuiltinName($builtin);
|
||||
$this->setBuiltinKey($builtin);
|
||||
}
|
||||
|
||||
$profile = idx($params, 'profile');
|
||||
|
|
Loading…
Reference in a new issue