diff --git a/lib/files/cache/cache.php b/lib/files/cache/cache.php index cba48e4dbe..138a5e6e63 100644 --- a/lib/files/cache/cache.php +++ b/lib/files/cache/cache.php @@ -234,7 +234,7 @@ class Cache { $entry = $this->get($file); if ($entry['mimetype'] === 'httpd/unix-directory') { $children = $this->getFolderContents($file); - foreach($children as $child){ + foreach ($children as $child) { $this->remove($child['path']); } } @@ -325,7 +325,9 @@ class Cache { $query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*filecache` WHERE `parent` = ? AND `storage` = ?'); $result = $query->execute(array($id, $this->storageId)); $totalSize = 0; + $hasChilds = 0; while ($row = $result->fetchRow()) { + $hasChilds = true; $size = (int)$row['size']; if ($size === -1) { $totalSize = -1; @@ -335,7 +337,9 @@ class Cache { } } - $this->update($id, array('size' => $totalSize)); + if ($hasChilds) { + $this->update($id, array('size' => $totalSize)); + } return $totalSize; } diff --git a/lib/files/cache/watcher.php b/lib/files/cache/watcher.php new file mode 100644 index 0000000000..f04ca9b465 --- /dev/null +++ b/lib/files/cache/watcher.php @@ -0,0 +1,70 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\Files\Cache; + +/** + * check the storage backends for updates and change the cache accordingly + */ +class Watcher { + /** + * @var \OC\Files\Storage\Storage $storage + */ + private $storage; + + /** + * @var Cache $cache + */ + private $cache; + + /** + * @var Scanner $scanner; + */ + private $scanner; + + /** + * @param \OC\Files\Storage\Storage $storage + */ + public function __construct(\OC\Files\Storage\Storage $storage) { + $this->storage = $storage; + $this->cache = $storage->getCache(); + $this->scanner = $storage->getScanner(); + } + + /** + * check $path for updates + * + * @param string $path + */ + public function checkUpdate($path) { + $cachedEntry = $this->cache->get($path); + if ($this->storage->hasUpdated($path, $cachedEntry['mtime'])) { + if ($cachedEntry['mimetype'] === 'httpd/unix-directory') { + $this->scanner->scan($path, Scanner::SCAN_SHALLOW); + $this->cleanFolder($path); + } else { + $this->scanner->scanFile($path); + } + $this->scanner->correctFolderSize($path); + } + } + + /** + * remove deleted files in $path from the cache + * + * @param string $path + */ + public function cleanFolder($path) { + $cachedContent = $this->cache->getFolderContents($path); + foreach ($cachedContent as $entry) { + if (!$this->storage->file_exists($entry['path'])) { + $this->cache->remove($entry['path']); + } + } + } +} diff --git a/tests/lib/files/cache/watcher.php b/tests/lib/files/cache/watcher.php new file mode 100644 index 0000000000..a7076d9b0b --- /dev/null +++ b/tests/lib/files/cache/watcher.php @@ -0,0 +1,86 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Files\Cache; + +class Watcher extends \PHPUnit_Framework_TestCase { + + /** + * @var \OC\Files\Storage\Storage[] $storages; + */ + private $storages = array(); + + public function setUp() { + \OC\Files\Filesystem::clearMounts(); + } + + public function tearDown() { + foreach ($this->storages as $storage) { + $cache = $storage->getCache(); + $ids = $cache->getAll(); + \OC\Files\Cache\Permissions::removeMultiple($ids, \OC_User::getUser()); + $cache->clear(); + } + } + + function testWatcher() { + $storage = $this->getTestStorage(); + $cache = $storage->getCache(); + $updater = new \OC\Files\Cache\Watcher($storage); + + //set the mtime to the past so it can detect an mtime change + $cache->put('', array('mtime' => 10)); + + $this->assertTrue($cache->inCache('folder/bar.txt')); + $this->assertTrue($cache->inCache('folder/bar2.txt')); + + $this->assertFalse($cache->inCache('bar.test')); + $storage->file_put_contents('bar.test', 'foo'); + $updater->checkUpdate(''); + $this->assertTrue($cache->inCache('bar.test')); + $cachedData = $cache->get('bar.test'); + $this->assertEquals(3, $cachedData['size']); + + $cache->put('bar.test', array('mtime' => 10)); + $storage->file_put_contents('bar.test', 'test data'); + + $updater->checkUpdate('bar.test'); + $cachedData = $cache->get('bar.test'); + $this->assertEquals(9, $cachedData['size']); + + $cache->put('folder', array('mtime' => 10)); + + $storage->unlink('folder/bar2.txt'); + $updater->checkUpdate('folder'); + + $this->assertTrue($cache->inCache('folder/bar.txt')); + $this->assertFalse($cache->inCache('folder/bar2.txt')); + } + + /** + * @param bool $scan + * @return \OC\Files\Storage\Storage + */ + private function getTestStorage($scan = true) { + $storage = new \OC\Files\Storage\Temporary(array()); + $textData = "dummy file data\n"; + $imgData = file_get_contents(\OC::$SERVERROOT . '/core/img/logo.png'); + $storage->mkdir('folder'); + $storage->file_put_contents('foo.txt', $textData); + $storage->file_put_contents('foo.png', $imgData); + $storage->file_put_contents('folder/bar.txt', $textData); + $storage->file_put_contents('folder/bar2.txt', $textData); + + if ($scan) { + $scanner = $storage->getScanner(); + $scanner->scan(''); + } + $this->storages[] = $storage; + return $storage; + } +} diff --git a/tests/lib/files/view.php b/tests/lib/files/view.php index 5144fb1caa..8ff03963e4 100644 --- a/tests/lib/files/view.php +++ b/tests/lib/files/view.php @@ -20,6 +20,8 @@ class View extends \PHPUnit_Framework_TestCase { public function tearDown() { foreach ($this->storages as $storage) { $cache = $storage->getCache(); + $ids = $cache->getAll(); + \OC\Files\Cache\Permissions::removeMultiple($ids, \OC_User::getUser()); $cache->clear(); } }