Differential D20743 Diff 49458 src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php
Changeset View
Changeset View
Standalone View
Standalone View
src/infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php
<?php | <?php | ||||
final class PhabricatorStorageManagementDumpWorkflow | final class PhabricatorStorageManagementDumpWorkflow | ||||
extends PhabricatorStorageManagementWorkflow { | extends PhabricatorStorageManagementWorkflow { | ||||
protected function didConstruct() { | protected function didConstruct() { | ||||
$this | $this | ||||
->setName('dump') | ->setName('dump') | ||||
->setExamples('**dump** [__options__]') | ->setExamples('**dump** [__options__]') | ||||
->setSynopsis(pht('Dump all data in storage to stdout.')) | ->setSynopsis(pht('Dump all data in storage to stdout.')) | ||||
->setArguments( | ->setArguments( | ||||
array( | array( | ||||
array( | array( | ||||
'name' => 'for-replica', | 'name' => 'for-replica', | ||||
'help' => pht( | 'help' => pht( | ||||
'Add __--master-data__ to the __mysqldump__ command, '. | 'Add __--master-data__ to the __mysqldump__ command, '. | ||||
'generating a CHANGE MASTER statement in the output.'), | 'generating a CHANGE MASTER statement in the output. This '. | ||||
'option also dumps all data, including caches.'), | |||||
), | ), | ||||
array( | array( | ||||
'name' => 'output', | 'name' => 'output', | ||||
'param' => 'file', | 'param' => 'file', | ||||
'help' => pht( | 'help' => pht( | ||||
'Write output directly to disk. This handles errors better '. | 'Write output directly to disk. This handles errors better '. | ||||
'than using pipes. Use with __--compress__ to gzip the '. | 'than using pipes. Use with __--compress__ to gzip the '. | ||||
'output.'), | 'output.'), | ||||
Show All 23 Lines | final class PhabricatorStorageManagementDumpWorkflow | ||||
protected function isReadOnlyWorkflow() { | protected function isReadOnlyWorkflow() { | ||||
return true; | return true; | ||||
} | } | ||||
public function didExecute(PhutilArgumentParser $args) { | public function didExecute(PhutilArgumentParser $args) { | ||||
$output_file = $args->getArg('output'); | $output_file = $args->getArg('output'); | ||||
$is_compress = $args->getArg('compress'); | $is_compress = $args->getArg('compress'); | ||||
$is_overwrite = $args->getArg('overwrite'); | $is_overwrite = $args->getArg('overwrite'); | ||||
$is_noindex = $args->getArg('no-indexes'); | |||||
$is_replica = $args->getArg('for-replica'); | |||||
if ($is_compress) { | if ($is_compress) { | ||||
if ($output_file === null) { | if ($output_file === null) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
'The "--compress" flag can only be used alongside "--output".')); | 'The "--compress" flag can only be used alongside "--output".')); | ||||
} | } | ||||
Show All 9 Lines | public function didExecute(PhutilArgumentParser $args) { | ||||
if ($is_overwrite) { | if ($is_overwrite) { | ||||
if ($output_file === null) { | if ($output_file === null) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
'The "--overwrite" flag can only be used alongside "--output".')); | 'The "--overwrite" flag can only be used alongside "--output".')); | ||||
} | } | ||||
} | } | ||||
if ($is_replica && $is_noindex) { | |||||
throw new PhutilArgumentUsageException( | |||||
pht( | |||||
'The "--for-replica" flag can not be used with the '. | |||||
'"--no-indexes" flag. Replication dumps must contain a complete '. | |||||
'representation of database state.')); | |||||
} | |||||
if ($output_file !== null) { | if ($output_file !== null) { | ||||
if (Filesystem::pathExists($output_file)) { | if (Filesystem::pathExists($output_file)) { | ||||
if (!$is_overwrite) { | if (!$is_overwrite) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
'Output file "%s" already exists. Use "--overwrite" '. | 'Output file "%s" already exists. Use "--overwrite" '. | ||||
'to overwrite.', | 'to overwrite.', | ||||
$output_file)); | $output_file)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
$api = $this->getSingleAPI(); | $api = $this->getSingleAPI(); | ||||
$patches = $this->getPatches(); | $patches = $this->getPatches(); | ||||
$with_indexes = !$args->getArg('no-indexes'); | |||||
$applied = $api->getAppliedPatches(); | $applied = $api->getAppliedPatches(); | ||||
if ($applied === null) { | if ($applied === null) { | ||||
throw new PhutilArgumentUsageException( | throw new PhutilArgumentUsageException( | ||||
pht( | pht( | ||||
'There is no database storage initialized in the current storage '. | 'There is no database storage initialized in the current storage '. | ||||
'namespace ("%s"). Use "bin/storage upgrade" to initialize '. | 'namespace ("%s"). Use "bin/storage upgrade" to initialize '. | ||||
'storage or use "--namespace" to choose a different namespace.', | 'storage or use "--namespace" to choose a different namespace.', | ||||
$api->getNamespace())); | $api->getNamespace())); | ||||
} | } | ||||
$ref = $api->getRef(); | $ref = $api->getRef(); | ||||
$ref_key = $ref->getRefKey(); | $ref_key = $ref->getRefKey(); | ||||
$schemata_query = id(new PhabricatorConfigSchemaQuery()) | $schemata_query = id(new PhabricatorConfigSchemaQuery()) | ||||
->setAPIs(array($api)) | ->setAPIs(array($api)) | ||||
->setRefs(array($ref)); | ->setRefs(array($ref)); | ||||
$actual_map = $schemata_query->loadActualSchemata(); | $actual_map = $schemata_query->loadActualSchemata(); | ||||
$expect_map = $schemata_query->loadExpectedSchemata(); | $expect_map = $schemata_query->loadExpectedSchemata(); | ||||
$schemata = $actual_map[$ref_key]; | $schemata = $actual_map[$ref_key]; | ||||
$expect = $expect_map[$ref_key]; | $expect = $expect_map[$ref_key]; | ||||
$with_caches = $is_replica; | |||||
$with_indexes = !$is_noindex; | |||||
$targets = array(); | $targets = array(); | ||||
foreach ($schemata->getDatabases() as $database_name => $database) { | foreach ($schemata->getDatabases() as $database_name => $database) { | ||||
$expect_database = $expect->getDatabase($database_name); | $expect_database = $expect->getDatabase($database_name); | ||||
foreach ($database->getTables() as $table_name => $table) { | foreach ($database->getTables() as $table_name => $table) { | ||||
// NOTE: It's possible for us to find tables in these database which | // NOTE: It's possible for us to find tables in these database which | ||||
// we don't expect to be there. For example, an older version of | // we don't expect to be there. For example, an older version of | ||||
// Phabricator may have had a table that was later dropped. We assume | // Phabricator may have had a table that was later dropped. We assume | ||||
// these are data tables and always dump them, erring on the side of | // these are data tables and always dump them, erring on the side of | ||||
// caution. | // caution. | ||||
$persistence = PhabricatorConfigTableSchema::PERSISTENCE_DATA; | $persistence = PhabricatorConfigTableSchema::PERSISTENCE_DATA; | ||||
if ($expect_database) { | if ($expect_database) { | ||||
$expect_table = $expect_database->getTable($table_name); | $expect_table = $expect_database->getTable($table_name); | ||||
if ($expect_table) { | if ($expect_table) { | ||||
$persistence = $expect_table->getPersistenceType(); | $persistence = $expect_table->getPersistenceType(); | ||||
} | } | ||||
} | } | ||||
switch ($persistence) { | switch ($persistence) { | ||||
case PhabricatorConfigTableSchema::PERSISTENCE_CACHE: | case PhabricatorConfigTableSchema::PERSISTENCE_CACHE: | ||||
// When dumping tables, leave the data in cache tables in the | // When dumping tables, leave the data in cache tables in the | ||||
// database. This will be automatically rebuild after the data | // database. This will be automatically rebuild after the data | ||||
// is restored and does not need to be persisted in backups. | // is restored and does not need to be persisted in backups. | ||||
$with_data = false; | $with_data = $with_caches; | ||||
break; | break; | ||||
case PhabricatorConfigTableSchema::PERSISTENCE_INDEX: | case PhabricatorConfigTableSchema::PERSISTENCE_INDEX: | ||||
// When dumping tables, leave index data behind of the caller | // When dumping tables, leave index data behind of the caller | ||||
// specified "--no-indexes". These tables can be rebuilt manually | // specified "--no-indexes". These tables can be rebuilt manually | ||||
// from other tables, but do not rebuild automatically. | // from other tables, but do not rebuild automatically. | ||||
$with_data = $with_indexes; | $with_data = $with_indexes; | ||||
break; | break; | ||||
case PhabricatorConfigTableSchema::PERSISTENCE_DATA: | case PhabricatorConfigTableSchema::PERSISTENCE_DATA: | ||||
Show All 23 Lines | public function didExecute(PhutilArgumentParser $args) { | ||||
$argv = array(); | $argv = array(); | ||||
$argv[] = '--hex-blob'; | $argv[] = '--hex-blob'; | ||||
$argv[] = '--single-transaction'; | $argv[] = '--single-transaction'; | ||||
$argv[] = '--default-character-set'; | $argv[] = '--default-character-set'; | ||||
$argv[] = $api->getClientCharset(); | $argv[] = $api->getClientCharset(); | ||||
if ($args->getArg('for-replica')) { | if ($is_replica) { | ||||
$argv[] = '--master-data'; | $argv[] = '--master-data'; | ||||
} | } | ||||
$argv[] = '-u'; | $argv[] = '-u'; | ||||
$argv[] = $api->getUser(); | $argv[] = $api->getUser(); | ||||
$argv[] = '-h'; | $argv[] = '-h'; | ||||
$argv[] = $host; | $argv[] = $host; | ||||
▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | try { | ||||
} | } | ||||
throw $ex; | throw $ex; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
private function writeData($data, $file, $is_compress, $output_file) { | private function writeData($data, $file, $is_compress, $output_file) { | ||||
if (!strlen($data)) { | if (!strlen($data)) { | ||||
return; | return; | ||||
} | } | ||||
if (!$file) { | if (!$file) { | ||||
$ok = fwrite(STDOUT, $data); | $ok = fwrite(STDOUT, $data); | ||||
} else if ($is_compress) { | } else if ($is_compress) { | ||||
Show All 15 Lines |