mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-18 04:42:40 +01:00
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
This commit is contained in:
parent
e187519f00
commit
be00264ae7
10 changed files with 69 additions and 4 deletions
2
resources/sql/autopatches/20170418.files.isDeleted.sql
Normal file
2
resources/sql/autopatches/20170418.files.isDeleted.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_file.file
|
||||
ADD isDeleted BOOL NOT NULL DEFAULT 0;
|
|
@ -1098,6 +1098,7 @@ phutil_register_library_map(array(
|
|||
'FileAllocateConduitAPIMethod' => 'applications/files/conduit/FileAllocateConduitAPIMethod.php',
|
||||
'FileConduitAPIMethod' => 'applications/files/conduit/FileConduitAPIMethod.php',
|
||||
'FileCreateMailReceiver' => 'applications/files/mail/FileCreateMailReceiver.php',
|
||||
'FileDeletionWorker' => 'applications/files/worker/FileDeletionWorker.php',
|
||||
'FileDownloadConduitAPIMethod' => 'applications/files/conduit/FileDownloadConduitAPIMethod.php',
|
||||
'FileInfoConduitAPIMethod' => 'applications/files/conduit/FileInfoConduitAPIMethod.php',
|
||||
'FileMailReceiver' => 'applications/files/mail/FileMailReceiver.php',
|
||||
|
@ -5977,6 +5978,7 @@ phutil_register_library_map(array(
|
|||
'FileAllocateConduitAPIMethod' => 'FileConduitAPIMethod',
|
||||
'FileConduitAPIMethod' => 'ConduitAPIMethod',
|
||||
'FileCreateMailReceiver' => 'PhabricatorMailReceiver',
|
||||
'FileDeletionWorker' => 'PhabricatorWorker',
|
||||
'FileDownloadConduitAPIMethod' => 'FileConduitAPIMethod',
|
||||
'FileInfoConduitAPIMethod' => 'FileConduitAPIMethod',
|
||||
'FileMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||
|
|
|
@ -143,6 +143,7 @@ final class PhabricatorFileDataController extends PhabricatorFileController {
|
|||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($this->phid))
|
||||
->withIsDeleted(false)
|
||||
->executeOne();
|
||||
|
||||
if (!$file) {
|
||||
|
|
|
@ -9,6 +9,7 @@ final class PhabricatorFileDeleteController extends PhabricatorFileController {
|
|||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->withIsDeleted(false)
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
|
@ -25,8 +26,15 @@ final class PhabricatorFileDeleteController extends PhabricatorFileController {
|
|||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$engine = new PhabricatorDestructionEngine();
|
||||
$engine->destroyObject($file);
|
||||
// Mark the file for deletion, save it, and schedule a worker to
|
||||
// sweep by later and pick it up.
|
||||
$file->setIsDeleted(true)->save();
|
||||
|
||||
PhabricatorWorker::scheduleTask(
|
||||
'FileDeletionWorker',
|
||||
array('objectPHID' => $file->getPHID()),
|
||||
array('priority' => PhabricatorWorker::PRIORITY_BULK));
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI('/file/');
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
|||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($phid))
|
||||
->withIsDeleted(false)
|
||||
->executeOne();
|
||||
|
||||
if (!$file) {
|
||||
|
@ -25,6 +26,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
|||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->withIsDeleted(false)
|
||||
->executeOne();
|
||||
if (!$file) {
|
||||
return new Aphront404Response();
|
||||
|
|
|
@ -36,7 +36,9 @@ final class PhabricatorFileEditEngine
|
|||
}
|
||||
|
||||
protected function newObjectQuery() {
|
||||
return new PhabricatorFileQuery();
|
||||
$query = new PhabricatorFileQuery();
|
||||
$query->withIsDeleted(false);
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function getObjectCreateTitleText($object) {
|
||||
|
|
|
@ -15,6 +15,7 @@ final class PhabricatorFileQuery
|
|||
private $maxLength;
|
||||
private $names;
|
||||
private $isPartial;
|
||||
private $isDeleted;
|
||||
private $needTransforms;
|
||||
private $builtinKeys;
|
||||
|
||||
|
@ -119,6 +120,11 @@ final class PhabricatorFileQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withIsDeleted($deleted) {
|
||||
$this->isDeleted = $deleted;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withNameNgrams($ngrams) {
|
||||
return $this->withNgramsConstraint(
|
||||
id(new PhabricatorFileNameNgrams()),
|
||||
|
@ -396,6 +402,13 @@ final class PhabricatorFileQuery
|
|||
(int)$this->isPartial);
|
||||
}
|
||||
|
||||
if ($this->isDeleted !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'isDeleted = %d',
|
||||
(int)$this->isDeleted);
|
||||
}
|
||||
|
||||
if ($this->builtinKeys !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
|
|
|
@ -16,7 +16,9 @@ final class PhabricatorFileSearchEngine
|
|||
}
|
||||
|
||||
public function newQuery() {
|
||||
return new PhabricatorFileQuery();
|
||||
$query = new PhabricatorFileQuery();
|
||||
$query->withIsDeleted(false);
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function buildCustomSearchFields() {
|
||||
|
|
|
@ -59,6 +59,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
protected $isExplicitUpload = 1;
|
||||
protected $viewPolicy = PhabricatorPolicies::POLICY_USER;
|
||||
protected $isPartial = 0;
|
||||
protected $isDeleted = 0;
|
||||
|
||||
private $objects = self::ATTACHABLE;
|
||||
private $objectPHIDs = self::ATTACHABLE;
|
||||
|
@ -103,6 +104,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
'mailKey' => 'bytes20',
|
||||
'isPartial' => 'bool',
|
||||
'builtinKey' => 'text64?',
|
||||
'isDeleted' => 'bool',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_phid' => null,
|
||||
|
|
31
src/applications/files/worker/FileDeletionWorker.php
Normal file
31
src/applications/files/worker/FileDeletionWorker.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
final class FileDeletionWorker extends PhabricatorWorker {
|
||||
|
||||
private function loadFile() {
|
||||
$phid = idx($this->getTaskData(), 'objectPHID');
|
||||
if (!$phid) {
|
||||
throw new PhabricatorWorkerPermanentFailureException(
|
||||
pht('No "%s" in task data.', 'objectPHID'));
|
||||
}
|
||||
|
||||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs(array($phid))
|
||||
->executeOne();
|
||||
|
||||
if (!$file) {
|
||||
throw new PhabricatorWorkerPermanentFailureException(
|
||||
pht('File "%s" does not exist.', $phid));
|
||||
}
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
protected function doWork() {
|
||||
$file = $this->loadFile();
|
||||
$engine = new PhabricatorDestructionEngine();
|
||||
$engine->destroyObject($file);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue