From 644a8ab797fb39847638048c887c2c358c962f62 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 22 Jan 2016 16:02:21 +0100 Subject: [PATCH 1/3] add IUserMountCache->getMountsForFileId --- lib/private/files/config/usermountcache.php | 58 +++++++++ lib/public/files/config/iusermountcache.php | 15 +++ tests/lib/files/config/usermountcache.php | 132 ++++++++++++++++++-- 3 files changed, 198 insertions(+), 7 deletions(-) diff --git a/lib/private/files/config/usermountcache.php b/lib/private/files/config/usermountcache.php index e3a494e93a..1d1589380d 100644 --- a/lib/private/files/config/usermountcache.php +++ b/lib/private/files/config/usermountcache.php @@ -22,9 +22,11 @@ namespace OC\Files\Config; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use OC\Files\Filesystem; use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IUserMountCache; use OCP\Files\Mount\IMountPoint; +use OCP\Files\NotFoundException; use OCP\ICache; use OCP\IDBConnection; use OCP\ILogger; @@ -53,6 +55,8 @@ class UserMountCache implements IUserMountCache { */ private $logger; + private $cacheInfoCache = []; + /** * UserMountCache constructor. * @@ -200,6 +204,60 @@ class UserMountCache implements IUserMountCache { return array_map([$this, 'dbRowToMountInfo'], $rows); } + /** + * @param $fileId + * @return array + * @throws \OCP\Files\NotFoundException + */ + private function getCacheInfoFromFileId($fileId) { + if (!isset($this->cacheInfoCache[$fileId])) { + $builder = $this->connection->getQueryBuilder(); + $query = $builder->select('storage', 'path') + ->from('filecache') + ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, \PDO::PARAM_INT))); + + $row = $query->execute()->fetch(); + if (is_array($row)) { + $this->cacheInfoCache[$fileId] = [ + (int)$row['storage'], + $row['path'] + ]; + } else { + throw new NotFoundException('File with id "' . $fileId . '" not found'); + } + } + return $this->cacheInfoCache[$fileId]; + } + + /** + * @param int $fileId + * @return ICachedMountInfo[] + * @since 9.0.0 + */ + public function getMountsForFileId($fileId) { + try { + list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId); + } catch (NotFoundException $e) { + return []; + } + $mountsForStorage = $this->getMountsForStorageId($storageId); + + // filter mounts that are from the same storage but a different directory + return array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) { + if ($fileId === $mount->getRootId()) { + return true; + } + try { + list(, $internalMountPath) = $this->getCacheInfoFromFileId($mount->getRootId()); + } catch (NotFoundException $e) { + return false; + } + + return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/'; + }); + + } + /** * Remove all cached mounts for a user * diff --git a/lib/public/files/config/iusermountcache.php b/lib/public/files/config/iusermountcache.php index f722ad1631..77f58cd867 100644 --- a/lib/public/files/config/iusermountcache.php +++ b/lib/public/files/config/iusermountcache.php @@ -40,6 +40,8 @@ interface IUserMountCache { public function registerMounts(IUser $user, array $mounts); /** + * Get all cached mounts for a user + * * @param IUser $user * @return ICachedMountInfo[] * @since 9.0.0 @@ -47,6 +49,8 @@ interface IUserMountCache { public function getMountsForUser(IUser $user); /** + * Get all cached mounts by storage + * * @param int $numericStorageId * @return ICachedMountInfo[] * @since 9.0.0 @@ -54,12 +58,23 @@ interface IUserMountCache { public function getMountsForStorageId($numericStorageId); /** + * Get all cached mounts by root + * * @param int $rootFileId * @return ICachedMountInfo[] * @since 9.0.0 */ public function getMountsForRootId($rootFileId); + /** + * Get all cached mounts that contain a file + * + * @param int $fileId + * @return ICachedMountInfo[] + * @since 9.0.0 + */ + public function getMountsForFileId($fileId); + /** * Remove all cached mounts for a user * diff --git a/tests/lib/files/config/usermountcache.php b/tests/lib/files/config/usermountcache.php index 26449b5dd2..0f5e8f4bae 100644 --- a/tests/lib/files/config/usermountcache.php +++ b/tests/lib/files/config/usermountcache.php @@ -8,8 +8,8 @@ namespace Test\Files\Config; +use OC\DB\QueryBuilder\Literal; use OC\Files\Mount\MountPoint; -use OC\Files\Storage\Temporary; use OC\Log; use OC\User\Manager; use OCP\Files\Config\ICachedMountInfo; @@ -37,7 +37,10 @@ class UserMountCache extends TestCase { */ private $cache; + private $fileIds = []; + public function setUp() { + $this->fileIds = []; $this->connection = \OC::$server->getDatabaseConnection(); $this->userManager = new Manager(null); $userBackend = new Dummy(); @@ -51,6 +54,14 @@ class UserMountCache extends TestCase { $builder = $this->connection->getQueryBuilder(); $builder->delete('mounts')->execute(); + + $builder = $this->connection->getQueryBuilder(); + + foreach ($this->fileIds as $fileId) { + $builder->delete('filecache') + ->where($builder->expr()->eq('fileid', new Literal($fileId))) + ->execute(); + } } private function getStorage($storageId, $rootId) { @@ -208,9 +219,7 @@ class UserMountCache extends TestCase { $this->clearCache(); $cachedMounts = $this->cache->getMountsForStorageId(3); - usort($cachedMounts, function (ICachedMountInfo $a, ICachedMountInfo $b) { - return strcmp($a->getUser()->getUID(), $b->getUser()->getUID()); - }); + $this->sortMounts($cachedMounts); $this->assertCount(2, $cachedMounts); @@ -238,9 +247,7 @@ class UserMountCache extends TestCase { $this->clearCache(); $cachedMounts = $this->cache->getMountsForRootId(4); - usort($cachedMounts, function (ICachedMountInfo $a, ICachedMountInfo $b) { - return strcmp($a->getUser()->getUID(), $b->getUser()->getUID()); - }); + $this->sortMounts($cachedMounts); $this->assertCount(2, $cachedMounts); @@ -254,4 +261,115 @@ class UserMountCache extends TestCase { $this->assertEquals(4, $cachedMounts[1]->getRootId()); $this->assertEquals(3, $cachedMounts[1]->getStorageId()); } + + private function sortMounts(&$mounts) { + usort($mounts, function (ICachedMountInfo $a, ICachedMountInfo $b) { + return strcmp($a->getUser()->getUID(), $b->getUser()->getUID()); + }); + } + + private function createCacheEntry($internalPath, $storageId) { + $this->connection->insertIfNotExist('*PREFIX*filecache', [ + 'storage' => $storageId, + 'path' => $internalPath, + 'path_hash' => md5($internalPath), + 'parent' => -1, + 'name' => basename($internalPath), + 'mimetype' => 0, + 'mimepart' => 0, + 'size' => 0, + 'storage_mtime' => 0, + 'encrypted' => false, + 'unencrypted_size' => 0, + 'etag' => '', + 'permissions' => 31 + ]); + $id = (int)$this->connection->lastInsertId('*PREFIX*filecache'); + $this->fileIds[] = $id; + return $id; + } + + public function testGetMountsForFileIdRootId() { + $user1 = $this->userManager->get('u1'); + + $rootId = $this->createCacheEntry('', 2); + + $mount1 = new MountPoint($this->getStorage(2, $rootId), '/foo/'); + + $this->cache->registerMounts($user1, [$mount1]); + + $this->clearCache(); + + $cachedMounts = $this->cache->getMountsForFileId($rootId); + + $this->assertCount(1, $cachedMounts); + + $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint()); + $this->assertEquals($user1, $cachedMounts[0]->getUser()); + $this->assertEquals($rootId, $cachedMounts[0]->getRootId()); + $this->assertEquals(2, $cachedMounts[0]->getStorageId()); + } + + public function testGetMountsForFileIdSubFolder() { + $user1 = $this->userManager->get('u1'); + + $rootId = $this->createCacheEntry('', 2); + $fileId = $this->createCacheEntry('/foo/bar', 2); + + $mount1 = new MountPoint($this->getStorage(2, $rootId), '/foo/'); + + $this->cache->registerMounts($user1, [$mount1]); + + $this->clearCache(); + + $cachedMounts = $this->cache->getMountsForFileId($fileId); + + $this->assertCount(1, $cachedMounts); + + $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint()); + $this->assertEquals($user1, $cachedMounts[0]->getUser()); + $this->assertEquals($rootId, $cachedMounts[0]->getRootId()); + $this->assertEquals(2, $cachedMounts[0]->getStorageId()); + } + + public function testGetMountsForFileIdSubFolderMount() { + $user1 = $this->userManager->get('u1'); + + $this->createCacheEntry('', 2); + $folderId = $this->createCacheEntry('/foo', 2); + $fileId = $this->createCacheEntry('/foo/bar', 2); + + $mount1 = new MountPoint($this->getStorage(2, $folderId), '/foo/'); + + $this->cache->registerMounts($user1, [$mount1]); + + $this->clearCache(); + + $cachedMounts = $this->cache->getMountsForFileId($fileId); + + $this->assertCount(1, $cachedMounts); + + $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint()); + $this->assertEquals($user1, $cachedMounts[0]->getUser()); + $this->assertEquals($folderId, $cachedMounts[0]->getRootId()); + $this->assertEquals(2, $cachedMounts[0]->getStorageId()); + } + + public function testGetMountsForFileIdSubFolderMountOutside() { + $user1 = $this->userManager->get('u1'); + + $this->createCacheEntry('', 2); + $folderId = $this->createCacheEntry('/foo', 2); + $fileId = $this->createCacheEntry('/bar/asd', 2); + + $mount1 = new MountPoint($this->getStorage(2, $folderId), '/foo/'); + + $this->cache->registerMounts($user1, [$mount1]); + + $this->clearCache(); + + $cachedMounts = $this->cache->getMountsForFileId($fileId); + + $this->assertCount(0, $cachedMounts); + } } From 0c7922cf7071b45c5eed782aa8e84416ea91a1ad Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 26 Jan 2016 14:50:57 +0100 Subject: [PATCH 2/3] Use new constants --- lib/private/files/config/usermountcache.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/private/files/config/usermountcache.php b/lib/private/files/config/usermountcache.php index 1d1589380d..7d7b03fbc0 100644 --- a/lib/private/files/config/usermountcache.php +++ b/lib/private/files/config/usermountcache.php @@ -23,6 +23,7 @@ namespace OC\Files\Config; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use OC\Files\Filesystem; +use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IUserMountCache; use OCP\Files\Mount\IMountPoint; @@ -137,7 +138,7 @@ class UserMountCache implements IUserMountCache { $query = $builder->update('mounts') ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint())) ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID()))) - ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), \PDO::PARAM_INT))); + ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT))); $query->execute(); } @@ -147,7 +148,7 @@ class UserMountCache implements IUserMountCache { $query = $builder->delete('mounts') ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID()))) - ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), \PDO::PARAM_INT))); + ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT))); $query->execute(); } @@ -182,7 +183,7 @@ class UserMountCache implements IUserMountCache { $builder = $this->connection->getQueryBuilder(); $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point') ->from('mounts') - ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, \PDO::PARAM_INT))); + ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT))); $rows = $query->execute()->fetchAll(); @@ -197,7 +198,7 @@ class UserMountCache implements IUserMountCache { $builder = $this->connection->getQueryBuilder(); $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point') ->from('mounts') - ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, \PDO::PARAM_INT))); + ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT))); $rows = $query->execute()->fetchAll(); @@ -214,7 +215,7 @@ class UserMountCache implements IUserMountCache { $builder = $this->connection->getQueryBuilder(); $query = $builder->select('storage', 'path') ->from('filecache') - ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, \PDO::PARAM_INT))); + ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); $row = $query->execute()->fetch(); if (is_array($row)) { @@ -276,7 +277,7 @@ class UserMountCache implements IUserMountCache { $query = $builder->delete('mounts') ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId))) - ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, \PDO::PARAM_INT))); + ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); $query->execute(); } @@ -284,7 +285,7 @@ class UserMountCache implements IUserMountCache { $builder = $this->connection->getQueryBuilder(); $query = $builder->delete('mounts') - ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, \PDO::PARAM_INT))); + ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); $query->execute(); } } From 2563c3ffafb225742c8bf559bbcf567e878d93df Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 26 Jan 2016 14:51:06 +0100 Subject: [PATCH 3/3] Fix failing oracle and postgres tests --- tests/lib/files/config/usermountcache.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/lib/files/config/usermountcache.php b/tests/lib/files/config/usermountcache.php index 0f5e8f4bae..070c2f6176 100644 --- a/tests/lib/files/config/usermountcache.php +++ b/tests/lib/files/config/usermountcache.php @@ -279,11 +279,11 @@ class UserMountCache extends TestCase { 'mimepart' => 0, 'size' => 0, 'storage_mtime' => 0, - 'encrypted' => false, + 'encrypted' => 0, 'unencrypted_size' => 0, 'etag' => '', 'permissions' => 31 - ]); + ], ['storage', 'path_hash']); $id = (int)$this->connection->lastInsertId('*PREFIX*filecache'); $this->fileIds[] = $id; return $id;