diff --git a/src/applications/config/check/PhabricatorStorageSetupCheck.php b/src/applications/config/check/PhabricatorStorageSetupCheck.php --- a/src/applications/config/check/PhabricatorStorageSetupCheck.php +++ b/src/applications/config/check/PhabricatorStorageSetupCheck.php @@ -10,15 +10,8 @@ * @phutil-external-symbol class PhabricatorStartup */ protected function executeChecks() { - $chunk_engine_active = false; - - $engines = PhabricatorFileStorageEngine::loadWritableEngines(); - foreach ($engines as $engine) { - if ($engine->isChunkEngine()) { - $chunk_engine_active = true; - break; - } - } + $engines = PhabricatorFileStorageEngine::loadWritableChunkEngines(); + $chunk_engine_active = (bool)$engines; if (!$chunk_engine_active) { $doc_href = PhabricatorEnv::getDocLink('Configuring File Storage'); diff --git a/src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php b/src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php --- a/src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php +++ b/src/applications/files/applicationpanel/PhabricatorFilesApplicationStorageEnginePanel.php @@ -18,6 +18,7 @@ $engines = PhabricatorFileStorageEngine::loadAllEngines(); $writable_engines = PhabricatorFileStorageEngine::loadWritableEngines(); + $chunk_engines = PhabricatorFileStorageEngine::loadWritableChunkEngines(); $yes = pht('Yes'); $no = pht('No'); @@ -44,7 +45,7 @@ $test = $no; } - if (isset($writable_engines[$key])) { + if (isset($writable_engines[$key]) || isset($chunk_engines[$key])) { $rowc[] = 'highlighted'; } else { $rowc[] = null; diff --git a/src/applications/files/conduit/FileAllocateConduitAPIMethod.php b/src/applications/files/conduit/FileAllocateConduitAPIMethod.php --- a/src/applications/files/conduit/FileAllocateConduitAPIMethod.php +++ b/src/applications/files/conduit/FileAllocateConduitAPIMethod.php @@ -85,39 +85,35 @@ ); } + // If there are any non-chunk engines which this file can fit into, + // just tell the client to upload the file. $engines = PhabricatorFileStorageEngine::loadStorageEngines($length); if ($engines) { + return array( + 'upload' => true, + 'filePHID' => null, + ); + } - // Pick the first engine. If the file is small enough to fit into a - // single engine without chunking, this will be a non-chunk engine and - // we'll just tell the client to upload the file. - $engine = head($engines); - if ($engine) { - if (!$engine->isChunkEngine()) { - return array( - 'upload' => true, - 'filePHID' => null, - ); - } - - // Otherwise, this is a large file and we need to perform a chunked - // upload. - - $chunk_properties = $properties; - - if ($hash) { - $chunk_properties += array( - 'chunkedHash' => $chunked_hash, - ); - } - - $file = $engine->allocateChunks($length, $chunk_properties); - - return array( - 'upload' => true, - 'filePHID' => $file->getPHID(), + // Otherwise, this is a large file and we want to perform a chunked + // upload if we have a chunk engine available. + $chunk_engines = PhabricatorFileStorageEngine::loadWritableChunkEngines(); + if ($chunk_engines) { + $chunk_properties = $properties; + + if ($hash) { + $chunk_properties += array( + 'chunkedHash' => $chunked_hash, ); } + + $chunk_engine = head($chunk_engines); + $file = $chunk_engine->allocateChunks($length, $chunk_properties); + + return array( + 'upload' => true, + 'filePHID' => $file->getPHID(), + ); } // None of the storage engines can accept this file. diff --git a/src/applications/files/engine/PhabricatorFileStorageEngine.php b/src/applications/files/engine/PhabricatorFileStorageEngine.php --- a/src/applications/files/engine/PhabricatorFileStorageEngine.php +++ b/src/applications/files/engine/PhabricatorFileStorageEngine.php @@ -12,6 +12,7 @@ * @task construct Constructing an Engine * @task meta Engine Metadata * @task file Managing File Data + * @task load Loading Storage Engines */ abstract class PhabricatorFileStorageEngine { @@ -188,12 +189,17 @@ abstract public function deleteFile($handle); + +/* -( Loading Storage Engines )-------------------------------------------- */ + + /** * Select viable default storage engines according to configuration. We'll * select the MySQL and Local Disk storage engines if they are configured * to allow a given file. * * @param int File size in bytes. + * @task load */ public static function loadStorageEngines($length) { $engines = self::loadWritableEngines(); @@ -213,6 +219,10 @@ return $writable; } + + /** + * @task load + */ public static function loadAllEngines() { static $engines; @@ -246,28 +256,72 @@ return $engines; } - public static function loadWritableEngines() { + + /** + * @task load + */ + private static function loadProductionEngines() { $engines = self::loadAllEngines(); - $writable = array(); + $active = array(); foreach ($engines as $key => $engine) { if ($engine->isTestEngine()) { continue; } + $active[$key] = $engine; + } + + return $active; + } + + + /** + * @task load + */ + public static function loadWritableEngines() { + $engines = self::loadProductionEngines(); + + $writable = array(); + foreach ($engines as $key => $engine) { if (!$engine->canWriteFiles()) { continue; } + if ($engine->isChunkEngine()) { + // Don't select chunk engines as writable. + continue; + } $writable[$key] = $engine; } return $writable; } + /** + * @task load + */ + public static function loadWritableChunkEngines() { + $engines = self::loadProductionEngines(); + + $chunk = array(); + foreach ($engines as $key => $engine) { + if (!$engine->canWriteFiles()) { + continue; + } + if (!$engine->isChunkEngine()) { + continue; + } + $chunk[$key] = $engine; + } + + return $chunk; + } + + /** - * Return the largest file size which can be uploaded without chunking. + * Return the largest file size which can not be uploaded in chunks. * * Files smaller than this will always upload in one request, so clients * can safely skip the allocation step. @@ -275,14 +329,10 @@ * @return int|null Byte size, or `null` if there is no chunk support. */ public static function getChunkThreshold() { - $engines = self::loadWritableEngines(); + $engines = self::loadWritableChunkEngines(); $min = null; foreach ($engines as $engine) { - if (!$engine->isChunkEngine()) { - continue; - } - if (!$min) { $min = $engine; continue;