Do not use -1 as the size for the root folder of the home storage

This commit is contained in:
Robin Appelman 2013-11-08 12:57:28 +01:00 committed by Vincent Petry
parent a745901d50
commit 32a703ab36
5 changed files with 196 additions and 19 deletions

48
lib/private/files/cache/homecache.php vendored Normal file
View File

@ -0,0 +1,48 @@
<?php
/**
* Copyright (c) 2012 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;
class HomeCache extends Cache {
/**
* get the size of a folder and set it in the cache
*
* @param string $path
* @return int
*/
public function calculateFolderSize($path) {
$totalSize = 0;
$entry = $this->get($path);
if ($entry && $entry['mimetype'] === 'httpd/unix-directory') {
$isRoot = ($path === '/' or $path === '');
$id = $entry['fileid'];
$sql = 'SELECT SUM(`size`), MIN(`size`) FROM `*PREFIX*filecache` ' .
'WHERE `parent` = ? AND `storage` = ?';
if ($isRoot) {
// filter out non-scanned dirs at the root
$sql .= ' AND `size` >= 0';
}
$result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId()));
if ($row = $result->fetchRow()) {
list($sum, $min) = array_values($row);
$sum = (int)$sum;
$min = (int)$min;
if ($min === -1) {
$totalSize = $min;
} else {
$totalSize = $sum;
}
if ($entry['size'] !== $totalSize) {
$this->update($id, array('size' => $totalSize));
}
}
}
return $totalSize;
}
}

View File

