From 740ea0d30e8ed8967e5d940b971e8854812c627d Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 6 Dec 2018 13:58:57 +0100 Subject: [PATCH] try to grab the appdata folder directly without going trough the whole tree Signed-off-by: Robin Appelman --- lib/private/Files/AppData/AppData.php | 90 ++++++++++++++++++------- lib/private/Files/AppData/Factory.php | 7 +- tests/lib/Files/AppData/AppDataTest.php | 24 ++----- 3 files changed, 77 insertions(+), 44 deletions(-) diff --git a/lib/private/Files/AppData/AppData.php b/lib/private/Files/AppData/AppData.php index e25bf45044..3d098ad98c 100644 --- a/lib/private/Files/AppData/AppData.php +++ b/lib/private/Files/AppData/AppData.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace OC\Files\AppData; +use OC\Cache\CappedMemoryCache; use OC\Files\SimpleFS\SimpleFolder; use OCP\Files\IAppData; use OCP\Files\IRootFolder; @@ -48,6 +49,9 @@ class AppData implements IAppData { /** @var Folder */ private $folder; + /** @var (ISimpleFolder|NotFoundException)[]|CappedMemoryCache */ + private $folders; + /** * AppData constructor. * @@ -62,6 +66,32 @@ class AppData implements IAppData { $this->rootFolder = $rootFolder; $this->config = $systemConfig; $this->appId = $appId; + $this->folders = new CappedMemoryCache(); + } + + private function getAppDataFolderName() { + $instanceId = $this->config->getValue('instanceid', null); + if ($instanceId === null) { + throw new \RuntimeException('no instance id!'); + } + + return 'appdata_' . $instanceId; + } + + private function getAppDataRootFolder(): Folder { + $name = $this->getAppDataFolderName(); + + try { + /** @var Folder $node */ + $node = $this->rootFolder->get($name); + return $node; + } catch (NotFoundException $e) { + try { + return $this->rootFolder->newFolder($name); + } catch (NotPermittedException $e) { + throw new \RuntimeException('Could not get appdata folder'); + } + } } /** @@ -70,56 +100,64 @@ class AppData implements IAppData { */ private function getAppDataFolder(): Folder { if ($this->folder === null) { - $instanceId = $this->config->getValue('instanceid', null); - if ($instanceId === null) { - throw new \RuntimeException('no instance id!'); - } - - $name = 'appdata_' . $instanceId; + $name = $this->getAppDataFolderName(); try { - $appDataFolder = $this->rootFolder->get($name); + $this->folder = $this->rootFolder->get($name . '/' . $this->appId); } catch (NotFoundException $e) { + $appDataRootFolder = $this->getAppDataRootFolder(); + try { - $appDataFolder = $this->rootFolder->newFolder($name); - } catch (NotPermittedException $e) { - throw new \RuntimeException('Could not get appdata folder'); + $this->folder = $appDataRootFolder->get($this->appId); + } catch (NotFoundException $e) { + try { + $this->folder = $appDataRootFolder->newFolder($this->appId); + } catch (NotPermittedException $e) { + throw new \RuntimeException('Could not get appdata folder for ' . $this->appId); + } } } - - try { - $appDataFolder = $appDataFolder->get($this->appId); - } catch (NotFoundException $e) { - try { - $appDataFolder = $appDataFolder->newFolder($this->appId); - } catch (NotPermittedException $e) { - throw new \RuntimeException('Could not get appdata folder for ' . $this->appId); - } - } - - $this->folder = $appDataFolder; } return $this->folder; } public function getFolder(string $name): ISimpleFolder { - $node = $this->getAppDataFolder()->get($name); + $key = $this->appId . '/' . $name; + if ($cachedFolder = $this->folders->get($key)) { + if ($cachedFolder instanceof \Exception) { + throw $cachedFolder; + } else { + return $cachedFolder; + } + } + try { + $path = $this->getAppDataFolderName() . '/' . $this->appId . '/' . $name; + $node = $this->rootFolder->get($path); + } catch (NotFoundException $e) { + $this->folders->set($key, $e); + throw $e; + } /** @var Folder $node */ - return new SimpleFolder($node); + $folder = new SimpleFolder($node); + $this->folders->set($key, $folder); + return $folder; } public function newFolder(string $name): ISimpleFolder { + $key = $this->appId . '/' . $name; $folder = $this->getAppDataFolder()->newFolder($name); - return new SimpleFolder($folder); + $simpleFolder = new SimpleFolder($folder); + $this->folders->set($key, $simpleFolder); + return $simpleFolder; } public function getDirectoryListing(): array { $listing = $this->getAppDataFolder()->getDirectoryListing(); - $fileListing = array_map(function(Node $folder) { + $fileListing = array_map(function (Node $folder) { if ($folder instanceof Folder) { return new SimpleFolder($folder); } diff --git a/lib/private/Files/AppData/Factory.php b/lib/private/Files/AppData/Factory.php index fba2232db0..5c7d554ba5 100644 --- a/lib/private/Files/AppData/Factory.php +++ b/lib/private/Files/AppData/Factory.php @@ -34,6 +34,8 @@ class Factory { /** @var SystemConfig */ private $config; + private $folders = []; + public function __construct(IRootFolder $rootFolder, SystemConfig $systemConfig) { @@ -46,6 +48,9 @@ class Factory { * @return AppData */ public function get(string $appId): AppData { - return new AppData($this->rootFolder, $this->config, $appId); + if (!isset($this->folders[$appId])) { + $this->folders[$appId] = new AppData($this->rootFolder, $this->config, $appId); + } + return $this->folders[$appId]; } } diff --git a/tests/lib/Files/AppData/AppDataTest.php b/tests/lib/Files/AppData/AppDataTest.php index 3247ce7ba9..1d5cea0faf 100644 --- a/tests/lib/Files/AppData/AppDataTest.php +++ b/tests/lib/Files/AppData/AppDataTest.php @@ -55,30 +55,22 @@ class AppDataTest extends \Test\TestCase { } private function setupAppFolder() { - $dataFolder = $this->createMock(Folder::class); $appFolder = $this->createMock(Folder::class); - $this->rootFolder->expects($this->once()) + $this->rootFolder->expects($this->any()) ->method('get') - ->with($this->equalTo('appdata_iid')) - ->willReturn($dataFolder); - $dataFolder->expects($this->once()) - ->method('get') - ->with($this->equalTo('myApp')) + ->with($this->equalTo('appdata_iid/myApp')) ->willReturn($appFolder); - return [$dataFolder, $appFolder]; + return $appFolder; } public function testGetFolder() { - $folders = $this->setupAppFolder(); - $appFolder = $folders[1]; - $folder = $this->createMock(Folder::class); - $appFolder->expects($this->once()) + $this->rootFolder->expects($this->once()) ->method('get') - ->with($this->equalTo('folder')) + ->with($this->equalTo('appdata_iid/myApp/folder')) ->willReturn($folder); $result = $this->appData->getFolder('folder'); @@ -86,8 +78,7 @@ class AppDataTest extends \Test\TestCase { } public function testNewFolder() { - $folders = $this->setupAppFolder(); - $appFolder = $folders[1]; + $appFolder = $this->setupAppFolder(); $folder = $this->createMock(Folder::class); @@ -101,8 +92,7 @@ class AppDataTest extends \Test\TestCase { } public function testGetDirectoryListing() { - $folders = $this->setupAppFolder(); - $appFolder = $folders[1]; + $appFolder = $this->setupAppFolder(); $file = $this->createMock(File::class); $folder = $this->createMock(Folder::class);