Full restore: say to run occ upgrade before rerunning a restore that stopped after the database; remove empty spool folders of a stopped restore
This commit is contained in:
@@ -17,6 +17,9 @@ instead carried by the app description, the git tag, the release, and this file.
|
|||||||
cannot be read this way is read as before. Restores from other locations work as before.
|
cannot be read this way is read as before. Restores from other locations work as before.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- After a full restore stopped halfway, running it again with `--force` was refused when the
|
||||||
|
database was already restored: Nextcloud then first wants `occ upgrade`. The guide and the
|
||||||
|
error message now say so.
|
||||||
- A full restore of a backup made before 1.0.0-rc.2 with `--skip-missing-tables` failed on
|
- A full restore of a backup made before 1.0.0-rc.2 with `--skip-missing-tables` failed on
|
||||||
PostgreSQL with "relation ... does not exist": the left-out tables were still looked up to set
|
PostgreSQL with "relation ... does not exist": the left-out tables were still looked up to set
|
||||||
their ID counters. It now skips them. A new test restores a backup made by 1.0.0-rc.1 on
|
their ID counters. It now skips them. A new test restores a backup made by 1.0.0-rc.1 on
|
||||||
|
|||||||
@@ -95,6 +95,8 @@ out with `--skip-missing-tables`.
|
|||||||
|
|
||||||
**8. Let the restore run.** It restores the database, then the data directory, and takes hours for
|
**8. Let the restore run.** It restores the database, then the data directory, and takes hours for
|
||||||
a large backup. If it stops halfway, fix the cause and run the same command again with `--force`.
|
a large backup. If it stops halfway, fix the cause and run the same command again with `--force`.
|
||||||
|
If occ then says that Nextcloud or one of the apps requires an upgrade, the database is already
|
||||||
|
the old server's: run `occ upgrade` first, then the same command with `--force`.
|
||||||
|
|
||||||
**9. After the restore.** These worked in our tests:
|
**9. After the restore.** These worked in our tests:
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ HELP);
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$output->writeln('<error>' . $e->getMessage() . '</error>');
|
$output->writeln('<error>' . $e->getMessage() . '</error>');
|
||||||
$output->writeln('If this happened after the restore had started, the instance may be partly restored: fix the cause and run the same command again with --force.');
|
$output->writeln('If this happened after the restore had started, the instance may be partly restored: fix the cause and run the same command again with --force.');
|
||||||
|
$output->writeln('If occ then says that Nextcloud needs an upgrade (the database is already the old server\'s), run occ upgrade first.');
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
$output->writeln(sprintf(
|
$output->writeln(sprintf(
|
||||||
|
|||||||
@@ -237,6 +237,11 @@ final class Repository {
|
|||||||
if (!$this->backend instanceof IReadsAhead || !$this->backend->canReadAhead()) {
|
if (!$this->backend instanceof IReadsAhead || !$this->backend->canReadAhead()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// what a restore that was stopped left behind: empty, its files were unlinked when opened
|
||||||
|
$stale = glob(rtrim($target, '/') . '/.ngb-restore-spool-*', GLOB_ONLYDIR);
|
||||||
|
foreach ($stale === false ? [] : $stale as $dir) {
|
||||||
|
@rmdir($dir);
|
||||||
|
}
|
||||||
$plan = new ReadAheadPlan(rtrim($target, '/') . '/.ngb-restore-spool-' . bin2hex(random_bytes(4)));
|
$plan = new ReadAheadPlan(rtrim($target, '/') . '/.ngb-restore-spool-' . bin2hex(random_bytes(4)));
|
||||||
foreach ($this->streamEntries($snapshotId) as $entry) {
|
foreach ($this->streamEntries($snapshotId) as $entry) {
|
||||||
if ($prefix !== '' && !str_starts_with($entry['p'], $prefix)) {
|
if ($prefix !== '' && !str_starts_with($entry['p'], $prefix)) {
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ class ReadAheadTest extends TestCase {
|
|||||||
$this->snapshot = $repo->backupDirectory($this->src)['snapshot'];
|
$this->snapshot = $repo->backupDirectory($this->src)['snapshot'];
|
||||||
}
|
}
|
||||||
|
|
||||||
private function restore(ReadAheadBackend $backend, string $prefix = ''): string {
|
private function restore(ReadAheadBackend $backend, string $prefix = '', ?string $target = null): string {
|
||||||
$target = $this->tempDir();
|
$target ??= $this->tempDir();
|
||||||
$repo = Repository::openWithKey($backend, $this->keys, null, null);
|
$repo = Repository::openWithKey($backend, $this->keys, null, null);
|
||||||
$repo->restore($this->snapshot, $target, $prefix);
|
$repo->restore($this->snapshot, $target, $prefix);
|
||||||
return $target;
|
return $target;
|
||||||
@@ -66,6 +66,13 @@ class ReadAheadTest extends TestCase {
|
|||||||
$this->assertLessThanOrEqual(count($backend->inner->list('packs')) + 1, count($backend->asked));
|
$this->assertLessThanOrEqual(count($backend->inner->list('packs')) + 1, count($backend->asked));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testTheEmptySpoolOfAStoppedRestoreIsRemoved(): void {
|
||||||
|
$target = $this->tempDir();
|
||||||
|
mkdir("$target/.ngb-restore-spool-0badc0de", 0700); // a restore that was killed
|
||||||
|
|
||||||
|
$this->assertRestored($this->restore(new ReadAheadBackend(new LocalBackend($this->root)), '', $target));
|
||||||
|
}
|
||||||
|
|
||||||
public function testARangeThatCouldNotBeReadAheadIsReadTheUsualWay(): void {
|
public function testARangeThatCouldNotBeReadAheadIsReadTheUsualWay(): void {
|
||||||
$backend = new ReadAheadBackend(new LocalBackend($this->root), fail: [1]);
|
$backend = new ReadAheadBackend(new LocalBackend($this->root), fail: [1]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user