From cdc8c40d60e874e1214f33b1c8f15d923ed90873 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 1 Dec 2015 16:41:28 +0100 Subject: [PATCH 01/17] Add public cache interface --- lib/private/files/cache/cache.php | 3 +- lib/public/files/cache/icache.php | 262 ++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 lib/public/files/cache/icache.php diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 7a976e1888..bb2da63fc4 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -33,6 +33,7 @@ namespace OC\Files\Cache; +use OCP\Files\Cache\ICache; use \OCP\Files\IMimeTypeLoader; use OCP\IDBConnection; @@ -46,7 +47,7 @@ use OCP\IDBConnection; * - Updater: listens to changes made to the filesystem inside of the ownCloud instance and updates the cache where needed * - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater */ -class Cache { +class Cache implements ICache { const NOT_FOUND = 0; const PARTIAL = 1; //only partial data available, file not cached in the database const SHALLOW = 2; //folder in cache, but not all child files are completely scanned diff --git a/lib/public/files/cache/icache.php b/lib/public/files/cache/icache.php new file mode 100644 index 0000000000..5e8ca50273 --- /dev/null +++ b/lib/public/files/cache/icache.php @@ -0,0 +1,262 @@ +> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCP\Files\Cache; + +/** + * Metadata cache for a storage + * + * The cache stores the metadata for all files and folders in a storage and is kept up to date trough the following mechanisms: + * + * - Scanner: scans the storage and updates the cache where needed + * - Watcher: checks for changes made to the filesystem outside of the ownCloud instance and rescans files and folder when a change is detected + * - Updater: listens to changes made to the filesystem inside of the ownCloud instance and updates the cache where needed + * - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater + */ +interface ICache { + const NOT_FOUND = 0; + const PARTIAL = 1; //only partial data available, file not cached in the database + const SHALLOW = 2; //folder in cache, but not all child files are completely scanned + const COMPLETE = 3; + + /** + * Get the numeric storage id for this cache's storage + * + * @return int + */ + public function getNumericStorageId(); + + /** + * get the stored metadata of a file or folder + * + * the returned cache entry contains at least the following values: + * [ + * 'fileid' => int, the numeric id of a file (see getId) + * 'storage' => int, the numeric id of the storage the file is stored on + * 'path' => string, the path of the file within the storage ('foo/bar.txt') + * 'name' => string, the basename of a file ('bar.txt) + * 'mimetype' => string, the full mimetype of the file ('text/plain') + * 'mimepart' => string, the first half of the mimetype ('text') + * 'size' => int, the size of the file or folder in bytes + * 'mtime' => int, the last modified date of the file as unix timestamp as shown in the ui + * 'storage_mtime' => int, the last modified date of the file as unix timestamp as stored on the storage + * Note that when a file is updated we also update the mtime of all parent folders to make it visible to the user which folder has had updates most recently + * This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed + * 'etag' => string, the etag for the file + * An etag is used for change detection of files and folders, an etag of a file changes whenever the content of the file changes + * Etag for folders change whenever a file in the folder has changed + * 'permissions' int, the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE + * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE + * ] + * + * @param string | int $file either the path of a file or folder or the file id for a file or folder + * @return array|false the cache entry as array of false if the file is not found in the cache + */ + public function get($file); + + /** + * get the metadata of all files stored in $folder + * + * @param string $folder + * @return array + */ + public function getFolderContents($folder); + + /** + * get the metadata of all files stored in $folder + * + * @param int $fileId the file id of the folder + * @return array + */ + public function getFolderContentsById($fileId); + + /** + * store meta data for a file or folder + * + * @param string $file + * @param array $data + * + * @return int file id + * @throws \RuntimeException + */ + public function put($file, array $data); + + /** + * update the metadata of an existing file or folder in the cache + * + * @param int $id the fileid of the existing file or folder + * @param array $data [$key => $value] the metadata to update, only the fields provided in the array will be updated, non-provided values will remain unchanged + */ + public function update($id, array $data); + + /** + * get the file id for a file + * + * A file id is a numeric id for a file or folder that's unique within an owncloud instance which stays the same for the lifetime of a file + * + * File ids are easiest way for apps to store references to a file since unlike paths they are not affected by renames or sharing + * + * @param string $file + * @return int + */ + public function getId($file); + + /** + * get the id of the parent folder of a file + * + * @param string $file + * @return int + */ + public function getParentId($file); + + /** + * check if a file is available in the cache + * + * @param string $file + * @return bool + */ + public function inCache($file); + + /** + * remove a file or folder from the cache + * + * when removing a folder from the cache all files and folders inside the folder will be removed as well + * + * @param string $file + */ + public function remove($file); + + /** + * Move a file or folder in the cache + * + * @param string $source + * @param string $target + */ + public function move($source, $target); + + /** + * Move a file or folder in the cache + * + * @param \OCP\Files\Cache\ICache $sourceCache + * @param string $sourcePath + * @param string $targetPath + * @throws \OC\DatabaseException + */ + public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath); + + /** + * remove all entries for files that are stored on the storage from the cache + */ + public function clear(); + + /** + * Get the scan status of a file + * + * - ICache::NOT_FOUND: File is not in the cache + * - ICache::PARTIAL: File is not stored in the cache but some incomplete data is known + * - ICache::SHALLOW: The folder and it's direct children are in the cache but not all sub folders are fully scanned + * - ICache::COMPLETE: The file or folder, with all it's children) are fully scanned + * + * @param string $file + * + * @return int ICache::NOT_FOUND, ICache::PARTIAL, ICache::SHALLOW or ICache::COMPLETE + */ + public function getStatus($file); + + /** + * search for files matching $pattern + * + * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%') + * @return array an array of cache entries where the name matches the search pattern + */ + public function search($pattern); + + /** + * search for files by mimetype + * + * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image') + * where it will search for all mimetypes in the group ('image/*') + * @return array an array of cache entries where the mimetype matches the search + */ + public function searchByMime($mimetype); + + /** + * Search for files by tag of a given users. + * + * Note that every user can tag files differently. + * + * @param string|int $tag name or tag id + * @param string $userId owner of the tags + * @return array file data + */ + public function searchByTag($tag, $userId); + + /** + * Re-calculate the folder size and the size of all parent folders + * + * @param string|boolean $path + * @param array $data (optional) meta data of the folder + */ + public function correctFolderSize($path, $data = null); + + /** + * calculate the size of a folder and set it in the cache + * + * @param string $path + * @param array $entry (optional) meta data of the folder + * @return int + */ + public function calculateFolderSize($path, $entry = null); + + /** + * get all file ids on the files on the storage + * + * @return int[] + */ + public function getAll(); + + /** + * find a folder in the cache which has not been fully scanned + * + * If multiple incomplete folders are in the cache, the one with the highest id will be returned, + * use the one with the highest id gives the best result with the background scanner, since that is most + * likely the folder where we stopped scanning previously + * + * @return string|bool the path of the folder or false when no folder matched + */ + public function getIncomplete(); + + /** + * get the path of a file on this storage by it's file id + * + * @param int $id the file id of the file or folder to search + * @return string|null the path of the file (relative to the storage) or null if a file with the given id does not exists within this cache + */ + public function getPathById($id); + + /** + * normalize the given path for usage in the cache + * + * @param string $path + * @return string + */ + public function normalize($path); +} From 2dcdc8147780707b11c03c92281a8076b0a873b6 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 14:03:52 +0100 Subject: [PATCH 02/17] propagator interface --- lib/private/files/cache/propagator.php | 6 +++-- lib/public/files/cache/ipropagator.php | 34 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 lib/public/files/cache/ipropagator.php diff --git a/lib/private/files/cache/propagator.php b/lib/private/files/cache/propagator.php index 56abcdadee..1e85a2ecc8 100644 --- a/lib/private/files/cache/propagator.php +++ b/lib/private/files/cache/propagator.php @@ -21,10 +21,12 @@ namespace OC\Files\Cache; +use OCP\Files\Cache\IPropagator; + /** * Propagate etags and mtimes within the storage */ -class Propagator { +class Propagator implements IPropagator { /** * @var \OC\Files\Storage\Storage */ @@ -41,7 +43,7 @@ class Propagator { /** * @param string $internalPath * @param int $time - * @return array[] all propagated entries + * @return array[] all propagated cache entries */ public function propagateChange($internalPath, $time) { $cache = $this->storage->getCache($internalPath); diff --git a/lib/public/files/cache/ipropagator.php b/lib/public/files/cache/ipropagator.php new file mode 100644 index 0000000000..90bdf9af53 --- /dev/null +++ b/lib/public/files/cache/ipropagator.php @@ -0,0 +1,34 @@ +> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCP\Files\Cache; + +/** + * Propagate etags and mtimes within the storage + */ +interface IPropagator { + /** + * @param string $internalPath + * @param int $time + * @return array[] all propagated cache entries + */ + public function propagateChange($internalPath, $time); +} From 3ab0ccd4a253364775a2baf6b058e8f7f0d293fc Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 14:13:42 +0100 Subject: [PATCH 03/17] add cache entry interface --- lib/private/files/cache/cacheentry.php | 110 +++++++++++++++++++++++ lib/public/files/cache/icachenetry.php | 118 +++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 lib/private/files/cache/cacheentry.php create mode 100644 lib/public/files/cache/icachenetry.php diff --git a/lib/private/files/cache/cacheentry.php b/lib/private/files/cache/cacheentry.php new file mode 100644 index 0000000000..10ea949cab --- /dev/null +++ b/lib/private/files/cache/cacheentry.php @@ -0,0 +1,110 @@ +> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\Files\Cache; + +use OCP\Files\Cache\ICacheEntry; + +/** + * meta data for a file or folder + */ +class CacheEntry implements ICacheEntry, \ArrayAccess { + /** + * @var array + */ + private $data; + + public function __construct(array $data) { + $this->data = $data; + } + + public function offsetSet($offset, $value) { + $this->data[$offset] = $value; + } + + public function offsetExists($offset) { + return isset($this->data[$offset]); + } + + public function offsetUnset($offset) { + unset($this->data[$offset]); + } + + public function offsetGet($offset) { + if (isset($this->data[$offset])) { + return $this->data[$offset]; + } else { + return null; + } + } + + public function getId() { + return (int)$this->data['fileid']; + } + + public function getStorageId() { + return $this->data['storage']; + } + + + public function getPath() { + return $this->data['path']; + } + + + public function getName() { + return $this->data['name']; + } + + + public function getMimeType() { + return $this->data['mimetype']; + } + + + public function getMimePart() { + return $this->data['mimepart']; + } + + public function getSize() { + return $this->data['size']; + } + + public function getMTime() { + return $this->data['mtime']; + } + + public function getStorageMTime() { + return $this->data['storage_mtime']; + } + + public function getEtag() { + return $this->data['etag']; + } + + public function getPermissions() { + return $this->data['permissions']; + } + + public function isEncrypted() { + return isset($this->data['encrypted']) && $this->data['encrypted']; + } +} diff --git a/lib/public/files/cache/icachenetry.php b/lib/public/files/cache/icachenetry.php new file mode 100644 index 0000000000..62b25ebc28 --- /dev/null +++ b/lib/public/files/cache/icachenetry.php @@ -0,0 +1,118 @@ +> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCP\Files\Cache; + +/** + * meta data for a file or folder + */ +interface ICacheEntry { + /** + * Get the numeric id of a file + * + * @return int + */ + public function getId(); + + /** + * Get the numeric id for the storage + * + * @return int + */ + public function getStorageId(); + + /** + * Get the path of the file relative to the storage root + * + * @return string + */ + public function getPath(); + + /** + * Get the file name + * + * @return string + */ + public function getName(); + + /** + * Get the full mimetype + * + * @return string + */ + public function getMimeType(); + + /** + * Get the first part of the mimetype + * + * @return string + */ + public function getMimePart(); + + /** + * Get the file size in bytes + * + * @return int + */ + public function getSize(); + + /** + * Get the last modified date as unix timestamp + * + * @return int + */ + public function getMTime(); + + /** + * Get the last modified date on the storage as unix timestamp + * + * Note that when a file is updated we also update the mtime of all parent folders to make it visible to the user which folder has had updates most recently + * This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed + * + * @return int + */ + public function getStorageMTime(); + + /** + * Get the etag for the file + * + * An etag is used for change detection of files and folders, an etag of a file changes whenever the content of the file changes + * Etag for folders change whenever a file in the folder has changed + * + * @return string + */ + public function getEtag(); + + /** + * Get the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE + * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE + * + * @return int + */ + public function getPermissions(); + + /** + * Check if the file is encrypted + * + * @return bool + */ + public function isEncrypted(); +} From 5d0451b84862c2c905b7d1a8d5943ac53d87f990 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 14:49:27 +0100 Subject: [PATCH 04/17] Safe teardowns --- apps/files_sharing/tests/backend.php | 6 ++++-- apps/files_sharing/tests/external/cache.php | 4 +++- apps/files_sharing/tests/sharedmount.php | 6 ++++-- apps/files_sharing/tests/updater.php | 6 ++++-- apps/files_sharing/tests/watcher.php | 12 +++++++----- apps/files_versions/tests/versions.php | 10 ++++++---- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/files_sharing/tests/backend.php b/apps/files_sharing/tests/backend.php index 0e151d9e76..acb5985539 100644 --- a/apps/files_sharing/tests/backend.php +++ b/apps/files_sharing/tests/backend.php @@ -58,8 +58,10 @@ class Test_Files_Sharing_Backend extends TestCase { } protected function tearDown() { - $this->view->unlink($this->filename); - $this->view->deleteAll($this->folder); + if ($this->view) { + $this->view->unlink($this->filename); + $this->view->deleteAll($this->folder); + } parent::tearDown(); } diff --git a/apps/files_sharing/tests/external/cache.php b/apps/files_sharing/tests/external/cache.php index 52e01677fa..3e078bf372 100644 --- a/apps/files_sharing/tests/external/cache.php +++ b/apps/files_sharing/tests/external/cache.php @@ -75,7 +75,9 @@ class Cache extends TestCase { } protected function tearDown() { - $this->cache->clear(); + if ($this->cache) { + $this->cache->clear(); + } parent::tearDown(); } diff --git a/apps/files_sharing/tests/sharedmount.php b/apps/files_sharing/tests/sharedmount.php index 347ec0d2a7..e01deeb60f 100644 --- a/apps/files_sharing/tests/sharedmount.php +++ b/apps/files_sharing/tests/sharedmount.php @@ -48,8 +48,10 @@ class Test_Files_Sharing_Mount extends OCA\Files_sharing\Tests\TestCase { } protected function tearDown() { - $this->view->unlink($this->folder); - $this->view->unlink($this->filename); + if ($this->view) { + $this->view->unlink($this->folder); + $this->view->unlink($this->filename); + } parent::tearDown(); } diff --git a/apps/files_sharing/tests/updater.php b/apps/files_sharing/tests/updater.php index 02c5f487e0..dd1f83c99a 100644 --- a/apps/files_sharing/tests/updater.php +++ b/apps/files_sharing/tests/updater.php @@ -52,8 +52,10 @@ class Test_Files_Sharing_Updater extends OCA\Files_Sharing\Tests\TestCase { } protected function tearDown() { - $this->view->unlink($this->filename); - $this->view->deleteAll($this->folder); + if ($this->view) { + $this->view->unlink($this->filename); + $this->view->deleteAll($this->folder); + } parent::tearDown(); } diff --git a/apps/files_sharing/tests/watcher.php b/apps/files_sharing/tests/watcher.php index 021f10bacc..247fb59f35 100644 --- a/apps/files_sharing/tests/watcher.php +++ b/apps/files_sharing/tests/watcher.php @@ -88,13 +88,15 @@ class Test_Files_Sharing_Watcher extends OCA\Files_sharing\Tests\TestCase { self::loginHelper(self::TEST_FILES_SHARING_API_USER1); - $fileinfo = $this->view->getFileInfo('container/shareddir'); - \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, - self::TEST_FILES_SHARING_API_USER2); + if ($this->view) { + $fileinfo = $this->view->getFileInfo('container/shareddir'); + \OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_USER, + self::TEST_FILES_SHARING_API_USER2); - $this->view->deleteAll('container'); + $this->view->deleteAll('container'); - $this->ownerCache->clear(); + $this->ownerCache->clear(); + } parent::tearDown(); } diff --git a/apps/files_versions/tests/versions.php b/apps/files_versions/tests/versions.php index 74d6006cfd..ac922b74b9 100644 --- a/apps/files_versions/tests/versions.php +++ b/apps/files_versions/tests/versions.php @@ -86,10 +86,12 @@ class Test_Files_Versioning extends \Test\TestCase { } protected function tearDown() { - $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/'); - $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/'); - $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/'); - $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/'); + if ($this->rootView) { + $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files/'); + $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files/'); + $this->rootView->deleteAll(self::TEST_VERSIONS_USER . '/files_versions/'); + $this->rootView->deleteAll(self::TEST_VERSIONS_USER2 . '/files_versions/'); + } \OC_Hook::clear(); From 6d321f5f6b4e22f0c8124572662361a1f53e7c3a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 14:59:13 +0100 Subject: [PATCH 05/17] Return a class from cache operations instead of an array --- apps/files_sharing/lib/cache.php | 13 ++-- lib/private/files/cache/cache.php | 64 +++++++------------ lib/private/files/cache/cacheentry.php | 4 ++ lib/private/files/cache/homecache.php | 4 +- lib/private/files/cache/scanner.php | 3 +- .../files/cache/wrapper/cachewrapper.php | 15 +++-- lib/private/files/fileinfo.php | 3 +- .../files/storage/wrapper/encryption.php | 4 +- lib/private/files/view.php | 7 +- lib/public/files/cache/icache.php | 32 ++-------- .../{icachenetry.php => icacheentry.php} | 0 11 files changed, 63 insertions(+), 86 deletions(-) rename lib/public/files/cache/{icachenetry.php => icacheentry.php} (100%) diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index 714cc144c0..10d1e78792 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -33,6 +33,7 @@ namespace OC\Files\Cache; use OC\User\NoUserException; +use OCP\Files\Cache\ICacheEntry; use OCP\Share_Backend_Collection; /** @@ -98,8 +99,8 @@ class Shared_Cache extends Cache { /** * get the stored metadata of a file or folder * - * @param string $file - * @return array|false + * @param string|int $file + * @return ICacheEntry|false */ public function get($file) { $mimetypeLoader = \OC::$server->getMimeTypeLoader(); @@ -161,7 +162,7 @@ class Shared_Cache extends Cache { * get the metadata of all files stored in $folder * * @param string $folderId - * @return array|false + * @return ICacheEntry[]|false */ public function getFolderContentsById($folderId) { $cache = $this->getSourceCache(''); @@ -281,7 +282,7 @@ class Shared_Cache extends Cache { * search for files matching $pattern * * @param string $pattern - * @return array of file data + * @return ICacheEntry[] of file data */ public function search($pattern) { @@ -320,7 +321,7 @@ class Shared_Cache extends Cache { * search for files by mimetype * * @param string $mimetype - * @return array + * @return ICacheEntry[] */ public function searchByMime($mimetype) { $mimepart = null; @@ -373,7 +374,7 @@ class Shared_Cache extends Cache { * * @param string|int $tag tag to search for * @param string $userId owner of the tags - * @return array file data + * @return ICacheEntry[] file data */ public function searchByTag($tag, $userId) { // TODO: inject this diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index bb2da63fc4..527c8b76e5 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -34,6 +34,7 @@ namespace OC\Files\Cache; use OCP\Files\Cache\ICache; +use OCP\Files\Cache\ICacheEntry; use \OCP\Files\IMimeTypeLoader; use OCP\IDBConnection; @@ -48,11 +49,6 @@ use OCP\IDBConnection; * - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater */ class Cache implements ICache { - const NOT_FOUND = 0; - const PARTIAL = 1; //only partial data available, file not cached in the database - const SHALLOW = 2; //folder in cache, but not all child files are completely scanned - const COMPLETE = 3; - /** * @var array partial data for the cache */ @@ -106,28 +102,8 @@ class Cache implements ICache { /** * get the stored metadata of a file or folder * - * the returned cache entry contains at least the following values: - * [ - * 'fileid' => int, the numeric id of a file (see getId) - * 'storage' => int, the numeric id of the storage the file is stored on - * 'path' => string, the path of the file within the storage ('foo/bar.txt') - * 'name' => string, the basename of a file ('bar.txt) - * 'mimetype' => string, the full mimetype of the file ('text/plain') - * 'mimepart' => string, the first half of the mimetype ('text') - * 'size' => int, the size of the file or folder in bytes - * 'mtime' => int, the last modified date of the file as unix timestamp as shown in the ui - * 'storage_mtime' => int, the last modified date of the file as unix timestamp as stored on the storage - * Note that when a file is updated we also update the mtime of all parent folders to make it visible to the user which folder has had updates most recently - * This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed - * 'etag' => string, the etag for the file - * An etag is used for change detection of files and folders, an etag of a file changes whenever the content of the file changes - * Etag for folders change whenever a file in the folder has changed - * 'permissions' int, the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE - * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE - * ] - * * @param string | int $file either the path of a file or folder or the file id for a file or folder - * @return array|false the cache entry as array of false if the file is not found in the cache + * @return ICacheEntry|false the cache entry as array of false if the file is not found in the cache */ public function get($file) { if (is_string($file) or $file == '') { @@ -157,6 +133,7 @@ class Cache implements ICache { if (isset($this->partial[$file])) { $data = $this->partial[$file]; } + return $data; } else { //fix types $data['fileid'] = (int)$data['fileid']; @@ -172,16 +149,15 @@ class Cache implements ICache { $data['storage_mtime'] = $data['mtime']; } $data['permissions'] = (int)$data['permissions']; + return new CacheEntry($data); } - - return $data; } /** * get the metadata of all files stored in $folder * * @param string $folder - * @return array + * @return ICacheEntry[] */ public function getFolderContents($folder) { $fileId = $this->getId($folder); @@ -192,7 +168,7 @@ class Cache implements ICache { * get the metadata of all files stored in $folder * * @param int $fileId the file id of the folder - * @return array + * @return ICacheEntry[] */ public function getFolderContentsById($fileId) { if ($fileId > -1) { @@ -212,7 +188,9 @@ class Cache implements ICache { $file['storage_mtime'] = (int)$file['storage_mtime']; $file['size'] = 0 + $file['size']; } - return $files; + return array_map(function (array $data) { + return new CacheEntry($data); + }, $files); } else { return array(); } @@ -393,7 +371,7 @@ class Cache implements ICache { return -1; } else { $parent = $this->getParentPath($file); - return (int) $this->getId($parent); + return (int)$this->getId($parent); } } @@ -482,12 +460,12 @@ class Cache implements ICache { /** * Move a file or folder in the cache * - * @param \OC\Files\Cache\Cache $sourceCache + * @param \OCP\Files\Cache\ICache $sourceCache * @param string $sourcePath * @param string $targetPath * @throws \OC\DatabaseException */ - public function moveFromCache(Cache $sourceCache, $sourcePath, $targetPath) { + public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { // normalize source and target $sourcePath = $this->normalize($sourcePath); $targetPath = $this->normalize($targetPath); @@ -572,7 +550,7 @@ class Cache implements ICache { * search for files matching $pattern * * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%') - * @return array an array of cache entries where the name matches the search pattern + * @return ICacheEntry[] an array of cache entries where the name matches the search pattern */ public function search($pattern) { // normalize pattern @@ -595,7 +573,9 @@ class Cache implements ICache { $row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']); $files[] = $row; } - return $files; + return array_map(function(array $data) { + return new CacheEntry($data); + }, $files); } /** @@ -603,7 +583,7 @@ class Cache implements ICache { * * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image') * where it will search for all mimetypes in the group ('image/*') - * @return array an array of cache entries where the mimetype matches the search + * @return ICacheEntry[] an array of cache entries where the mimetype matches the search */ public function searchByMime($mimetype) { if (strpos($mimetype, '/')) { @@ -621,7 +601,9 @@ class Cache implements ICache { $row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']); $files[] = $row; } - return $files; + return array_map(function (array $data) { + return new CacheEntry($data); + }, $files); } /** @@ -631,7 +613,7 @@ class Cache implements ICache { * * @param string|int $tag name or tag id * @param string $userId owner of the tags - * @return array file data + * @return ICacheEntry[] file data */ public function searchByTag($tag, $userId) { $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' . @@ -666,7 +648,9 @@ class Cache implements ICache { while ($row = $result->fetch()) { $files[] = $row; } - return $files; + return array_map(function (array $data) { + return new CacheEntry($data); + }, $files); } /** diff --git a/lib/private/files/cache/cacheentry.php b/lib/private/files/cache/cacheentry.php index 10ea949cab..3db3b3f8aa 100644 --- a/lib/private/files/cache/cacheentry.php +++ b/lib/private/files/cache/cacheentry.php @@ -107,4 +107,8 @@ class CacheEntry implements ICacheEntry, \ArrayAccess { public function isEncrypted() { return isset($this->data['encrypted']) && $this->data['encrypted']; } + + public function getData() { + return $this->data; + } } diff --git a/lib/private/files/cache/homecache.php b/lib/private/files/cache/homecache.php index 693896fccf..ae92504ddd 100644 --- a/lib/private/files/cache/homecache.php +++ b/lib/private/files/cache/homecache.php @@ -26,6 +26,8 @@ namespace OC\Files\Cache; +use OCP\Files\Cache\ICacheEntry; + class HomeCache extends Cache { /** * get the size of a folder and set it in the cache @@ -67,7 +69,7 @@ class HomeCache extends Cache { /** * @param string $path - * @return array + * @return ICacheEntry */ public function get($path) { $data = parent::get($path); diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index 79f749394f..fa12378ae9 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -160,6 +160,7 @@ class Scanner extends BasicEmitter { $data['parent'] = $parentId; } if (is_null($cacheData)) { + /** @var CacheEntry $cacheData */ $cacheData = $this->cache->get($file); } if ($cacheData and $reuseExisting and isset($cacheData['fileid'])) { @@ -182,7 +183,7 @@ class Scanner extends BasicEmitter { } } // Only update metadata that has changed - $newData = array_diff_assoc($data, $cacheData); + $newData = array_diff_assoc($data, $cacheData->getData()); } else { $newData = $data; $fileId = -1; diff --git a/lib/private/files/cache/wrapper/cachewrapper.php b/lib/private/files/cache/wrapper/cachewrapper.php index f401b7482e..39a6b63205 100644 --- a/lib/private/files/cache/wrapper/cachewrapper.php +++ b/lib/private/files/cache/wrapper/cachewrapper.php @@ -25,6 +25,7 @@ namespace OC\Files\Cache\Wrapper; use OC\Files\Cache\Cache; +use OCP\Files\Cache\ICacheEntry; class CacheWrapper extends Cache { /** @@ -42,8 +43,8 @@ class CacheWrapper extends Cache { /** * Make it easy for wrappers to modify every returned cache entry * - * @param array $entry - * @return array + * @param ICacheEntry $entry + * @return ICacheEntry */ protected function formatCacheEntry($entry) { return $entry; @@ -53,7 +54,7 @@ class CacheWrapper extends Cache { * get the stored metadata of a file or folder * * @param string /int $file - * @return array|false + * @return ICacheEntry|false */ public function get($file) { $result = $this->cache->get($file); @@ -67,7 +68,7 @@ class CacheWrapper extends Cache { * get the metadata of all files stored in $folder * * @param string $folder - * @return array + * @return ICacheEntry[] */ public function getFolderContents($folder) { // cant do a simple $this->cache->.... call here since getFolderContentsById needs to be called on this @@ -178,7 +179,7 @@ class CacheWrapper extends Cache { * search for files matching $pattern * * @param string $pattern - * @return array an array of file data + * @return ICacheEntry[] an array of file data */ public function search($pattern) { $results = $this->cache->search($pattern); @@ -189,7 +190,7 @@ class CacheWrapper extends Cache { * search for files by mimetype * * @param string $mimetype - * @return array + * @return ICacheEntry[] */ public function searchByMime($mimetype) { $results = $this->cache->searchByMime($mimetype); @@ -201,7 +202,7 @@ class CacheWrapper extends Cache { * * @param string|int $tag name or tag id * @param string $userId owner of the tags - * @return array file data + * @return ICacheEntry[] file data */ public function searchByTag($tag, $userId) { $results = $this->cache->searchByTag($tag, $userId); diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index 3e5e894eed..1e6fe474f7 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -29,6 +29,7 @@ namespace OC\Files; +use OCP\Files\Cache\ICacheEntry; use OCP\IUser; class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { @@ -71,7 +72,7 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @param string|boolean $path * @param Storage\Storage $storage * @param string $internalPath - * @param array $data + * @param array|ICacheEntry $data * @param \OCP\Files\Mount\IMountPoint $mount * @param \OCP\IUser|null $owner */ diff --git a/lib/private/files/storage/wrapper/encryption.php b/lib/private/files/storage/wrapper/encryption.php index fda28079d0..69438ef0c7 100644 --- a/lib/private/files/storage/wrapper/encryption.php +++ b/lib/private/files/storage/wrapper/encryption.php @@ -28,6 +28,7 @@ namespace OC\Files\Storage\Wrapper; use OC\Encryption\Exceptions\ModuleDoesNotExistsException; use OC\Encryption\Update; use OC\Encryption\Util; +use OC\Files\Cache\CacheEntry; use OC\Files\Filesystem; use OC\Files\Mount\Manager; use OC\Files\Storage\LocalTempFileTrait; @@ -123,13 +124,14 @@ class Encryption extends Wrapper { public function filesize($path) { $fullPath = $this->getFullPath($path); + /** @var CacheEntry $info */ $info = $this->getCache()->get($path); if (isset($this->unencryptedSize[$fullPath])) { $size = $this->unencryptedSize[$fullPath]; // update file cache $info['encrypted'] = true; $info['size'] = $size; - $this->getCache()->put($path, $info); + $this->getCache()->put($path, $info->getData()); return $size; } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 7b0f1d3725..6f8a6db9f9 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -47,6 +47,7 @@ use OC\Files\Cache\Updater; use OC\Files\Mount\MoveableMount; use OC\Files\Storage\Storage; use OC\User\User; +use OCP\Files\Cache\ICacheEntry; use OCP\Files\FileNameTooLongException; use OCP\Files\InvalidCharacterInPathException; use OCP\Files\InvalidPathException; @@ -1274,7 +1275,7 @@ class View { if ($storage) { $data = $this->getCacheEntry($storage, $internalPath, $relativePath); - if (!is_array($data)) { + if (!$data instanceof ICacheEntry) { return false; } @@ -1334,7 +1335,7 @@ class View { $data = $this->getCacheEntry($storage, $internalPath, $directory); - if (!is_array($data) || !isset($data['fileid'])) { + if (!$data instanceof ICacheEntry || !isset($data['fileid'])) { return []; } @@ -1345,7 +1346,7 @@ class View { /** * @var \OC\Files\FileInfo[] $files */ - $files = array_map(function (array $content) use ($path, $storage, $mount, $sharingDisabled) { + $files = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) { if ($sharingDisabled) { $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE; } diff --git a/lib/public/files/cache/icache.php b/lib/public/files/cache/icache.php index 5e8ca50273..f75bcbcc8e 100644 --- a/lib/public/files/cache/icache.php +++ b/lib/public/files/cache/icache.php @@ -47,28 +47,8 @@ interface ICache { /** * get the stored metadata of a file or folder * - * the returned cache entry contains at least the following values: - * [ - * 'fileid' => int, the numeric id of a file (see getId) - * 'storage' => int, the numeric id of the storage the file is stored on - * 'path' => string, the path of the file within the storage ('foo/bar.txt') - * 'name' => string, the basename of a file ('bar.txt) - * 'mimetype' => string, the full mimetype of the file ('text/plain') - * 'mimepart' => string, the first half of the mimetype ('text') - * 'size' => int, the size of the file or folder in bytes - * 'mtime' => int, the last modified date of the file as unix timestamp as shown in the ui - * 'storage_mtime' => int, the last modified date of the file as unix timestamp as stored on the storage - * Note that when a file is updated we also update the mtime of all parent folders to make it visible to the user which folder has had updates most recently - * This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed - * 'etag' => string, the etag for the file - * An etag is used for change detection of files and folders, an etag of a file changes whenever the content of the file changes - * Etag for folders change whenever a file in the folder has changed - * 'permissions' int, the permissions for the file stored as bitwise combination of \OCP\PERMISSION_READ, \OCP\PERMISSION_CREATE - * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE - * ] - * * @param string | int $file either the path of a file or folder or the file id for a file or folder - * @return array|false the cache entry as array of false if the file is not found in the cache + * @return ICacheEntry[]|false the cache entry or false if the file is not found in the cache */ public function get($file); @@ -76,7 +56,7 @@ interface ICache { * get the metadata of all files stored in $folder * * @param string $folder - * @return array + * @return ICacheEntry[] */ public function getFolderContents($folder); @@ -84,7 +64,7 @@ interface ICache { * get the metadata of all files stored in $folder * * @param int $fileId the file id of the folder - * @return array + * @return ICacheEntry[] */ public function getFolderContentsById($fileId); @@ -185,7 +165,7 @@ interface ICache { * search for files matching $pattern * * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%') - * @return array an array of cache entries where the name matches the search pattern + * @return ICacheEntry[] an array of cache entries where the name matches the search pattern */ public function search($pattern); @@ -194,7 +174,7 @@ interface ICache { * * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image') * where it will search for all mimetypes in the group ('image/*') - * @return array an array of cache entries where the mimetype matches the search + * @return ICacheEntry[] an array of cache entries where the mimetype matches the search */ public function searchByMime($mimetype); @@ -205,7 +185,7 @@ interface ICache { * * @param string|int $tag name or tag id * @param string $userId owner of the tags - * @return array file data + * @return ICacheEntry[] file data */ public function searchByTag($tag, $userId); diff --git a/lib/public/files/cache/icachenetry.php b/lib/public/files/cache/icacheentry.php similarity index 100% rename from lib/public/files/cache/icachenetry.php rename to lib/public/files/cache/icacheentry.php From 5fae07f422eede80d7ace5f909f9f9ea853d7d89 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 15:05:29 +0100 Subject: [PATCH 06/17] add scanner interface --- apps/dav/lib/connector/sabre/objecttree.php | 3 +- apps/files_sharing/lib/scanner.php | 2 +- lib/private/files/cache/scanner.php | 11 +-- lib/public/files/cache/iscanner.php | 74 +++++++++++++++++++++ 4 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 lib/public/files/cache/iscanner.php diff --git a/apps/dav/lib/connector/sabre/objecttree.php b/apps/dav/lib/connector/sabre/objecttree.php index ba4c855f58..55b310a440 100644 --- a/apps/dav/lib/connector/sabre/objecttree.php +++ b/apps/dav/lib/connector/sabre/objecttree.php @@ -135,9 +135,8 @@ class ObjectTree extends \Sabre\DAV\Tree { /** * @var \OC\Files\Storage\Storage $storage */ - $scanner = $storage->getScanner($internalPath); // get data directly - $data = $scanner->getData($internalPath); + $data = $storage->getMetaData($internalPath); $info = new FileInfo($absPath, $storage, $internalPath, $data, $mount); } else { $info = null; diff --git a/apps/files_sharing/lib/scanner.php b/apps/files_sharing/lib/scanner.php index 1152c49755..bd6a28a493 100644 --- a/apps/files_sharing/lib/scanner.php +++ b/apps/files_sharing/lib/scanner.php @@ -35,7 +35,7 @@ class SharedScanner extends Scanner { * * @return array an array of metadata of the file */ - public function getData($path){ + protected function getData($path){ $data = parent::getData($path); $sourcePath = $this->storage->getSourcePath($path); list($sourceStorage, $internalPath) = \OC\Files\Filesystem::resolvePath($sourcePath); diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index fa12378ae9..9215114937 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -37,6 +37,7 @@ namespace OC\Files\Cache; use OC\Files\Filesystem; use OC\Hooks\BasicEmitter; use OCP\Config; +use OCP\Files\Cache\IScanner; use OCP\Lock\ILockingProvider; /** @@ -50,7 +51,7 @@ use OCP\Lock\ILockingProvider; * * @package OC\Files\Cache */ -class Scanner extends BasicEmitter { +class Scanner extends BasicEmitter implements IScanner { /** * @var \OC\Files\Storage\Storage $storage */ @@ -81,12 +82,6 @@ class Scanner extends BasicEmitter { */ protected $lockingProvider; - const SCAN_RECURSIVE = true; - const SCAN_SHALLOW = false; - - const REUSE_ETAG = 1; - const REUSE_SIZE = 2; - public function __construct(\OC\Files\Storage\Storage $storage) { $this->storage = $storage; $this->storageId = $this->storage->getId(); @@ -112,7 +107,7 @@ class Scanner extends BasicEmitter { * @param string $path * @return array an array of metadata of the file */ - public function getData($path) { + protected function getData($path) { $data = $this->storage->getMetaData($path); if (is_null($data)) { \OCP\Util::writeLog('OC\Files\Cache\Scanner', "!!! Path '$path' is not accessible or present !!!", \OCP\Util::DEBUG); diff --git a/lib/public/files/cache/iscanner.php b/lib/public/files/cache/iscanner.php new file mode 100644 index 0000000000..7aa3fb1605 --- /dev/null +++ b/lib/public/files/cache/iscanner.php @@ -0,0 +1,74 @@ +> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCP\Files\Cache; + +/** + * Scan files form the storage and save to the cache + */ +interface IScanner { + const SCAN_RECURSIVE = true; + const SCAN_SHALLOW = false; + + const REUSE_ETAG = 1; + const REUSE_SIZE = 2; + + /** + * scan a single file and store it in the cache + * + * @param string $file + * @param int $reuseExisting + * @param int $parentId + * @param array | null $cacheData existing data in the cache for the file to be scanned + * @param bool $lock set to false to disable getting an additional read lock during scanning + * @return array an array of metadata of the scanned file + * @throws \OC\ServerNotAvailableException + * @throws \OCP\Lock\LockedException + */ + public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true); + + /** + * scan a folder and all it's children + * + * @param string $path + * @param bool $recursive + * @param int $reuse + * @param bool $lock set to false to disable getting an additional read lock during scanning + * @return array an array of the meta data of the scanned file or folder + */ + public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true); + + /** + * check if the file should be ignored when scanning + * NOTE: files with a '.part' extension are ignored as well! + * prevents unfinished put requests to be scanned + * + * @param string $file + * @return boolean + */ + public static function isPartialFile($file); + + /** + * walk over any folders that are not fully scanned yet and scan them + */ + public function backgroundScan(); +} + From c27894791ebc2174cad82dc4039e8bb343114c50 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 15:11:09 +0100 Subject: [PATCH 07/17] Add updater interface and expose cache interfaces from storage --- lib/private/files/cache/updater.php | 15 ++++--- lib/public/files/cache/iupdater.php | 68 +++++++++++++++++++++++++++++ lib/public/files/storage.php | 24 ++++++++++ 3 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 lib/public/files/cache/iupdater.php diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php index c5b1e7de32..12ff802dd5 100644 --- a/lib/private/files/cache/updater.php +++ b/lib/private/files/cache/updater.php @@ -24,12 +24,13 @@ */ namespace OC\Files\Cache; +use OCP\Files\Cache\IUpdater; /** * Update the cache and propagate changes * */ -class Updater { +class Updater implements IUpdater { /** * @var bool */ @@ -145,18 +146,18 @@ class Updater { /** * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders * - * @param \OC\Files\Storage\Storage $sourceStorage + * @param \OCP\Files\Storage $sourceStorage * @param string $source * @param string $target */ - public function renameFromStorage(\OC\Files\Storage\Storage $sourceStorage, $source, $target) { + public function renameFromStorage(\OCP\Files\Storage $sourceStorage, $source, $target) { if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) { return; } $time = time(); - $sourceCache = $sourceStorage->getCache($source); + $sourceCache = $sourceStorage->getCache(); $sourceUpdater = $sourceStorage->getUpdater(); $sourcePropagator = $sourceStorage->getPropagator(); @@ -181,7 +182,9 @@ class Updater { $sourceCache->correctFolderSize($source); $this->cache->correctFolderSize($target); - $sourceUpdater->correctParentStorageMtime($source); + if ($sourceUpdater instanceof Updater) { + $sourceUpdater->correctParentStorageMtime($source); + } $this->correctParentStorageMtime($target); $this->updateStorageMTimeOnly($target); $sourcePropagator->propagateChange($source, $time); @@ -205,7 +208,7 @@ class Updater { * * @param string $internalPath */ - public function correctParentStorageMtime($internalPath) { + private function correctParentStorageMtime($internalPath) { $parentId = $this->cache->getParentId($internalPath); $parent = dirname($internalPath); if ($parentId != -1) { diff --git a/lib/public/files/cache/iupdater.php b/lib/public/files/cache/iupdater.php new file mode 100644 index 0000000000..cf2b471053 --- /dev/null +++ b/lib/public/files/cache/iupdater.php @@ -0,0 +1,68 @@ +> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCP\Files\Cache; +use OCP\Files\Storage; + +/** + * Update the cache and propagate changes + * + */ +interface IUpdater { + /** + * Get the propagator for etags and mtime for the view the updater works on + * + * @return IPropagator + */ + public function getPropagator(); + + /** + * Propagate etag and mtime changes for the parent folders of $path up to the root of the filesystem + * + * @param string $path the path of the file to propagate the changes for + * @param int|null $time the timestamp to set as mtime for the parent folders, if left out the current time is used + */ + public function propagate($path, $time = null); + + /** + * Update the cache for $path and update the size, etag and mtime of the parent folders + * + * @param string $path + * @param int $time + */ + public function update($path, $time = null); + + /** + * Remove $path from the cache and update the size, etag and mtime of the parent folders + * + * @param string $path + */ + public function remove($path); + + /** + * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders + * + * @param \OCP\Files\Storage $sourceStorage + * @param string $source + * @param string $target + */ + public function renameFromStorage(Storage $sourceStorage, $source, $target); +} diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index f6f5081aba..063455a270 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -33,6 +33,10 @@ // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; +use OCP\Files\Cache\ICache; +use OCP\Files\Cache\IPropagator; +use OCP\Files\Cache\IScanner; +use OCP\Files\Cache\IUpdater; use OCP\Files\InvalidPathException; use OCP\Lock\ILockingProvider; @@ -468,4 +472,24 @@ interface Storage { * @since 9.0.0 */ public function getOwner($path); + + /** + * @return ICache + */ + public function getCache(); + + /** + * @return IPropagator + */ + public function getPropagator(); + + /** + * @return IScanner + */ + public function getScanner(); + + /** + * @return IUpdater + */ + public function getUpdater(); } From a3d50ef49a4c7183086398133793d4788bbf7901 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 15:14:40 +0100 Subject: [PATCH 08/17] add watcher interface --- apps/files_sharing/lib/watcher.php | 3 +- lib/private/files/cache/watcher.php | 13 +++-- lib/public/files/cache/iwatcher.php | 74 +++++++++++++++++++++++++++++ lib/public/files/storage.php | 6 +++ 4 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 lib/public/files/cache/iwatcher.php diff --git a/apps/files_sharing/lib/watcher.php b/apps/files_sharing/lib/watcher.php index 9a8968f226..5b4736c21e 100644 --- a/apps/files_sharing/lib/watcher.php +++ b/apps/files_sharing/lib/watcher.php @@ -24,6 +24,7 @@ */ namespace OC\Files\Cache; +use OCP\Files\Cache\ICacheEntry; /** * check the storage backends for updates and change the cache accordingly @@ -38,7 +39,7 @@ class Shared_Watcher extends Watcher { * Update the cache for changes to $path * * @param string $path - * @param array $cachedData + * @param ICacheEntry $cachedData */ public function update($path, $cachedData) { parent::update($path, $cachedData); diff --git a/lib/private/files/cache/watcher.php b/lib/private/files/cache/watcher.php index bb80dcbd80..a00e875a2d 100644 --- a/lib/private/files/cache/watcher.php +++ b/lib/private/files/cache/watcher.php @@ -22,14 +22,13 @@ */ namespace OC\Files\Cache; +use OCP\Files\Cache\ICacheEntry; +use OCP\Files\Cache\IWatcher; /** * check the storage backends for updates and change the cache accordingly */ -class Watcher { - const CHECK_NEVER = 0; // never check the underlying filesystem for updates - const CHECK_ONCE = 1; // check the underlying filesystem for updates once every request for each file - const CHECK_ALWAYS = 2; // always check the underlying filesystem for updates +class Watcher implements IWatcher { protected $watchPolicy = self::CHECK_ONCE; @@ -77,7 +76,7 @@ class Watcher { * check $path for updates and update if needed * * @param string $path - * @param array $cachedEntry + * @param ICacheEntry|null $cachedEntry * @return boolean true if path was updated */ public function checkUpdate($path, $cachedEntry = null) { @@ -96,7 +95,7 @@ class Watcher { * Update the cache for changes to $path * * @param string $path - * @param array $cachedData + * @param ICacheEntry $cachedData */ public function update($path, $cachedData) { if ($this->storage->is_dir($path)) { @@ -114,7 +113,7 @@ class Watcher { * Check if the cache for $path needs to be updated * * @param string $path - * @param array $cachedData + * @param ICacheEntry $cachedData * @return bool */ public function needsUpdate($path, $cachedData) { diff --git a/lib/public/files/cache/iwatcher.php b/lib/public/files/cache/iwatcher.php new file mode 100644 index 0000000000..f9695f6585 --- /dev/null +++ b/lib/public/files/cache/iwatcher.php @@ -0,0 +1,74 @@ +> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCP\Files\Cache; + +/** + * check the storage backends for updates and change the cache accordingly + */ +interface IWatcher { + const CHECK_NEVER = 0; // never check the underlying filesystem for updates + const CHECK_ONCE = 1; // check the underlying filesystem for updates once every request for each file + const CHECK_ALWAYS = 2; // always check the underlying filesystem for updates + + /** + * @param int $policy either IWatcher::CHECK_NEVER, IWatcher::CHECK_ONCE, IWatcher::CHECK_ALWAYS + */ + public function setPolicy($policy); + + /** + * @return int either IWatcher::CHECK_NEVER, IWatcher::CHECK_ONCE, IWatcher::CHECK_ALWAYS + */ + public function getPolicy(); + + /** + * check $path for updates and update if needed + * + * @param string $path + * @param ICacheEntry|null $cachedEntry + * @return boolean true if path was updated + */ + public function checkUpdate($path, $cachedEntry = null); + + /** + * Update the cache for changes to $path + * + * @param string $path + * @param ICacheEntry $cachedData + */ + public function update($path, $cachedData); + + /** + * Check if the cache for $path needs to be updated + * + * @param string $path + * @param ICacheEntry $cachedData + * @return bool + */ + public function needsUpdate($path, $cachedData); + + /** + * remove deleted files in $path from the cache + * + * @param string $path + */ + public function cleanFolder($path); +} diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index 063455a270..e59cecbdf7 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -37,6 +37,7 @@ use OCP\Files\Cache\ICache; use OCP\Files\Cache\IPropagator; use OCP\Files\Cache\IScanner; use OCP\Files\Cache\IUpdater; +use OCP\Files\Cache\IWatcher; use OCP\Files\InvalidPathException; use OCP\Lock\ILockingProvider; @@ -492,4 +493,9 @@ interface Storage { * @return IUpdater */ public function getUpdater(); + + /** + * @return IWatcher + */ + public function getWatcher(); } From 989995a8529cbb46db0d5f7ab0ec965a82e66bc0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 15:14:52 +0100 Subject: [PATCH 09/17] fix phpdoc --- lib/public/files/storage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index e59cecbdf7..85cd05a1ee 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -469,7 +469,7 @@ interface Storage { public function setAvailability($isAvailable); /** - * @param $path path for which to retrieve the owner + * @param string $path path for which to retrieve the owner * @since 9.0.0 */ public function getOwner($path); From dcbeeced3bad6b31dc9790bc9b9a65c75762e5fe Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 15:17:58 +0100 Subject: [PATCH 10/17] add since tags --- lib/public/files/cache/icache.php | 26 ++++++++++++++++++++++++++ lib/public/files/cache/icacheentry.php | 14 ++++++++++++++ lib/public/files/cache/ipropagator.php | 3 +++ lib/public/files/cache/iscanner.php | 7 +++++++ lib/public/files/cache/iupdater.php | 6 ++++++ lib/public/files/cache/iwatcher.php | 8 ++++++++ lib/public/files/storage.php | 5 +++++ 7 files changed, 69 insertions(+) diff --git a/lib/public/files/cache/icache.php b/lib/public/files/cache/icache.php index f75bcbcc8e..add2b9791e 100644 --- a/lib/public/files/cache/icache.php +++ b/lib/public/files/cache/icache.php @@ -30,6 +30,8 @@ namespace OCP\Files\Cache; * - Watcher: checks for changes made to the filesystem outside of the ownCloud instance and rescans files and folder when a change is detected * - Updater: listens to changes made to the filesystem inside of the ownCloud instance and updates the cache where needed * - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater + * + * @since 9.0.0 */ interface ICache { const NOT_FOUND = 0; @@ -41,6 +43,7 @@ interface ICache { * Get the numeric storage id for this cache's storage * * @return int + * @since 9.0.0 */ public function getNumericStorageId(); @@ -49,6 +52,7 @@ interface ICache { * * @param string | int $file either the path of a file or folder or the file id for a file or folder * @return ICacheEntry[]|false the cache entry or false if the file is not found in the cache + * @since 9.0.0 */ public function get($file); @@ -57,6 +61,7 @@ interface ICache { * * @param string $folder * @return ICacheEntry[] + * @since 9.0.0 */ public function getFolderContents($folder); @@ -65,6 +70,7 @@ interface ICache { * * @param int $fileId the file id of the folder * @return ICacheEntry[] + * @since 9.0.0 */ public function getFolderContentsById($fileId); @@ -76,6 +82,7 @@ interface ICache { * * @return int file id * @throws \RuntimeException + * @since 9.0.0 */ public function put($file, array $data); @@ -84,6 +91,7 @@ interface ICache { * * @param int $id the fileid of the existing file or folder * @param array $data [$key => $value] the metadata to update, only the fields provided in the array will be updated, non-provided values will remain unchanged + * @since 9.0.0 */ public function update($id, array $data); @@ -96,6 +104,7 @@ interface ICache { * * @param string $file * @return int + * @since 9.0.0 */ public function getId($file); @@ -104,6 +113,7 @@ interface ICache { * * @param string $file * @return int + * @since 9.0.0 */ public function getParentId($file); @@ -112,6 +122,7 @@ interface ICache { * * @param string $file * @return bool + * @since 9.0.0 */ public function inCache($file); @@ -121,6 +132,7 @@ interface ICache { * when removing a folder from the cache all files and folders inside the folder will be removed as well * * @param string $file + * @since 9.0.0 */ public function remove($file); @@ -129,6 +141,7 @@ interface ICache { * * @param string $source * @param string $target + * @since 9.0.0 */ public function move($source, $target); @@ -139,11 +152,14 @@ interface ICache { * @param string $sourcePath * @param string $targetPath * @throws \OC\DatabaseException + * @since 9.0.0 */ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath); /** * remove all entries for files that are stored on the storage from the cache + * + * @since 9.0.0 */ public function clear(); @@ -158,6 +174,7 @@ interface ICache { * @param string $file * * @return int ICache::NOT_FOUND, ICache::PARTIAL, ICache::SHALLOW or ICache::COMPLETE + * @since 9.0.0 */ public function getStatus($file); @@ -166,6 +183,7 @@ interface ICache { * * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%') * @return ICacheEntry[] an array of cache entries where the name matches the search pattern + * @since 9.0.0 */ public function search($pattern); @@ -175,6 +193,7 @@ interface ICache { * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image') * where it will search for all mimetypes in the group ('image/*') * @return ICacheEntry[] an array of cache entries where the mimetype matches the search + * @since 9.0.0 */ public function searchByMime($mimetype); @@ -186,6 +205,7 @@ interface ICache { * @param string|int $tag name or tag id * @param string $userId owner of the tags * @return ICacheEntry[] file data + * @since 9.0.0 */ public function searchByTag($tag, $userId); @@ -194,6 +214,7 @@ interface ICache { * * @param string|boolean $path * @param array $data (optional) meta data of the folder + * @since 9.0.0 */ public function correctFolderSize($path, $data = null); @@ -203,6 +224,7 @@ interface ICache { * @param string $path * @param array $entry (optional) meta data of the folder * @return int + * @since 9.0.0 */ public function calculateFolderSize($path, $entry = null); @@ -210,6 +232,7 @@ interface ICache { * get all file ids on the files on the storage * * @return int[] + * @since 9.0.0 */ public function getAll(); @@ -221,6 +244,7 @@ interface ICache { * likely the folder where we stopped scanning previously * * @return string|bool the path of the folder or false when no folder matched + * @since 9.0.0 */ public function getIncomplete(); @@ -229,6 +253,7 @@ interface ICache { * * @param int $id the file id of the file or folder to search * @return string|null the path of the file (relative to the storage) or null if a file with the given id does not exists within this cache + * @since 9.0.0 */ public function getPathById($id); @@ -237,6 +262,7 @@ interface ICache { * * @param string $path * @return string + * @since 9.0.0 */ public function normalize($path); } diff --git a/lib/public/files/cache/icacheentry.php b/lib/public/files/cache/icacheentry.php index 62b25ebc28..8d14bd2c55 100644 --- a/lib/public/files/cache/icacheentry.php +++ b/lib/public/files/cache/icacheentry.php @@ -23,12 +23,15 @@ namespace OCP\Files\Cache; /** * meta data for a file or folder + * + * @since 9.0.0 */ interface ICacheEntry { /** * Get the numeric id of a file * * @return int + * @since 9.0.0 */ public function getId(); @@ -36,6 +39,7 @@ interface ICacheEntry { * Get the numeric id for the storage * * @return int + * @since 9.0.0 */ public function getStorageId(); @@ -43,6 +47,7 @@ interface ICacheEntry { * Get the path of the file relative to the storage root * * @return string + * @since 9.0.0 */ public function getPath(); @@ -50,6 +55,7 @@ interface ICacheEntry { * Get the file name * * @return string + * @since 9.0.0 */ public function getName(); @@ -57,6 +63,7 @@ interface ICacheEntry { * Get the full mimetype * * @return string + * @since 9.0.0 */ public function getMimeType(); @@ -64,6 +71,7 @@ interface ICacheEntry { * Get the first part of the mimetype * * @return string + * @since 9.0.0 */ public function getMimePart(); @@ -71,6 +79,7 @@ interface ICacheEntry { * Get the file size in bytes * * @return int + * @since 9.0.0 */ public function getSize(); @@ -78,6 +87,7 @@ interface ICacheEntry { * Get the last modified date as unix timestamp * * @return int + * @since 9.0.0 */ public function getMTime(); @@ -88,6 +98,7 @@ interface ICacheEntry { * This can differ from the mtime on the underlying storage which usually only changes when a direct child is added, removed or renamed * * @return int + * @since 9.0.0 */ public function getStorageMTime(); @@ -98,6 +109,7 @@ interface ICacheEntry { * Etag for folders change whenever a file in the folder has changed * * @return string + * @since 9.0.0 */ public function getEtag(); @@ -106,6 +118,7 @@ interface ICacheEntry { * \OCP\PERMISSION_UPDATE, \OCP\PERMISSION_DELETE and \OCP\PERMISSION_SHARE * * @return int + * @since 9.0.0 */ public function getPermissions(); @@ -113,6 +126,7 @@ interface ICacheEntry { * Check if the file is encrypted * * @return bool + * @since 9.0.0 */ public function isEncrypted(); } diff --git a/lib/public/files/cache/ipropagator.php b/lib/public/files/cache/ipropagator.php index 90bdf9af53..7f7dbada53 100644 --- a/lib/public/files/cache/ipropagator.php +++ b/lib/public/files/cache/ipropagator.php @@ -23,12 +23,15 @@ namespace OCP\Files\Cache; /** * Propagate etags and mtimes within the storage + * + * @since 9.0.0 */ interface IPropagator { /** * @param string $internalPath * @param int $time * @return array[] all propagated cache entries + * @since 9.0.0 */ public function propagateChange($internalPath, $time); } diff --git a/lib/public/files/cache/iscanner.php b/lib/public/files/cache/iscanner.php index 7aa3fb1605..6f7309d01e 100644 --- a/lib/public/files/cache/iscanner.php +++ b/lib/public/files/cache/iscanner.php @@ -23,6 +23,8 @@ namespace OCP\Files\Cache; /** * Scan files form the storage and save to the cache + * + * @since 9.0.0 */ interface IScanner { const SCAN_RECURSIVE = true; @@ -42,6 +44,7 @@ interface IScanner { * @return array an array of metadata of the scanned file * @throws \OC\ServerNotAvailableException * @throws \OCP\Lock\LockedException + * @since 9.0.0 */ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true); @@ -53,6 +56,7 @@ interface IScanner { * @param int $reuse * @param bool $lock set to false to disable getting an additional read lock during scanning * @return array an array of the meta data of the scanned file or folder + * @since 9.0.0 */ public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $lock = true); @@ -63,11 +67,14 @@ interface IScanner { * * @param string $file * @return boolean + * @since 9.0.0 */ public static function isPartialFile($file); /** * walk over any folders that are not fully scanned yet and scan them + * + * @since 9.0.0 */ public function backgroundScan(); } diff --git a/lib/public/files/cache/iupdater.php b/lib/public/files/cache/iupdater.php index cf2b471053..074447cc9e 100644 --- a/lib/public/files/cache/iupdater.php +++ b/lib/public/files/cache/iupdater.php @@ -25,12 +25,14 @@ use OCP\Files\Storage; /** * Update the cache and propagate changes * + * @since 9.0.0 */ interface IUpdater { /** * Get the propagator for etags and mtime for the view the updater works on * * @return IPropagator + * @since 9.0.0 */ public function getPropagator(); @@ -39,6 +41,7 @@ interface IUpdater { * * @param string $path the path of the file to propagate the changes for * @param int|null $time the timestamp to set as mtime for the parent folders, if left out the current time is used + * @since 9.0.0 */ public function propagate($path, $time = null); @@ -47,6 +50,7 @@ interface IUpdater { * * @param string $path * @param int $time + * @since 9.0.0 */ public function update($path, $time = null); @@ -54,6 +58,7 @@ interface IUpdater { * Remove $path from the cache and update the size, etag and mtime of the parent folders * * @param string $path + * @since 9.0.0 */ public function remove($path); @@ -63,6 +68,7 @@ interface IUpdater { * @param \OCP\Files\Storage $sourceStorage * @param string $source * @param string $target + * @since 9.0.0 */ public function renameFromStorage(Storage $sourceStorage, $source, $target); } diff --git a/lib/public/files/cache/iwatcher.php b/lib/public/files/cache/iwatcher.php index f9695f6585..a61975036f 100644 --- a/lib/public/files/cache/iwatcher.php +++ b/lib/public/files/cache/iwatcher.php @@ -23,6 +23,8 @@ namespace OCP\Files\Cache; /** * check the storage backends for updates and change the cache accordingly + * + * @since 9.0.0 */ interface IWatcher { const CHECK_NEVER = 0; // never check the underlying filesystem for updates @@ -31,11 +33,13 @@ interface IWatcher { /** * @param int $policy either IWatcher::CHECK_NEVER, IWatcher::CHECK_ONCE, IWatcher::CHECK_ALWAYS + * @since 9.0.0 */ public function setPolicy($policy); /** * @return int either IWatcher::CHECK_NEVER, IWatcher::CHECK_ONCE, IWatcher::CHECK_ALWAYS + * @since 9.0.0 */ public function getPolicy(); @@ -45,6 +49,7 @@ interface IWatcher { * @param string $path * @param ICacheEntry|null $cachedEntry * @return boolean true if path was updated + * @since 9.0.0 */ public function checkUpdate($path, $cachedEntry = null); @@ -53,6 +58,7 @@ interface IWatcher { * * @param string $path * @param ICacheEntry $cachedData + * @since 9.0.0 */ public function update($path, $cachedData); @@ -62,6 +68,7 @@ interface IWatcher { * @param string $path * @param ICacheEntry $cachedData * @return bool + * @since 9.0.0 */ public function needsUpdate($path, $cachedData); @@ -69,6 +76,7 @@ interface IWatcher { * remove deleted files in $path from the cache * * @param string $path + * @since 9.0.0 */ public function cleanFolder($path); } diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index 85cd05a1ee..d3eb67975b 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -476,26 +476,31 @@ interface Storage { /** * @return ICache + * @since 9.0.0 */ public function getCache(); /** * @return IPropagator + * @since 9.0.0 */ public function getPropagator(); /** * @return IScanner + * @since 9.0.0 */ public function getScanner(); /** * @return IUpdater + * @since 9.0.0 */ public function getUpdater(); /** * @return IWatcher + * @since 9.0.0 */ public function getWatcher(); } From 62d383e1ba70b85c488bf72c83d2b117476b100b Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 15:20:12 +0100 Subject: [PATCH 11/17] fix tests --- tests/lib/files/cache/cache.php | 2 +- tests/lib/files/cache/scanner.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/lib/files/cache/cache.php b/tests/lib/files/cache/cache.php index d674ac27fa..de4ae9cd8e 100644 --- a/tests/lib/files/cache/cache.php +++ b/tests/lib/files/cache/cache.php @@ -556,7 +556,7 @@ class Cache extends \Test\TestCase { $this->assertEquals($folderWith00F6, $unNormalizedFolderName['name']); // put normalized folder - $this->assertTrue(is_array($this->cache->get('folder/' . $folderWith00F6))); + $this->assertInstanceOf('\OCP\Files\Cache\ICacheEntry', $this->cache->get('folder/' . $folderWith00F6)); $this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith00F6, $data)); // at this point we should have only one folder named "Schön" diff --git a/tests/lib/files/cache/scanner.php b/tests/lib/files/cache/scanner.php index 8186fe2949..b1eb3f589e 100644 --- a/tests/lib/files/cache/scanner.php +++ b/tests/lib/files/cache/scanner.php @@ -7,6 +7,7 @@ */ namespace Test\Files\Cache; +use OC\Files\Cache\CacheEntry; /** * Class Scanner @@ -226,6 +227,7 @@ class Scanner extends \Test\TestCase { // manipulate etag to simulate an empty etag $this->scanner->scan('', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG); + /** @var CacheEntry $data0 */ $data0 = $this->cache->get('folder/bar.txt'); $this->assertInternalType('string', $data0['etag']); $data1 = $this->cache->get('folder'); @@ -233,7 +235,7 @@ class Scanner extends \Test\TestCase { $data2 = $this->cache->get(''); $this->assertInternalType('string', $data2['etag']); $data0['etag'] = ''; - $this->cache->put('folder/bar.txt', $data0); + $this->cache->put('folder/bar.txt', $data0->getData()); // rescan $this->scanner->scan('folder/bar.txt', \OC\Files\Cache\Scanner::SCAN_SHALLOW, \OC\Files\Cache\Scanner::REUSE_ETAG); From d2c579e16772cb6666d95d484b9aa11764217a0a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 15:28:49 +0100 Subject: [PATCH 12/17] fix quota wrapper --- lib/private/files/storage/wrapper/quota.php | 4 +++- tests/lib/files/storage/wrapper/quota.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/private/files/storage/wrapper/quota.php b/lib/private/files/storage/wrapper/quota.php index 55c826092c..844505679d 100644 --- a/lib/private/files/storage/wrapper/quota.php +++ b/lib/private/files/storage/wrapper/quota.php @@ -25,6 +25,8 @@ namespace OC\Files\Storage\Wrapper; +use OCP\Files\Cache\ICacheEntry; + class Quota extends Wrapper { /** @@ -64,7 +66,7 @@ class Quota extends Wrapper { $cache = $storage->getCache(); } $data = $cache->get($path); - if (is_array($data) and isset($data['size'])) { + if ($data instanceof ICacheEntry and isset($data['size'])) { return $data['size']; } else { return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED; diff --git a/tests/lib/files/storage/wrapper/quota.php b/tests/lib/files/storage/wrapper/quota.php index 95bc2ff7a1..d087a3eef3 100644 --- a/tests/lib/files/storage/wrapper/quota.php +++ b/tests/lib/files/storage/wrapper/quota.php @@ -9,6 +9,8 @@ namespace Test\Files\Storage\Wrapper; //ensure the constants are loaded +use OC\Files\Cache\CacheEntry; + \OC::$loader->load('\OC\Files\Filesystem'); /** @@ -194,7 +196,7 @@ class Quota extends \Test\Files\Storage\Storage { $cache->expects($this->once()) ->method('get') ->with('files') - ->will($this->returnValue(array('size' => 50))); + ->will($this->returnValue(new CacheEntry(['size' => 50]))); $instance = new \OC\Files\Storage\Wrapper\Quota(array('storage' => $storage, 'quota' => 1024, 'root' => 'files')); From e77e76fef4e55df2ff68b28934ced8b5b110e971 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 2 Dec 2015 15:38:17 +0100 Subject: [PATCH 13/17] fix object store storage --- lib/private/files/objectstore/objectstorestorage.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/private/files/objectstore/objectstorestorage.php b/lib/private/files/objectstore/objectstorestorage.php index 9cea07b7f6..35c2c19c75 100644 --- a/lib/private/files/objectstore/objectstorestorage.php +++ b/lib/private/files/objectstore/objectstorestorage.php @@ -25,6 +25,7 @@ namespace OC\Files\ObjectStore; use Icewind\Streams\IteratorDirectory; +use OC\Files\Cache\CacheEntry; use OCP\Files\ObjectStore\IObjectStore; class ObjectStoreStorage extends \OC\Files\Storage\Common { @@ -192,7 +193,12 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common { public function stat($path) { $path = $this->normalizePath($path); - return $this->getCache()->get($path); + $cacheEntry = $this->getCache()->get($path); + if ($cacheEntry instanceof CacheEntry) { + return $cacheEntry->getData(); + } else { + return false; + } } /** From 3deb3bd16399cd7e23a02b45c66e32495dbfda0d Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 4 Dec 2015 14:26:47 +0100 Subject: [PATCH 14/17] Add IStorage interface for consistent naming minor phpdoc fixed --- lib/private/files/cache/updater.php | 5 +- lib/public/files/cache/iscanner.php | 4 +- lib/public/files/cache/iupdater.php | 7 +- lib/public/files/storage.php | 48 +-- lib/public/files/storage/istorage.php | 509 ++++++++++++++++++++++++++ 5 files changed, 523 insertions(+), 50 deletions(-) create mode 100644 lib/public/files/storage/istorage.php diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php index 12ff802dd5..58d8e53cfd 100644 --- a/lib/private/files/cache/updater.php +++ b/lib/private/files/cache/updater.php @@ -25,6 +25,7 @@ namespace OC\Files\Cache; use OCP\Files\Cache\IUpdater; +use OCP\Files\Storage\IStorage; /** * Update the cache and propagate changes @@ -146,11 +147,11 @@ class Updater implements IUpdater { /** * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders * - * @param \OCP\Files\Storage $sourceStorage + * @param IStorage $sourceStorage * @param string $source * @param string $target */ - public function renameFromStorage(\OCP\Files\Storage $sourceStorage, $source, $target) { + public function renameFromStorage(IStorage $sourceStorage, $source, $target) { if (!$this->enabled or Scanner::isPartialFile($source) or Scanner::isPartialFile($target)) { return; } diff --git a/lib/public/files/cache/iscanner.php b/lib/public/files/cache/iscanner.php index 6f7309d01e..47e33a98ba 100644 --- a/lib/public/files/cache/iscanner.php +++ b/lib/public/files/cache/iscanner.php @@ -22,7 +22,7 @@ namespace OCP\Files\Cache; /** - * Scan files form the storage and save to the cache + * Scan files from the storage and save to the cache * * @since 9.0.0 */ @@ -49,7 +49,7 @@ interface IScanner { public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true); /** - * scan a folder and all it's children + * scan a folder and all its children * * @param string $path * @param bool $recursive diff --git a/lib/public/files/cache/iupdater.php b/lib/public/files/cache/iupdater.php index 074447cc9e..241cd8636a 100644 --- a/lib/public/files/cache/iupdater.php +++ b/lib/public/files/cache/iupdater.php @@ -20,7 +20,8 @@ */ namespace OCP\Files\Cache; -use OCP\Files\Storage; + +use OCP\Files\Storage\IStorage; /** * Update the cache and propagate changes @@ -65,10 +66,10 @@ interface IUpdater { /** * Rename a file or folder in the cache and update the size, etag and mtime of the parent folders * - * @param \OCP\Files\Storage $sourceStorage + * @param IStorage $sourceStorage * @param string $source * @param string $target * @since 9.0.0 */ - public function renameFromStorage(Storage $sourceStorage, $source, $target); + public function renameFromStorage(IStorage $sourceStorage, $source, $target); } diff --git a/lib/public/files/storage.php b/lib/public/files/storage.php index d3eb67975b..1c12522144 100644 --- a/lib/public/files/storage.php +++ b/lib/public/files/storage.php @@ -33,21 +33,19 @@ // use OCP namespace for all classes that are considered public. // This means that they should be used by apps instead of the internal ownCloud classes namespace OCP\Files; -use OCP\Files\Cache\ICache; -use OCP\Files\Cache\IPropagator; -use OCP\Files\Cache\IScanner; -use OCP\Files\Cache\IUpdater; -use OCP\Files\Cache\IWatcher; -use OCP\Files\InvalidPathException; + +use OCP\Files\Storage\IStorage; use OCP\Lock\ILockingProvider; /** * Provide a common interface to all different storage options * * All paths passed to the storage are relative to the storage and should NOT have a leading slash. + * * @since 6.0.0 + * @deprecated 9.0.0 use \OCP\Files\Storage\IStorage instead */ -interface Storage { +interface Storage extends IStorage { /** * $parameters is a free form array with the configuration options needed to construct the storage * @@ -467,40 +465,4 @@ interface Storage { * @param bool $isAvailable */ public function setAvailability($isAvailable); - - /** - * @param string $path path for which to retrieve the owner - * @since 9.0.0 - */ - public function getOwner($path); - - /** - * @return ICache - * @since 9.0.0 - */ - public function getCache(); - - /** - * @return IPropagator - * @since 9.0.0 - */ - public function getPropagator(); - - /** - * @return IScanner - * @since 9.0.0 - */ - public function getScanner(); - - /** - * @return IUpdater - * @since 9.0.0 - */ - public function getUpdater(); - - /** - * @return IWatcher - * @since 9.0.0 - */ - public function getWatcher(); } diff --git a/lib/public/files/storage/istorage.php b/lib/public/files/storage/istorage.php new file mode 100644 index 0000000000..377bb96ea2 --- /dev/null +++ b/lib/public/files/storage/istorage.php @@ -0,0 +1,509 @@ + + * @author Michael Roth + * @author Morris Jobke + * @author Robin Appelman + * @author Robin McCorkell + * @author Thomas Müller + * @author Vincent Petry + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +/** + * Public interface of ownCloud for apps to use. + * Files/Storage interface + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Files\Storage; + +use OCP\Files\Cache\ICache; +use OCP\Files\Cache\IPropagator; +use OCP\Files\Cache\IScanner; +use OCP\Files\Cache\IUpdater; +use OCP\Files\Cache\IWatcher; +use OCP\Files\InvalidPathException; +use OCP\Lock\ILockingProvider; + +/** + * Provide a common interface to all different storage options + * + * All paths passed to the storage are relative to the storage and should NOT have a leading slash. + * + * @since 9.0.0 + */ +interface IStorage { + /** + * $parameters is a free form array with the configuration options needed to construct the storage + * + * @param array $parameters + * @since 9.0.0 + */ + public function __construct($parameters); + + /** + * Get the identifier for the storage, + * the returned id should be the same for every storage object that is created with the same parameters + * and two storage objects with the same id should refer to two storages that display the same files. + * + * @return string + * @since 9.0.0 + */ + public function getId(); + + /** + * see http://php.net/manual/en/function.mkdir.php + * implementations need to implement a recursive mkdir + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function mkdir($path); + + /** + * see http://php.net/manual/en/function.rmdir.php + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function rmdir($path); + + /** + * see http://php.net/manual/en/function.opendir.php + * + * @param string $path + * @return resource|false + * @since 9.0.0 + */ + public function opendir($path); + + /** + * see http://php.net/manual/en/function.is-dir.php + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function is_dir($path); + + /** + * see http://php.net/manual/en/function.is-file.php + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function is_file($path); + + /** + * see http://php.net/manual/en/function.stat.php + * only the following keys are required in the result: size and mtime + * + * @param string $path + * @return array|false + * @since 9.0.0 + */ + public function stat($path); + + /** + * see http://php.net/manual/en/function.filetype.php + * + * @param string $path + * @return string|false + * @since 9.0.0 + */ + public function filetype($path); + + /** + * see http://php.net/manual/en/function.filesize.php + * The result for filesize when called on a folder is required to be 0 + * + * @param string $path + * @return int|false + * @since 9.0.0 + */ + public function filesize($path); + + /** + * check if a file can be created in $path + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function isCreatable($path); + + /** + * check if a file can be read + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function isReadable($path); + + /** + * check if a file can be written to + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function isUpdatable($path); + + /** + * check if a file can be deleted + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function isDeletable($path); + + /** + * check if a file can be shared + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function isSharable($path); + + /** + * get the full permissions of a path. + * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php + * + * @param string $path + * @return int + * @since 9.0.0 + */ + public function getPermissions($path); + + /** + * see http://php.net/manual/en/function.file_exists.php + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function file_exists($path); + + /** + * see http://php.net/manual/en/function.filemtime.php + * + * @param string $path + * @return int|false + * @since 9.0.0 + */ + public function filemtime($path); + + /** + * see http://php.net/manual/en/function.file_get_contents.php + * + * @param string $path + * @return string|false + * @since 9.0.0 + */ + public function file_get_contents($path); + + /** + * see http://php.net/manual/en/function.file_put_contents.php + * + * @param string $path + * @param string $data + * @return bool + * @since 9.0.0 + */ + public function file_put_contents($path, $data); + + /** + * see http://php.net/manual/en/function.unlink.php + * + * @param string $path + * @return bool + * @since 9.0.0 + */ + public function unlink($path); + + /** + * see http://php.net/manual/en/function.rename.php + * + * @param string $path1 + * @param string $path2 + * @return bool + * @since 9.0.0 + */ + public function rename($path1, $path2); + + /** + * see http://php.net/manual/en/function.copy.php + * + * @param string $path1 + * @param string $path2 + * @return bool + * @since 9.0.0 + */ + public function copy($path1, $path2); + + /** + * see http://php.net/manual/en/function.fopen.php + * + * @param string $path + * @param string $mode + * @return resource|false + * @since 9.0.0 + */ + public function fopen($path, $mode); + + /** + * get the mimetype for a file or folder + * The mimetype for a folder is required to be "httpd/unix-directory" + * + * @param string $path + * @return string|false + * @since 9.0.0 + */ + public function getMimeType($path); + + /** + * see http://php.net/manual/en/function.hash-file.php + * + * @param string $type + * @param string $path + * @param bool $raw + * @return string|false + * @since 9.0.0 + */ + public function hash($type, $path, $raw = false); + + /** + * see http://php.net/manual/en/function.free_space.php + * + * @param string $path + * @return int|false + * @since 9.0.0 + */ + public function free_space($path); + + /** + * search for occurrences of $query in file names + * + * @param string $query + * @return array|false + * @since 9.0.0 + */ + public function search($query); + + /** + * see http://php.net/manual/en/function.touch.php + * If the backend does not support the operation, false should be returned + * + * @param string $path + * @param int $mtime + * @return bool + * @since 9.0.0 + */ + public function touch($path, $mtime = null); + + /** + * get the path to a local version of the file. + * The local version of the file can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string|false + * @since 9.0.0 + */ + public function getLocalFile($path); + + /** + * get the path to a local version of the folder. + * The local version of the folder can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string|false + * @since 9.0.0 + */ + public function getLocalFolder($path); + + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + * @since 9.0.0 + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + public function hasUpdated($path, $time); + + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string|false + * @since 9.0.0 + */ + public function getETag($path); + + /** + * Returns whether the storage is local, which means that files + * are stored on the local filesystem instead of remotely. + * Calling getLocalFile() for local storages should always + * return the local files, whereas for non-local storages + * it might return a temporary file. + * + * @return bool true if the files are stored locally, false otherwise + * @since 9.0.0 + */ + public function isLocal(); + + /** + * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class + * + * @param string $class + * @return bool + * @since 9.0.0 + */ + public function instanceOfStorage($class); + + /** + * A custom storage implementation can return an url for direct download of a give file. + * + * For now the returned array can hold the parameter url - in future more attributes might follow. + * + * @param string $path + * @return array|false + * @since 9.0.0 + */ + public function getDirectDownload($path); + + /** + * @param string $path the path of the target folder + * @param string $fileName the name of the file itself + * @return void + * @throws InvalidPathException + * @since 9.0.0 + */ + public function verifyPath($path, $fileName); + + /** + * @param \OCP\Files\Storage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + * @since 9.0.0 + */ + public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath); + + /** + * @param \OCP\Files\Storage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + * @since 9.0.0 + */ + public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath); + + /** + * @param string $path The path of the file to acquire the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @throws \OCP\Lock\LockedException + * @since 9.0.0 + */ + public function acquireLock($path, $type, ILockingProvider $provider); + + /** + * @param string $path The path of the file to acquire the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @since 9.0.0 + */ + public function releaseLock($path, $type, ILockingProvider $provider); + + /** + * @param string $path The path of the file to change the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @throws \OCP\Lock\LockedException + * @since 9.0.0 + */ + public function changeLock($path, $type, ILockingProvider $provider); + + /** + * Test a storage for availability + * + * @since 9.0.0 + * @return bool + */ + public function test(); + + /** + * @since 9.0.0 + * @return array [ available, last_checked ] + */ + public function getAvailability(); + + /** + * @since 9.0.0 + * @param bool $isAvailable + */ + public function setAvailability($isAvailable); + + /** + * @param string $path path for which to retrieve the owner + * @since 9.0.0 + */ + public function getOwner($path); + + /** + * @return ICache + * @since 9.0.0 + */ + public function getCache(); + + /** + * @return IPropagator + * @since 9.0.0 + */ + public function getPropagator(); + + /** + * @return IScanner + * @since 9.0.0 + */ + public function getScanner(); + + /** + * @return IUpdater + * @since 9.0.0 + */ + public function getUpdater(); + + /** + * @return IWatcher + * @since 9.0.0 + */ + public function getWatcher(); +} From 0724ac1e5ed83926ed9cbbb8c660b40ef1254da8 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 4 Jan 2016 14:07:03 +0100 Subject: [PATCH 15/17] split locking related methods to their own interface --- lib/private/files/storage/common.php | 3 +- lib/public/files/storage/ilockingstorage.php | 60 ++++++++++++++++++++ lib/public/files/storage/istorage.php | 27 --------- 3 files changed, 62 insertions(+), 28 deletions(-) create mode 100644 lib/public/files/storage/ilockingstorage.php diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index c27f9d759f..95bb3f74ba 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -46,6 +46,7 @@ use OCP\Files\FileNameTooLongException; use OCP\Files\InvalidCharacterInPathException; use OCP\Files\InvalidPathException; use OCP\Files\ReservedWordException; +use OCP\Files\Storage\ILockingStorage; use OCP\Lock\ILockingProvider; /** @@ -59,7 +60,7 @@ use OCP\Lock\ILockingProvider; * Some \OC\Files\Storage\Common methods call functions which are first defined * in classes which extend it, e.g. $this->stat() . */ -abstract class Common implements Storage { +abstract class Common implements Storage, ILockingStorage { use LocalTempFileTrait; diff --git a/lib/public/files/storage/ilockingstorage.php b/lib/public/files/storage/ilockingstorage.php new file mode 100644 index 0000000000..32cc32ffb0 --- /dev/null +++ b/lib/public/files/storage/ilockingstorage.php @@ -0,0 +1,60 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCP\Files\Storage; + +use OCP\Lock\ILockingProvider; + +/** + * Storage backends that require explicit locking + * + * Storage backends implementing this interface do not need to implement their own locking implementation but should use the provided lockingprovider instead + * The implementation of the locking methods only need to map internal storage paths to "lock keys" + * + * @since 9.0.0 + */ +interface ILockingStorage { + /** + * @param string $path The path of the file to acquire the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @throws \OCP\Lock\LockedException + * @since 9.0.0 + */ + public function acquireLock($path, $type, ILockingProvider $provider); + + /** + * @param string $path The path of the file to acquire the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @since 9.0.0 + */ + public function releaseLock($path, $type, ILockingProvider $provider); + + /** + * @param string $path The path of the file to change the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @throws \OCP\Lock\LockedException + * @since 9.0.0 + */ + public function changeLock($path, $type, ILockingProvider $provider); +} diff --git a/lib/public/files/storage/istorage.php b/lib/public/files/storage/istorage.php index 377bb96ea2..4bc5e3536d 100644 --- a/lib/public/files/storage/istorage.php +++ b/lib/public/files/storage/istorage.php @@ -40,7 +40,6 @@ use OCP\Files\Cache\IScanner; use OCP\Files\Cache\IUpdater; use OCP\Files\Cache\IWatcher; use OCP\Files\InvalidPathException; -use OCP\Lock\ILockingProvider; /** * Provide a common interface to all different storage options @@ -425,32 +424,6 @@ interface IStorage { */ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath); - /** - * @param string $path The path of the file to acquire the lock for - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - * @throws \OCP\Lock\LockedException - * @since 9.0.0 - */ - public function acquireLock($path, $type, ILockingProvider $provider); - - /** - * @param string $path The path of the file to acquire the lock for - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - * @since 9.0.0 - */ - public function releaseLock($path, $type, ILockingProvider $provider); - - /** - * @param string $path The path of the file to change the lock for - * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE - * @param \OCP\Lock\ILockingProvider $provider - * @throws \OCP\Lock\LockedException - * @since 9.0.0 - */ - public function changeLock($path, $type, ILockingProvider $provider); - /** * Test a storage for availability * From bdf51d9ea4a3fb3e6b0e3d019ed06ca0d9cb3d3a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 4 Jan 2016 14:11:21 +0100 Subject: [PATCH 16/17] only trigger locking on lockingstorages --- lib/private/files/cache/scanner.php | 17 ++++++-- lib/private/files/storage/wrapper/wrapper.php | 15 +++++-- lib/private/files/view.php | 41 +++++++++++-------- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/lib/private/files/cache/scanner.php b/lib/private/files/cache/scanner.php index 9215114937..743b50f54a 100644 --- a/lib/private/files/cache/scanner.php +++ b/lib/private/files/cache/scanner.php @@ -38,6 +38,7 @@ use OC\Files\Filesystem; use OC\Hooks\BasicEmitter; use OCP\Config; use OCP\Files\Cache\IScanner; +use OCP\Files\Storage\ILockingStorage; use OCP\Lock\ILockingProvider; /** @@ -132,7 +133,9 @@ class Scanner extends BasicEmitter implements IScanner { and !Filesystem::isFileBlacklisted($file) ) { if ($lock) { - $this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); + if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $this->storage->acquireLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); + } } $this->emit('\OC\Files\Cache\Scanner', 'scanFile', array($file, $this->storageId)); \OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId)); @@ -192,7 +195,9 @@ class Scanner extends BasicEmitter implements IScanner { $this->removeFromCache($file); } if ($lock) { - $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); + if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $this->storage->releaseLock($file, ILockingProvider::LOCK_SHARED, $this->lockingProvider); + } } return $data; } @@ -259,7 +264,9 @@ class Scanner extends BasicEmitter implements IScanner { $reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG; } if ($lock) { - $this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); + if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $this->storage->acquireLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); + } } $data = $this->scanFile($path, $reuse, -1, null, $lock); if ($data and $data['mimetype'] === 'httpd/unix-directory') { @@ -267,7 +274,9 @@ class Scanner extends BasicEmitter implements IScanner { $data['size'] = $size; } if ($lock) { - $this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); + if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $this->storage->releaseLock($path, ILockingProvider::LOCK_SHARED, $this->lockingProvider); + } } return $data; } diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php index 472c60b5fa..c632aa399e 100644 --- a/lib/private/files/storage/wrapper/wrapper.php +++ b/lib/private/files/storage/wrapper/wrapper.php @@ -26,9 +26,10 @@ namespace OC\Files\Storage\Wrapper; use OCP\Files\InvalidPathException; +use OCP\Files\Storage\ILockingStorage; use OCP\Lock\ILockingProvider; -class Wrapper implements \OC\Files\Storage\Storage { +class Wrapper implements \OC\Files\Storage\Storage, ILockingStorage { /** * @var \OC\Files\Storage\Storage $storage */ @@ -583,7 +584,9 @@ class Wrapper implements \OC\Files\Storage\Storage { * @throws \OCP\Lock\LockedException */ public function acquireLock($path, $type, ILockingProvider $provider) { - $this->storage->acquireLock($path, $type, $provider); + if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $this->storage->acquireLock($path, $type, $provider); + } } /** @@ -592,7 +595,9 @@ class Wrapper implements \OC\Files\Storage\Storage { * @param \OCP\Lock\ILockingProvider $provider */ public function releaseLock($path, $type, ILockingProvider $provider) { - $this->storage->releaseLock($path, $type, $provider); + if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $this->storage->releaseLock($path, $type, $provider); + } } /** @@ -601,6 +606,8 @@ class Wrapper implements \OC\Files\Storage\Storage { * @param \OCP\Lock\ILockingProvider $provider */ public function changeLock($path, $type, ILockingProvider $provider) { - $this->storage->changeLock($path, $type, $provider); + if ($this->storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $this->storage->changeLock($path, $type, $provider); + } } } diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 6f8a6db9f9..55b8da165e 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -43,7 +43,6 @@ namespace OC\Files; use Icewind\Streams\CallbackWrapper; -use OC\Files\Cache\Updater; use OC\Files\Mount\MoveableMount; use OC\Files\Storage\Storage; use OC\User\User; @@ -53,6 +52,7 @@ use OCP\Files\InvalidCharacterInPathException; use OCP\Files\InvalidPathException; use OCP\Files\NotFoundException; use OCP\Files\ReservedWordException; +use OCP\Files\Storage\ILockingStorage; use OCP\IUser; use OCP\Lock\ILockingProvider; use OCP\Lock\LockedException; @@ -1835,11 +1835,14 @@ class View { $mount = $this->getMountForLock($absolutePath, $lockMountPoint); if ($mount) { try { - $mount->getStorage()->acquireLock( - $mount->getInternalPath($absolutePath), - $type, - $this->lockingProvider - ); + $storage = $mount->getStorage(); + if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $storage->acquireLock( + $mount->getInternalPath($absolutePath), + $type, + $this->lockingProvider + ); + } } catch (\OCP\Lock\LockedException $e) { // rethrow with the a human-readable path throw new \OCP\Lock\LockedException( @@ -1873,11 +1876,14 @@ class View { $mount = $this->getMountForLock($absolutePath, $lockMountPoint); if ($mount) { try { - $mount->getStorage()->changeLock( - $mount->getInternalPath($absolutePath), - $type, - $this->lockingProvider - ); + $storage = $mount->getStorage(); + if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $storage->changeLock( + $mount->getInternalPath($absolutePath), + $type, + $this->lockingProvider + ); + } } catch (\OCP\Lock\LockedException $e) { // rethrow with the a human-readable path throw new \OCP\Lock\LockedException( @@ -1908,11 +1914,14 @@ class View { $mount = $this->getMountForLock($absolutePath, $lockMountPoint); if ($mount) { - $mount->getStorage()->releaseLock( - $mount->getInternalPath($absolutePath), - $type, - $this->lockingProvider - ); + $storage = $mount->getStorage(); + if ($storage->instanceOfStorage('\OCP\Files\Storage\ILockingStorage')) { + $storage->releaseLock( + $mount->getInternalPath($absolutePath), + $type, + $this->lockingProvider + ); + } } return true; From 7530f66f52308cb2f24478495fcffdd44ce3db41 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Mon, 4 Jan 2016 14:11:29 +0100 Subject: [PATCH 17/17] remove unneeded public cache methods --- lib/public/files/cache/icache.php | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/lib/public/files/cache/icache.php b/lib/public/files/cache/icache.php index add2b9791e..07396db458 100644 --- a/lib/public/files/cache/icache.php +++ b/lib/public/files/cache/icache.php @@ -209,25 +209,6 @@ interface ICache { */ public function searchByTag($tag, $userId); - /** - * Re-calculate the folder size and the size of all parent folders - * - * @param string|boolean $path - * @param array $data (optional) meta data of the folder - * @since 9.0.0 - */ - public function correctFolderSize($path, $data = null); - - /** - * calculate the size of a folder and set it in the cache - * - * @param string $path - * @param array $entry (optional) meta data of the folder - * @return int - * @since 9.0.0 - */ - public function calculateFolderSize($path, $entry = null); - /** * get all file ids on the files on the storage *