Merge pull request #5768 from owncloud/quota-workaroundwhenmissingrootsize-home-only
Do not use -1 as the size for the root folder of the home storage
This commit is contained in:
commit
408ce91b25
8 changed files with 303 additions and 25 deletions
40
lib/private/files/cache/homecache.php
vendored
Normal file
40
lib/private/files/cache/homecache.php
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?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) {
|
||||
if ($path !== '/' and $path !== '') {
|
||||
return parent::calculateFolderSize($path);
|
||||
}
|
||||
|
||||
$totalSize = 0;
|
||||
$entry = $this->get($path);
|
||||
if ($entry && $entry['mimetype'] === 'httpd/unix-directory') {
|
||||
$id = $entry['fileid'];
|
||||
$sql = 'SELECT SUM(`size`) FROM `*PREFIX*filecache` ' .
|
||||
'WHERE `parent` = ? AND `storage` = ? AND `size` >= 0';
|
||||
$result = \OC_DB::executeAudited($sql, array($id, $this->getNumericStorageId()));
|
||||
if ($row = $result->fetchRow()) {
|
||||
list($sum) = array_values($row);
|
||||
$totalSize = (int)$sum;
|
||||
if ($entry['size'] !== $totalSize) {
|
||||
$this->update($id, array('size' => $totalSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $totalSize;
|
||||
}
|
||||
}
|
|
@ -307,10 +307,18 @@ class Filesystem {
|
|||
$root = \OC_User::getHome($user);
|
||||
|
||||
$userObject = \OC_User::getManager()->get($user);
|
||||
if (\OC\Files\Cache\Storage::exists('local::' . $root . '/') or is_null($userObject)) {
|
||||
|
||||
if (!is_null($userObject)) {
|
||||
// check for legacy home id (<= 5.0.12)
|
||||
if (\OC\Files\Cache\Storage::exists('local::' . $root . '/')) {
|
||||
self::mount('\OC\Files\Storage\Home', array('user' => $userObject, 'legacy' => true), $user);
|
||||
}
|
||||
else {
|
||||
self::mount('\OC\Files\Storage\Home', array('user' => $userObject), $user);
|
||||
}
|
||||
}
|
||||
else {
|
||||
self::mount('\OC\Files\Storage\Local', array('datadir' => $root), $user);
|
||||
} else {
|
||||
self::mount('\OC\Files\Storage\Home', array('user' => $userObject), $user);
|
||||
}
|
||||
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
|
||||
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ namespace OC\Files\Storage;
|
|||
* Specialized version of Local storage for home directory usage
|
||||
*/
|
||||
class Home extends Local {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var \OC\User\User $user
|
||||
*/
|
||||
|
@ -20,11 +25,25 @@ class Home extends Local {
|
|||
public function __construct($arguments) {
|
||||
$this->user = $arguments['user'];
|
||||
$datadir = $this->user->getHome();
|
||||
if (isset($arguments['legacy']) && $arguments['legacy']) {
|
||||
// legacy home id (<= 5.0.12)
|
||||
$this->id = 'local::' . $datadir . '/';
|
||||
}
|
||||
else {
|
||||
$this->id = 'home::' . $this->user->getUID();
|
||||
}
|
||||
|
||||
parent::__construct(array('datadir' => $datadir));
|
||||
}
|
||||
|
||||
public function getId() {
|
||||
return 'home::' . $this->user->getUID();
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCache($path = '') {
|
||||
if (!isset($this->cache)) {
|
||||
$this->cache = new \OC\Files\Cache\HomeCache($this);
|
||||
}
|
||||
return $this->cache;
|
||||
}
|
||||
}
|
||||
|
|
55
tests/lib/files/cache/cache.php
vendored
55
tests/lib/files/cache/cache.php
vendored
|
@ -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
95
tests/lib/files/cache/homecache.php
vendored
Normal 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));
|
||||
}
|
||||
}
|
|
@ -41,9 +41,12 @@ class Filesystem extends \PHPUnit_Framework_TestCase {
|
|||
foreach ($this->tmpDirs as $dir) {
|
||||
\OC_Helper::rmdirr($dir);
|
||||
}
|
||||
\OC\Files\Filesystem::clearMounts();
|
||||
\OC_User::setUserId('');
|
||||
}
|
||||
|
||||
public function setUp() {
|
||||
\OC_User::setUserId('');
|
||||
\OC\Files\Filesystem::clearMounts();
|
||||
}
|
||||
|
||||
|
@ -103,6 +106,67 @@ class Filesystem extends \PHPUnit_Framework_TestCase {
|
|||
// \OC\Files\Filesystem::file_put_contents('/bar//foo', $fh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a local storage mount is used when passed user
|
||||
* does not exist.
|
||||
*/
|
||||
public function testLocalMountWhenUserDoesNotExist() {
|
||||
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
|
||||
$userId = uniqid('user_');
|
||||
|
||||
\OC\Files\Filesystem::initMountPoints($userId);
|
||||
|
||||
$homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
|
||||
|
||||
$this->assertInstanceOf('\OC\Files\Storage\Local', $homeMount);
|
||||
$this->assertEquals('local::' . $datadir . '/' . $userId . '/', $homeMount->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the home storage is used for the user's mount point
|
||||
*/
|
||||
public function testHomeMount() {
|
||||
$userId = uniqid('user_');
|
||||
|
||||
\OC_User::createUser($userId, $userId);
|
||||
|
||||
\OC\Files\Filesystem::initMountPoints($userId);
|
||||
|
||||
$homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
|
||||
|
||||
$this->assertInstanceOf('\OC\Files\Storage\Home', $homeMount);
|
||||
$this->assertEquals('home::' . $userId, $homeMount->getId());
|
||||
|
||||
\OC_User::deleteUser($userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the home storage is used in legacy mode
|
||||
* for the user's mount point
|
||||
*/
|
||||
public function testLegacyHomeMount() {
|
||||
$datadir = \OC_Config::getValue("datadirectory", \OC::$SERVERROOT . "/data");
|
||||
$userId = uniqid('user_');
|
||||
|
||||
// insert storage into DB by constructing it
|
||||
// to make initMountsPoint find its existence
|
||||
$localStorage = new \OC\Files\Storage\Local(array('datadir' => $datadir . '/' . $userId . '/'));
|
||||
// this will trigger the insert
|
||||
$cache = $localStorage->getCache();
|
||||
|
||||
\OC_User::createUser($userId, $userId);
|
||||
\OC\Files\Filesystem::initMountPoints($userId);
|
||||
|
||||
$homeMount = \OC\Files\Filesystem::getStorage('/' . $userId . '/');
|
||||
|
||||
$this->assertInstanceOf('\OC\Files\Storage\Home', $homeMount);
|
||||
$this->assertEquals('local::' . $datadir. '/' . $userId . '/', $homeMount->getId());
|
||||
|
||||
\OC_User::deleteUser($userId);
|
||||
// delete storage entry
|
||||
$cache->clear();
|
||||
}
|
||||
|
||||
public function dummyHook($arguments) {
|
||||
$path = $arguments['path'];
|
||||
$this->assertEquals($path, \OC\Files\Filesystem::normalizePath($path)); //the path passed to the hook should already be normalized
|
||||
|
|
|
@ -56,8 +56,8 @@ class Home extends Storage {
|
|||
|
||||
public function setUp() {
|
||||
$this->tmpDir = \OC_Helper::tmpFolder();
|
||||
$userId = uniqid('user_');
|
||||
$this->user = new DummyUser($userId, $this->tmpDir);
|
||||
$this->userId = uniqid('user_');
|
||||
$this->user = new DummyUser($this->userId, $this->tmpDir);
|
||||
$this->instance = new \OC\Files\Storage\Home(array('user' => $this->user));
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,32 @@ class Home extends Storage {
|
|||
\OC_Helper::rmdirr($this->tmpDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the root path matches the data dir
|
||||
*/
|
||||
public function testRoot() {
|
||||
$this->assertEquals($this->tmpDir, $this->instance->getLocalFolder(''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the home id is in the format home::user1
|
||||
*/
|
||||
public function testId() {
|
||||
$this->assertEquals('home::' . $this->userId, $this->instance->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the legacy home id is in the format local::/path/to/datadir/user1/
|
||||
*/
|
||||
public function testLegacyId() {
|
||||
$this->instance = new \OC\Files\Storage\Home(array('user' => $this->user, 'legacy' => true));
|
||||
$this->assertEquals('local::' . $this->tmpDir . '/', $this->instance->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that getCache() returns an instance of HomeCache
|
||||
*/
|
||||
public function testGetCacheReturnsHomeCache() {
|
||||
$this->assertInstanceOf('\OC\Files\Cache\HomeCache', $this->instance->getCache());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue