Skip to content

Commit eeb4de0

Browse files
authored
Merge pull request #32708 from nextcloud/unencrypted-size-24
[24] store unencrypted size in the unencrypted_size column
2 parents e2c213a + fd2afe6 commit eeb4de0

File tree

10 files changed

+164
-56
lines changed

10 files changed

+164
-56
lines changed

lib/private/Files/Cache/Cache.php

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
* along with this program. If not, see <http://www.gnu.org/licenses/>
3838
*
3939
*/
40+
4041
namespace OC\Files\Cache;
4142

4243
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
@@ -188,6 +189,7 @@ public static function cacheEntryFromData($data, IMimeTypeLoader $mimetypeLoader
188189
$data['fileid'] = (int)$data['fileid'];
189190
$data['parent'] = (int)$data['parent'];
190191
$data['size'] = 0 + $data['size'];
192+
$data['unencrypted_size'] = 0 + ($data['unencrypted_size'] ?? 0);
191193
$data['mtime'] = (int)$data['mtime'];
192194
$data['storage_mtime'] = (int)$data['storage_mtime'];
193195
$data['encryptedVersion'] = (int)$data['encrypted'];
@@ -428,7 +430,7 @@ public function update($id, array $data) {
428430
protected function normalizeData(array $data): array {
429431
$fields = [
430432
'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted',
431-
'etag', 'permissions', 'checksum', 'storage'];
433+
'etag', 'permissions', 'checksum', 'storage', 'unencrypted_size'];
432434
$extensionFields = ['metadata_etag', 'creation_time', 'upload_time'];
433435

434436
$doNotCopyStorageMTime = false;
@@ -873,27 +875,56 @@ public function calculateFolderSize($path, $entry = null) {
873875
$id = $entry['fileid'];
874876

875877
$query = $this->getQueryBuilder();
876-
$query->selectAlias($query->func()->sum('size'), 'f1')
877-
->selectAlias($query->func()->min('size'), 'f2')
878+
$query->select('size', 'unencrypted_size')
878879
->from('filecache')
879-
->whereStorageId($this->getNumericStorageId())
880880
->whereParent($id);
881881

882882
$result = $query->execute();
883-
$row = $result->fetch();
883+
$rows = $result->fetchAll();
884884
$result->closeCursor();
885885

886-
if ($row) {
887-
[$sum, $min] = array_values($row);
886+
if ($rows) {
887+
$sizes = array_map(function (array $row) {
888+
return (int)$row['size'];
889+
}, $rows);
890+
$unencryptedOnlySizes = array_map(function (array $row) {
891+
return (int)$row['unencrypted_size'];
892+
}, $rows);
893+
$unencryptedSizes = array_map(function (array $row) {
894+
return (int)(($row['unencrypted_size'] > 0) ? $row['unencrypted_size']: $row['size']);
895+
}, $rows);
896+
897+
$sum = array_sum($sizes);
898+
$min = min($sizes);
899+
900+
$unencryptedSum = array_sum($unencryptedSizes);
901+
$unencryptedMin = min($unencryptedSizes);
902+
$unencryptedMax = max($unencryptedOnlySizes);
903+
888904
$sum = 0 + $sum;
889905
$min = 0 + $min;
890906
if ($min === -1) {
891907
$totalSize = $min;
892908
} else {
893909
$totalSize = $sum;
894910
}
911+
if ($unencryptedMin === -1 || $min === -1) {
912+
$unencryptedTotal = $unencryptedMin;
913+
} else {
914+
$unencryptedTotal = $unencryptedSum;
915+
}
895916
if ($entry['size'] !== $totalSize) {
896-
$this->update($id, ['size' => $totalSize]);
917+
// only set unencrypted size for a folder if any child entries have it set
918+
if ($unencryptedMax > 0) {
919+
$this->update($id, [
920+
'size' => $totalSize,
921+
'unencrypted_size' => $unencryptedTotal,
922+
]);
923+
} else {
924+
$this->update($id, [
925+
'size' => $totalSize,
926+
]);
927+
}
897928
}
898929
}
899930
}

lib/private/Files/Cache/CacheEntry.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,12 @@ public function getData() {
132132
public function __clone() {
133133
$this->data = array_merge([], $this->data);
134134
}
135+
136+
public function getUnencryptedSize(): int {
137+
if (isset($this->data['unencrypted_size']) && $this->data['unencrypted_size'] > 0) {
138+
return $this->data['unencrypted_size'];
139+
} else {
140+
return $this->data['size'];
141+
}
142+
}
135143
}

lib/private/Files/Cache/CacheQueryBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function __construct(IDBConnection $connection, SystemConfig $systemConfi
4444
public function selectFileCache(string $alias = null) {
4545
$name = $alias ? $alias : 'filecache';
4646
$this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", 'name', 'mimetype', 'mimepart', 'size', 'mtime',
47-
'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'metadata_etag', 'creation_time', 'upload_time')
47+
'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'metadata_etag', 'creation_time', 'upload_time', 'unencrypted_size')
4848
->from('filecache', $name)
4949
->leftJoin($name, 'filecache_extended', 'fe', $this->expr()->eq("$name.fileid", 'fe.fileid'));
5050

lib/private/Files/Cache/Propagator.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
namespace OC\Files\Cache;
2626

27+
use OC\DB\QueryBuilder\QueryFunction;
28+
use OC\Files\Storage\Wrapper\Encryption;
2729
use OCP\DB\QueryBuilder\IQueryBuilder;
2830
use OCP\Files\Cache\IPropagator;
2931
use OCP\Files\Storage\IReliableEtagStorage;
@@ -113,6 +115,20 @@ public function propagateChange($internalPath, $time, $sizeDifference = 0) {
113115
->andWhere($builder->expr()->in('path_hash', $hashParams))
114116
->andWhere($builder->expr()->gt('size', $builder->expr()->literal(-1, IQueryBuilder::PARAM_INT)));
115117

118+
if ($this->storage->instanceOfStorage(Encryption::class)) {
119+
// in case of encryption being enabled after some files are already uploaded, some entries will have an unencrypted_size of 0 and a non-zero size
120+
$eq = $builder->expr()->eq('unencrypted_size', $builder->expr()->literal(0, IQueryBuilder::PARAM_INT));
121+
$sizeColumn = $builder->getColumnName('size');
122+
$unencryptedSizeColumn = $builder->getColumnName('unencrypted_size');
123+
$builder->set('unencrypted_size', $builder->func()->greatest(
124+
$builder->func()->add(
125+
new QueryFunction("CASE WHEN $eq THEN $unencryptedSizeColumn ELSE $sizeColumn END"),
126+
$builder->createNamedParameter($sizeDifference)
127+
),
128+
$builder->createNamedParameter(-1, IQueryBuilder::PARAM_INT)
129+
));
130+
}
131+
116132
$builder->execute();
117133
}
118134
}

lib/private/Files/FileInfo.php

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ public function __construct($path, $storage, $internalPath, $data, $mount, $owne
101101
$this->data = $data;
102102
$this->mount = $mount;
103103
$this->owner = $owner;
104-
$this->rawSize = $this->data['size'] ?? 0;
104+
if (isset($this->data['unencrypted_size'])) {
105+
$this->rawSize = $this->data['unencrypted_size'];
106+
} else {
107+
$this->rawSize = $this->data['size'] ?? 0;
108+
}
105109
}
106110

107111
public function offsetSet($offset, $value): void {
@@ -208,7 +212,12 @@ public function getEtag() {
208212
public function getSize($includeMounts = true) {
209213
if ($includeMounts) {
210214
$this->updateEntryfromSubMounts();
211-
return isset($this->data['size']) ? 0 + $this->data['size'] : 0;
215+
216+
if (isset($this->data['unencrypted_size']) && $this->data['unencrypted_size'] > 0) {
217+
return $this->data['unencrypted_size'];
218+
} else {
219+
return isset($this->data['size']) ? 0 + $this->data['size'] : 0;
220+
}
212221
} else {
213222
return $this->rawSize;
214223
}
@@ -386,7 +395,19 @@ private function updateEntryfromSubMounts() {
386395
* @param string $entryPath full path of the child entry
387396
*/
388397
public function addSubEntry($data, $entryPath) {
389-
$this->data['size'] += isset($data['size']) ? $data['size'] : 0;
398+
if (!$data) {
399+
return;
400+
}
401+
$hasUnencryptedSize = isset($data['unencrypted_size']) && $data['unencrypted_size'] > 0;
402+
if ($hasUnencryptedSize) {
403+
$subSize = $data['unencrypted_size'];
404+
} else {
405+
$subSize = $data['size'] ?: 0;
406+
}
407+
$this->data['size'] += $subSize;
408+
if ($hasUnencryptedSize) {
409+
$this->data['unencrypted_size'] += $subSize;
410+
}
390411
if (isset($data['mtime'])) {
391412
$this->data['mtime'] = max($this->data['mtime'], $data['mtime']);
392413
}

0 commit comments

Comments
 (0)