From 0d842e0550a15b7b6c501dae2ec24a61b72ef8c9 Mon Sep 17 00:00:00 2001
From: Robin Appelman <robin@icewind.nl>
Date: Sun, 18 Sep 2016 18:36:53 +0200
Subject: [PATCH] optimize Folder::getById to use less queries

Signed-off-by: Robin Appelman <robin@icewind.nl>
---
 lib/private/Files/Config/CachedMountInfo.php  |  18 ++-
 .../Files/Config/LazyStorageMountInfo.php     |   9 ++
 lib/private/Files/Config/UserMountCache.php   |  30 ++--
 lib/private/Files/Node/Folder.php             |  59 ++++---
 lib/private/Files/Node/Root.php               |  14 +-
 lib/private/Server.php                        |   4 +-
 lib/public/Files/Config/ICachedMountInfo.php  |   8 +
 tests/lib/Files/Config/UserMountCacheTest.php | 111 ++++++++-----
 tests/lib/Files/Node/FileTest.php             |  48 +++---
 tests/lib/Files/Node/FolderTest.php           | 153 ++++++++++++------
 tests/lib/Files/Node/HookConnectorTest.php    |   7 +-
 tests/lib/Files/Node/IntegrationTest.php      |   2 +-
 tests/lib/Files/Node/NodeTest.php             |   9 +-
 tests/lib/Files/Node/RootTest.php             |  13 +-
 14 files changed, 328 insertions(+), 157 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
