diff options
author | Robin Appelman <robin@icewind.nl> | 2016-09-18 18:36:53 +0200 |
---|---|---|
committer | Robin Appelman <robin@icewind.nl> | 2016-10-12 16:12:28 +0200 |
commit | 0d842e0550a15b7b6c501dae2ec24a61b72ef8c9 (patch) | |
tree | 06c880a305b73d603675b724ae73c944ad484225 /lib | |
parent | b2d68c00091f8bcba104cabfe0f7e2c78cc7a8d0 (diff) | |
download | nextcloud-server-0d842e0550a15b7b6c501dae2ec24a61b72ef8c9.tar.gz nextcloud-server-0d842e0550a15b7b6c501dae2ec24a61b72ef8c9.zip |
optimize Folder::getById to use less queries
Signed-off-by: Robin Appelman <robin@icewind.nl>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/Files/Config/CachedMountInfo.php | 18 | ||||
-rw-r--r-- | lib/private/Files/Config/LazyStorageMountInfo.php | 9 | ||||
-rw-r--r-- | lib/private/Files/Config/UserMountCache.php | 30 | ||||
-rw-r--r-- | lib/private/Files/Node/Folder.php | 59 | ||||
-rw-r--r-- | lib/private/Files/Node/Root.php | 14 | ||||
-rw-r--r-- | lib/private/Server.php | 4 | ||||
-rw-r--r-- | lib/public/Files/Config/ICachedMountInfo.php | 8 |
7 files changed, 102 insertions, 40 deletions
diff --git a/lib/private/Files/Config/CachedMountInfo.php b/lib/private/Files/Config/CachedMountInfo.php index 74812b3ed8c..c4132a34431 100644 --- a/lib/private/Files/Config/CachedMountInfo.php +++ b/lib/private/Files/Config/CachedMountInfo.php @@ -54,6 +54,11 @@ class CachedMountInfo implements ICachedMountInfo { protected $mountId; /** + * @var string + */ + protected $rootInternalPath; + + /** * CachedMountInfo constructor. * * @param IUser $user @@ -61,13 +66,15 @@ class CachedMountInfo implements ICachedMountInfo { * @param int $rootId * @param string $mountPoint * @param int|null $mountId + * @param string $rootInternalPath */ - public function __construct(IUser $user, $storageId, $rootId, $mountPoint, $mountId = null) { + public function __construct(IUser $user, $storageId, $rootId, $mountPoint, $mountId = null, $rootInternalPath = '') { $this->user = $user; $this->storageId = $storageId; $this->rootId = $rootId; $this->mountPoint = $mountPoint; $this->mountId = $mountId; + $this->rootInternalPath = $rootInternalPath; } /** @@ -122,4 +129,13 @@ class CachedMountInfo implements ICachedMountInfo { public function getMountId() { return $this->mountId; } + + /** + * Get the internal path (within the storage) of the root of the mount + * + * @return string + */ + public function getRootInternalPath() { + return $this->rootInternalPath; + } } diff --git a/lib/private/Files/Config/LazyStorageMountInfo.php b/lib/private/Files/Config/LazyStorageMountInfo.php index 4df813d57d0..40d463c5103 100644 --- a/lib/private/Files/Config/LazyStorageMountInfo.php +++ b/lib/private/Files/Config/LazyStorageMountInfo.php @@ -76,4 +76,13 @@ class LazyStorageMountInfo extends CachedMountInfo { public function getMountId() { return $this->mount->getMountId(); } + + /** + * Get the internal path (within the storage) of the root of the mount + * + * @return string + */ + public function getRootInternalPath() { + return $this->mount->getInternalPath($this->mount->getMountPoint()); + } } diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index bd8343fa440..e9e142d0d4b 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -31,6 +31,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IUserMountCache; use OCP\Files\Mount\IMountPoint; +use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\ICache; use OCP\IDBConnection; @@ -187,7 +188,7 @@ class UserMountCache implements IUserMountCache { private function dbRowToMountInfo(array $row) { $user = $this->userManager->get($row['user_id']); - return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id']); + return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $row['mount_id'], isset($row['path'])? $row['path']:''); } /** @@ -197,8 +198,9 @@ class UserMountCache implements IUserMountCache { public function getMountsForUser(IUser $user) { if (!isset($this->mountsForUsers[$user->getUID()])) { $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id') - ->from('mounts') + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') + ->from('mounts', 'm') + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID()))); $rows = $query->execute()->fetchAll(); @@ -214,8 +216,9 @@ class UserMountCache implements IUserMountCache { */ public function getMountsForStorageId($numericStorageId) { $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id') - ->from('mounts') + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') + ->from('mounts', 'm') + ->innerJoin('m', 'filecache', 'f' , $builder->expr()->eq('m.root_id', 'f.fileid')) ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT))); $rows = $query->execute()->fetchAll(); @@ -229,8 +232,9 @@ class UserMountCache implements IUserMountCache { */ public function getMountsForRootId($rootFileId) { $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id') - ->from('mounts') + $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path') + ->from('mounts', 'm') + ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid')) ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT))); $rows = $query->execute()->fetchAll(); @@ -246,7 +250,7 @@ class UserMountCache implements IUserMountCache { private function getCacheInfoFromFileId($fileId) { if (!isset($this->cacheInfoCache[$fileId])) { $builder = $this->connection->getQueryBuilder(); - $query = $builder->select('storage', 'path') + $query = $builder->select('storage', 'path', 'mimetype') ->from('filecache') ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); @@ -254,7 +258,8 @@ class UserMountCache implements IUserMountCache { if (is_array($row)) { $this->cacheInfoCache[$fileId] = [ (int)$row['storage'], - $row['path'] + $row['path'], + (int)$row['mimetype'] ]; } else { throw new NotFoundException('File with id "' . $fileId . '" not found'); @@ -281,15 +286,10 @@ class UserMountCache implements IUserMountCache { if ($fileId === $mount->getRootId()) { return true; } - try { - list(, $internalMountPath) = $this->getCacheInfoFromFileId($mount->getRootId()); - } catch (NotFoundException $e) { - return false; - } + $internalMountPath = $mount->getRootInternalPath(); return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/'; }); - } /** diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index e67e4817e2a..b12ded8e796 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -28,6 +28,7 @@ namespace OC\Files\Node; use OC\DB\QueryBuilder\Literal; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\Config\ICachedMountInfo; use OCP\Files\FileInfo; use OCP\Files\Mount\IMountPoint; use OCP\Files\NotFoundException; @@ -83,7 +84,7 @@ class Folder extends Node implements \OCP\Files\Folder { public function getDirectoryListing() { $folderContent = $this->view->getDirectoryContent($this->path); - return array_map(function(FileInfo $info) { + return array_map(function (FileInfo $info) { if ($info->getMimetype() === 'httpd/unix-directory') { return new Folder($this->root, $this->view, $info->getPath(), $info); } else { @@ -253,7 +254,7 @@ class Folder extends Node implements \OCP\Files\Folder { } } - return array_map(function(FileInfo $file) { + return array_map(function (FileInfo $file) { return $this->createNode($file->getPath(), $file); }, $files); } @@ -263,29 +264,45 @@ class Folder extends Node implements \OCP\Files\Folder { * @return \OC\Files\Node\Node[] */ public function getById($id) { + $mountCache = $this->root->getUserMountCache(); + $mountsContainingFile = $mountCache->getMountsForFileId($id); $mounts = $this->root->getMountsIn($this->path); $mounts[] = $this->root->getMount($this->path); - // reverse the array so we start with the storage this view is in - // which is the most likely to contain the file we're looking for - $mounts = array_reverse($mounts); + /** @var IMountPoint[] $folderMounts */ + $folderMounts = array_combine(array_map(function (IMountPoint $mountPoint) { + return $mountPoint->getMountPoint(); + }, $mounts), $mounts); + + /** @var ICachedMountInfo[] $mountsContainingFile */ + $mountsContainingFile = array_values(array_filter($mountsContainingFile, function (ICachedMountInfo $cachedMountInfo) use ($folderMounts) { + return isset($folderMounts[$cachedMountInfo->getMountPoint()]); + })); - $nodes = array(); - foreach ($mounts as $mount) { - /** - * @var \OC\Files\Mount\MountPoint $mount - */ - if ($mount->getStorage()) { - $cache = $mount->getStorage()->getCache(); - $internalPath = $cache->getPathById($id); - if (is_string($internalPath)) { - $fullPath = $mount->getMountPoint() . $internalPath; - if (!is_null($path = $this->getRelativePath($fullPath))) { - $nodes[] = $this->get($path); - } - } - } + if (count($mountsContainingFile) === 0) { + return []; } - return $nodes; + + // we only need to get the cache info once, since all mounts we found point to the same storage + + $mount = $folderMounts[$mountsContainingFile[0]->getMountPoint()]; + $cacheEntry = $mount->getStorage()->getCache()->get($id); + // cache jails will hide the "true" internal path + $internalPath = ltrim($mountsContainingFile[0]->getRootInternalPath() . '/' . $cacheEntry->getPath(), '/'); + + $nodes = array_map(function (ICachedMountInfo $cachedMountInfo) use ($cacheEntry, $folderMounts, $internalPath) { + $mount = $folderMounts[$cachedMountInfo->getMountPoint()]; + $pathRelativeToMount = substr($internalPath, strlen($cachedMountInfo->getRootInternalPath())); + $pathRelativeToMount = ltrim($pathRelativeToMount, '/'); + $absolutePath = $cachedMountInfo->getMountPoint() . $pathRelativeToMount; + return $this->root->createNode($absolutePath, new \OC\Files\FileInfo( + $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount, + \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount)) + )); + }, $mountsContainingFile); + + return array_filter($nodes, function (Node $node) { + return $this->getRelativePath($node->getPath()); + }); } public function getFreeSpace() { diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index 007847fb513..0cda2c8b822 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -31,6 +31,7 @@ namespace OC\Files\Node; use OC\Cache\CappedMemoryCache; use OC\Files\Mount\Manager; use OC\Files\Mount\MountPoint; +use OCP\Files\Config\IUserMountCache; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OC\Hooks\PublicEmitter; @@ -75,16 +76,23 @@ class Root extends Folder implements IRootFolder { private $userFolderCache; /** + * @var IUserMountCache + */ + private $userMountCache; + + /** * @param \OC\Files\Mount\Manager $manager * @param \OC\Files\View $view * @param \OC\User\User|null $user + * @param IUserMountCache $userMountCache */ - public function __construct($manager, $view, $user) { + public function __construct($manager, $view, $user, IUserMountCache $userMountCache) { parent::__construct($this, $view, ''); $this->mountManager = $manager; $this->user = $user; $this->emitter = new PublicEmitter(); $this->userFolderCache = new CappedMemoryCache(); + $this->userMountCache = $userMountCache; } /** @@ -361,4 +369,8 @@ class Root extends Folder implements IRootFolder { public function clearCache() { $this->userFolderCache = new CappedMemoryCache(); } + + public function getUserMountCache() { + return $this->userMountCache; + } } diff --git a/lib/private/Server.php b/lib/private/Server.php index b49e94b554e..291714b23d1 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -175,10 +175,10 @@ class Server extends ServerContainer implements IServerContainer { $this->registerService('SystemTagObjectMapper', function (Server $c) { return $c->query('SystemTagManagerFactory')->getObjectMapper(); }); - $this->registerService('RootFolder', function () { + $this->registerService('RootFolder', function (Server $c) { $manager = \OC\Files\Filesystem::getMountManager(null); $view = new View(); - $root = new Root($manager, $view, null); + $root = new Root($manager, $view, null, $c->getUserMountCache()); $connector = new HookConnector($root, $view); $connector->viewToNode(); return $root; diff --git a/lib/public/Files/Config/ICachedMountInfo.php b/lib/public/Files/Config/ICachedMountInfo.php index 2986f1d98c5..f5c5bb87ead 100644 --- a/lib/public/Files/Config/ICachedMountInfo.php +++ b/lib/public/Files/Config/ICachedMountInfo.php @@ -68,4 +68,12 @@ interface ICachedMountInfo { * @since 9.1.0 */ public function getMountId(); + + /** + * Get the internal path (within the storage) of the root of the mount + * + * @return string + * @since 9.2.0 + */ + public function getRootInternalPath(); } |