[Pkg-owncloud-commits] [owncloud] 14/34: Refactor Cache\Updater to work outside of the users home

David Prévot taffit at moszumanska.debian.org
Fri Oct 17 01:32:16 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository owncloud.

commit 45738b6b7ab4bbf42f677f97ca56d8c31d142bd7
Author: Robin Appelman <icewind at owncloud.com>
Date:   Mon Aug 4 14:29:46 2014 +0200

    Refactor Cache\Updater to work outside of the users home
---
 lib/private/files/cache/changepropagator.php |   8 +-
 lib/private/files/cache/updater.php          | 207 +++++++++------------------
 lib/private/files/view.php                   |  69 +++++----
 tests/lib/files/cache/updater.php            |   1 -
 4 files changed, 111 insertions(+), 174 deletions(-)

diff --git a/lib/private/files/cache/changepropagator.php b/lib/private/files/cache/changepropagator.php
index 30f2e67..2967c8f 100644
--- a/lib/private/files/cache/changepropagator.php
+++ b/lib/private/files/cache/changepropagator.php
@@ -57,9 +57,11 @@ class ChangePropagator {
 			 */
 
 			list($storage, $internalPath) = $this->view->resolvePath($parent);
-			$cache = $storage->getCache();
-			$id = $cache->getId($internalPath);
-			$cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath)));
+			if ($storage) {
+				$cache = $storage->getCache();
+				$id = $cache->getId($internalPath);
+				$cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath)));
+			}
 		}
 	}
 