@ -21,11 +21,11 @@ namespace OC\Files\Storage;
*/
abstract class Common implements \OC\Files\Storage\Storage {
private $cache;
private $scanner;
private $permissioncache;
private $watcher;
private $storageCache;
protected $cache;
protected $scanner;
protected $permissioncache;
protected $watcher;
protected $storageCache;
public function __construct($parameters) {
}

View File

@ -27,4 +27,11 @@ class Home extends Local {
public function getId() {
return 'home::' . $this->user->getUID();
}
public function getCache($path = '') {
if (!isset($this->cache)) {
$this->cache = new \OC\Files\Cache\HomeCache($this);
}
return $this->cache;
}
}

View File

@ -18,11 +18,11 @@ class LongId extends \OC\Files\Storage\Temporary {
class Cache extends \PHPUnit_Framework_TestCase {
/**
* @var \OC\Files\Storage\Temporary $storage;
* @var \OC\Files\Storage\Temporary $storage ;
*/
private $storage;
/**
* @var \OC\Files\Storage\Temporary $storage2;
* @var \OC\Files\Storage\Temporary $storage2 ;
*/
private $storage2;
@ -137,6 +137,33 @@ class Cache extends \PHPUnit_Framework_TestCase {
$this->assertFalse($this->cache->inCache('folder/bar'));
}
public function testRootFolderSizeForNonHomeStorage() {
$dir1 = 'knownsize';
$dir2 = 'unknownsize';
$fileData = array();
$fileData[''] = array('size' => -1, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
$fileData[$dir1] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
$fileData[$dir2] = array('size' => -1, 'mtime' => 25, 'mimetype' => 'httpd/unix-directory');
$this->cache->put('', $fileData['']);
$this->cache->put($dir1, $fileData[$dir1]);
$this->cache->put($dir2, $fileData[$dir2]);
$this->assertTrue($this->cache->inCache($dir1));
$this->assertTrue($this->cache->inCache($dir2));
// check that root size ignored the unknown sizes
$this->assertEquals(-1, $this->cache->calculateFolderSize(''));
// clean up
$this->cache->remove('');
$this->cache->remove($dir1);
$this->cache->remove($dir2);
$this->assertFalse($this->cache->inCache($dir1));
$this->assertFalse($this->cache->inCache($dir2));
}
function testStatus() {
$this->assertEquals(\OC\Files\Cache\Cache::NOT_FOUND, $this->cache->getStatus('foo'));
$this->cache->put('foo', array('size' => -1));
@ -247,14 +274,14 @@ class Cache extends \PHPUnit_Framework_TestCase {
$data = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'foo/file');
$this->cache->put('foo', $data);
$cachedData = $this->cache->get('foo');
$this->assertEquals($data['mtime'], $cachedData['storage_mtime']);//if no storage_mtime is saved, mtime should be used
$this->assertEquals($data['mtime'], $cachedData['storage_mtime']); //if no storage_mtime is saved, mtime should be used
$this->cache->put('foo', array('storage_mtime' => 30));//when setting storage_mtime, mtime is also set
$this->cache->put('foo', array('storage_mtime' => 30)); //when setting storage_mtime, mtime is also set
$cachedData = $this->cache->get('foo');
$this->assertEquals(30, $cachedData['storage_mtime']);
$this->assertEquals(30, $cachedData['mtime']);
$this->cache->put('foo', array('mtime' => 25));//setting mtime does not change storage_mtime
$this->cache->put('foo', array('mtime' => 25)); //setting mtime does not change storage_mtime
$cachedData = $this->cache->get('foo');
$this->assertEquals(30, $cachedData['storage_mtime']);
$this->assertEquals(25, $cachedData['mtime']);
@ -295,18 +322,18 @@ class Cache extends \PHPUnit_Framework_TestCase {
$this->assertGreaterThan(0, $cacheMock->put('folder', $data));
// put un-normalized folder
$this->assertFalse($cacheMock->get('folder/' .$folderWith0308));
$this->assertGreaterThan(0, $cacheMock->put('folder/' .$folderWith0308, $data));
$this->assertFalse($cacheMock->get('folder/' . $folderWith0308));
$this->assertGreaterThan(0, $cacheMock->put('folder/' . $folderWith0308, $data));
// get un-normalized folder by name
$unNormalizedFolderName = $cacheMock->get('folder/' .$folderWith0308);
$unNormalizedFolderName = $cacheMock->get('folder/' . $folderWith0308);
// check if database layer normalized the folder name (this should not happen)
$this->assertEquals($folderWith0308, $unNormalizedFolderName['name']);
// put normalized folder
$this->assertFalse($cacheMock->get('folder/' . $folderWith00F6));
$this->assertGreaterThan(0, $cacheMock->put('folder/' .$folderWith00F6, $data));
$this->assertGreaterThan(0, $cacheMock->put('folder/' . $folderWith00F6, $data));
// this is our bug, we have two different hashes with the same name (Schön)
$this->assertEquals(2, count($cacheMock->getFolderContents('folder')));
@ -317,7 +344,7 @@ class Cache extends \PHPUnit_Framework_TestCase {
*/
public function testWithNormalizer() {
if(!class_exists('Patchwork\PHP\Shim\Normalizer')) {
if (!class_exists('Patchwork\PHP\Shim\Normalizer')) {
$this->markTestSkipped('The 3rdparty Normalizer extension is not available.');
return;
}
@ -335,18 +362,18 @@ class Cache extends \PHPUnit_Framework_TestCase {
$this->assertGreaterThan(0, $this->cache->put('folder', $data));
// put un-normalized folder
$this->assertFalse($this->cache->get('folder/' .$folderWith0308));
$this->assertGreaterThan(0, $this->cache->put('folder/' .$folderWith0308, $data));
$this->assertFalse($this->cache->get('folder/' . $folderWith0308));
$this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith0308, $data));
// get un-normalized folder by name
$unNormalizedFolderName = $this->cache->get('folder/' .$folderWith0308);
$unNormalizedFolderName = $this->cache->get('folder/' . $folderWith0308);
// check if folder name was normalized
$this->assertEquals($folderWith00F6, $unNormalizedFolderName['name']);
// put normalized folder
$this->assertTrue(is_array($this->cache->get('folder/' . $folderWith00F6)));
$this->assertGreaterThan(0, $this->cache->put('folder/' .$folderWith00F6, $data));
$this->assertGreaterThan(0, $this->cache->put('folder/' . $folderWith00F6, $data));
// at this point we should have only one folder named "Schön"
$this->assertEquals(1, count($this->cache->getFolderContents('folder')));

95
tests/lib/files/cache/homecache.php vendored Normal file
View File

@ -0,0 +1,95 @@
<?php
/**
* Copyright (c) 2012 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;
class DummyUser extends \OC\User\User {
/**
* @var string $home
*/
private $home;
/**
* @var string $uid
*/
private $uid;
public function __construct($uid, $home) {
$this->home = $home;
$this->uid = $uid;
}
/**
* @return string
*/
public function getHome() {
return $this->home;
}
/**
* @return string
*/
public function getUID() {
return $this->uid;
}
}
class HomeCache extends \PHPUnit_Framework_TestCase {
/**
* @var \OC\Files\Storage\Home $storage
*/
private $storage;
/**
* @var \OC\Files\Cache\HomeCache $cache
*/
private $cache;
/**
* @var \OC\User\User $user
*/
private $user;
public function setUp() {
$this->user = new DummyUser('foo', \OC_Helper::tmpFolder());
$this->storage = new \OC\Files\Storage\Home(array('user' => $this->user));
$this->cache = $this->storage->getCache();
}
/**
* Tests that the root folder size calculation ignores the subdirs that have an unknown
* size. This makes sure that quota calculation still works as it's based on the root
* folder size.
*/
public function testRootFolderSizeIgnoresUnknownUpdate() {
$dir1 = 'knownsize';
$dir2 = 'unknownsize';
$fileData = array();
$fileData[''] = array('size' => -1, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
$fileData[$dir1] = array('size' => 1000, 'mtime' => 20, 'mimetype' => 'httpd/unix-directory');
$fileData[$dir2] = array('size' => -1, 'mtime' => 25, 'mimetype' => 'httpd/unix-directory');
$this->cache->put('', $fileData['']);
$this->cache->put($dir1, $fileData[$dir1]);
$this->cache->put($dir2, $fileData[$dir2]);
$this->assertTrue($this->cache->inCache($dir1));
$this->assertTrue($this->cache->inCache($dir2));
// check that root size ignored the unknown sizes
$this->assertEquals(1000, $this->cache->calculateFolderSize(''));
// clean up
$this->cache->remove('');
$this->cache->remove($dir1);
$this->cache->remove($dir2);
$this->assertFalse($this->cache->inCache($dir1));
$this->assertFalse($this->cache->inCache($dir2));
}
}