From 1a716578fd20890860d6c2f9b3d3f26ed055ed3c Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 22 Aug 2025 19:11:23 +0200 Subject: [PATCH 1/2] fix: fix moving cache items from cache jail with sharding Signed-off-by: Robin Appelman --- lib/private/Files/Cache/Cache.php | 16 +++++++++++++--- lib/private/Files/Cache/Wrapper/CacheWrapper.php | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index 329466e682d80..1f7b74a3e2203 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -10,6 +10,8 @@ use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use OC\DB\Exceptions\DbalException; use OC\DB\QueryBuilder\Sharded\ShardDefinition; +use OC\Files\Cache\Wrapper\CacheJail; +use OC\Files\Cache\Wrapper\CacheWrapper; use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchQuery; use OC\Files\Storage\Wrapper\Encryption; @@ -1215,8 +1217,16 @@ public function getCacheEntryFromSearchResult(ICacheEntry $rawEntry): ?ICacheEnt } private function moveFromStorageSharded(ShardDefinition $shardDefinition, ICache $sourceCache, ICacheEntry $sourceEntry, $targetPath): void { + $sourcePath = $sourceEntry->getPath(); + while ($sourceCache instanceof CacheWrapper) { + if ($sourceCache instanceof CacheJail) { + $sourcePath = $sourceCache->getSourcePath($sourcePath); + } + $sourceCache = $sourceCache->getCache(); + } + if ($sourceEntry->getMimeType() === ICacheEntry::DIRECTORY_MIMETYPE) { - $fileIds = $this->getChildIds($sourceCache->getNumericStorageId(), $sourceEntry->getPath()); + $fileIds = $this->getChildIds($sourceCache->getNumericStorageId(), $sourcePath); } else { $fileIds = []; } @@ -1234,9 +1244,9 @@ private function moveFromStorageSharded(ShardDefinition $shardDefinition, ICache // when moving from an encrypted storage to a non-encrypted storage remove the `encrypted` mark $removeEncryptedFlag = ($sourceCache instanceof Cache && $sourceCache->hasEncryptionWrapper()) && !$this->hasEncryptionWrapper(); - $sourcePathLength = strlen($sourceEntry->getPath()); + $sourcePathLength = strlen($sourcePath); foreach ($cacheItems as &$cacheItem) { - if ($cacheItem['path'] === $sourceEntry->getPath()) { + if ($cacheItem['path'] === $sourcePath) { $cacheItem['path'] = $targetPath; $cacheItem['parent'] = $this->getParentId($targetPath); $cacheItem['name'] = basename($cacheItem['path']); diff --git a/lib/private/Files/Cache/Wrapper/CacheWrapper.php b/lib/private/Files/Cache/Wrapper/CacheWrapper.php index f2f1036d6a398..7fd4cd921aeec 100644 --- a/lib/private/Files/Cache/Wrapper/CacheWrapper.php +++ b/lib/private/Files/Cache/Wrapper/CacheWrapper.php @@ -37,7 +37,10 @@ public function __construct(?ICache $cache, ?CacheDependencies $dependencies = n } } - protected function getCache() { + public function getCache(): ICache { + if (!$this->cache) { + throw new \Exception('Source cache not initialized'); + } return $this->cache; } @@ -202,7 +205,12 @@ public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) { * remove all entries for files that are stored on the storage from the cache */ public function clear() { - $this->getCache()->clear(); + $cache = $this->getCache(); + if ($cache instanceof Cache) { + $cache->clear(); + } else { + $cache->remove(''); + } } /** @@ -252,7 +260,9 @@ public function calculateFolderSize($path, $entry = null) { * @return int[] */ public function getAll() { - return $this->getCache()->getAll(); + /** @var Cache $cache */ + $cache = $this->getCache(); + return $cache->getAll(); } /** From afe77e32f2baf6d7565d85d9a49c57686c6290c5 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Fri, 22 Aug 2025 19:11:37 +0200 Subject: [PATCH 2/2] test: test moving cache items from cache jail with sharding Signed-off-by: Robin Appelman --- tests/lib/Files/Cache/CacheTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/lib/Files/Cache/CacheTest.php b/tests/lib/Files/Cache/CacheTest.php index 383962b7224ea..0ce5a5ac2b38e 100644 --- a/tests/lib/Files/Cache/CacheTest.php +++ b/tests/lib/Files/Cache/CacheTest.php @@ -10,6 +10,7 @@ use OC\Files\Cache\Cache; use OC\Files\Cache\CacheEntry; +use OC\Files\Cache\Wrapper\CacheJail; use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchQuery; use OC\Files\Storage\Temporary; @@ -521,6 +522,24 @@ public function testMoveFromCache(): void { $this->assertTrue($this->cache->inCache('targetfolder/sub')); } + public function testMoveFromCacheJail(): void { + $data = ['size' => 100, 'mtime' => 50, 'mimetype' => 'foo/bar']; + $folderData = ['size' => 100, 'mtime' => 50, 'mimetype' => ICacheEntry::DIRECTORY_MIMETYPE]; + + $this->cache2->put('folder', $folderData); + $this->cache2->put('folder/sub', $data); + + $jail = new CacheJail($this->cache2, 'folder'); + + $this->cache->moveFromCache($jail, 'sub', 'targetsub'); + + $this->assertTrue($this->cache2->inCache('folder')); + $this->assertFalse($this->cache2->inCache('folder/sub')); + + $this->assertTrue($this->cache->inCache('targetsub')); + $this->assertEquals($this->cache->getId(''), $this->cache->get('targetsub')->getParentId()); + } + public function testGetIncomplete(): void { $file1 = 'folder1'; $file2 = 'folder2';