diff options
author | Lukas Reschke <lukas@statuscode.ch> | 2016-12-13 14:19:56 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-13 14:19:56 +0100 |
commit | ed7b18799f7d57ab9346e224b4dcea0961c9537f (patch) | |
tree | 58c26752ca7d74c3833beb2e7a83d041b1adf3f9 | |
parent | edd01e3ce4809e040c4a75432c531be6a80022d2 (diff) | |
parent | 69575f099cad658e3ff41b0ff064614035ac2c02 (diff) | |
download | nextcloud-server-ed7b18799f7d57ab9346e224b4dcea0961c9537f.tar.gz nextcloud-server-ed7b18799f7d57ab9346e224b4dcea0961c9537f.zip |
Merge pull request #2636 from nextcloud/add-repair-step-to-fix-mountsv11.0.0
Add a repair step to fix broken mounts
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | lib/private/Repair.php | 2 | ||||
-rw-r--r-- | lib/private/Repair/NC11/FixMountStorages.php | 78 | ||||
-rw-r--r-- | tests/lib/Repair/NC11/FixMountStoragesTest.php | 132 |
5 files changed, 214 insertions, 0 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 4f0a058e4e5..19f995e3b6f 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -680,6 +680,7 @@ return array( 'OC\\Repair\\MoveUpdaterStepFile' => $baseDir . '/lib/private/Repair/MoveUpdaterStepFile.php', 'OC\\Repair\\NC11\\CleanPreviews' => $baseDir . '/lib/private/Repair/NC11/CleanPreviews.php', 'OC\\Repair\\NC11\\CleanPreviewsBackgroundJob' => $baseDir . '/lib/private/Repair/NC11/CleanPreviewsBackgroundJob.php', + 'OC\\Repair\\NC11\\FixMountStorages' => $baseDir . '/lib/private/Repair/NC11/FixMountStorages.php', 'OC\\Repair\\NC11\\MoveAvatars' => $baseDir . '/lib/private/Repair/NC11/MoveAvatars.php', 'OC\\Repair\\NC11\\MoveAvatarsBackgroundJob' => $baseDir . '/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php', 'OC\\Repair\\OldGroupMembershipShares' => $baseDir . '/lib/private/Repair/OldGroupMembershipShares.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 2ab2da2ea57..d5fe21da19f 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -710,6 +710,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Repair\\MoveUpdaterStepFile' => __DIR__ . '/../../..' . '/lib/private/Repair/MoveUpdaterStepFile.php', 'OC\\Repair\\NC11\\CleanPreviews' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/CleanPreviews.php', 'OC\\Repair\\NC11\\CleanPreviewsBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/CleanPreviewsBackgroundJob.php', + 'OC\\Repair\\NC11\\FixMountStorages' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/FixMountStorages.php', 'OC\\Repair\\NC11\\MoveAvatars' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatars.php', 'OC\\Repair\\NC11\\MoveAvatarsBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php', 'OC\\Repair\\OldGroupMembershipShares' => __DIR__ . '/../../..' . '/lib/private/Repair/OldGroupMembershipShares.php', diff --git a/lib/private/Repair.php b/lib/private/Repair.php index c212ea90744..16236fd6bcc 100644 --- a/lib/private/Repair.php +++ b/lib/private/Repair.php @@ -37,6 +37,7 @@ use OC\Repair\Collation; use OC\Repair\DropOldJobs; use OC\Repair\MoveUpdaterStepFile; use OC\Repair\NC11\CleanPreviews; +use OC\Repair\NC11\FixMountStorages; use OC\Repair\NC11\MoveAvatars; use OC\Repair\OldGroupMembershipShares; use OC\Repair\RemoveGetETagEntries; @@ -161,6 +162,7 @@ class Repair implements IOutput{ \OC::$server->getUserManager(), \OC::$server->getConfig() ), + new FixMountStorages(\OC::$server->getDatabaseConnection()), ]; } diff --git a/lib/private/Repair/NC11/FixMountStorages.php b/lib/private/Repair/NC11/FixMountStorages.php new file mode 100644 index 00000000000..d57a356dff9 --- /dev/null +++ b/lib/private/Repair/NC11/FixMountStorages.php @@ -0,0 +1,78 @@ +<?php +/** + * @copyright 2016 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.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 OC\Repair\NC11; + +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class FixMountStorages implements IRepairStep { + + /** @var IDBConnection */ + private $db; + + /** + * @param IDBConnection $db + */ + public function __construct(IDBConnection $db) { + $this->db = $db; + } + + /** + * @return string + */ + public function getName() { + return 'Fix potential broken mount points'; + } + + public function run(IOutput $output) { + $query = $this->db->getQueryBuilder(); + $query->select('m.id', 'f.storage') + ->from('mounts', 'm') + ->leftJoin('m', 'filecache', 'f', $query->expr()->eq('m.root_id', 'f.fileid')) + ->where($query->expr()->neq('m.storage_id', 'f.storage')); + + $update = $this->db->getQueryBuilder(); + $update->update('mounts') + ->set('storage_id', $update->createParameter('storage')) + ->where($query->expr()->eq('id', $update->createParameter('mount'))); + + $result = $query->execute(); + $entriesUpdated = 0; + while ($row = $result->fetch()) { + $update->setParameter('storage', $row['storage'], IQueryBuilder::PARAM_INT) + ->setParameter('mount', $row['id'], IQueryBuilder::PARAM_INT); + $update->execute(); + $entriesUpdated++; + } + $result->closeCursor(); + + if ($entriesUpdated > 0) { + $output->info($entriesUpdated . ' mounts updated'); + return; + } + + $output->info('No mounts updated'); + } +} diff --git a/tests/lib/Repair/NC11/FixMountStoragesTest.php b/tests/lib/Repair/NC11/FixMountStoragesTest.php new file mode 100644 index 00000000000..12e09105038 --- /dev/null +++ b/tests/lib/Repair/NC11/FixMountStoragesTest.php @@ -0,0 +1,132 @@ +<?php +/** + * @copyright 2016 Joas Schilling <coding@schilljs.com> + * + * @author Joas Schilling <coding@schilljs.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 Test\Repair\NC11; + +use OC\Repair\NC11\FixMountStorages; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use Test\TestCase; + +/** + * Class FixMountStoragesTest + * + * @package Test\Repair\NC11 + * @group DB + */ +class FixMountStoragesTest extends TestCase { + + /** @var IDBConnection */ + private $db; + + /** @var FixMountStorages */ + private $repair; + + public function setUp() { + parent::setUp(); + + $this->db = \OC::$server->getDatabaseConnection(); + + $this->repair = new FixMountStorages( + $this->db + ); + } + + public function testGetName() { + $this->assertSame('Fix potential broken mount points', $this->repair->getName()); + } + + public function testRun() { + // Valid mount + $file1 = $this->createFile(42); + $mount1 = $this->createMount($file1, 42); + $this->assertStorage($mount1, 42); + + // Broken mount + $file2 = $this->createFile(23); + $mount2 = $this->createMount($file2, 1337); + $this->assertStorage($mount2, 1337); + + /** @var IOutput|\PHPUnit_Framework_MockObject_MockObject $output */ + $output = $this->createMock(IOutput::class); + $output->expects($this->at(0)) + ->method('info') + ->with('1 mounts updated'); + + $this->repair->run($output); + $this->assertStorage($mount1, 42); + $this->assertStorage($mount2, 23); + + $output->expects($this->at(0)) + ->method('info') + ->with('No mounts updated'); + + $this->repair->run($output); + $this->assertStorage($mount1, 42); + $this->assertStorage($mount2, 23); + } + + + protected function createFile($storage) { + $query = $this->db->getQueryBuilder(); + + $query->insert('filecache') + ->values([ + 'storage' => $query->createNamedParameter($storage, IQueryBuilder::PARAM_INT), + 'path_hash' => $query->createNamedParameter(static::getUniqueID(), IQueryBuilder::PARAM_STR), + 'encrypted' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT), + 'size' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT), + 'unencrypted_size' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT), + ]); + $query->execute(); + + return $query->getLastInsertId(); + } + + protected function createMount($fileId, $storage) { + $query = $this->db->getQueryBuilder(); + + $query->insert('mounts') + ->values([ + 'storage_id' => $query->createNamedParameter($storage, IQueryBuilder::PARAM_INT), + 'root_id' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT), + 'user_id' => $query->createNamedParameter(static::getUniqueID(), IQueryBuilder::PARAM_STR), + 'mount_point' => $query->createNamedParameter(static::getUniqueID(), IQueryBuilder::PARAM_STR), + ]); + $query->execute(); + + return $query->getLastInsertId(); + } + + protected function assertStorage($mount, $storage) { + $query = $this->db->getQueryBuilder(); + $query->select('storage_id') + ->from('mounts') + ->where($query->expr()->eq('id', $query->createNamedParameter($mount, IQueryBuilder::PARAM_INT))); + $result = $query->execute(); + $row = $result->fetch(); + $result->closeCursor(); + + $this->assertEquals($storage, $row['storage_id']); + } +} |