summaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
authorRobin Appelman <icewind@owncloud.com>2015-11-10 16:14:08 +0100
committerRobin Appelman <icewind@owncloud.com>2015-11-19 13:32:00 +0100
commit888df3933df7f3588de11085035d2d3ae9292fb0 (patch)
treeb7976666e9249b0be163b57fb064f3a1ade26919 /lib/private
parentd006a7c723e4c51a4132b0f8817392bf1f3cd534 (diff)
downloadnextcloud-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.php16
-rw-r--r--lib/private/files/cache/changepropagator.php24
-rw-r--r--lib/private/files/cache/propagator.php66
-rw-r--r--lib/private/files/fileinfo.php27
-rw-r--r--lib/private/files/storage/common.php18
-rw-r--r--lib/private/files/storage/storage.php8
-rw-r--r--lib/private/files/storage/wrapper/wrapper.php7
-rw-r--r--lib/private/files/view.php13
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