@@ -53,6 +53,11 @@ class CachedMountInfo implements ICachedMountInfo {
 	 */
 	protected $mountId;
 
+	/**
+	 * @var string
+	 */
+	protected $rootInternalPath;
+
 	/**
 	 * CachedMountInfo constructor.
 	 *
@@ -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;
@@ -74,17 +75,24 @@ 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();
 }
diff --git a/tests/lib/Files/Config/UserMountCacheTest.php b/tests/lib/Files/Config/UserMountCacheTest.php
index 85bc4146a2d..51d488e6dee 100644
--- a/tests/lib/Files/Config/UserMountCacheTest.php
+++ b/tests/lib/Files/Config/UserMountCacheTest.php
@@ -64,7 +64,9 @@ class UserMountCacheTest extends TestCase {
 		}
 	}
 
-	private function getStorage($storageId, $rootId) {
+	private function getStorage($storageId) {
+		$rootId = $this->createCacheEntry('', $storageId);
+
 		$storageCache = $this->getMockBuilder('\OC\Files\Cache\Storage')
 			->disableOriginalConstructor()
 			->getMock();
@@ -89,7 +91,7 @@ class UserMountCacheTest extends TestCase {
 			->method('getCache')
 			->will($this->returnValue($cache));
 
-		return $storage;
+		return [$storage, $rootId];
 	}
 
 	private function clearCache() {
@@ -99,7 +101,7 @@ class UserMountCacheTest extends TestCase {
 	public function testNewMounts() {
 		$user = $this->userManager->get('u1');
 
-		$storage = $this->getStorage(10, 20);
+		list($storage) = $this->getStorage(10);
 		$mount = new MountPoint($storage, '/asd/');
 
 		$this->cache->registerMounts($user, [$mount]);
@@ -119,7 +121,7 @@ class UserMountCacheTest extends TestCase {
 	public function testSameMounts() {
 		$user = $this->userManager->get('u1');
 
-		$storage = $this->getStorage(10, 20);
+		list($storage) = $this->getStorage(10);
 		$mount = new MountPoint($storage, '/asd/');
 
 		$this->cache->registerMounts($user, [$mount]);
@@ -143,7 +145,7 @@ class UserMountCacheTest extends TestCase {
 	public function testRemoveMounts() {
 		$user = $this->userManager->get('u1');
 
-		$storage = $this->getStorage(10, 20);
+		list($storage) = $this->getStorage(10);
 		$mount = new MountPoint($storage, '/asd/');
 
 		$this->cache->registerMounts($user, [$mount]);
@@ -162,7 +164,7 @@ class UserMountCacheTest extends TestCase {
 	public function testChangeMounts() {
 		$user = $this->userManager->get('u1');
 
-		$storage = $this->getStorage(10, 20);
+		list($storage) = $this->getStorage(10);
 		$mount = new MountPoint($storage, '/bar/');
 
 		$this->cache->registerMounts($user, [$mount]);
@@ -185,7 +187,7 @@ class UserMountCacheTest extends TestCase {
 	public function testChangeMountId() {
 		$user = $this->userManager->get('u1');
 
-		$storage = $this->getStorage(10, 20);
+		list($storage) = $this->getStorage(10);
 		$mount = new MountPoint($storage, '/foo/', null, null, null, null);
 
 		$this->cache->registerMounts($user, [$mount]);
@@ -209,8 +211,10 @@ class UserMountCacheTest extends TestCase {
 		$user1 = $this->userManager->get('u1');
 		$user2 = $this->userManager->get('u2');
 
-		$mount1 = new MountPoint($this->getStorage(1, 2), '/foo/');
-		$mount2 = new MountPoint($this->getStorage(3, 4), '/bar/');
+		list($storage1, $id1) = $this->getStorage(1);
+		list($storage2, $id2) = $this->getStorage(2);
+		$mount1 = new MountPoint($storage1, '/foo/');
+		$mount2 = new MountPoint($storage2, '/bar/');
 
 		$this->cache->registerMounts($user1, [$mount1, $mount2]);
 		$this->cache->registerMounts($user2, [$mount2]);
@@ -222,69 +226,73 @@ class UserMountCacheTest extends TestCase {
 		$this->assertCount(2, $cachedMounts);
 		$this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
 		$this->assertEquals($user1, $cachedMounts[0]->getUser());
-		$this->assertEquals(2, $cachedMounts[0]->getRootId());
+		$this->assertEquals($id1, $cachedMounts[0]->getRootId());
 		$this->assertEquals(1, $cachedMounts[0]->getStorageId());
 
 		$this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
 		$this->assertEquals($user1, $cachedMounts[1]->getUser());
-		$this->assertEquals(4, $cachedMounts[1]->getRootId());
-		$this->assertEquals(3, $cachedMounts[1]->getStorageId());
+		$this->assertEquals($id2, $cachedMounts[1]->getRootId());
+		$this->assertEquals(2, $cachedMounts[1]->getStorageId());
 	}
 
 	public function testGetMountsByStorageId() {
 		$user1 = $this->userManager->get('u1');
 		$user2 = $this->userManager->get('u2');
 
-		$mount1 = new MountPoint($this->getStorage(1, 2), '/foo/');
-		$mount2 = new MountPoint($this->getStorage(3, 4), '/bar/');
+		list($storage1, $id1) = $this->getStorage(1);
+		list($storage2, $id2) = $this->getStorage(2);
+		$mount1 = new MountPoint($storage1, '/foo/');
+		$mount2 = new MountPoint($storage2, '/bar/');
 
 		$this->cache->registerMounts($user1, [$mount1, $mount2]);
 		$this->cache->registerMounts($user2, [$mount2]);
 
 		$this->clearCache();
 
-		$cachedMounts = $this->cache->getMountsForStorageId(3);
+		$cachedMounts = $this->cache->getMountsForStorageId(2);
 		$this->sortMounts($cachedMounts);
 
 		$this->assertCount(2, $cachedMounts);
 
 		$this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
 		$this->assertEquals($user1, $cachedMounts[0]->getUser());
-		$this->assertEquals(4, $cachedMounts[0]->getRootId());
-		$this->assertEquals(3, $cachedMounts[0]->getStorageId());
+		$this->assertEquals($id2, $cachedMounts[0]->getRootId());
+		$this->assertEquals(2, $cachedMounts[0]->getStorageId());
 
 		$this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
 		$this->assertEquals($user2, $cachedMounts[1]->getUser());
-		$this->assertEquals(4, $cachedMounts[1]->getRootId());
-		$this->assertEquals(3, $cachedMounts[1]->getStorageId());
+		$this->assertEquals($id2, $cachedMounts[1]->getRootId());
+		$this->assertEquals(2, $cachedMounts[1]->getStorageId());
 	}
 
 	public function testGetMountsByRootId() {
 		$user1 = $this->userManager->get('u1');
 		$user2 = $this->userManager->get('u2');
 
-		$mount1 = new MountPoint($this->getStorage(1, 2), '/foo/');
-		$mount2 = new MountPoint($this->getStorage(3, 4), '/bar/');
+		list($storage1, $id1) = $this->getStorage(1);
+		list($storage2, $id2) = $this->getStorage(2);
+		$mount1 = new MountPoint($storage1, '/foo/');
+		$mount2 = new MountPoint($storage2, '/bar/');
 
 		$this->cache->registerMounts($user1, [$mount1, $mount2]);
 		$this->cache->registerMounts($user2, [$mount2]);
 
 		$this->clearCache();
 
-		$cachedMounts = $this->cache->getMountsForRootId(4);
+		$cachedMounts = $this->cache->getMountsForRootId($id2);
 		$this->sortMounts($cachedMounts);
 
 		$this->assertCount(2, $cachedMounts);
 
 		$this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
 		$this->assertEquals($user1, $cachedMounts[0]->getUser());
-		$this->assertEquals(4, $cachedMounts[0]->getRootId());
-		$this->assertEquals(3, $cachedMounts[0]->getStorageId());
+		$this->assertEquals($id2, $cachedMounts[0]->getRootId());
+		$this->assertEquals(2, $cachedMounts[0]->getStorageId());
 
 		$this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
 		$this->assertEquals($user2, $cachedMounts[1]->getUser());
-		$this->assertEquals(4, $cachedMounts[1]->getRootId());
-		$this->assertEquals(3, $cachedMounts[1]->getStorageId());
+		$this->assertEquals($id2, $cachedMounts[1]->getRootId());
+		$this->assertEquals(2, $cachedMounts[1]->getStorageId());
 	}
 
 	private function sortMounts(&$mounts) {
@@ -294,7 +302,8 @@ class UserMountCacheTest extends TestCase {
 	}
 
 	private function createCacheEntry($internalPath, $storageId) {
-		$this->connection->insertIfNotExist('*PREFIX*filecache', [
+		$internalPath = trim($internalPath, '/');
+		$inserted = $this->connection->insertIfNotExist('*PREFIX*filecache', [
 			'storage' => $storageId,
 			'path' => $internalPath,
 			'path_hash' => md5($internalPath),
@@ -309,17 +318,23 @@ class UserMountCacheTest extends TestCase {
 			'etag' => '',
 			'permissions' => 31
 		], ['storage', 'path_hash']);
-		$id = (int)$this->connection->lastInsertId('*PREFIX*filecache');
-		$this->fileIds[] = $id;
+		if ($inserted) {
+			$id = (int)$this->connection->lastInsertId('*PREFIX*filecache');
+			$this->fileIds[] = $id;
+		} else {
+			$sql = 'SELECT fileid FROM *PREFIX*filecache WHERE `storage` = ? AND `path_hash` =?';
+			$query = $this->connection->prepare($sql);
+			$query->execute([$storageId, md5($internalPath)]);
+			return (int)$query->fetchColumn();
+		}
 		return $id;
 	}
 
 	public function testGetMountsForFileIdRootId() {
 		$user1 = $this->userManager->get('u1');
 
-		$rootId = $this->createCacheEntry('', 2);
-
-		$mount1 = new MountPoint($this->getStorage(2, $rootId), '/foo/');
+		list($storage1, $rootId) = $this->getStorage(2);
+		$mount1 = new MountPoint($storage1, '/foo/');
 
 		$this->cache->registerMounts($user1, [$mount1]);
 
@@ -338,10 +353,10 @@ class UserMountCacheTest extends TestCase {
 	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/');
+		list($storage1, $rootId) = $this->getStorage(2);
+		$mount1 = new MountPoint($storage1, '/foo/');
 
 		$this->cache->registerMounts($user1, [$mount1]);
 
@@ -360,11 +375,19 @@ class UserMountCacheTest extends TestCase {
 	public function testGetMountsForFileIdSubFolderMount() {
 		$user1 = $this->userManager->get('u1');
 
-		$this->createCacheEntry('', 2);
+		list($storage1, $rootId) = $this->getStorage(2);
 		$folderId = $this->createCacheEntry('/foo', 2);
 		$fileId = $this->createCacheEntry('/foo/bar', 2);
 
-		$mount1 = new MountPoint($this->getStorage(2, $folderId), '/foo/');
+
+		$mount1 = $this->getMockBuilder('\OC\Files\Mount\MountPoint')
+			->setConstructorArgs([$storage1, '/'])
+			->setMethods(['getStorageRootId'])
+			->getMock();
+
+		$mount1->expects($this->any())
+			->method('getStorageRootId')
+			->will($this->returnValue($folderId));
 
 		$this->cache->registerMounts($user1, [$mount1]);
 
@@ -374,20 +397,30 @@ class UserMountCacheTest extends TestCase {
 
 		$this->assertCount(1, $cachedMounts);
 
-		$this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
+		$this->assertEquals('/', $cachedMounts[0]->getMountPoint());
 		$this->assertEquals($user1, $cachedMounts[0]->getUser());
 		$this->assertEquals($folderId, $cachedMounts[0]->getRootId());
 		$this->assertEquals(2, $cachedMounts[0]->getStorageId());
+		$this->assertEquals('foo', $cachedMounts[0]->getRootInternalPath());
 	}
 
 	public function testGetMountsForFileIdSubFolderMountOutside() {
 		$user1 = $this->userManager->get('u1');
 
-		$this->createCacheEntry('', 2);
+		list($storage1, $rootId) = $this->getStorage(2);
 		$folderId = $this->createCacheEntry('/foo', 2);
 		$fileId = $this->createCacheEntry('/bar/asd', 2);
 
-		$mount1 = new MountPoint($this->getStorage(2, $folderId), '/foo/');
+		$mount1 = $this->getMockBuilder('\OC\Files\Mount\MountPoint')
+			->setConstructorArgs([$storage1, '/foo/'])
+			->setMethods(['getStorageRootId'])
+			->getMock();
+
+		$mount1->expects($this->any())
+			->method('getStorageRootId')
+			->will($this->returnValue($folderId));
+
+		$this->cache->registerMounts($user1, [$mount1]);
 
 		$this->cache->registerMounts($user1, [$mount1]);
 
diff --git a/tests/lib/Files/Node/FileTest.php b/tests/lib/Files/Node/FileTest.php
index 1b665bd4c72..b7a2fa2a1a3 100644
--- a/tests/lib/Files/Node/FileTest.php
+++ b/tests/lib/Files/Node/FileTest.php
@@ -21,6 +21,9 @@ class FileTest extends \Test\TestCase {
 	/** @var \OC\Files\View|\PHPUnit_Framework_MockObject_MockObject */
 	private $view;
 
+	/** @var \OCP\Files\Config\IUserMountCache|\PHPUnit_Framework_MockObject_MockObject */
+	private $userMountCache;
+
 	protected function setUp() {
 		parent::setUp();
 		$config = $this->getMockBuilder('\OCP\IConfig')
@@ -34,6 +37,9 @@ class FileTest extends \Test\TestCase {
 		$this->view = $this->getMockBuilder('\OC\Files\View')
 			->disableOriginalConstructor()
 			->getMock();
+		$this->userMountCache = $this->getMockBuilder('\OCP\Files\Config\IUserMountCache')
+			->disableOriginalConstructor()
+			->getMock();
 	}
 
 	protected function getMockStorage() {
@@ -52,7 +58,7 @@ class FileTest extends \Test\TestCase {
 	public function testDelete() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$root->expects($this->exactly(2))
@@ -102,7 +108,7 @@ class FileTest extends \Test\TestCase {
 			$hooksRun++;
 		};
 
-		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user, $this->userMountCache);
 		$root->listen('\OC\Files', 'preDelete', $preListener);
 		$root->listen('\OC\Files', 'postDelete', $postListener);
 
@@ -132,7 +138,7 @@ class FileTest extends \Test\TestCase {
 	public function testDeleteNotPermitted() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$root->expects($this->any())
@@ -151,7 +157,7 @@ class FileTest extends \Test\TestCase {
 	public function testGetContent() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$hook = function ($file) {
@@ -181,7 +187,7 @@ class FileTest extends \Test\TestCase {
 	public function testGetContentNotPermitted() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$root->expects($this->any())
@@ -200,7 +206,7 @@ class FileTest extends \Test\TestCase {
 	public function testPutContent() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$root->expects($this->any())
@@ -227,7 +233,7 @@ class FileTest extends \Test\TestCase {
 	public function testPutContentNotPermitted() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$this->view->expects($this->once())
@@ -242,7 +248,7 @@ class FileTest extends \Test\TestCase {
 	public function testGetMimeType() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$this->view->expects($this->once())
@@ -259,7 +265,7 @@ class FileTest extends \Test\TestCase {
 		fwrite($stream, 'bar');
 		rewind($stream);
 
-		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user, $this->userMountCache);
 
 		$hook = function ($file) {
 			throw new \Exception('Hooks are not supposed to be called');
@@ -287,7 +293,7 @@ class FileTest extends \Test\TestCase {
 	public function testFOpenWrite() {
 		$stream = fopen('php://memory', 'w+');
 
-		$root = new \OC\Files\Node\Root($this->manager, new $this->view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, new $this->view, $this->user, $this->userMountCache);
 
 		$hooksCalled = 0;
 		$hook = function ($file) use (&$hooksCalled) {
@@ -320,7 +326,7 @@ class FileTest extends \Test\TestCase {
 	 * @expectedException \OCP\Files\NotPermittedException
 	 */
 	public function testFOpenReadNotPermitted() {
-		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user, $this->userMountCache);
 
 		$hook = function ($file) {
 			throw new \Exception('Hooks are not supposed to be called');
@@ -339,7 +345,7 @@ class FileTest extends \Test\TestCase {
 	 * @expectedException \OCP\Files\NotPermittedException
 	 */
 	public function testFOpenReadWriteNoReadPermissions() {
-		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user, $this->userMountCache);
 
 		$hook = function () {
 			throw new \Exception('Hooks are not supposed to be called');
@@ -358,7 +364,7 @@ class FileTest extends \Test\TestCase {
 	 * @expectedException \OCP\Files\NotPermittedException
 	 */
 	public function testFOpenReadWriteNoWritePermissions() {
-		$root = new \OC\Files\Node\Root($this->manager, new $this->view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, new $this->view, $this->user, $this->userMountCache);
 
 		$hook = function () {
 			throw new \Exception('Hooks are not supposed to be called');
@@ -376,7 +382,7 @@ class FileTest extends \Test\TestCase {
 	public function testCopySameStorage() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$this->view->expects($this->any())
@@ -409,7 +415,7 @@ class FileTest extends \Test\TestCase {
 	public function testCopyNotPermitted() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		/**
@@ -447,7 +453,7 @@ class FileTest extends \Test\TestCase {
 	public function testCopyNoParent() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$this->view->expects($this->never())
@@ -469,7 +475,7 @@ class FileTest extends \Test\TestCase {
 	public function testCopyParentIsFile() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$this->view->expects($this->never())
@@ -490,7 +496,7 @@ class FileTest extends \Test\TestCase {
 	public function testMoveSameStorage() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$this->view->expects($this->any())
@@ -520,7 +526,7 @@ class FileTest extends \Test\TestCase {
 	public function testMoveNotPermitted() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$this->view->expects($this->any())
@@ -547,7 +553,7 @@ class FileTest extends \Test\TestCase {
 	public function testMoveNoParent() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		/**
@@ -577,7 +583,7 @@ class FileTest extends \Test\TestCase {
 	public function testMoveParentIsFile() {
 		/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject $root */
 		$root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 
 		$this->view->expects($this->never())
diff --git a/tests/lib/Files/Node/FolderTest.php b/tests/lib/Files/Node/FolderTest.php
index 17cb2f2caa2..e592013eb6a 100644
--- a/tests/lib/Files/Node/FolderTest.php
+++ b/tests/lib/Files/Node/FolderTest.php
@@ -9,6 +9,8 @@
 namespace Test\Files\Node;
 
 use OC\Files\Cache\Cache;
+use OC\Files\Cache\CacheEntry;
+use OC\Files\Config\CachedMountInfo;
 use OC\Files\FileInfo;
 use OC\Files\Mount\Manager;
 use OC\Files\Mount\MountPoint;
@@ -32,9 +34,15 @@ use OCP\Files\Storage;
 class FolderTest extends \Test\TestCase {
 	private $user;
 
+	/** @var \OCP\Files\Config\IUserMountCache|\PHPUnit_Framework_MockObject_MockObject */
+	private $userMountCache;
+
 	protected function setUp() {
 		parent::setUp();
 		$this->user = new \OC\User\User('', new \Test\Util\User\Dummy);
+		$this->userMountCache = $this->getMockBuilder('\OCP\Files\Config\IUserMountCache')
+			->disableOriginalConstructor()
+			->getMock();
 	}
 
 	protected function getMockStorage() {
@@ -56,7 +64,7 @@ class FolderTest extends \Test\TestCase {
 		 */
 		$view = $this->createMock(View::class);
 		$root = $this->getMockBuilder(Root::class)
-			->setConstructorArgs([$manager, $view, $this->user])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])
 			->getMock();
 		$root->expects($this->any())
 			->method('getUser')
@@ -110,7 +118,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = new \OC\Files\Node\Root($manager, $view, $this->user);
+		$root = new \OC\Files\Node\Root($manager, $view, $this->user, $this->userMountCache);
 		$root->listen('\OC\Files', 'preDelete', $preListener);
 		$root->listen('\OC\Files', 'postDelete', $postListener);
 
@@ -142,7 +150,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -163,7 +171,7 @@ class FolderTest extends \Test\TestCase {
 		 */
 		$view = $this->createMock(View::class);
 		$root = $this->getMockBuilder(Root::class)
-			->setConstructorArgs([$manager, $view, $this->user])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])
 			->getMock();
 		$root->expects($this->any())
 			->method('getUser')
@@ -194,7 +202,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -213,7 +221,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -235,7 +243,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -255,7 +263,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -285,7 +293,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -305,7 +313,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -335,7 +343,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -355,7 +363,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -375,7 +383,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -423,7 +431,8 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -471,7 +480,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -519,7 +528,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -567,7 +576,7 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$root->expects($this->any())
 			->method('getUser')
 			->will($this->returnValue($this->user));
@@ -647,26 +656,34 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])->setConstructorArgs([$manager, $view, $this->user])->getMock();
-		$root->expects($this->any())
-			->method('getUser')
-			->will($this->returnValue($this->user));
+		$root = $this->getMockBuilder(Root::class)->setMethods(['getMountsIn', 'getMount'])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$storage = $this->createMock(\OC\Files\Storage\Storage::class);
 		$mount = new MountPoint($storage, '/bar');
 		$cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock();
 
-		$view->expects($this->once())
-			->method('getFileInfo')
-			->will($this->returnValue(new FileInfo('/bar/foo/qwerty', null, 'qwerty', ['mimetype' => 'text/plain'], null)));
+		$fileInfo = new CacheEntry(['path' => 'foo/qwerty', 'mimetype' => 'text/plain'], null);
 
 		$storage->expects($this->once())
 			->method('getCache')
 			->will($this->returnValue($cache));
 
+		$this->userMountCache->expects($this->any())
+			->method('getMountsForFileId')
+			->with(1)
+			->will($this->returnValue([new CachedMountInfo(
+				$this->user,
+				1,
+				0,
+				'/bar/',
+				1,
+				''
+			)]));
+
 		$cache->expects($this->once())
-			->method('getPathById')
-			->with('1')
-			->will($this->returnValue('foo/qwerty'));
+			->method('get')
+			->with(1)
+			->will($this->returnValue($fileInfo));
 
 		$root->expects($this->once())
 			->method('getMountsIn')
@@ -690,22 +707,34 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])->setConstructorArgs([$manager, $view, $this->user])->getMock();
-		$root->expects($this->any())
-			->method('getUser')
-			->will($this->returnValue($this->user));
+		$root = $this->getMockBuilder(Root::class)->setMethods(['getMountsIn', 'getMount'])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$storage = $this->createMock(\OC\Files\Storage\Storage::class);
 		$mount = new MountPoint($storage, '/bar');
 		$cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock();
 
+		$fileInfo = new CacheEntry(['path' => 'foobar', 'mimetype' => 'text/plain'], null);
+
 		$storage->expects($this->once())
 			->method('getCache')
 			->will($this->returnValue($cache));
 
+		$this->userMountCache->expects($this->any())
+			->method('getMountsForFileId')
+			->with(1)
+			->will($this->returnValue([new CachedMountInfo(
+				$this->user,
+				1,
+				0,
+				'/bar/',
+				1,
+				''
+			)]));
+
 		$cache->expects($this->once())
-			->method('getPathById')
-			->with('1')
-			->will($this->returnValue('foobar'));
+			->method('get')
+			->with(1)
+			->will($this->returnValue($fileInfo));
 
 		$root->expects($this->once())
 			->method('getMountsIn')
@@ -719,7 +748,7 @@ class FolderTest extends \Test\TestCase {
 
 		$node = new \OC\Files\Node\Folder($root, $view, '/bar/foo');
 		$result = $node->getById(1);
-		$this->assertCount(0, $result);
+		$this->assertEquals(0, count($result));
 	}
 
 	public function testGetByIdMultipleStorages() {
@@ -728,27 +757,49 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])->setConstructorArgs([$manager, $view, $this->user])->getMock();
-		$root->expects($this->any())
-			->method('getUser')
-			->will($this->returnValue($this->user));
+		$root = $this->getMockBuilder(Root::class)->setMethods(['getMountsIn', 'getMount'])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		$storage = $this->createMock(\OC\Files\Storage\Storage::class);
 		$mount1 = new MountPoint($storage, '/bar');
 		$mount2 = new MountPoint($storage, '/bar/foo/asd');
 		$cache = $this->getMockBuilder(Cache::class)->setConstructorArgs([''])->getMock();
 
-		$view->expects($this->any())
-			->method('getFileInfo')
-			->will($this->returnValue(new FileInfo('/bar/foo/qwerty', null, 'qwerty', ['mimetype' => 'plain'], null)));
+		$fileInfo = new CacheEntry(['path' => 'foo/qwerty', 'mimetype' => 'text/plain'], null);
+
+		$storage->expects($this->once())
+			->method('getCache')
+			->will($this->returnValue($cache));
+
+		$this->userMountCache->expects($this->any())
+			->method('getMountsForFileId')
+			->with(1)
+			->will($this->returnValue([
+				new CachedMountInfo(
+					$this->user,
+					1,
+					0,
+					'/bar/',
+					1,
+					''
+				),
+				new CachedMountInfo(
+					$this->user,
+					1,
+					0,
+					'/bar/foo/asd/',
+					1,
+					''
+				)
+			]));
 
 		$storage->expects($this->any())
 			->method('getCache')
 			->will($this->returnValue($cache));
 
 		$cache->expects($this->any())
-			->method('getPathById')
-			->with('1')
-			->will($this->returnValue('foo/qwerty'));
+			->method('get')
+			->with(1)
+			->will($this->returnValue($fileInfo));
 
 		$root->expects($this->any())
 			->method('getMountsIn')
@@ -786,7 +837,8 @@ class FolderTest extends \Test\TestCase {
 		 * @var \OC\Files\View | \PHPUnit_Framework_MockObject_MockObject $view
 		 */
 		$view = $this->createMock(View::class);
-		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 
 		$view->expects($this->any())
 			->method('file_exists')
@@ -811,7 +863,8 @@ class FolderTest extends \Test\TestCase {
 		 */
 		$view = $this->createMock(View::class);
 		/** @var \PHPUnit_Framework_MockObject_MockObject|\OC\Files\Node\Root $root */
-		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		/** @var \PHPUnit_Framework_MockObject_MockObject|\OC\Files\FileInfo $folderInfo */
 		$folderInfo = $this->getMockBuilder('\OC\Files\FileInfo')
 			->disableOriginalConstructor()->getMock();
@@ -869,7 +922,8 @@ class FolderTest extends \Test\TestCase {
 		 */
 		$view = $this->createMock(View::class);
 		/** @var \PHPUnit_Framework_MockObject_MockObject|\OC\Files\Node\Root $root */
-		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		/** @var \PHPUnit_Framework_MockObject_MockObject|\OC\Files\FileInfo $folderInfo */
 		$folderInfo = $this->getMockBuilder('\OC\Files\FileInfo')
 			->disableOriginalConstructor()->getMock();
@@ -925,7 +979,8 @@ class FolderTest extends \Test\TestCase {
 		 */
 		$view = $this->createMock(View::class);
 		/** @var \PHPUnit_Framework_MockObject_MockObject|\OC\Files\Node\Root $root */
-		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])->setConstructorArgs([$manager, $view, $this->user])->getMock();
+		$root = $this->getMockBuilder(Root::class)->setMethods(['getUser', 'getMountsIn', 'getMount'])
+			->setConstructorArgs([$manager, $view, $this->user, $this->userMountCache])->getMock();
 		/** @var \PHPUnit_Framework_MockObject_MockObject|\OC\Files\FileInfo $folderInfo */
 		$folderInfo = $this->getMockBuilder('\OC\Files\FileInfo')
 			->disableOriginalConstructor()->getMock();
diff --git a/tests/lib/Files/Node/HookConnectorTest.php b/tests/lib/Files/Node/HookConnectorTest.php
index 7245dd37593..013fcabf222 100644
--- a/tests/lib/Files/Node/HookConnectorTest.php
+++ b/tests/lib/Files/Node/HookConnectorTest.php
@@ -50,7 +50,12 @@ class HookConnectorTest extends TestCase {
 		$this->registerMount($this->userId, new Temporary(), '/' . $this->userId . '/files/');
 		\OC_Util::setupFS($this->userId);
 		$this->view = new View();
-		$this->root = new Root(Filesystem::getMountManager(), $this->view, \OC::$server->getUserManager()->get($this->userId));
+		$this->root = new Root(
+			Filesystem::getMountManager(),
+			$this->view,
+			\OC::$server->getUserManager()->get($this->userId),
+			\OC::$server->getUserMountCache()
+		);
 	}
 
 	public function tearDown() {
diff --git a/tests/lib/Files/Node/IntegrationTest.php b/tests/lib/Files/Node/IntegrationTest.php
index f52e0623e14..da753f833c2 100644
--- a/tests/lib/Files/Node/IntegrationTest.php
+++ b/tests/lib/Files/Node/IntegrationTest.php
@@ -47,7 +47,7 @@ class IntegrationTest extends \Test\TestCase {
 		$this->loginAsUser($user->getUID());
 
 		$this->view = new View();
-		$this->root = new Root($manager, $this->view, $user);
+		$this->root = new Root($manager, $this->view, $user, \OC::$server->getUserMountCache());
 		$storage = new Temporary(array());
 		$subStorage = new Temporary(array());
 		$this->storages[] = $storage;
diff --git a/tests/lib/Files/Node/NodeTest.php b/tests/lib/Files/Node/NodeTest.php
index 2fd47680bac..b7e2f336a60 100644
--- a/tests/lib/Files/Node/NodeTest.php
+++ b/tests/lib/Files/Node/NodeTest.php
@@ -22,6 +22,8 @@ class NodeTest extends \Test\TestCase {
 
 	/** @var \OC\Files\Node\Root|\PHPUnit_Framework_MockObject_MockObject */
 	private $root;
+	/** @var \OCP\Files\Config\IUserMountCache|\PHPUnit_Framework_MockObject_MockObject */
+	private $userMountCache;
 
 	protected function setUp() {
 		parent::setUp();
@@ -41,8 +43,11 @@ class NodeTest extends \Test\TestCase {
 		$this->view = $this->getMockBuilder('\OC\Files\View')
 			->disableOriginalConstructor()
 			->getMock();
+		$this->userMountCache = $this->getMockBuilder('\OCP\Files\Config\IUserMountCache')
+			->disableOriginalConstructor()
+			->getMock();
 		$this->root = $this->getMockBuilder('\OC\Files\Node\Root')
-			->setConstructorArgs([$this->manager, $this->view, $this->user])
+			->setConstructorArgs([$this->manager, $this->view, $this->user, $this->userMountCache])
 			->getMock();
 	}
 
@@ -268,7 +273,7 @@ class NodeTest extends \Test\TestCase {
 			$hooksRun++;
 		};
 
-		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $this->view, $this->user, $this->userMountCache);
 		$root->listen('\OC\Files', 'preTouch', $preListener);
 		$root->listen('\OC\Files', 'postTouch', $postListener);
 
diff --git a/tests/lib/Files/Node/RootTest.php b/tests/lib/Files/Node/RootTest.php
index 92aebcddab4..f42a42c42b1 100644
--- a/tests/lib/Files/Node/RootTest.php
+++ b/tests/lib/Files/Node/RootTest.php
@@ -16,6 +16,8 @@ class RootTest extends \Test\TestCase {
 
 	/** @var \OC\Files\Mount\Manager */
 	private $manager;
+	/** @var \OCP\Files\Config\IUserMountCache|\PHPUnit_Framework_MockObject_MockObject */
+	private $userMountCache;
 
 	protected function setUp() {
 		parent::setUp();
@@ -32,6 +34,9 @@ class RootTest extends \Test\TestCase {
 		$this->manager = $this->getMockBuilder('\OC\Files\Mount\Manager')
 			->disableOriginalConstructor()
 			->getMock();
+		$this->userMountCache = $this->getMockBuilder('\OCP\Files\Config\IUserMountCache')
+			->disableOriginalConstructor()
+			->getMock();
 	}
 
 	protected function getFileInfo($data) {
@@ -51,7 +56,7 @@ class RootTest extends \Test\TestCase {
 		$view = $this->getMockBuilder('\OC\Files\View')
 			->disableOriginalConstructor()
 			->getMock();
-		$root = new \OC\Files\Node\Root($this->manager, $view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $view, $this->user, $this->userMountCache);
 
 		$view->expects($this->once())
 			->method('getFileInfo')
@@ -80,7 +85,7 @@ class RootTest extends \Test\TestCase {
 		$view = $this->getMockBuilder('\OC\Files\View')
 			->disableOriginalConstructor()
 			->getMock();
-		$root = new \OC\Files\Node\Root($this->manager, $view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $view, $this->user, $this->userMountCache);
 
 		$view->expects($this->once())
 			->method('getFileInfo')
@@ -101,7 +106,7 @@ class RootTest extends \Test\TestCase {
 		$view = $this->getMockBuilder('\OC\Files\View')
 			->disableOriginalConstructor()
 			->getMock();
-		$root = new \OC\Files\Node\Root($this->manager, $view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $view, $this->user, $this->userMountCache);
 
 		$root->get('/../foo');
 	}
@@ -116,7 +121,7 @@ class RootTest extends \Test\TestCase {
 		$view = $this->getMockBuilder('\OC\Files\View')
 			->disableOriginalConstructor()
 			->getMock();
-		$root = new \OC\Files\Node\Root($this->manager, $view, $this->user);
+		$root = new \OC\Files\Node\Root($this->manager, $view, $this->user, $this->userMountCache);
 
 		$root->get('/bar/foo');
 	}
-- 
GitLab