Merge pull request #57514 from nextcloud/carl/optimize-cacheentry

perf(files): Optimize CacheEntry creation
This commit is contained in:
Andy Scherzinger 2026-01-15 12:57:42 +01:00 committed by GitHub
commit 06b064e5f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 62 additions and 55 deletions

View file

@ -9,6 +9,7 @@ namespace OCA\Files_Sharing\Tests;
use OC\Files\Cache\Cache;
use OC\Files\Filesystem;
use OC\Files\SetupManager;
use OC\Files\Storage\Storage;
use OC\Files\Storage\Temporary;
use OC\Files\Storage\Wrapper\Jail;
@ -16,6 +17,7 @@ use OC\Files\View;
use OCA\Files_Sharing\SharedStorage;
use OCP\Constants;
use OCP\Files\Cache\IWatcher;
use OCP\Files\IRootFolder;
use OCP\IUserManager;
use OCP\Server;
use OCP\Share\IShare;
@ -424,8 +426,7 @@ class CacheTest extends TestCase {
$share = $this->shareManager->createShare($share);
$share->setStatus(IShare::STATUS_ACCEPTED);
$this->shareManager->updateShare($share);
\OC_Util::tearDownFS();
Server::get(SetupManager::class)->tearDown();
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$this->assertTrue(Filesystem::file_exists('/test.txt'));
@ -456,7 +457,7 @@ class CacheTest extends TestCase {
$share = $this->shareManager->createShare($share);
$share->setStatus(IShare::STATUS_ACCEPTED);
$this->shareManager->updateShare($share);
\OC_Util::tearDownFS();
Server::get(SetupManager::class)->tearDown();
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$this->assertTrue(Filesystem::file_exists('/foo'));
@ -484,7 +485,7 @@ class CacheTest extends TestCase {
$share = $this->shareManager->createShare($share);
$share->setStatus(IShare::STATUS_ACCEPTED);
$this->shareManager->updateShare($share);
\OC_Util::tearDownFS();
Server::get(SetupManager::class)->tearDown();
[$sourceStorage] = Filesystem::resolvePath('/' . self::TEST_FILES_SHARING_API_USER1 . '/files/foo');
@ -521,7 +522,7 @@ class CacheTest extends TestCase {
$share = $this->shareManager->createShare($share);
$share->setStatus(IShare::STATUS_ACCEPTED);
$this->shareManager->updateShare($share);
\OC_Util::tearDownFS();
Server::get(SetupManager::class)->tearDown();
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$this->assertEquals('foo', Filesystem::file_get_contents('/sub/foo.txt'));
@ -560,7 +561,7 @@ class CacheTest extends TestCase {
$share = $this->shareManager->createShare($share);
$share->setStatus(IShare::STATUS_ACCEPTED);
$this->shareManager->updateShare($share);
\OC_Util::tearDownFS();
Server::get(SetupManager::class)->tearDown();
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
@ -571,7 +572,7 @@ class CacheTest extends TestCase {
$this->assertCount(1, $results);
}
public function testWatcherRootChange() {
public function testWatcherRootChange(): void {
$sourceStorage = new Temporary();
$sourceStorage->mkdir('shared');
$sourceStorage->file_put_contents('shared/foo.txt', 'foo');
@ -581,7 +582,8 @@ class CacheTest extends TestCase {
self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
$rootFolder = \OC::$server->getUserFolder(self::TEST_FILES_SHARING_API_USER1);
$rootFolder = Server::get(IRootFolder::class)
->getUserFolder(self::TEST_FILES_SHARING_API_USER1);
$node = $rootFolder->get('foo/shared');
$this->assertEquals(3, $node->getSize());
@ -594,14 +596,14 @@ class CacheTest extends TestCase {
$share = $this->shareManager->createShare($share);
$share->setStatus(IShare::STATUS_ACCEPTED);
$this->shareManager->updateShare($share);
\OC_Util::tearDownFS();
Server::get(SetupManager::class)->tearDown();
self::loginHelper(self::TEST_FILES_SHARING_API_USER2);
$view = Filesystem::getView();
$this->assertTrue($sourceStorage->rmdir('shared'));
$sourceStorage->rmdir('shared');
$this->assertFalse($view->getFileInfo('shared'));
$this->assertFalse(Server::get(IRootFolder::class)
->getUserFolder(self::TEST_FILES_SHARING_API_USER2)
->nodeExists('shared'));
}
}

View file

@ -148,41 +148,50 @@ class Cache implements ICache {
/**
* Create a CacheEntry from database row
*
* @param array $data
* @param IMimeTypeLoader $mimetypeLoader
* @return CacheEntry
*/
public static function cacheEntryFromData($data, IMimeTypeLoader $mimetypeLoader) {
//fix types
$data['name'] = (string)$data['name'];
$data['path'] = (string)$data['path'];
$data['fileid'] = (int)$data['fileid'];
$data['parent'] = (int)$data['parent'];
$data['size'] = Util::numericToNumber($data['size']);
$data['unencrypted_size'] = Util::numericToNumber($data['unencrypted_size'] ?? 0);
$data['mtime'] = (int)$data['mtime'];
$data['storage_mtime'] = (int)$data['storage_mtime'];
$data['encryptedVersion'] = (int)$data['encrypted'];
$data['encrypted'] = (bool)$data['encrypted'];
$data['storage_id'] = $data['storage'];
$data['storage'] = (int)$data['storage'];
$data['mimetype'] = $mimetypeLoader->getMimetypeById($data['mimetype']);
$data['mimepart'] = $mimetypeLoader->getMimetypeById($data['mimepart']);
if ($data['storage_mtime'] == 0) {
$data['storage_mtime'] = $data['mtime'];
public static function cacheEntryFromData(array $data, IMimeTypeLoader $mimetypeLoader): CacheEntry {
$normalized = [
'name' => (string)$data['name'],
'etag' => (string)$data['etag'],
'path' => (string)$data['path'],
'path_hash' => (string)$data['path_hash'],
'checksum' => (string)$data['checksum'],
'fileid' => (int)$data['fileid'],
'parent' => (int)$data['parent'],
'size' => Util::numericToNumber($data['size']),
'unencrypted_size' => Util::numericToNumber($data['unencrypted_size'] ?? 0),
'mtime' => (int)$data['mtime'],
'storage_mtime' => (int)($data['storage_mtime'] ?: $data['mtime']),
'encryptedVersion' => (int)$data['encrypted'],
'encrypted' => (bool)$data['encrypted'],
'storage_id' => $data['storage'],
'storage_string_id' => isset($data['storage_string_id']) ? (string)$data['storage_string_id'] : null,
'storage' => (int)$data['storage'],
'mimetype' => $mimetypeLoader->getMimetypeById($data['mimetype']),
'mimepart' => $mimetypeLoader->getMimetypeById($data['mimepart']),
'permissions' => (int)$data['permissions'],
'creation_time' => isset($data['creation_time']) ? (int)$data['creation_time'] : null,
'upload_time' => isset($data['upload_time']) ? (int)$data['upload_time'] : null,
'metadata_etag' => isset($data['metadata_etag']) ? (string)$data['metadata_etag'] : null,
'scan_permissions' => $data['scan_permissions'] ?? ($data['f_permissions'] ?? null),
'metadata' => $data['metadata'] ?? null,
'meta_json' => $data['meta_json'] ?? null,
'meta_sync_token' => $data['meta_sync_token'] ?? null,
];
if (isset($data['folder_id'])) {
// groupfolders specific fields
$normalized['folder_id'] = (int)$data['folder_id'];
$normalized['mount_point'] = (string)$data['mount_point'];
$normalized['quota'] = $data['quota'];
$normalized['acl'] = (int)$data['acl'];
$normalized['acl_default_no_permission'] = (int)$data['acl_default_no_permission'];
$normalized['storage_id'] = (int)$data['storage_id'];
$normalized['root_id'] = (int)$data['root_id'];
$normalized['options'] = (string)$data['options'];
}
if (isset($data['f_permissions'])) {
$data['scan_permissions'] ??= $data['f_permissions'];
}
$data['permissions'] = (int)$data['permissions'];
if (isset($data['creation_time'])) {
$data['creation_time'] = (int)$data['creation_time'];
}
if (isset($data['upload_time'])) {
$data['upload_time'] = (int)$data['upload_time'];
}
return new CacheEntry($data);
return new CacheEntry($normalized);
}
/**

View file

@ -13,13 +13,9 @@ use OCP\Files\Cache\ICacheEntry;
* meta data for a file or folder
*/
class CacheEntry implements ICacheEntry {
/**
* @var array
*/
private $data;
public function __construct(array $data) {
$this->data = $data;
public function __construct(
private array $data,
) {
}
public function offsetSet($offset, $value): void {

View file

@ -587,9 +587,9 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$sourceEntry = $sourceStorage->getCache()->get($sourceInternalPath);
$sourceEntryData = $sourceEntry->getData();
// $sourceEntry['permissions'] here is the permissions from the jailed storage for the current
// user. Instead we use $sourceEntryData['scan_permissions'] that are the permissions from the
// user. Instead, we use $sourceEntryData['scan_permissions'] that are the permissions from the
// unjailed storage.
if (is_array($sourceEntryData) && array_key_exists('scan_permissions', $sourceEntryData)) {
if (is_array($sourceEntryData) && $sourceEntryData['scan_permissions'] !== null) {
$sourceEntry['permissions'] = $sourceEntryData['scan_permissions'];
}
$this->copyInner($sourceStorage->getCache(), $sourceEntry, $targetInternalPath);