]> source.dussan.org Git - nextcloud-server.git/commitdiff
Add a change propagator class to handle propagating etag and mtime changes
authorRobin Appelman <icewind@owncloud.com>
Fri, 30 May 2014 13:55:17 +0000 (15:55 +0200)
committerRobin Appelman <icewind@owncloud.com>
Tue, 10 Jun 2014 14:16:46 +0000 (16:16 +0200)
lib/private/files/cache/changepropagator.php [new file with mode: 0644]
tests/lib/files/cache/changepropagator.php [new file with mode: 0644]

diff --git a/lib/private/files/cache/changepropagator.php b/lib/private/files/cache/changepropagator.php
new file mode 100644 (file)
index 0000000..30f2e67
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\Files\Cache;
+
+/**
+ * Propagates changes in etag and mtime up the filesystem tree
+ *
+ * @package OC\Files\Cache
+ */
+class ChangePropagator {
+       /**
+        * @var string[]
+        */
+       protected $changedFiles = array();
+
+       /**
+        * @var \OC\Files\View
+        */
+       protected $view;
+
+       /**
+        * @param \OC\Files\View $view
+        */
+       public function __construct(\OC\Files\View $view) {
+               $this->view = $view;
+       }
+
+       public function addChange($path) {
+               $this->changedFiles[] = $path;
+       }
+
+       public function getChanges() {
+               return $this->changedFiles;
+       }
+
+       /**
+        * propagate the registered changes to their parent folders
+        *
+        * @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();
+               if (!$time) {
+                       $time = time();
+               }
+               foreach ($parents as $parent) {
+                       /**
+                        * @var \OC\Files\Storage\Storage $storage
+                        * @var string $internalPath
+                        */
+
+                       list($storage, $internalPath) = $this->view->resolvePath($parent);
+                       $cache = $storage->getCache();
+                       $id = $cache->getId($internalPath);
+                       $cache->update($id, array('mtime' => $time, 'etag' => $storage->getETag($internalPath)));
+               }
+       }
+
+       /**
+        * @return string[]
+        */
+       public function getAllParents() {
+               $parents = array();
+               foreach ($this->getChanges() as $path) {
+                       $parents = array_values(array_unique(array_merge($parents, $this->getParents($path))));
+               }
+               return $parents;
+       }
+
+       /**
+        * get all parent folders of $path
+        *
+        * @param string $path
+        * @return string[]
+        */
+       protected function getParents($path) {
+               $parts = explode('/', $path);
+
+               // remove the singe file
+               array_pop($parts);
+               $result = array('/');
+               $resultPath = '';
+               foreach ($parts as $part) {
+                       if ($part) {
+                               $resultPath .= '/' . $part;
+                               $result[] = $resultPath;
+                       }
+               }
+               return $result;
+       }
+}
diff --git a/tests/lib/files/cache/changepropagator.php b/tests/lib/files/cache/changepropagator.php
new file mode 100644 (file)
index 0000000..9beff27
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\Files\Cache;
+
+use OC\Files\Filesystem;
+use OC\Files\Storage\Temporary;
+use OC\Files\View;
+
+class ChangePropagator extends \PHPUnit_Framework_TestCase {
+       /**
+        * @var \OC\Files\Cache\ChangePropagator
+        */
+       private $propagator;
+
+       /**
+        * @var \OC\Files\View
+        */
+       private $view;
+
+       public function setUp() {
+               $storage = new Temporary(array());
+               $root = '/' . uniqid();
+               Filesystem::mount($storage, array(), $root);
+               $this->view = new View($root);
+               $this->propagator = new \OC\Files\Cache\ChangePropagator($this->view);
+       }
+
+       public function testGetParentsSingle() {
+               $this->propagator->addChange('/foo/bar/asd');
+               $this->assertEquals(array('/', '/foo', '/foo/bar'), $this->propagator->getAllParents());
+       }
+
+       public function testGetParentsMultiple() {
+               $this->propagator->addChange('/foo/bar/asd');
+               $this->propagator->addChange('/foo/qwerty');
+               $this->propagator->addChange('/foo/asd/bar');
+               $this->assertEquals(array('/', '/foo', '/foo/bar', '/foo/asd'), $this->propagator->getAllParents());
+       }
+
+       public function testSinglePropagate() {
+               $this->view->mkdir('/foo');
+               $this->view->mkdir('/foo/bar');
+               $this->view->file_put_contents('/foo/bar/sad.txt', 'qwerty');
+
+               $oldInfo1 = $this->view->getFileInfo('/');
+               $oldInfo2 = $this->view->getFileInfo('/foo');
+               $oldInfo3 = $this->view->getFileInfo('/foo/bar');
+
+               $time = time() + 50;
+
+               $this->propagator->addChange('/foo/bar/sad.txt');
+               $this->propagator->propagateChanges($time);
+
+               $newInfo1 = $this->view->getFileInfo('/');
+               $newInfo2 = $this->view->getFileInfo('/foo');
+               $newInfo3 = $this->view->getFileInfo('/foo/bar');
+
+               $this->assertEquals($newInfo1->getMTime(), $time);
+               $this->assertEquals($newInfo2->getMTime(), $time);
+               $this->assertEquals($newInfo3->getMTime(), $time);
+
+               $this->assertNotEquals($oldInfo1->getEtag(), $newInfo1->getEtag());
+               $this->assertNotEquals($oldInfo2->getEtag(), $newInfo2->getEtag());
+               $this->assertNotEquals($oldInfo3->getEtag(), $newInfo3->getEtag());
+       }
+}