diff --git a/lib/private/files/cache/updater.php b/lib/private/files/cache/updater.php
index 0e5e07c..a59dc7c 100644
--- a/lib/private/files/cache/updater.php
+++ b/lib/private/files/cache/updater.php
@@ -9,166 +9,122 @@
 namespace OC\Files\Cache;
 
 /**
- * listen to filesystem hooks and change the cache accordingly
+ * Update the cache and propagate changes
  */
 class Updater {
+	/**
+	 * @var \OC\Files\View
+	 */
+	protected $view;
 
 	/**
-	 * resolve a path to a storage and internal path
-	 *
-	 * @param string $path the relative path
-	 * @return array an array consisting of the storage and the internal path
+	 * @var \OC\Files\Cache\ChangePropagator
+	 */
+	protected $propagator;
+
+	/**
+	 * @param \OC\Files\View $view
 	 */
-	static public function resolvePath($path) {
-		$view = \OC\Files\Filesystem::getView();
-		return $view->resolvePath($path);
+	public function __construct($view) {
+		$this->view = $view;
+		$this->propagator = new ChangePropagator($view);
 	}
 
 	/**
-	 * perform a write update
+	 * Update the cache for $path
 	 *
-	 * @param string $path the relative path of the file
+	 * @param string $path
 	 */
-	static public function writeUpdate($path) {
+	public function update($path) {
 		/**
 		 * @var \OC\Files\Storage\Storage $storage
 		 * @var string $internalPath
 		 */
-		list($storage, $internalPath) = self::resolvePath($path);
+		list($storage, $internalPath) = $this->view->resolvePath($path);
 		if ($storage) {
+			$this->propagator->addChange($path);
 			$cache = $storage->getCache($internalPath);
 			$scanner = $storage->getScanner($internalPath);
 			$data = $scanner->scan($internalPath, Scanner::SCAN_SHALLOW);
+			$this->correctParentStorageMtime($storage, $internalPath);
 			$cache->correctFolderSize($internalPath, $data);
-			self::correctFolder($path, $storage->filemtime($internalPath));
-			self::correctParentStorageMtime($storage, $internalPath);
 		}
 	}
 
 	/**
-	 * perform a delete update
+	 * Remove $path from the cache
 	 *
-	 * @param string $path the relative path of the file
+	 * @param string $path
 	 */
-	static public function deleteUpdate($path) {
+	public function remove($path) {
 		/**
 		 * @var \OC\Files\Storage\Storage $storage
 		 * @var string $internalPath
 		 */
-		list($storage, $internalPath) = self::resolvePath($path);
+		list($storage, $internalPath) = $this->view->resolvePath($path);
 		if ($storage) {
 			$parent = dirname($internalPath);
 			if ($parent === '.') {
 				$parent = '';
 			}
+			$this->propagator->addChange($path);
 			$cache = $storage->getCache($internalPath);
 			$cache->remove($internalPath);
 			$cache->correctFolderSize($parent);
-			self::correctFolder($path, time());
-			self::correctParentStorageMtime($storage, $internalPath);
+			$this->correctParentStorageMtime($storage, $internalPath);
 		}
 	}
 
 	/**
-	 * preform a rename update
-	 *
-	 * @param string $from the relative path of the source file
-	 * @param string $to the relative path of the target file
+	 * @param string $source
+	 * @param string $target
 	 */
-	static public function renameUpdate($from, $to) {
+	public function rename($source, $target) {
 		/**
-		 * @var \OC\Files\Storage\Storage $storageFrom
-		 * @var \OC\Files\Storage\Storage $storageTo
-		 * @var string $internalFrom
-		 * @var string $internalTo
+		 * @var \OC\Files\Storage\Storage $sourceStorage
+		 * @var \OC\Files\Storage\Storage $targetStorage
+		 * @var string $sourceInternalPath
+		 * @var string $targetInternalPath
 		 */
-		list($storageFrom, $internalFrom) = self::resolvePath($from);
+		list($sourceStorage, $sourceInternalPath) = $this->view->resolvePath($source);
 		// if it's a moved mountpoint we dont need to do anything
-		if ($internalFrom === '') {
+		if ($sourceInternalPath === '') {
 			return;
 		}
-		list($storageTo, $internalTo) = self::resolvePath($to);
-		if ($storageFrom && $storageTo) {
-			if ($storageFrom === $storageTo) {
-				$cache = $storageFrom->getCache($internalFrom);
-				$cache->move($internalFrom, $internalTo);
-				if (pathinfo($internalFrom, PATHINFO_EXTENSION) !== pathinfo($internalTo, PATHINFO_EXTENSION)) {
-					// redetect mime type change
-					$mimeType = $storageTo->getMimeType($internalTo);
-					$fileId = $storageTo->getCache()->getId($internalTo);
-					$storageTo->getCache()->update($fileId, array('mimetype' => $mimeType));
+		list($targetStorage, $targetInternalPath) = $this->view->resolvePath($target);
+
+		if ($sourceStorage && $targetStorage) {
+			if ($sourceStorage === $targetStorage) {
+				$cache = $sourceStorage->getCache($sourceInternalPath);
+				$cache->move($sourceInternalPath, $targetInternalPath);
+
+				if (pathinfo($sourceInternalPath, PATHINFO_EXTENSION) !== pathinfo($targetInternalPath, PATHINFO_EXTENSION)) {
+					// handle mime type change
+					$mimeType = $sourceStorage->getMimeType($targetInternalPath);
+					$fileId = $cache->getId($targetInternalPath);
+					$cache->update($fileId, array('mimetype' => $mimeType));
 				}
-				$cache->correctFolderSize($internalFrom);
-				$cache->correctFolderSize($internalTo);
-				self::correctFolder($from, time());
-				self::correctFolder($to, time());
-				self::correctParentStorageMtime($storageFrom, $internalFrom);
-				self::correctParentStorageMtime($storageTo, $internalTo);
-			} else {
-				self::deleteUpdate($from);
-				self::writeUpdate($to);
-			}
-		}
-	}
-
-	/**
-	 * get file owner and path
-	 * @param string $filename
-	 * @return string[] with the owner's uid and the owner's path
-	 */
-	private static function getUidAndFilename($filename) {
-
-		$uid = \OC\Files\Filesystem::getOwner($filename);
-		\OC\Files\Filesystem::initMountPoints($uid);
 
-		$filename = (strpos($filename, '/') !== 0) ? '/' . $filename : $filename;
-		if ($uid != \OCP\User::getUser()) {
-			$info = \OC\Files\Filesystem::getFileInfo($filename);
-			if (!$info) {
-				return array($uid, '/files' . $filename);
+				$cache->correctFolderSize($sourceInternalPath);
+				$cache->correctFolderSize($targetInternalPath);
+				$this->correctParentStorageMtime($sourceStorage, $sourceInternalPath);
+				$this->correctParentStorageMtime($targetStorage, $targetInternalPath);
+				$this->propagator->addChange($source);
+				$this->propagator->addChange($target);
+			} else {
+				$this->remove($source);
+				$this->update($target);
 			}
-			$ownerView = new \OC\Files\View('/' . $uid . '/files');
-			$filename = $ownerView->getPath($info['fileid']);
 		}
-		return array($uid, '/files' . $filename);
 	}
 
 	/**
-	 * Update the mtime and ETag of all parent folders
+	 * propagate the updates to their parent folders
 	 *
-	 * @param string $path
-	 * @param string $time
+	 * @param int $time (optional) the mtime to set for the folders, if not set the current time is used
 	 */
-	static public function correctFolder($path, $time) {
-		if ($path !== '' && $path !== '/' && $path !== '\\') {
-			list($owner, $realPath) = self::getUidAndFilename(dirname($path));
-
-			/**
-			 * @var \OC\Files\Storage\Storage $storage
-			 * @var string $internalPath
-			 */
-			$view = new \OC\Files\View('/' . $owner);
-
-			list($storage, $internalPath) = $view->resolvePath($realPath);
-			$cache = $storage->getCache();
-			$id = $cache->getId($internalPath);
-
-			while ($id !== -1) {
-				$cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath)));
-				if ($realPath !== '') {
-					$realPath = dirname($realPath);
-					if ($realPath === DIRECTORY_SEPARATOR) {
-						$realPath = "";
-					}
-					// check storage for parent in case we change the storage in this step
-					list($storage, $internalPath) = $view->resolvePath($realPath);
-					$cache = $storage->getCache();
-					$id = $cache->getId($internalPath);
-				} else {
-					$id = -1;
-				}
-			}
-		}
+	public function propagate($time = null) {
+		$this->propagator->propagateChanges($time);
 	}
 
 	/**
@@ -177,52 +133,17 @@ class Updater {
 	 * @param \OC\Files\Storage\Storage $storage
 	 * @param string $internalPath
 	 */
-	static private function correctParentStorageMtime($storage, $internalPath) {
+	private function correctParentStorageMtime($storage, $internalPath) {
 		$cache = $storage->getCache();
 		$parentId = $cache->getParentId($internalPath);
 		$parent = dirname($internalPath);
-
-		if ($parent === '.' || $parent === '/' || $parent === '\\') {
-			$parent = '';
-		}
-
 		if ($parentId != -1) {
 			$cache->update($parentId, array('storage_mtime' => $storage->filemtime($parent)));
 		}
 	}
 
-	/**
-	 * @param array $params
-	 */
-	static public function writeHook($params) {
-		self::writeUpdate($params['path']);
-	}
-
-	/**
-	 * @param array $params
-	 */
-	static public function touchHook($params) {
-		$path = $params['path'];
-		list($storage, $internalPath) = self::resolvePath($path);
-		$cache = $storage->getCache();
-		$id = $cache->getId($internalPath);
-		if ($id !== -1) {
-			$cache->update($id, array('etag' => $storage->getETag($internalPath)));
-		}
-		self::writeUpdate($path);
-	}
-
-	/**
-	 * @param array $params
-	 */
-	static public function renameHook($params) {
-		self::renameUpdate($params['oldpath'], $params['newpath']);
-	}
-
-	/**
-	 * @param array $params
-	 */
-	static public function deleteHook($params) {
-		self::deleteUpdate($params['path']);
+	public function __destruct() {
+		// propagate any leftover changes
+		$this->propagator->propagateChanges();
 	}
 }
diff --git a/lib/private/files/view.php b/lib/private/files/view.php
index baf765d..691f3f1 100644
--- a/lib/private/files/view.php
+++ b/lib/private/files/view.php
@@ -31,8 +31,14 @@ use OC\Files\Mount\MoveableMount;
 class View {
 	private $fakeRoot = '';
 
+	/**
+	 * @var \OC\Files\Cache\Updater
+	 */
+	protected $updater;
+
 	public function __construct($root = '') {
 		$this->fakeRoot = $root;
+		$this->updater = new Updater($this);
 	}
 
 	public function getAbsolutePath($path = '/') {
@@ -158,7 +164,10 @@ class View {
 	 * for \OC\Files\Storage\Storage via basicOperation().
 	 */
 	public function mkdir($path) {
-		return $this->basicOperation('mkdir', $path, array('create', 'write'));
+		$result = $this->basicOperation('mkdir', $path, array('create', 'write'));
+		$this->updater->update($path);
+		$this->updater->propagate();
+		return $result;
 	}
 
 	/**
@@ -168,10 +177,10 @@ class View {
 	 * @param string $path relative to data/
 	 * @return boolean
 	 */
-	protected function removeMount($mount, $path){
+	protected function removeMount($mount, $path) {
 		if ($mount instanceof MoveableMount) {
 			// cut of /user/files to get the relative path to data/user/files
-			$pathParts= explode('/', $path, 4);
+			$pathParts = explode('/', $path, 4);
 			$relPath = '/' . $pathParts[3];
 			\OC_Hook::emit(
 				Filesystem::CLASSNAME, "umount",
@@ -194,13 +203,16 @@ class View {
 	}
 
 	public function rmdir($path) {
-		$absolutePath= $this->getAbsolutePath($path);
+		$absolutePath = $this->getAbsolutePath($path);
 		$mount = Filesystem::getMountManager()->find($absolutePath);
 		if ($mount->getInternalPath($absolutePath) === '') {
 			return $this->removeMount($mount, $path);
 		}
 		if ($this->is_dir($path)) {
-			return $this->basicOperation('rmdir', $path, array('delete'));
+			$result = $this->basicOperation('rmdir', $path, array('delete'));
+			$this->updater->remove($path);
+			$this->updater->propagate();
+			return $result;
 		} else {
 			return false;
 		}
@@ -310,9 +322,14 @@ class View {
 			if(!$this->file_exists($path)){
 				return false;
 			}
+			if (is_null($mtime)) {
+				$mtime = time();
+			}
 			//if native touch fails, we emulate it by changing the mtime in the cache
 			$this->putFileInfo($path, array('mtime' => $mtime));
 		}
+		$this->updater->update($path);
+		$this->updater->propagate($mtime);
 		return true;
 	}
 
@@ -374,10 +391,9 @@ class View {
 					list ($count, $result) = \OC_Helper::streamCopy($data, $target);
 					fclose($target);
 					fclose($data);
+					$this->updater->update($path);
+					$this->updater->propagate();
 					if ($this->shouldEmitHooks($path) && $result !== false) {
-						Updater::writeHook(array(
-							'path' => $this->getHookPath($path)
-						));
 						$this->emit_file_hooks_post($exists, $path);
 					}
 					\OC_FileProxy::runPostProxies('file_put_contents', $absolutePath, $count);
@@ -390,7 +406,10 @@ class View {
 			}
 		} else {
 			$hooks = ($this->file_exists($path)) ? array('update', 'write') : array('create', 'write');
-			return $this->basicOperation('file_put_contents', $path, $hooks, $data);
+			$result = $this->basicOperation('file_put_contents', $path, $hooks, $data);
+			$this->updater->update($path);
+			$this->updater->propagate();
+			return $result;
 		}
 	}
 
@@ -405,7 +424,10 @@ class View {
 		if ($mount->getInternalPath($absolutePath) === '') {
 			return $this->removeMount($mount, $absolutePath);
 		}
-		return $this->basicOperation('unlink', $path, array('delete'));
+		$result = $this->basicOperation('unlink', $path, array('delete'));
+		$this->updater->remove($path);
+		$this->updater->propagate();
+		return $result;
 	}
 
 	/**
@@ -495,15 +517,16 @@ class View {
 						}
 					}
 				}
-				if ($this->shouldEmitHooks() && (Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
+				if ((Cache\Scanner::isPartialFile($path1) && !Cache\Scanner::isPartialFile($path2)) && $result !== false) {
 					// if it was a rename from a part file to a regular file it was a write and not a rename operation
-					Updater::writeHook(array('path' => $this->getHookPath($path2)));
-					$this->emit_file_hooks_post($exists, $path2);
+					$this->updater->update($path2);
+					$this->updater->propagate();
+					if ($this->shouldEmitHooks()) {
+						$this->emit_file_hooks_post($exists, $path2);
+					}
 				} elseif ($this->shouldEmitHooks() && $result !== false) {
-					Updater::renameHook(array(
-						'oldpath' => $this->getHookPath($path1),
-						'newpath' => $this->getHookPath($path2)
-					));
+					$this->updater->rename($path1, $path2);
+					$this->updater->propagate();
 					\OC_Hook::emit(
 						Filesystem::CLASSNAME,
 						Filesystem::signal_post_rename,
@@ -582,6 +605,8 @@ class View {
 						fclose($target);
 					}
 				}
+				$this->updater->update($path2);
+				$this->updater->propagate();
 				if ($this->shouldEmitHooks() && $result !== false) {
 					\OC_Hook::emit(
 						Filesystem::CLASSNAME,
@@ -805,16 +830,6 @@ class View {
 		$run = true;
 		if ($this->shouldEmitHooks($path)) {
 			foreach ($hooks as $hook) {
-				// manually triger updater hooks to ensure they are called first
-				if ($post) {
-					if ($hook == 'write') {
-						Updater::writeHook(array('path' => $path));
-					} elseif ($hook == 'touch') {
-						Updater::touchHook(array('path' => $path));
-					} else if ($hook == 'delete') {
-						Updater::deleteHook(array('path' => $path));
-					}
-				}
 				if ($hook != 'read') {
 					\OC_Hook::emit(
 						Filesystem::CLASSNAME,
diff --git a/tests/lib/files/cache/updater.php b/tests/lib/files/cache/updater.php
index b874e41..39c521c 100644
--- a/tests/lib/files/cache/updater.php
+++ b/tests/lib/files/cache/updater.php
@@ -266,7 +266,6 @@ class Updater extends \PHPUnit_Framework_TestCase {
 		$cachedData = $this->cache->get('foo.txt');
 		$this->assertInternalType('string', $fooCachedData['etag']);
 		$this->assertInternalType('string', $cachedData['etag']);
-		$this->assertNotSame($fooCachedData['etag'], $cachedData['etag']);
 		$this->assertGreaterThanOrEqual($fooCachedData['mtime'], $cachedData['mtime']);
 
 		$cachedData = $this->cache->get('');

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud.git



More information about the Pkg-owncloud-commits mailing list