Merge pull request #26936 from nextcloud/external-storage-delete-clean
better cleanup of filecache when deleting an external storage
This commit is contained in:
commit
fa28782084
|
@ -479,44 +479,7 @@ abstract class StoragesService {
|
||||||
$this->triggerHooks($deletedStorage, Filesystem::signal_delete_mount);
|
$this->triggerHooks($deletedStorage, Filesystem::signal_delete_mount);
|
||||||
|
|
||||||
// delete oc_storages entries and oc_filecache
|
// delete oc_storages entries and oc_filecache
|
||||||
try {
|
\OC\Files\Cache\Storage::cleanByMountId($id);
|
||||||
$rustyStorageId = $this->getRustyStorageIdFromConfig($deletedStorage);
|
|
||||||
\OC\Files\Cache\Storage::remove($rustyStorageId);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
// can happen either for invalid configs where the storage could not
|
|
||||||
// be instantiated or whenever $user vars where used, in which case
|
|
||||||
// the storage id could not be computed
|
|
||||||
\OC::$server->getLogger()->logException($e, [
|
|
||||||
'level' => ILogger::ERROR,
|
|
||||||
'app' => 'files_external',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the rusty storage id from oc_storages from the given storage config.
|
|
||||||
*
|
|
||||||
* @param StorageConfig $storageConfig
|
|
||||||
* @return string rusty storage id
|
|
||||||
*/
|
|
||||||
private function getRustyStorageIdFromConfig(StorageConfig $storageConfig) {
|
|
||||||
// if any of the storage options contains $user, it is not possible
|
|
||||||
// to compute the possible storage id as we don't know which users
|
|
||||||
// mounted it already (and we certainly don't want to iterate over ALL users)
|
|
||||||
foreach ($storageConfig->getBackendOptions() as $value) {
|
|
||||||
if (strpos($value, '$user') !== false) {
|
|
||||||
throw new \Exception('Cannot compute storage id for deletion due to $user vars in the configuration');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: similar to ConfigAdapter->prepateStorageConfig()
|
|
||||||
$storageConfig->getAuthMechanism()->manipulateStorageConfig($storageConfig);
|
|
||||||
$storageConfig->getBackend()->manipulateStorageConfig($storageConfig);
|
|
||||||
|
|
||||||
$class = $storageConfig->getBackend()->getStorageClass();
|
|
||||||
$storageImpl = new $class($storageConfig->getBackendOptions());
|
|
||||||
|
|
||||||
return $storageImpl->getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -40,7 +40,11 @@ use OCA\Files_External\Service\BackendService;
|
||||||
use OCA\Files_External\Service\DBConfigService;
|
use OCA\Files_External\Service\DBConfigService;
|
||||||
use OCA\Files_External\Service\StoragesService;
|
use OCA\Files_External\Service\StoragesService;
|
||||||
use OCP\AppFramework\IAppContainer;
|
use OCP\AppFramework\IAppContainer;
|
||||||
|
use OCP\Files\Cache\ICache;
|
||||||
use OCP\Files\Config\IUserMountCache;
|
use OCP\Files\Config\IUserMountCache;
|
||||||
|
use OCP\Files\Mount\IMountPoint;
|
||||||
|
use OCP\Files\Storage\IStorage;
|
||||||
|
use OCP\IUser;
|
||||||
|
|
||||||
class CleaningDBConfig extends DBConfigService {
|
class CleaningDBConfig extends DBConfigService {
|
||||||
private $mountIds = [];
|
private $mountIds = [];
|
||||||
|
@ -279,10 +283,8 @@ abstract class StoragesServiceTest extends \Test\TestCase {
|
||||||
'password' => 'testPassword',
|
'password' => 'testPassword',
|
||||||
'root' => 'someroot',
|
'root' => 'someroot',
|
||||||
],
|
],
|
||||||
'webdav::test@example.com//someroot/',
|
'webdav::test@example.com//someroot/'
|
||||||
0
|
|
||||||
],
|
],
|
||||||
// special case with $user vars, cannot auto-remove the oc_storages entry
|
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
'host' => 'example.com',
|
'host' => 'example.com',
|
||||||
|
@ -290,8 +292,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
|
||||||
'password' => 'testPassword',
|
'password' => 'testPassword',
|
||||||
'root' => 'someroot',
|
'root' => 'someroot',
|
||||||
],
|
],
|
||||||
'webdav::someone@example.com//someroot/',
|
'webdav::someone@example.com//someroot/'
|
||||||
1
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -299,7 +300,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
|
||||||
/**
|
/**
|
||||||
* @dataProvider deleteStorageDataProvider
|
* @dataProvider deleteStorageDataProvider
|
||||||
*/
|
*/
|
||||||
public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion) {
|
public function testDeleteStorage($backendOptions, $rustyStorageId) {
|
||||||
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\DAV');
|
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\DAV');
|
||||||
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
|
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
|
||||||
$storage = new StorageConfig(255);
|
$storage = new StorageConfig(255);
|
||||||
|
@ -315,6 +316,31 @@ abstract class StoragesServiceTest extends \Test\TestCase {
|
||||||
// access, which isn't possible within this test
|
// access, which isn't possible within this test
|
||||||
$storageCache = new \OC\Files\Cache\Storage($rustyStorageId);
|
$storageCache = new \OC\Files\Cache\Storage($rustyStorageId);
|
||||||
|
|
||||||
|
/** @var IUserMountCache $mountCache */
|
||||||
|
$mountCache = \OC::$server->get(IUserMountCache::class);
|
||||||
|
$mountCache->clear();
|
||||||
|
$user = $this->createMock(IUser::class);
|
||||||
|
$user->method('getUID')->willReturn('test');
|
||||||
|
$cache = $this->createMock(ICache::class);
|
||||||
|
$storage = $this->createMock(IStorage::class);
|
||||||
|
$storage->method('getCache')->willReturn($cache);
|
||||||
|
$mount = $this->createMock(IMountPoint::class);
|
||||||
|
$mount->method('getStorage')
|
||||||
|
->willReturn($storage);
|
||||||
|
$mount->method('getStorageId')
|
||||||
|
->willReturn($rustyStorageId);
|
||||||
|
$mount->method('getNumericStorageId')
|
||||||
|
->willReturn($storageCache->getNumericId());
|
||||||
|
$mount->method('getStorageRootId')
|
||||||
|
->willReturn(1);
|
||||||
|
$mount->method('getMountPoint')
|
||||||
|
->willReturn('dummy');
|
||||||
|
$mount->method('getMountId')
|
||||||
|
->willReturn($id);
|
||||||
|
$mountCache->registerMounts($user, [
|
||||||
|
$mount
|
||||||
|
]);
|
||||||
|
|
||||||
// get numeric id for later check
|
// get numeric id for later check
|
||||||
$numericId = $storageCache->getNumericId();
|
$numericId = $storageCache->getNumericId();
|
||||||
|
|
||||||
|
@ -338,7 +364,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
|
||||||
$result = $storageCheckQuery->execute();
|
$result = $storageCheckQuery->execute();
|
||||||
$storages = $result->fetchAll();
|
$storages = $result->fetchAll();
|
||||||
$result->closeCursor();
|
$result->closeCursor();
|
||||||
$this->assertCount($expectedCountAfterDeletion, $storages, "expected $expectedCountAfterDeletion storages, got " . json_encode($storages));
|
$this->assertCount(0, $storages, "expected 0 storages, got " . json_encode($storages));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function actualDeletedUnexistingStorageTest() {
|
protected function actualDeletedUnexistingStorageTest() {
|
||||||
|
|
|
@ -204,7 +204,7 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
|
||||||
/**
|
/**
|
||||||
* @dataProvider deleteStorageDataProvider
|
* @dataProvider deleteStorageDataProvider
|
||||||
*/
|
*/
|
||||||
public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion) {
|
public function testDeleteStorage($backendOptions, $rustyStorageId) {
|
||||||
$this->expectException(\DomainException::class);
|
$this->expectException(\DomainException::class);
|
||||||
|
|
||||||
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
|
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');
|
||||||
|
|
|
@ -150,8 +150,8 @@ class UserStoragesServiceTest extends StoragesServiceTest {
|
||||||
/**
|
/**
|
||||||
* @dataProvider deleteStorageDataProvider
|
* @dataProvider deleteStorageDataProvider
|
||||||
*/
|
*/
|
||||||
public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion) {
|
public function testDeleteStorage($backendOptions, $rustyStorageId) {
|
||||||
parent::testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion);
|
parent::testDeleteStorage($backendOptions, $rustyStorageId);
|
||||||
|
|
||||||
// hook called once for user (first one was during test creation)
|
// hook called once for user (first one was during test creation)
|
||||||
$this->assertHookCall(
|
$this->assertHookCall(
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
namespace OC\Files\Cache;
|
namespace OC\Files\Cache;
|
||||||
|
|
||||||
|
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||||
use OCP\Files\Storage\IStorage;
|
use OCP\Files\Storage\IStorage;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
@ -219,4 +220,43 @@ class Storage {
|
||||||
$query->execute();
|
$query->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove the entry for the storage by the mount id
|
||||||
|
*
|
||||||
|
* @param int $mountId
|
||||||
|
*/
|
||||||
|
public static function cleanByMountId(int $mountId) {
|
||||||
|
$db = \OC::$server->getDatabaseConnection();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db->beginTransaction();
|
||||||
|
|
||||||
|
$query = $db->getQueryBuilder();
|
||||||
|
$query->select('storage_id')
|
||||||
|
->from('mounts')
|
||||||
|
->where($query->expr()->eq('mount_id', $query->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
|
||||||
|
$storageIds = $query->executeQuery()->fetchAll(\PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
$query = $db->getQueryBuilder();
|
||||||
|
$query->delete('filecache')
|
||||||
|
->where($query->expr()->in('storage', $query->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)));
|
||||||
|
$query->executeStatement();
|
||||||
|
|
||||||
|
$query = $db->getQueryBuilder();
|
||||||
|
$query->delete('storages')
|
||||||
|
->where($query->expr()->eq('numeric_id', $query->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)));
|
||||||
|
$query->executeStatement();
|
||||||
|
|
||||||
|
$query = $db->getQueryBuilder();
|
||||||
|
$query->delete('mounts')
|
||||||
|
->where($query->expr()->eq('mount_id', $query->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
|
||||||
|
$query->executeStatement();
|
||||||
|
|
||||||
|
$db->commit();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$db->rollBack();
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue