@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.

Make daemons perform file deletion

Summary:
Deletion is a possibly time-intensive process, especially with large
files that are backed by high-latency, chunked storage (such as
S3). Even ~200mb objects take minutes to delete, which makes for an
unhappy experience. Fixes T10828.

Test Plan:
Delete a large file, and stare in awe of the swiftness with
which I am redirected to the main file application.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: thoughtpolice, Korvin

Maniphest Tasks: T10828

Differential Revision: https://secure.phabricator.com/D15743

+69 -4
+2
resources/sql/autopatches/20170418.files.isDeleted.sql
··· 1 + ALTER TABLE {$NAMESPACE}_file.file 2 + ADD isDeleted BOOL NOT NULL DEFAULT 0;
+2
src/__phutil_library_map__.php
··· 1098 1098 'FileAllocateConduitAPIMethod' => 'applications/files/conduit/FileAllocateConduitAPIMethod.php', 1099 1099 'FileConduitAPIMethod' => 'applications/files/conduit/FileConduitAPIMethod.php', 1100 1100 'FileCreateMailReceiver' => 'applications/files/mail/FileCreateMailReceiver.php', 1101 + 'FileDeletionWorker' => 'applications/files/worker/FileDeletionWorker.php', 1101 1102 'FileDownloadConduitAPIMethod' => 'applications/files/conduit/FileDownloadConduitAPIMethod.php', 1102 1103 'FileInfoConduitAPIMethod' => 'applications/files/conduit/FileInfoConduitAPIMethod.php', 1103 1104 'FileMailReceiver' => 'applications/files/mail/FileMailReceiver.php', ··· 5977 5978 'FileAllocateConduitAPIMethod' => 'FileConduitAPIMethod', 5978 5979 'FileConduitAPIMethod' => 'ConduitAPIMethod', 5979 5980 'FileCreateMailReceiver' => 'PhabricatorMailReceiver', 5981 + 'FileDeletionWorker' => 'PhabricatorWorker', 5980 5982 'FileDownloadConduitAPIMethod' => 'FileConduitAPIMethod', 5981 5983 'FileInfoConduitAPIMethod' => 'FileConduitAPIMethod', 5982 5984 'FileMailReceiver' => 'PhabricatorObjectMailReceiver',
+1
src/applications/files/controller/PhabricatorFileDataController.php
··· 143 143 $file = id(new PhabricatorFileQuery()) 144 144 ->setViewer($viewer) 145 145 ->withPHIDs(array($this->phid)) 146 + ->withIsDeleted(false) 146 147 ->executeOne(); 147 148 148 149 if (!$file) {
+10 -2
src/applications/files/controller/PhabricatorFileDeleteController.php
··· 9 9 $file = id(new PhabricatorFileQuery()) 10 10 ->setViewer($viewer) 11 11 ->withIDs(array($id)) 12 + ->withIsDeleted(false) 12 13 ->requireCapabilities( 13 14 array( 14 15 PhabricatorPolicyCapability::CAN_VIEW, ··· 25 26 } 26 27 27 28 if ($request->isFormPost()) { 28 - $engine = new PhabricatorDestructionEngine(); 29 - $engine->destroyObject($file); 29 + // Mark the file for deletion, save it, and schedule a worker to 30 + // sweep by later and pick it up. 31 + $file->setIsDeleted(true)->save(); 32 + 33 + PhabricatorWorker::scheduleTask( 34 + 'FileDeletionWorker', 35 + array('objectPHID' => $file->getPHID()), 36 + array('priority' => PhabricatorWorker::PRIORITY_BULK)); 37 + 30 38 return id(new AphrontRedirectResponse())->setURI('/file/'); 31 39 } 32 40
+2
src/applications/files/controller/PhabricatorFileInfoController.php
··· 15 15 $file = id(new PhabricatorFileQuery()) 16 16 ->setViewer($viewer) 17 17 ->withPHIDs(array($phid)) 18 + ->withIsDeleted(false) 18 19 ->executeOne(); 19 20 20 21 if (!$file) { ··· 25 26 $file = id(new PhabricatorFileQuery()) 26 27 ->setViewer($viewer) 27 28 ->withIDs(array($id)) 29 + ->withIsDeleted(false) 28 30 ->executeOne(); 29 31 if (!$file) { 30 32 return new Aphront404Response();
+3 -1
src/applications/files/editor/PhabricatorFileEditEngine.php
··· 36 36 } 37 37 38 38 protected function newObjectQuery() { 39 - return new PhabricatorFileQuery(); 39 + $query = new PhabricatorFileQuery(); 40 + $query->withIsDeleted(false); 41 + return $query; 40 42 } 41 43 42 44 protected function getObjectCreateTitleText($object) {
+13
src/applications/files/query/PhabricatorFileQuery.php
··· 15 15 private $maxLength; 16 16 private $names; 17 17 private $isPartial; 18 + private $isDeleted; 18 19 private $needTransforms; 19 20 private $builtinKeys; 20 21 ··· 116 117 117 118 public function withIsPartial($partial) { 118 119 $this->isPartial = $partial; 120 + return $this; 121 + } 122 + 123 + public function withIsDeleted($deleted) { 124 + $this->isDeleted = $deleted; 119 125 return $this; 120 126 } 121 127 ··· 394 400 $conn, 395 401 'isPartial = %d', 396 402 (int)$this->isPartial); 403 + } 404 + 405 + if ($this->isDeleted !== null) { 406 + $where[] = qsprintf( 407 + $conn, 408 + 'isDeleted = %d', 409 + (int)$this->isDeleted); 397 410 } 398 411 399 412 if ($this->builtinKeys !== null) {
+3 -1
src/applications/files/query/PhabricatorFileSearchEngine.php
··· 16 16 } 17 17 18 18 public function newQuery() { 19 - return new PhabricatorFileQuery(); 19 + $query = new PhabricatorFileQuery(); 20 + $query->withIsDeleted(false); 21 + return $query; 20 22 } 21 23 22 24 protected function buildCustomSearchFields() {
+2
src/applications/files/storage/PhabricatorFile.php
··· 59 59 protected $isExplicitUpload = 1; 60 60 protected $viewPolicy = PhabricatorPolicies::POLICY_USER; 61 61 protected $isPartial = 0; 62 + protected $isDeleted = 0; 62 63 63 64 private $objects = self::ATTACHABLE; 64 65 private $objectPHIDs = self::ATTACHABLE; ··· 103 104 'mailKey' => 'bytes20', 104 105 'isPartial' => 'bool', 105 106 'builtinKey' => 'text64?', 107 + 'isDeleted' => 'bool', 106 108 ), 107 109 self::CONFIG_KEY_SCHEMA => array( 108 110 'key_phid' => null,
+31
src/applications/files/worker/FileDeletionWorker.php
··· 1 + <?php 2 + 3 + final class FileDeletionWorker extends PhabricatorWorker { 4 + 5 + private function loadFile() { 6 + $phid = idx($this->getTaskData(), 'objectPHID'); 7 + if (!$phid) { 8 + throw new PhabricatorWorkerPermanentFailureException( 9 + pht('No "%s" in task data.', 'objectPHID')); 10 + } 11 + 12 + $file = id(new PhabricatorFileQuery()) 13 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 14 + ->withPHIDs(array($phid)) 15 + ->executeOne(); 16 + 17 + if (!$file) { 18 + throw new PhabricatorWorkerPermanentFailureException( 19 + pht('File "%s" does not exist.', $phid)); 20 + } 21 + 22 + return $file; 23 + } 24 + 25 + protected function doWork() { 26 + $file = $this->loadFile(); 27 + $engine = new PhabricatorDestructionEngine(); 28 + $engine->destroyObject($file); 29 + } 30 + 31 + }