mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-42039 Restore: Avoid unnecessary archive file copy at start
Change the start of restore process so that the archive file can be passed as a pathnamehash pointing to the Moodle file object, rather than only as a filename in the temporary directory. This avoids making an unnecessary copy of the archive file, which can take a long time (and potentially cause a timeout) in the case of multi-gigabyte backups.
This commit is contained in:
parent
1cd39657b5
commit
a658b73cd0
@ -72,10 +72,23 @@ if (!check_dir_exists($tmpdir, true, true)) {
|
||||
// choose the backup file from backup files tree
|
||||
if ($action == 'choosebackupfile') {
|
||||
if ($fileinfo = $browser->get_file_info($filecontext, $component, $filearea, $itemid, $filepath, $filename)) {
|
||||
$filename = restore_controller::get_tempdir_name($course->id, $USER->id);
|
||||
$pathname = $tmpdir . '/' . $filename;
|
||||
$fileinfo->copy_to_pathname($pathname);
|
||||
$restore_url = new moodle_url('/backup/restore.php', array('contextid'=>$contextid, 'filename'=>$filename));
|
||||
if (is_a($fileinfo, 'file_info_stored')) {
|
||||
// Use the contenthash rather than copying the file where possible,
|
||||
// to improve performance and avoid timeouts with large files.
|
||||
$fs = get_file_storage();
|
||||
$params = $fileinfo->get_params();
|
||||
$file = $fs->get_file($params['contextid'], $params['component'], $params['filearea'],
|
||||
$params['itemid'], $params['filepath'], $params['filename']);
|
||||
$restore_url = new moodle_url('/backup/restore.php', array('contextid' => $contextid,
|
||||
'pathnamehash' => $file->get_pathnamehash(), 'contenthash' => $file->get_contenthash()));
|
||||
} else {
|
||||
// If it's some weird other kind of file then use old code.
|
||||
$filename = restore_controller::get_tempdir_name($course->id, $USER->id);
|
||||
$pathname = $tmpdir . '/' . $filename;
|
||||
$fileinfo->copy_to_pathname($pathname);
|
||||
$restore_url = new moodle_url('/backup/restore.php', array(
|
||||
'contextid' => $contextid, 'filename' => $filename));
|
||||
}
|
||||
redirect($restore_url);
|
||||
} else {
|
||||
redirect($url, get_string('filenotfound', 'error'));
|
||||
|
@ -185,6 +185,16 @@ class restore_ui_stage_confirm extends restore_ui_independent_stage implements f
|
||||
protected $contextid;
|
||||
protected $filename = null;
|
||||
protected $filepath = null;
|
||||
|
||||
/**
|
||||
* @var string Content hash of archive file to restore (if specified by hash)
|
||||
*/
|
||||
protected $contenthash = null;
|
||||
/**
|
||||
* @var string Pathname hash of stored_file object to restore
|
||||
*/
|
||||
protected $pathnamehash = null;
|
||||
|
||||
protected $details;
|
||||
|
||||
/**
|
||||
@ -194,27 +204,54 @@ class restore_ui_stage_confirm extends restore_ui_independent_stage implements f
|
||||
|
||||
public function __construct($contextid) {
|
||||
$this->contextid = $contextid;
|
||||
$this->filename = required_param('filename', PARAM_FILE);
|
||||
$this->filename = optional_param('filename', null, PARAM_FILE);
|
||||
if ($this->filename === null) {
|
||||
// Identify file object by its pathname hash.
|
||||
$this->pathnamehash = required_param('pathnamehash', PARAM_ALPHANUM);
|
||||
|
||||
// The file content hash is also passed for security; users
|
||||
// cannot guess the content hash (unless they know the file contents),
|
||||
// so this guarantees that either the system generated this link or
|
||||
// else the user has access to the restore archive anyhow.
|
||||
$this->contenthash = required_param('contenthash', PARAM_ALPHANUM);
|
||||
}
|
||||
}
|
||||
|
||||
public function process() {
|
||||
global $CFG;
|
||||
if (!file_exists("$CFG->tempdir/backup/".$this->filename)) {
|
||||
throw new restore_ui_exception('invalidrestorefile');
|
||||
}
|
||||
$outcome = $this->extract_file_to_dir();
|
||||
if ($outcome) {
|
||||
fulldelete($this->filename);
|
||||
if ($this->filename) {
|
||||
$archivepath = $CFG->tempdir . '/backup/' . $this->filename;
|
||||
if (!file_exists($archivepath)) {
|
||||
throw new restore_ui_exception('invalidrestorefile');
|
||||
}
|
||||
$outcome = $this->extract_file_to_dir($archivepath);
|
||||
if ($outcome) {
|
||||
fulldelete($archivepath);
|
||||
}
|
||||
} else {
|
||||
$fs = get_file_storage();
|
||||
$storedfile = $fs->get_file_by_hash($this->pathnamehash);
|
||||
if (!$storedfile || $storedfile->get_contenthash() !== $this->contenthash) {
|
||||
throw new restore_ui_exception('invalidrestorefile');
|
||||
}
|
||||
$outcome = $this->extract_file_to_dir($storedfile);
|
||||
}
|
||||
return $outcome;
|
||||
}
|
||||
protected function extract_file_to_dir() {
|
||||
|
||||
/**
|
||||
* Extracts the file.
|
||||
*
|
||||
* @param string|stored_file $source Archive file to extract
|
||||
*/
|
||||
protected function extract_file_to_dir($source) {
|
||||
global $CFG, $USER;
|
||||
|
||||
$this->filepath = restore_controller::get_tempdir_name($this->contextid, $USER->id);
|
||||
|
||||
$fb = get_file_packer('application/vnd.moodle.backup');
|
||||
$result = $fb->extract_to_pathname("$CFG->tempdir/backup/".$this->filename,
|
||||
"$CFG->tempdir/backup/$this->filepath/", null, $this);
|
||||
$result = $fb->extract_to_pathname($source,
|
||||
$CFG->tempdir . '/backup/' . $this->filepath . '/', null, $this);
|
||||
|
||||
// If any progress happened, end it.
|
||||
if ($this->startedprogress) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user