Skip to content

Commit

Permalink
restart an 'inprogress' unpack/pack
Browse files Browse the repository at this point in the history
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
  • Loading branch information
ArtificialOwl committed Oct 23, 2021
1 parent ac103e4 commit 69045b8
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 51 deletions.
1 change: 1 addition & 0 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<command>OCA\Backup\Command\PointRestore</command>
<command>OCA\Backup\Command\PointScan</command>
<command>OCA\Backup\Command\PointUnarchive</command>
<command>OCA\Backup\Command\PointUnlock</command>
<command>OCA\Backup\Command\PointUnpack</command>
<command>OCA\Backup\Command\PointUpload</command>

Expand Down
9 changes: 5 additions & 4 deletions lib/Command/PointDetails.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,23 +191,23 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}

$table = new Table($output);
$table->setHeaders(['Chunk Id', 'Size', 'Count', 'Part Id', 'Checksum', 'Algorithm', 'verified']);
$table->setHeaders(['Chunk Id', 'Size', 'Count', 'Part Id', 'Checksum', 'Algorithm', '']);
$table->render();

foreach ($data->getChunks() as $chunk) {
if ($point->isStatus(RestoringPoint::STATUS_PACKED)) {
if ($chunk->hasParts()) {
$this->displayDetailsPacked($table, $point, $chunk);

continue;
}

try {
$checked = $this->chunkService->getChecksum($point, $chunk);
} catch (ArchiveNotFoundException $e) {
$checked = '<error>missing chunk</error>';
}

$color = ($checked === $chunk->getChecksum()) ? 'info' : 'error';
$checked = '<' . $color . '>' . $checked . '</' . $color . '>';
$checked = '<' . $color . '>ok</' . $color . '>';

$table->appendRow(
[
Expand All @@ -216,6 +216,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$chunk->getCount(),
'not packed',
$chunk->getChecksum(),
'',
$checked
]
);
Expand Down
99 changes: 99 additions & 0 deletions lib/Command/PointUnlock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

declare(strict_types=1);


/**
* Nextcloud - Backup now. Restore later.
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@artificial-owl.com>
* @copyright 2021, Maxence Lange <maxence@artificial-owl.com>
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/


namespace OCA\Backup\Command;

use OC\Core\Command\Base;
use OCA\Backup\Exceptions\RestoringPointNotFoundException;
use OCA\Backup\Service\MetadataService;
use OCA\Backup\Service\PointService;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* Class PointUnlock
*
* @package OCA\Backup\Command
*/
class PointUnlock extends Base {


/** @var MetadataService */
private $metadataService;

/** @var PointService */
private $pointService;


/**
* PointUnlock constructor.
*
* @param PointService $pointService
* @param MetadataService $metadataService
*/
public function __construct(
PointService $pointService,
MetadataService $metadataService
) {
parent::__construct();

$this->pointService = $pointService;
$this->metadataService = $metadataService;
}


/**
*
*/
protected function configure() {
parent::configure();

$this->setName('backup:point:unlock')
->setDescription('Unlock a restoring point')
->addArgument('pointId', InputArgument::REQUIRED, 'id of the restoring point to unlock');
}


/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
* @throws RestoringPointNotFoundException
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
$point = $this->pointService->getLocalRestoringPoint($input->getArgument('pointId'));
$this->metadataService->unlock($point);

return 0;
}
}
8 changes: 8 additions & 0 deletions lib/Model/RestoringChunk.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@ public function setParts(array $parts): self {
return $this;
}

/**
* @return bool
*/
public function hasParts(): bool {
return !empty($this->parts);
}


/**
* @param RestoringChunkPart $part
*
Expand Down
23 changes: 20 additions & 3 deletions lib/Model/RestoringHealth.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,12 @@ public function getParts(): array {
* @return $this
*/
public function addPart(ChunkPartHealth $part): self {
$this->parts[$part->getChunkName() . '-' . $part->getPartName()] = $part;
$k = $this->generateName($part->getChunkName(), $part->getPartName());
$this->parts[$k] = $part;

return $this;
}


/**
* @param string $chunkName
* @param string $partName
Expand All @@ -155,14 +155,31 @@ public function addPart(ChunkPartHealth $part): self {
* @throws RestoringChunkPartNotFoundException
*/
public function getPart(string $chunkName, string $partName): ChunkPartHealth {
if (!array_key_exists($chunkName . '-' . $partName, $this->parts)) {
$k = $this->generateName($chunkName, $partName);
if (!array_key_exists($k, $this->parts)) {
throw new RestoringChunkPartNotFoundException();
}

return $this->parts[$chunkName . '-' . $partName];
}


/**
* @param string $chunkName
* @param string $partName
*
* @return string
*/
private function generateName(string $chunkName, string $partName = ''): string {
$k = $chunkName;
if ($partName !== '') {
$k .= '-' . $partName;
}

return $k;
}


/**
* @param array $data
*
Expand Down
1 change: 1 addition & 0 deletions lib/Model/RestoringPoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class RestoringPoint implements IDeserializable, INC23QueryRow, ISignedModel, Js
self::STATUS_PACKED => 'packed',
self::STATUS_COMPRESSED => 'compressed',
self::STATUS_ENCRYPTED => 'encrypted',
self::STATUS_PACKING => 'in process'
];

public const STATUS_ISSUE = 32;
Expand Down
87 changes: 50 additions & 37 deletions lib/Service/PackService.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,26 +148,35 @@ public function packPoint(RestoringPoint $point, bool $force = false): void {
$point->addStatus(RestoringPoint::STATUS_PACKING);
$this->metadataService->updateStatus($point);

$oldChunks = [];
foreach ($point->getRestoringData() as $data) {
foreach ($data->getChunks() as $chunk) {
if ($chunk->hasParts()) {
continue;
}

try {
$oldChunk = null;
if ($data->getType() === RestoringData::INTERNAL_DATA) {
$chunkPart = new RestoringChunkPart($chunk->getFilename());
$chunkPart->setChecksum($this->chunkService->getChecksum($point, $chunk));
$chunk->addPart($chunkPart);
} else {
$oldChunks[] = clone $chunk;
$oldChunk = clone $chunk;
$this->packChunk($point, $chunk);
}

$this->pointRequest->update($point, true);
$this->metadataService->saveMetadata($point);
if (!is_null($oldChunk)) {
$this->chunkService->removeChunkFile($point, $oldChunk);
}
} catch (Throwable $t) {
$point->setStatus(RestoringPoint::STATUS_ISSUE)
->getNotes()
->s('pack_error', $t->getMessage())
->sInt('pack_date', time());

$this->pointRequest->update($point);
// $this->pointRequest->update($point);
$this->metadataService->unlock($point);
throw new RestoringPointPackException(
'issue on chunk ' . $chunk->getName() . ' - ' . $t->getMessage()
Expand All @@ -178,14 +187,13 @@ public function packPoint(RestoringPoint $point, bool $force = false): void {
}
}

$this->removeOldChunkFiles($point, $oldChunks);
// $this->removeOldChunkFiles($point, $oldChunks);

$point
->removeStatus(RestoringPoint::STATUS_PACKING)
->addStatus(RestoringPoint::STATUS_PACKED)
->getNotes()
->u('pack_error')
->u('pack_date');
$point->removeStatus(RestoringPoint::STATUS_PACKING)
->addStatus(RestoringPoint::STATUS_PACKED)
->getNotes()
->u('pack_error')
->u('pack_date');

try {
$this->remoteStreamService->signPoint($point);
Expand Down Expand Up @@ -594,37 +602,43 @@ public function unpackPoint(RestoringPoint $point): void {
$this->metadataService->isLock($point);
$this->metadataService->lock($point);

$oldChunks = [];
$point->addStatus(RestoringPoint::STATUS_PACKING);
$this->metadataService->updateStatus($point);

$completed = true;
foreach ($point->getRestoringData() as $data) {
if ($data->getType() === RestoringData::INTERNAL_DATA) {
continue;
}

foreach ($data->getChunks() as $chunk) {
$oldChunks[] = clone $chunk;
try {
$oldChunk = clone $chunk;
$this->unpackChunk($point, $chunk);
} catch (Throwable $t) {
$this->metadataService->unlock($point);

throw $t;
$this->pointRequest->update($point, true);
$this->metadataService->saveMetadata($point);
try {
$this->removeOldChunkPartFiles($point, $oldChunk);
} catch (RestoringPointNotInitiatedException | NotPermittedException $e) {
}
} catch (Throwable $t) {
$completed = false;
}
}
}

try {
$this->removeOldChunkPartFiles($point, $oldChunks);
} catch (RestoringPointNotInitiatedException | NotPermittedException $e) {
}

$point->setStatus(RestoringPoint::STATUS_UNPACKED)
->unsetNotes();
if ($completed) {
$point->setStatus(RestoringPoint::STATUS_UNPACKED)
->removeStatus(RestoringPoint::STATUS_PACKING)
->unsetNotes();

try {
$this->remoteStreamService->signPoint($point);
$this->pointRequest->update($point, true);
$this->metadataService->saveMetadata($point);
} catch (SignatoryException | NotFoundException | NotPermittedException $e) {
try {
$this->remoteStreamService->signPoint($point);
$this->pointRequest->update($point, true);
$this->metadataService->saveMetadata($point);
} catch (SignatoryException | NotFoundException | NotPermittedException $e) {
}
}

$this->metadataService->unlock($point);
Expand Down Expand Up @@ -938,21 +952,20 @@ private function recreateChunk(RestoringPoint $point, RestoringChunk $chunk, str

/**
* @param RestoringPoint $point
* @param RestoringChunk[] $chunks
* @param RestoringChunk $chunk
*
* @throws NotPermittedException
* @throws RestoringPointNotInitiatedException
*/
private function removeOldChunkPartFiles(RestoringPoint $point, array $chunks): void {
foreach ($chunks as $chunk) {
$folder = $this->getPackFolder($point, $chunk);
foreach ($chunk->getParts() as $part) {
try {
$file = $folder->getFile($part->getName());
$file->delete();
} catch (Exception $e) {
}
private function removeOldChunkPartFiles(RestoringPoint $point, RestoringChunk $chunk): void {
$folder = $this->getPackFolder($point, $chunk);
foreach ($chunk->getParts() as $part) {
try {
$file = $folder->getFile($part->getName());
$file->delete();
} catch (Exception $e) {
}

}
}

Expand Down

0 comments on commit 69045b8

Please sign in to comment.