mirror of https://github.com/nextcloud/server
Merge pull request #33600 from nextcloud/lazy-quota
get quota for user only when needed
This commit is contained in:
commit
417f46e467
|
@ -172,10 +172,10 @@ class SetupManager {
|
||||||
*/
|
*/
|
||||||
if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) {
|
if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) {
|
||||||
if (is_object($storage->getUser())) {
|
if (is_object($storage->getUser())) {
|
||||||
$quota = OC_Util::getUserQuota($storage->getUser());
|
$user = $storage->getUser();
|
||||||
if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
|
return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
|
||||||
return new Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']);
|
return OC_Util::getUserQuota($user);
|
||||||
}
|
}, 'root' => 'files']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,40 +33,47 @@
|
||||||
namespace OC\Files\Storage\Wrapper;
|
namespace OC\Files\Storage\Wrapper;
|
||||||
|
|
||||||
use OC\Files\Filesystem;
|
use OC\Files\Filesystem;
|
||||||
|
use OC\SystemConfig;
|
||||||
use OCP\Files\Cache\ICacheEntry;
|
use OCP\Files\Cache\ICacheEntry;
|
||||||
|
use OCP\Files\FileInfo;
|
||||||
use OCP\Files\Storage\IStorage;
|
use OCP\Files\Storage\IStorage;
|
||||||
|
|
||||||
class Quota extends Wrapper {
|
class Quota extends Wrapper {
|
||||||
|
/** @var callable|null */
|
||||||
/**
|
protected $quotaCallback;
|
||||||
* @var int $quota
|
protected ?int $quota;
|
||||||
*/
|
protected string $sizeRoot;
|
||||||
protected $quota;
|
private SystemConfig $config;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string $sizeRoot
|
|
||||||
*/
|
|
||||||
protected $sizeRoot;
|
|
||||||
|
|
||||||
private $config;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $parameters
|
* @param array $parameters
|
||||||
*/
|
*/
|
||||||
public function __construct($parameters) {
|
public function __construct($parameters) {
|
||||||
parent::__construct($parameters);
|
parent::__construct($parameters);
|
||||||
$this->quota = $parameters['quota'];
|
$this->quota = $parameters['quota'] ?? null;
|
||||||
$this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : '';
|
$this->quotaCallback = $parameters['quotaCallback'] ?? null;
|
||||||
$this->config = \OC::$server->getSystemConfig();
|
$this->sizeRoot = $parameters['root'] ?? '';
|
||||||
|
$this->config = \OC::$server->get(SystemConfig::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int quota value
|
* @return int quota value
|
||||||
*/
|
*/
|
||||||
public function getQuota() {
|
public function getQuota(): int {
|
||||||
|
if ($this->quota === null) {
|
||||||
|
$quotaCallback = $this->quotaCallback;
|
||||||
|
if ($quotaCallback === null) {
|
||||||
|
throw new \Exception("No quota or quota callback provider");
|
||||||
|
}
|
||||||
|
$this->quota = $quotaCallback();
|
||||||
|
}
|
||||||
return $this->quota;
|
return $this->quota;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function hasQuota(): bool {
|
||||||
|
return $this->getQuota() !== FileInfo::SPACE_UNLIMITED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param \OC\Files\Storage\Storage $storage
|
* @param \OC\Files\Storage\Storage $storage
|
||||||
|
@ -100,7 +107,10 @@ class Quota extends Wrapper {
|
||||||
* @return int|bool
|
* @return int|bool
|
||||||
*/
|
*/
|
||||||
public function free_space($path) {
|
public function free_space($path) {
|
||||||
if ($this->quota < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
|
if (!$this->hasQuota()) {
|
||||||
|
return $this->storage->free_space($path);
|
||||||
|
}
|
||||||
|
if ($this->getQuota() < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
|
||||||
return $this->storage->free_space($path);
|
return $this->storage->free_space($path);
|
||||||
} else {
|
} else {
|
||||||
$used = $this->getSize($this->sizeRoot);
|
$used = $this->getSize($this->sizeRoot);
|
||||||
|
@ -108,7 +118,7 @@ class Quota extends Wrapper {
|
||||||
return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
|
return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
|
||||||
} else {
|
} else {
|
||||||
$free = $this->storage->free_space($path);
|
$free = $this->storage->free_space($path);
|
||||||
$quotaFree = max($this->quota - $used, 0);
|
$quotaFree = max($this->getQuota() - $used, 0);
|
||||||
// if free space is known
|
// if free space is known
|
||||||
if ($free >= 0) {
|
if ($free >= 0) {
|
||||||
$free = min($free, $quotaFree);
|
$free = min($free, $quotaFree);
|
||||||
|
@ -128,6 +138,9 @@ class Quota extends Wrapper {
|
||||||
* @return int|false
|
* @return int|false
|
||||||
*/
|
*/
|
||||||
public function file_put_contents($path, $data) {
|
public function file_put_contents($path, $data) {
|
||||||
|
if (!$this->hasQuota()) {
|
||||||
|
return $this->storage->file_put_contents($path, $data);
|
||||||
|
}
|
||||||
$free = $this->free_space($path);
|
$free = $this->free_space($path);
|
||||||
if ($free < 0 or strlen($data) < $free) {
|
if ($free < 0 or strlen($data) < $free) {
|
||||||
return $this->storage->file_put_contents($path, $data);
|
return $this->storage->file_put_contents($path, $data);
|
||||||
|
@ -144,6 +157,9 @@ class Quota extends Wrapper {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function copy($source, $target) {
|
public function copy($source, $target) {
|
||||||
|
if (!$this->hasQuota()) {
|
||||||
|
return $this->storage->copy($source, $target);
|
||||||
|
}
|
||||||
$free = $this->free_space($target);
|
$free = $this->free_space($target);
|
||||||
if ($free < 0 or $this->getSize($source) < $free) {
|
if ($free < 0 or $this->getSize($source) < $free) {
|
||||||
return $this->storage->copy($source, $target);
|
return $this->storage->copy($source, $target);
|
||||||
|
@ -160,6 +176,9 @@ class Quota extends Wrapper {
|
||||||
* @return resource|bool
|
* @return resource|bool
|
||||||
*/
|
*/
|
||||||
public function fopen($path, $mode) {
|
public function fopen($path, $mode) {
|
||||||
|
if (!$this->hasQuota()) {
|
||||||
|
return $this->storage->fopen($path, $mode);
|
||||||
|
}
|
||||||
$source = $this->storage->fopen($path, $mode);
|
$source = $this->storage->fopen($path, $mode);
|
||||||
|
|
||||||
// don't apply quota for part files
|
// don't apply quota for part files
|
||||||
|
@ -202,6 +221,9 @@ class Quota extends Wrapper {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
|
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
|
||||||
|
if (!$this->hasQuota()) {
|
||||||
|
return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
|
||||||
|
}
|
||||||
$free = $this->free_space($targetInternalPath);
|
$free = $this->free_space($targetInternalPath);
|
||||||
if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
|
if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
|
||||||
return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
|
return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
|
||||||
|
@ -217,6 +239,9 @@ class Quota extends Wrapper {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
|
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
|
||||||
|
if (!$this->hasQuota()) {
|
||||||
|
return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
|
||||||
|
}
|
||||||
$free = $this->free_space($targetInternalPath);
|
$free = $this->free_space($targetInternalPath);
|
||||||
if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
|
if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
|
||||||
return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
|
return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
|
||||||
|
@ -226,8 +251,11 @@ class Quota extends Wrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mkdir($path) {
|
public function mkdir($path) {
|
||||||
|
if (!$this->hasQuota()) {
|
||||||
|
return $this->storage->mkdir($path);
|
||||||
|
}
|
||||||
$free = $this->free_space($path);
|
$free = $this->free_space($path);
|
||||||
if ($this->shouldApplyQuota($path) && $free === 0.0) {
|
if ($this->shouldApplyQuota($path) && $free == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,8 +263,11 @@ class Quota extends Wrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function touch($path, $mtime = null) {
|
public function touch($path, $mtime = null) {
|
||||||
|
if (!$this->hasQuota()) {
|
||||||
|
return $this->storage->touch($path, $mtime);
|
||||||
|
}
|
||||||
$free = $this->free_space($path);
|
$free = $this->free_space($path);
|
||||||
if ($free === 0.0) {
|
if ($free == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
|
||||||
* @license AGPL-3.0
|
|
||||||
*
|
|
||||||
* This code is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License, version 3,
|
|
||||||
* as published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Test\Files\Storage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class HomeStorageQuotaTest
|
|
||||||
*
|
|
||||||
* @group DB
|
|
||||||
*/
|
|
||||||
class HomeStorageQuotaTest extends \Test\TestCase {
|
|
||||||
/**
|
|
||||||
* Tests that the home storage is not wrapped when no quota exists.
|
|
||||||
*/
|
|
||||||
public function testHomeStorageWrapperWithoutQuota() {
|
|
||||||
$user1 = $this->getUniqueID();
|
|
||||||
\OC::$server->getUserManager()->createUser($user1, 'test');
|
|
||||||
\OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', 'none');
|
|
||||||
\OC_User::setUserId($user1);
|
|
||||||
|
|
||||||
\OC_Util::setupFS($user1);
|
|
||||||
|
|
||||||
$userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/');
|
|
||||||
$this->assertNotNull($userMount);
|
|
||||||
$this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $userMount->getStorage());
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
\OC_User::setUserId('');
|
|
||||||
$user = \OC::$server->getUserManager()->get($user1);
|
|
||||||
if ($user !== null) {
|
|
||||||
$user->delete();
|
|
||||||
}
|
|
||||||
\OC::$server->getConfig()->deleteAllUserValues($user1);
|
|
||||||
\OC_Util::tearDownFS();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the home storage is not wrapped when no quota exists.
|
|
||||||
*/
|
|
||||||
public function testHomeStorageWrapperWithQuota() {
|
|
||||||
$user1 = $this->getUniqueID();
|
|
||||||
\OC::$server->getUserManager()->createUser($user1, 'test');
|
|
||||||
\OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', '1024');
|
|
||||||
\OC_User::setUserId($user1);
|
|
||||||
|
|
||||||
\OC_Util::setupFS($user1);
|
|
||||||
|
|
||||||
$userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/');
|
|
||||||
$this->assertNotNull($userMount);
|
|
||||||
$this->assertTrue($userMount->getStorage()->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota'));
|
|
||||||
|
|
||||||
// ensure that root wasn't wrapped
|
|
||||||
$rootMount = \OC\Files\Filesystem::getMountManager()->find('/');
|
|
||||||
$this->assertNotNull($rootMount);
|
|
||||||
$this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $rootMount->getStorage());
|
|
||||||
|
|
||||||
// clean up
|
|
||||||
\OC_User::setUserId('');
|
|
||||||
$user = \OC::$server->getUserManager()->get($user1);
|
|
||||||
if ($user !== null) {
|
|
||||||
$user->delete();
|
|
||||||
}
|
|
||||||
\OC::$server->getConfig()->deleteAllUserValues($user1);
|
|
||||||
\OC_Util::tearDownFS();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue