Passed
Push — master ( 4a4262...32927f )
by Roeland
24:24 queued 11:41
created

DeleteOrphanedFiles::cleanupOrphanedMounts()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 21
c 1
b 0
f 0
nc 3
nop 0
dl 0
loc 28
rs 9.584
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Christoph Wurst <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Morris Jobke <[email protected]>
8
 *
9
 * @license AGPL-3.0
10
 *
11
 * This code is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License, version 3,
13
 * as published by the Free Software Foundation.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU Affero General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Affero General Public License, version 3,
21
 * along with this program. If not, see <http://www.gnu.org/licenses/>
22
 *
23
 */
24
25
namespace OCA\Files\Command;
26
27
use OCP\IDBConnection;
28
use Symfony\Component\Console\Command\Command;
29
use Symfony\Component\Console\Input\InputInterface;
30
use Symfony\Component\Console\Output\OutputInterface;
31
32
/**
33
 * Delete all file entries that have no matching entries in the storage table.
34
 */
35
class DeleteOrphanedFiles extends Command {
36
	public const CHUNK_SIZE = 200;
37
38
	/**
39
	 * @var IDBConnection
40
	 */
41
	protected $connection;
42
43
	public function __construct(IDBConnection $connection) {
44
		$this->connection = $connection;
45
		parent::__construct();
46
	}
47
48
	protected function configure() {
49
		$this
50
			->setName('files:cleanup')
51
			->setDescription('cleanup filecache');
52
	}
53
54
	public function execute(InputInterface $input, OutputInterface $output): int {
55
		$deletedEntries = 0;
56
57
		$query = $this->connection->getQueryBuilder();
58
		$query->select('fc.fileid')
59
			->from('filecache', 'fc')
60
			->where($query->expr()->isNull('s.numeric_id'))
61
			->leftJoin('fc', 'storages', 's', $query->expr()->eq('fc.storage', 's.numeric_id'))
62
			->setMaxResults(self::CHUNK_SIZE);
63
64
		$deleteQuery = $this->connection->getQueryBuilder();
65
		$deleteQuery->delete('filecache')
66
			->where($deleteQuery->expr()->eq('fileid', $deleteQuery->createParameter('objectid')));
67
68
		$deletedInLastChunk = self::CHUNK_SIZE;
69
		while ($deletedInLastChunk === self::CHUNK_SIZE) {
70
			$deletedInLastChunk = 0;
71
			$result = $query->execute();
72
			while ($row = $result->fetch()) {
73
				$deletedInLastChunk++;
74
				$deletedEntries += $deleteQuery->setParameter('objectid', (int) $row['fileid'])
75
					->execute();
76
			}
77
			$result->closeCursor();
78
		}
79
80
		$output->writeln("$deletedEntries orphaned file cache entries deleted");
81
82
		$deletedMounts = $this->cleanupOrphanedMounts();
83
		$output->writeln("$deletedMounts orphaned mount entries deleted");
84
		return 0;
85
	}
86
87
	private function cleanupOrphanedMounts() {
88
		$deletedEntries = 0;
89
90
		$query = $this->connection->getQueryBuilder();
91
		$query->select('m.storage_id')
92
			->from('mounts', 'm')
93
			->where($query->expr()->isNull('s.numeric_id'))
94
			->leftJoin('m', 'storages', 's', $query->expr()->eq('m.storage_id', 's.numeric_id'))
95
			->groupBy('storage_id')
96
			->setMaxResults(self::CHUNK_SIZE);
97
98
		$deleteQuery = $this->connection->getQueryBuilder();
99
		$deleteQuery->delete('mounts')
100
			->where($deleteQuery->expr()->eq('storage_id', $deleteQuery->createParameter('storageid')));
101
102
		$deletedInLastChunk = self::CHUNK_SIZE;
103
		while ($deletedInLastChunk === self::CHUNK_SIZE) {
104
			$deletedInLastChunk = 0;
105
			$result = $query->execute();
106
			while ($row = $result->fetch()) {
107
				$deletedInLastChunk++;
108
				$deletedEntries += $deleteQuery->setParameter('storageid', (int) $row['storage_id'])
109
					->execute();
110
			}
111
			$result->closeCursor();
112
		}
113
114
		return $deletedEntries;
115
	}
116
}
117