diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 3bf63efce0ffb..b4b2b014cf604 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -1649,6 +1649,7 @@ 'OC\\Files\\ObjectStore\\Mapper' => $baseDir . '/lib/private/Files/ObjectStore/Mapper.php', 'OC\\Files\\ObjectStore\\ObjectStoreScanner' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreScanner.php', 'OC\\Files\\ObjectStore\\ObjectStoreStorage' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreStorage.php', + 'OC\\Files\\ObjectStore\\ObjectStoreUpdater' => $baseDir . '/lib/private/Files/ObjectStore/ObjectStoreUpdater.php', 'OC\\Files\\ObjectStore\\PrimaryObjectStoreConfig' => $baseDir . '/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php', 'OC\\Files\\ObjectStore\\S3' => $baseDir . '/lib/private/Files/ObjectStore/S3.php', 'OC\\Files\\ObjectStore\\S3ConfigTrait' => $baseDir . '/lib/private/Files/ObjectStore/S3ConfigTrait.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index f076aaca78302..49b7949f49516 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1690,6 +1690,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Files\\ObjectStore\\Mapper' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/Mapper.php', 'OC\\Files\\ObjectStore\\ObjectStoreScanner' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreScanner.php', 'OC\\Files\\ObjectStore\\ObjectStoreStorage' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreStorage.php', + 'OC\\Files\\ObjectStore\\ObjectStoreUpdater' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/ObjectStoreUpdater.php', 'OC\\Files\\ObjectStore\\PrimaryObjectStoreConfig' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/PrimaryObjectStoreConfig.php', 'OC\\Files\\ObjectStore\\S3' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3.php', 'OC\\Files\\ObjectStore\\S3ConfigTrait' => __DIR__ . '/../../..' . '/lib/private/Files/ObjectStore/S3ConfigTrait.php', diff --git a/lib/private/Files/Cache/Updater.php b/lib/private/Files/Cache/Updater.php index 03681036aa211..17d4062bd691c 100644 --- a/lib/private/Files/Cache/Updater.php +++ b/lib/private/Files/Cache/Updater.php @@ -272,7 +272,7 @@ private function updateStorageMTimeOnly($internalPath) { * * @param string $internalPath */ - private function correctParentStorageMtime($internalPath) { + public function correctParentStorageMtime($internalPath) { $parentId = $this->cache->getParentId($internalPath); $parent = dirname($internalPath); if ($parentId != -1) { diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index 752c3cf4fb79e..0f5d9ec6aa144 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -14,6 +14,7 @@ use Icewind\Streams\IteratorDirectory; use OC\Files\Cache\Cache; use OC\Files\Cache\CacheEntry; +use OC\Files\Cache\Updater; use OC\Files\Storage\PolyFill\CopyDirectory; use OCP\Files\Cache\ICache; use OCP\Files\Cache\ICacheEntry; @@ -152,7 +153,23 @@ public function rmdir(string $path): bool { return false; } - return $this->rmObjects($entry); + $result = $this->rmObjects($entry); + if ($result) { + $this->removeFromCache($entry); + } + return $result; + } + + /** + * Remove an item from cache and propagate the change to the parent folders. + * + * Similar logic to the `Updater` but done in-storage because we have the correct info to avoid expensive + * folder size calculations. + */ + private function removeFromCache(ICacheEntry $entry): void { + $this->cache->remove($entry->getId()); + $this->getUpdater()->correctParentStorageMtime($entry->getPath()); + $this->propagator->propagateChange($entry->getPath(), time(), -$entry->getSize()); } private function rmObjects(ICacheEntry $entry): bool { @@ -179,15 +196,21 @@ private function rmObjects(ICacheEntry $entry): bool { public function unlink(string $path): bool { $path = $this->normalizePath($path); $entry = $this->getCache()->get($path); + $result = false; if ($entry instanceof ICacheEntry) { if ($entry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) { - return $this->rmObjects($entry); + $result = $this->rmObjects($entry); } else { - return $this->rmObject($entry); + $result = $this->rmObject($entry); } } - return false; + + if ($result) { + $this->removeFromCache($entry); + } + + return $result; } public function rmObject(ICacheEntry $entry): bool { @@ -464,6 +487,7 @@ public function writeStream(string $path, $stream, ?int $size = null): int { } // update stat with new data $mTime = time(); + $oldSize = $stat['size'] ?? 0; $stat['size'] = (int)$size; $stat['mtime'] = $mTime; $stat['storage_mtime'] = $mTime; @@ -561,6 +585,9 @@ public function writeStream(string $path, $stream, ?int $size = null): int { } } + $this->getUpdater()->correctParentStorageMtime($path); + $this->propagator->propagateChange($path, $mTime, $stat['size'] - $oldSize); + return $size; } @@ -814,4 +841,18 @@ public function cancelChunkedWrite(string $targetPath, string $writeToken): void public function setPreserveCacheOnDelete(bool $preserve) { $this->preserveCacheItemsOnDelete = $preserve; } + + public function getUpdater(?IStorage $storage = null): Updater { + if (!$storage) { + $storage = $this; + } + if (!$storage->instanceOfStorage(self::class)) { + throw new \InvalidArgumentException('Storage is not of the correct class'); + } + /** @var self $storage */ + if (!isset($storage->updater)) { + $storage->updater = new ObjectStoreUpdater($storage); + } + return $storage->updater; + } } diff --git a/lib/private/Files/ObjectStore/ObjectStoreUpdater.php b/lib/private/Files/ObjectStore/ObjectStoreUpdater.php new file mode 100644 index 0000000000000..b35d883ae707b --- /dev/null +++ b/lib/private/Files/ObjectStore/ObjectStoreUpdater.php @@ -0,0 +1,25 @@ +