@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+40 -15
+2
resources/sql/autopatches/20160711.files.01.builtin.sql
··· 1 + ALTER TABLE {$NAMESPACE}_file.file 2 + ADD builtinKey VARCHAR(64) COLLATE {$COLLATE_TEXT};
+2
resources/sql/autopatches/20160711.files.02.builtinkey.sql
··· 1 + ALTER TABLE {$NAMESPACE}_file.file 2 + ADD UNIQUE KEY `key_builtin` (builtinKey);
+13
src/applications/files/query/PhabricatorFileQuery.php
··· 16 16 private $names; 17 17 private $isPartial; 18 18 private $needTransforms; 19 + private $builtinKeys; 19 20 20 21 public function withIDs(array $ids) { 21 22 $this->ids = $ids; ··· 44 45 45 46 public function withContentHashes(array $content_hashes) { 46 47 $this->contentHashes = $content_hashes; 48 + return $this; 49 + } 50 + 51 + public function withBuiltinKeys(array $keys) { 52 + $this->builtinKeys = $keys; 47 53 return $this; 48 54 } 49 55 ··· 382 388 $conn, 383 389 'isPartial = %d', 384 390 (int)$this->isPartial); 391 + } 392 + 393 + if ($this->builtinKeys !== null) { 394 + $where[] = qsprintf( 395 + $conn, 396 + 'builtinKey IN (%Ls)', 397 + $this->builtinKeys); 385 398 } 386 399 387 400 return $where;
+23 -15
src/applications/files/storage/PhabricatorFile.php
··· 42 42 protected $contentHash; 43 43 protected $metadata = array(); 44 44 protected $mailKey; 45 + protected $builtinKey; 45 46 46 47 protected $storageEngine; 47 48 protected $storageFormat; ··· 94 95 'isExplicitUpload' => 'bool?', 95 96 'mailKey' => 'bytes20', 96 97 'isPartial' => 'bool', 98 + 'builtinKey' => 'text64?', 97 99 ), 98 100 self::CONFIG_KEY_SCHEMA => array( 99 101 'key_phid' => null, ··· 115 117 ), 116 118 'key_partial' => array( 117 119 'columns' => array('authorPHID', 'isPartial'), 120 + ), 121 + 'key_builtin' => array( 122 + 'columns' => array('builtinKey'), 123 + 'unique' => true, 118 124 ), 119 125 ), 120 126 ) + parent::getConfiguration(); ··· 1070 1076 public static function loadBuiltins(PhabricatorUser $user, array $builtins) { 1071 1077 $builtins = mpull($builtins, null, 'getBuiltinFileKey'); 1072 1078 1073 - $specs = array(); 1074 - foreach ($builtins as $key => $buitin) { 1075 - $specs[] = array( 1076 - 'originalPHID' => PhabricatorPHIDConstants::PHID_VOID, 1077 - 'transform' => $key, 1078 - ); 1079 - } 1080 - 1081 1079 // NOTE: Anyone is allowed to access builtin files. 1082 1080 1083 1081 $files = id(new PhabricatorFileQuery()) 1084 1082 ->setViewer(PhabricatorUser::getOmnipotentUser()) 1085 - ->withTransforms($specs) 1083 + ->withBuiltinKeys(array_keys($builtins)) 1086 1084 ->execute(); 1087 1085 1088 1086 $results = array(); ··· 1109 1107 ); 1110 1108 1111 1109 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 1112 - $file = self::newFromFileData($data, $params); 1113 - $xform = id(new PhabricatorTransformedFile()) 1114 - ->setOriginalPHID(PhabricatorPHIDConstants::PHID_VOID) 1115 - ->setTransform($key) 1116 - ->setTransformedPHID($file->getPHID()) 1117 - ->save(); 1110 + try { 1111 + $file = self::newFromFileData($data, $params); 1112 + } catch (AphrontDuplicateKeyQueryException $ex) { 1113 + $file = id(new PhabricatorFileQuery()) 1114 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 1115 + ->withBuiltinKeys(array($key)) 1116 + ->executeOne(); 1117 + if (!$file) { 1118 + throw new Exception( 1119 + pht( 1120 + 'Collided mid-air when generating builtin file "%s", but '. 1121 + 'then failed to load the object we collided with.', 1122 + $key)); 1123 + } 1124 + } 1118 1125 unset($unguarded); 1119 1126 1120 1127 $file->attachObjectPHIDs(array()); ··· 1289 1296 $builtin = idx($params, 'builtin'); 1290 1297 if ($builtin) { 1291 1298 $this->setBuiltinName($builtin); 1299 + $this->setBuiltinKey($builtin); 1292 1300 } 1293 1301 1294 1302 $profile = idx($params, 'profile');