diff options
Diffstat (limited to 'lib/private/Files')
-rw-r--r-- | lib/private/Files/ObjectStore/Azure.php | 14 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/HomeObjectStoreStorage.php | 5 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/ObjectStoreStorage.php | 68 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/S3.php | 13 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/StorageObjectStore.php | 9 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/Swift.php | 9 |
6 files changed, 116 insertions, 2 deletions
diff --git a/lib/private/Files/ObjectStore/Azure.php b/lib/private/Files/ObjectStore/Azure.php index 553f593b299..24362647619 100644 --- a/lib/private/Files/ObjectStore/Azure.php +++ b/lib/private/Files/ObjectStore/Azure.php @@ -25,6 +25,7 @@ namespace OC\Files\ObjectStore; use MicrosoftAzure\Storage\Blob\BlobRestProxy; use MicrosoftAzure\Storage\Blob\Models\CreateBlockBlobOptions; use MicrosoftAzure\Storage\Common\Exceptions\ServiceException; +use OCP\Files\FileInfo; use OCP\Files\ObjectStore\IObjectStore; class Azure implements IObjectStore { @@ -133,4 +134,17 @@ class Azure implements IObjectStore { public function copyObject($from, $to) { $this->getBlobClient()->copyBlob($this->containerName, $to, $this->containerName, $from); } + + public function bytesUsed(): int { + // The only way to get the bytes used is by listing every object + // in the blob and sum their size + return FileInfo::SPACE_UNKNOWN; + } + + public function bytesQuota(): int { + // Azure doesn't have a way to set a quota on a specific blob container, + // only on a storage account + // https://learn.microsoft.com/en-us/answers/questions/627442/blob-general-v2-container-quota.html + return FileInfo::SPACE_UNLIMITED; + } } diff --git a/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php b/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php index b361249ff47..4e1f49a351c 100644 --- a/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/HomeObjectStoreStorage.php @@ -27,8 +27,9 @@ namespace OC\Files\ObjectStore; use OC\User\User; use OCP\IUser; +use OCP\Files\IHomeStorage; -class HomeObjectStoreStorage extends ObjectStoreStorage implements \OCP\Files\IHomeStorage { +class HomeObjectStoreStorage extends ObjectStoreStorage implements IHomeStorage { /** * The home user storage requires a user object to create a unique storage id * @param array $params @@ -60,7 +61,7 @@ class HomeObjectStoreStorage extends ObjectStoreStorage implements \OCP\Files\IH /** * @param string $path, optional - * @return \OC\User\User + * @return User */ public function getUser($path = null): IUser { return $this->user; diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index eb8aaffe1e0..48ca9486090 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -47,6 +47,10 @@ use OCP\Files\ObjectStore\IObjectStore; use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload; use OCP\Files\Storage\IChunkedFileWrite; use OCP\Files\Storage\IStorage; +use OCP\ICacheFactory; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Server; class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFileWrite { use CopyDirectory; @@ -738,4 +742,68 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil $urn = $this->getURN($cacheEntry->getId()); $this->objectStore->abortMultipartUpload($urn, $writeToken); } + + /** + * In case the admin has overwritten the global instance quota, + * default to the quota minus the used object storage size known by Nextcloud + * instead of unknown + * + * @param $path + */ + public function free_space($path) { + $cacheFactory = Server::get(ICacheFactory::class); + $memcache = $cacheFactory->createLocal('object_storage_info'); + $cacheKey = 'object_store_used_size'; + $size = $memcache->get($cacheKey); + if ($size) { + return $size; + } + + // Ask for the object store backend + $quota = $this->objectStore->bytesQuota(); + + // If not given, by the object store backend, check if we have an override + if ($quota < 0) { + /** @var IConfig $config */ + $config = Server::get(IConfig::class); + $quota = (int) $config->getAppValue('core', 'quota_instance_global', '0'); + } + + // If there's a quota in place + if ($quota > 0) { + // The used size, directly given by the object store backend + $size = $this->objectStore->bytesUsed(); + if ($size < 0) { + // Otherwise we just make the sum of all of the storages sizes currently in Nextcloud + // Note: This will not take into account object versioning handled + // on the object store backend's side such as when using files_versions_s3 + $size = $this->getUsedObjectStorageSizeInNextcloud(); + } + $freeSpace = $quota - $size; + $memcache->set($cacheKey, $freeSpace, 5 * 60); + return $freeSpace; + } + // Otherwise default to unknown + return parent::free_space($path); + } + + /** + * Returns the sum of file sizes from all of the users storages using object storage, + * as well as the global object store storage. + */ + public function getUsedObjectStorageSizeInNextcloud(): ?int { + $qb = Server::get(IDBConnection::class)->getQueryBuilder(); + $result = $qb->select($qb->func()->sum('size')) + ->from('filecache', 'fc') + ->join('fc', 'storages', 's', $qb->expr()->eq('fc.storage', 's.numeric_id')) + ->where($qb->expr()->like('s.id', $qb->createNamedParameter('object::%'))) + ->andWhere($qb->expr()->eq('fc.path', $qb->createNamedParameter(''))) + ->executeQuery(); + + $row = $result->fetchOne(); + if ($row) { + return (int) $row; + } + return null; + } } diff --git a/lib/private/Files/ObjectStore/S3.php b/lib/private/Files/ObjectStore/S3.php index b1cd89388ae..d4e207f9002 100644 --- a/lib/private/Files/ObjectStore/S3.php +++ b/lib/private/Files/ObjectStore/S3.php @@ -25,6 +25,7 @@ namespace OC\Files\ObjectStore; use Aws\Result; use Exception; +use OCP\Files\FileInfo; use OCP\Files\ObjectStore\IObjectStore; use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload; @@ -110,4 +111,16 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload { 'UploadId' => $uploadId ]); } + + public function bytesUsed(): int { + // The only way to get the bytes used is by listing every object + // in the bucket and sum their size + return FileInfo::SPACE_UNKNOWN; + } + + public function bytesQuota(): int { + // The quota is not obtainable through the S3 API, only through the + // specific Amazon Service Quotas API + return FileInfo::SPACE_UNLIMITED; + } } diff --git a/lib/private/Files/ObjectStore/StorageObjectStore.php b/lib/private/Files/ObjectStore/StorageObjectStore.php index 85926be897e..260238c106c 100644 --- a/lib/private/Files/ObjectStore/StorageObjectStore.php +++ b/lib/private/Files/ObjectStore/StorageObjectStore.php @@ -23,6 +23,7 @@ */ namespace OC\Files\ObjectStore; +use OCP\Files\FileInfo; use OCP\Files\ObjectStore\IObjectStore; use OCP\Files\Storage\IStorage; use function is_resource; @@ -91,4 +92,12 @@ class StorageObjectStore implements IObjectStore { public function copyObject($from, $to) { $this->storage->copy($from, $to); } + + public function bytesUsed(): int { + return FileInfo::SPACE_UNKNOWN; + } + + public function bytesQuota(): int { + return FileInfo::SPACE_UNLIMITED; + } } diff --git a/lib/private/Files/ObjectStore/Swift.php b/lib/private/Files/ObjectStore/Swift.php index b463cb9d44d..5a8860a6d51 100644 --- a/lib/private/Files/ObjectStore/Swift.php +++ b/lib/private/Files/ObjectStore/Swift.php @@ -29,6 +29,7 @@ use GuzzleHttp\Client; use GuzzleHttp\Exception\BadResponseException; use GuzzleHttp\Psr7\Utils; use Icewind\Streams\RetryWrapper; +use OCP\Files\FileInfo; use OCP\Files\NotFoundException; use OCP\Files\ObjectStore\IObjectStore; use OCP\Files\StorageAuthException; @@ -152,4 +153,12 @@ class Swift implements IObjectStore { 'destination' => $this->getContainer()->name . '/' . $to ]); } + + public function bytesUsed(): int { + return $this->getContainer()->bytesUsed; + } + + public function bytesQuota(): int { + return $this->getContainer()->getMetadata()['Quota-Bytes'] ?? FileInfo::SPACE_UNLIMITED; + } } |