diff options
author | Robin Appelman <icewind@owncloud.com> | 2015-11-10 16:14:08 +0100 |
---|---|---|
committer | Robin Appelman <icewind@owncloud.com> | 2015-11-19 13:32:00 +0100 |
commit | 888df3933df7f3588de11085035d2d3ae9292fb0 (patch) | |
tree | b7976666e9249b0be163b57fb064f3a1ade26919 /lib/private | |
parent | d006a7c723e4c51a4132b0f8817392bf1f3cd534 (diff) | |
download | nextcloud-server-888df3933df7f3588de11085035d2d3ae9292fb0.tar.gz nextcloud-server-888df3933df7f3588de11085035d2d3ae9292fb0.zip |
take the etag of child mounts into account for the folder etag
this replaces shared etag propagation
Diffstat (limited to 'lib/private')
-rw-r--r-- | lib/private/files/cache/cache.php | 16 | ||||
-rw-r--r-- | lib/private/files/cache/changepropagator.php | 24 | ||||
-rw-r--r-- | lib/private/files/cache/propagator.php | 66 | ||||
-rw-r--r-- | lib/private/files/fileinfo.php | 27 | ||||
-rw-r--r-- | lib/private/files/storage/common.php | 18 | ||||
-rw-r--r-- | lib/private/files/storage/storage.php | 8 | ||||
-rw-r--r-- | lib/private/files/storage/wrapper/wrapper.php | 7 | ||||
-rw-r--r-- | lib/private/files/view.php | 13 |
8 files changed, 158 insertions, 21 deletions
diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 40477243324..e6110c1925d 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -160,6 +160,7 @@ class Cache { } else { //fix types $data['fileid'] = (int)$data['fileid']; + $data['parent'] = (int)$data['parent']; $data['size'] = 0 + $data['size']; $data['mtime'] = (int)$data['mtime']; $data['storage_mtime'] = (int)$data['storage_mtime']; @@ -391,12 +392,17 @@ class Cache { if ($file === '') { return -1; } else { - $parent = dirname($file); - if ($parent === '.') { - $parent = ''; - } - return $this->getId($parent); + $parent = $this->getParentPath($file); + return (int) $this->getId($parent); + } + } + + private function getParentPath($path) { + $parent = dirname($path); + if ($parent === '.') { + $parent = ''; } + return $parent; } /** diff --git a/lib/private/files/cache/changepropagator.php b/lib/private/files/cache/changepropagator.php index 9696a82257e..2a48eb13c59 100644 --- a/lib/private/files/cache/changepropagator.php +++ b/lib/private/files/cache/changepropagator.php @@ -22,6 +22,7 @@ namespace OC\Files\Cache; +use OC\Files\Filesystem; use OC\Hooks\BasicEmitter; /** @@ -61,23 +62,30 @@ class ChangePropagator extends BasicEmitter { * @param int $time (optional) the mtime to set for the folders, if not set the current time is used */ public function propagateChanges($time = null) { - $parents = $this->getAllParents(); - $this->changedFiles = array(); + $changes = $this->getChanges(); + $this->changedFiles = []; if (!$time) { $time = time(); } - foreach ($parents as $parent) { + foreach ($changes as $change) { /** * @var \OC\Files\Storage\Storage $storage * @var string $internalPath */ - list($storage, $internalPath) = $this->view->resolvePath($parent); + $absolutePath = $this->view->getAbsolutePath($change); + $mount = $this->view->getMount($change); + $storage = $mount->getStorage(); + $internalPath = $mount->getInternalPath($absolutePath); if ($storage) { - $cache = $storage->getCache(); - $entry = $cache->get($internalPath); - $cache->update($entry['fileid'], array('mtime' => max($time, $entry['mtime']), 'etag' => $storage->getETag($internalPath))); - $this->emit('\OC\Files', 'propagate', [$parent, $entry]); + $propagator = $storage->getPropagator(); + $propagatedEntries = $propagator->propagateChange($internalPath, $time); + + foreach ($propagatedEntries as $entry) { + $absolutePath = Filesystem::normalizePath($mount->getMountPoint() . '/' . $entry['path']); + $relativePath = $this->view->getRelativePath($absolutePath); + $this->emit('\OC\Files', 'propagate', [$relativePath, $entry]); + } } } } diff --git a/lib/private/files/cache/propagator.php b/lib/private/files/cache/propagator.php new file mode 100644 index 00000000000..bd11cef5990 --- /dev/null +++ b/lib/private/files/cache/propagator.php @@ -0,0 +1,66 @@ +<?php +/** + * @author Robin Appelman <icewind@owncloud.com> + * + * @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 <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Files\Cache; + +/** + * Propagate etags and mtimes within the storage + */ +class Propagator { + /** + * @var \OC\Files\Storage\Storage + */ + protected $storage; + + /** + * @param \OC\Files\Storage\Storage $storage + */ + public function __construct(\OC\Files\Storage\Storage $storage) { + $this->storage = $storage; + } + + + /** + * @param string $internalPath + * @param int $time + * @return array[] all propagated entries + */ + public function propagateChange($internalPath, $time) { + $cache = $this->storage->getCache($internalPath); + + $parentId = $cache->getParentId($internalPath); + $propagatedEntries = []; + while ($parentId !== -1) { + $entry = $cache->get($parentId); + $propagatedEntries[] = $entry; + if (!$entry) { + return $propagatedEntries; + } + $mtime = max($time, $entry['mtime']); + + $cache->update($parentId, ['mtime' => $mtime, 'etag' => $this->storage->getETag($entry['path'])]); + + $parentId = $entry['parent']; + } + + return $propagatedEntries; + } +} diff --git a/lib/private/files/fileinfo.php b/lib/private/files/fileinfo.php index 2d2ef325d38..5b5e8697004 100644 --- a/lib/private/files/fileinfo.php +++ b/lib/private/files/fileinfo.php @@ -62,6 +62,11 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { private $owner; /** + * @var string[] + */ + private $childEtags = []; + + /** * @param string|boolean $path * @param Storage\Storage $storage * @param string $internalPath @@ -93,6 +98,8 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { public function offsetGet($offset) { if ($offset === 'type') { return $this->getType(); + } else if ($offset === 'etag') { + return $this->getEtag(); } elseif (isset($this->data[$offset])) { return $this->data[$offset]; } else { @@ -153,7 +160,12 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * @return string */ public function getEtag() { - return $this->data['etag']; + if (count($this->childEtags) > 0) { + $combinedEtag = $this->data['etag'] . '::' . implode('::', $this->childEtags); + return md5($combinedEtag); + } else { + return $this->data['etag']; + } } /** @@ -292,8 +304,19 @@ class FileInfo implements \OCP\Files\FileInfo, \ArrayAccess { * Sets the size, etag and size to for cross-storage childs * * @param array $data cache entry for the child + * @param string $entryPath full path of the child entry */ - public function addSubEntry($data) { + public function addSubEntry($data, $entryPath) { $this->data['size'] += isset($data['size']) ? $data['size'] : 0; + if (isset($data['mtime'])) { + $this->data['mtime'] = max($this->data['mtime'], $data['mtime']); + } + if (isset($data['etag'])) { + // prefix the etag with the relative path of the subentry to propagate etag on mount moves + $relativeEntryPath = substr($entryPath, strlen($this->getPath())); + // attach the permissions to propagate etag on permision changes of submounts + $permissions = isset($data['permissions']) ? $data['permissions'] : 0; + $this->childEtags[] = $relativeEntryPath . '/' . $data['etag'] . $permissions; + } } } diff --git a/lib/private/files/storage/common.php b/lib/private/files/storage/common.php index 77a70226b37..a52e7c35f87 100644 --- a/lib/private/files/storage/common.php +++ b/lib/private/files/storage/common.php @@ -37,6 +37,7 @@ namespace OC\Files\Storage; use OC\Files\Cache\Cache; +use OC\Files\Cache\Propagator; use OC\Files\Cache\Scanner; use OC\Files\Filesystem; use OC\Files\Cache\Watcher; @@ -64,6 +65,7 @@ abstract class Common implements Storage { protected $cache; protected $scanner; protected $watcher; + protected $propagator; protected $storageCache; protected $mountOptions = []; @@ -345,6 +347,22 @@ abstract class Common implements Storage { return $this->watcher; } + /** + * get a propagator instance for the cache + * + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Propagator + */ + public function getPropagator($storage = null) { + if (!$storage) { + $storage = $this; + } + if (!isset($this->propagator)) { + $this->propagator = new Propagator($storage); + } + return $this->propagator; + } + public function getStorageCache($storage = null) { if (!$storage) { $storage = $this; diff --git a/lib/private/files/storage/storage.php b/lib/private/files/storage/storage.php index f46ac544b56..3399c717890 100644 --- a/lib/private/files/storage/storage.php +++ b/lib/private/files/storage/storage.php @@ -68,6 +68,14 @@ interface Storage extends \OCP\Files\Storage { public function getWatcher($path = '', $storage = null); /** + * get a propagator instance for the cache + * + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Propagator + */ + public function getPropagator($storage = null); + + /** * @return \OC\Files\Cache\Storage */ public function getStorageCache(); diff --git a/lib/private/files/storage/wrapper/wrapper.php b/lib/private/files/storage/wrapper/wrapper.php index 048738170db..5327b94211b 100644 --- a/lib/private/files/storage/wrapper/wrapper.php +++ b/lib/private/files/storage/wrapper/wrapper.php @@ -430,6 +430,13 @@ class Wrapper implements \OC\Files\Storage\Storage { return $this->storage->getWatcher($path, $storage); } + public function getPropagator($storage = null) { + if (!$storage) { + $storage = $this; + } + return $this->storage->getPropagator($storage); + } + /** * @return \OC\Files\Cache\Storage */ diff --git a/lib/private/files/view.php b/lib/private/files/view.php index 5f19558a4fc..3ad9d36a384 100644 --- a/lib/private/files/view.php +++ b/lib/private/files/view.php @@ -707,10 +707,6 @@ class View { } else if ($result) { if ($internalPath1 !== '') { // dont do a cache update for moved mounts $this->updater->rename($path1, $path2); - } else { // only do etag propagation - $this->getUpdater()->getPropagator()->addChange($path1); - $this->getUpdater()->getPropagator()->addChange($path2); - $this->getUpdater()->getPropagator()->propagateChanges(); } } @@ -1179,6 +1175,11 @@ class View { } /** + * Get file info from cache + * + * If the file is not in cached it will be scanned + * If the file has changed on storage the cache will be updated + * * @param \OC\Files\Storage\Storage $storage * @param string $internalPath * @param string $relativePath @@ -1266,7 +1267,7 @@ class View { } $subCache = $subStorage->getCache(''); $rootEntry = $subCache->get(''); - $info->addSubEntry($rootEntry); + $info->addSubEntry($rootEntry, $mount->getMountPoint()); } } } @@ -1357,7 +1358,7 @@ class View { $entryName = substr($relativePath, 0, $pos); foreach ($files as &$entry) { if ($entry->getName() === $entryName) { - $entry->addSubEntry($rootEntry); + $entry->addSubEntry($rootEntry, $mountPoint); } } } else { //mountpoint in this folder, add an entry for it |