Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
also updated parent etags when a changed etag is detected during scan…
…ning

Signed-off-by: Robin Appelman <[email protected]>
  • Loading branch information
icewind1991 committed Feb 29, 2024
commit b2f39d43236f4fcf94c0a80a7ba4eb3a20bf0bfd
35 changes: 29 additions & 6 deletions lib/private/Files/Cache/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData =
$data['fileid'] = $fileId;
// only reuse data if the file hasn't explicitly changed
$mtimeUnchanged = isset($data['storage_mtime']) && isset($cacheData['storage_mtime']) && $data['storage_mtime'] === $cacheData['storage_mtime'];
// if the folder is marked as unscanned, never reuse etags
if ($mtimeUnchanged && $cacheData['size'] !== -1) {
$data['mtime'] = $cacheData['mtime'];
if (($reuseExisting & self::REUSE_SIZE) && ($data['size'] === -1)) {
Expand All @@ -217,6 +218,11 @@ public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData =

// Only update metadata that has changed
$newData = array_diff_assoc($data, $cacheData->getData());

// make it known to the caller that etag has been changed and needs propagation
if (isset($newData['etag'])) {
$data['etag_changed'] = true;
}
} else {
// we only updated unencrypted_size if it's already set
unset($data['unencrypted_size']);
Expand Down Expand Up @@ -380,7 +386,7 @@ protected function getExistingChildren($folderId) {
* @param array $data the data of the folder before (re)scanning the children
* @return int|float the size of the scanned folder or -1 if the size is unknown at this stage
*/
protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true, array $data = []) {
protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true, array $data = [], &$etagChanged = false) {
if ($reuse === -1) {
$reuse = ($recursive === self::SCAN_SHALLOW) ? self::REUSE_ETAG | self::REUSE_SIZE : self::REUSE_ETAG;
}
Expand All @@ -389,10 +395,14 @@ protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse
if (!is_null($folderId)) {
$folderId = $this->cache->getId($path);
}
$childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size);
$childQueue = $this->handleChildren($path, $recursive, $reuse, $folderId, $lock, $size, $etagChanged);

foreach ($childQueue as $child => $childId) {
$childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock);
// "etag changed" propagates up, but not down, so we pass `false` to the children even if we already know that the etag of the current folder changed
$childEtagChanged = false;
$childSize = $this->scanChildren($child, $recursive, $reuse, $childId, $lock, [], $childEtagChanged);
$etagChanged |= $childEtagChanged;

if ($childSize === -1) {
$size = -1;
} elseif ($size !== -1) {
Expand All @@ -406,15 +416,24 @@ protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse
if ($this->storage->instanceOfStorage(Encryption::class)) {
$this->cache->calculateFolderSize($path);
} else {
if ($this->cacheActive && $oldSize !== $size) {
$this->cache->update($folderId, ['size' => $size]);
if ($this->cacheActive) {
$updatedData = [];
if ($oldSize !== $size) {
$updatedData['size'] = $size;
}
if ($etagChanged) {
$updatedData['etag'] = uniqid();
}
if ($updatedData) {
$this->cache->update($folderId, $updatedData);
}
}
}
$this->emit('\OC\Files\Cache\Scanner', 'postScanFolder', [$path, $this->storageId]);
return $size;
}

private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$size) {
private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$size, bool &$etagChanged) {
// we put this in it's own function so it cleans up the memory before we start recursing
$existingChildren = $this->getExistingChildren($folderId);
$newChildren = iterator_to_array($this->storage->getDirectoryContent($path));
Expand Down Expand Up @@ -462,6 +481,10 @@ private function handleChildren($path, $recursive, $reuse, $folderId, $lock, &$s
} elseif ($size !== -1) {
$size += $data['size'];
}

if (isset($data['etag_changed']) && $data['etag_changed']) {
$etagChanged = true;
}
}
} catch (Exception $ex) {
// might happen if inserting duplicate while a scanning
Expand Down
7 changes: 5 additions & 2 deletions lib/private/Files/ObjectStore/NoopScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,13 @@ public function scan($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $loc
* @param string $path
* @param bool $recursive
* @param int $reuse
* @param array $folderData existing cache data for the folder to be scanned
* @param ?int $folderId
* @param bool $lock
* @param array $data
* @param bool &$etagChanged
* @return int the size of the scanned folder or -1 if the size is unknown at this stage
*/
protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true, array $data = []) {
protected function scanChildren($path, $recursive = self::SCAN_RECURSIVE, $reuse = -1, $folderId = null, $lock = true, array $data = [], &$etagChanged = false) {
return 0;
}

Expand Down