Skip to content

Commit 6e43ef9

Browse files
committed
feat: implement support for authoritative mount providers [skip ci]
Signed-off-by: Salvatore Martire <[email protected]>
1 parent 7761111 commit 6e43ef9

File tree

8 files changed

+439
-79
lines changed

8 files changed

+439
-79
lines changed

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,7 @@
16601660
'OC\\Files\\Cache\\CacheQueryBuilder' => $baseDir . '/lib/private/Files/Cache/CacheQueryBuilder.php',
16611661
'OC\\Files\\Cache\\FailedCache' => $baseDir . '/lib/private/Files/Cache/FailedCache.php',
16621662
'OC\\Files\\Cache\\FileAccess' => $baseDir . '/lib/private/Files/Cache/FileAccess.php',
1663+
'OC\\Files\\Cache\\FileMetadataCache' => $baseDir . '/lib/private/Files/Cache/FileMetadataCache.php',
16631664
'OC\\Files\\Cache\\HomeCache' => $baseDir . '/lib/private/Files/Cache/HomeCache.php',
16641665
'OC\\Files\\Cache\\HomePropagator' => $baseDir . '/lib/private/Files/Cache/HomePropagator.php',
16651666
'OC\\Files\\Cache\\LocalRootScanner' => $baseDir . '/lib/private/Files/Cache/LocalRootScanner.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
17011701
'OC\\Files\\Cache\\CacheQueryBuilder' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/CacheQueryBuilder.php',
17021702
'OC\\Files\\Cache\\FailedCache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/FailedCache.php',
17031703
'OC\\Files\\Cache\\FileAccess' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/FileAccess.php',
1704+
'OC\\Files\\Cache\\FileMetadataCache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/FileMetadataCache.php',
17041705
'OC\\Files\\Cache\\HomeCache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/HomeCache.php',
17051706
'OC\\Files\\Cache\\HomePropagator' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/HomePropagator.php',
17061707
'OC\\Files\\Cache\\LocalRootScanner' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/LocalRootScanner.php',
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OC\Files\Cache;
6+
7+
use OCP\Cache\CappedMemoryCache;
8+
use OCP\Files\Cache\ICacheEntry;
9+
10+
/**
11+
* This class uses FileAccess to fetch data to populate ICacheEntry objects
12+
* and caches them in memory for subsequent access.
13+
*/
14+
class FileMetadataCache {
15+
16+
private const CACHE_SIZE = 50000;
17+
18+
private const MAX_QUERIED_ITEMS = 1000;
19+
20+
private CappedMemoryCache $fileCache;
21+
22+
public function __construct(
23+
private readonly FileAccess $fileAccess,
24+
) {
25+
$this->fileCache = new CappedMemoryCache(self::CACHE_SIZE);
26+
}
27+
28+
/**
29+
* Returns file metadata by retrieving it from an in-memory cache or the
30+
* database.
31+
*
32+
* @param int[] $fileIds
33+
* @return array<int, ICacheEntry|null>
34+
* @see FileAccess::getByFileIds()
35+
*/
36+
public function getByFileIds(array $fileIds): array {
37+
// avoid thrashing the cache if we are asked to query too many ids
38+
$skipCaching = \count($fileIds) >= self::CACHE_SIZE;
39+
40+
$cacheArray = $this->fileCache->getData();
41+
42+
$result = [];
43+
$missingIds = [];
44+
foreach ($fileIds as $fileId) {
45+
$stringFileId = (string)$fileId;
46+
if (\array_key_exists($stringFileId, $cacheArray)) {
47+
$result[$fileId] = $this->fileCache->get($stringFileId);
48+
} else {
49+
$missingIds[] = $fileId;
50+
}
51+
}
52+
53+
foreach (array_chunk($missingIds, self::MAX_QUERIED_ITEMS) as $chunk) {
54+
foreach ($this->fileAccess->getByFileIds($chunk) as $id => $fileMetadata) {
55+
$result[$id] = $fileMetadata;
56+
if (!$skipCaching || \count($this->fileCache->getData()) < self::CACHE_SIZE) {
57+
$this->fileCache->set((string)$id, $fileMetadata);
58+
}
59+
}
60+
}
61+
62+
return $result;
63+
}
64+
}

lib/private/Files/Config/MountProviderCollection.php

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,21 @@
99

1010
use OC\Hooks\Emitter;
1111
use OC\Hooks\EmitterTrait;
12+
use OCA\Files_Sharing\MountProvider;
1213
use OCP\Diagnostics\IEventLogger;
1314
use OCP\Files\Config\IHomeMountProvider;
1415
use OCP\Files\Config\IMountProvider;
16+
use OCP\Files\Config\IMountProviderArgs;
1517
use OCP\Files\Config\IMountProviderCollection;
18+
use OCP\Files\Config\IPartialMountProvider;
1619
use OCP\Files\Config\IRootMountProvider;
1720
use OCP\Files\Config\IUserMountCache;
1821
use OCP\Files\Mount\IMountManager;
1922
use OCP\Files\Mount\IMountPoint;
2023
use OCP\Files\Storage\IStorageFactory;
2124
use OCP\IUser;
25+
use function get_class;
26+
use function in_array;
2227

2328
class MountProviderCollection implements IMountProviderCollection, Emitter {
2429
use EmitterTrait;
@@ -29,7 +34,7 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
2934
private array $homeProviders = [];
3035

3136
/**
32-
* @var list<IMountProvider>
37+
* @var array<class-string<IMountProvider>, IMountProvider>
3338
*/
3439
private array $providers = [];
3540

@@ -75,19 +80,51 @@ private function getUserMountsForProviders(IUser $user, array $providers): array
7580
* @return list<IMountPoint>
7681
*/
7782
public function getMountsForUser(IUser $user): array {
78-
return $this->getUserMountsForProviders($user, $this->providers);
83+
return $this->getUserMountsForProviders($user, array_values($this->providers));
84+
}
85+
86+
/**
87+
* @param IMountProviderArgs[] $mountProviderArgs
88+
* @return array<string, IMountPoint> IMountPoint array indexed by mount
89+
* point.
90+
*/
91+
public function getUserMountsFromProviderByPath(
92+
string $providerClass,
93+
string $path,
94+
array $mountProviderArgs,
95+
): array {
96+
$provider = $this->providers[$providerClass] ?? null;
97+
if ($provider === null) {
98+
return [];
99+
}
100+
101+
if (!is_a($providerClass, IPartialMountProvider::class, true)) {
102+
throw new \LogicException(
103+
'Mount provider does not support partial mounts'
104+
);
105+
}
106+
107+
/** @var IPartialMountProvider $provider */
108+
return $provider->getMountsFromMountPoints(
109+
$path,
110+
$mountProviderArgs,
111+
$this->loader,
112+
);
79113
}
80114

81115
/**
82116
* Returns the mounts for the user from the specified provider classes.
83117
* Providers not registered in the MountProviderCollection will be skipped.
84118
*
119+
* @inheritdoc
120+
*
85121
* @return list<IMountPoint>
86122
*/
87123
public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array {
88124
$providers = array_filter(
89125
$this->providers,
90-
fn (IMountProvider $mountProvider) => (in_array(get_class($mountProvider), $mountProviderClasses))
126+
fn (string $providerClass) => in_array($providerClass, $mountProviderClasses),
127+
ARRAY_FILTER_USE_KEY
91128
);
92129
return $this->getUserMountsForProviders($user, $providers);
93130
}
@@ -100,16 +137,21 @@ public function addMountForUser(IUser $user, IMountManager $mountManager, ?calla
100137
// to check for name collisions
101138
$firstMounts = [];
102139
if ($providerFilter) {
103-
$providers = array_filter($this->providers, $providerFilter);
140+
$providers = array_filter($this->providers, $providerFilter, ARRAY_FILTER_USE_KEY);
104141
} else {
105142
$providers = $this->providers;
106143
}
107-
$firstProviders = array_filter($providers, function (IMountProvider $provider) {
108-
return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
109-
});
110-
$lastProviders = array_filter($providers, function (IMountProvider $provider) {
111-
return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
112-
});
144+
$firstProviders
145+
= array_filter(
146+
$providers,
147+
fn (string $providerClass) => ($providerClass !== MountProvider::class),
148+
ARRAY_FILTER_USE_KEY
149+
);
150+
$lastProviders = array_filter(
151+
$providers,
152+
fn (string $providerClass) => $providerClass === MountProvider::class,
153+
ARRAY_FILTER_USE_KEY
154+
);
113155
foreach ($firstProviders as $provider) {
114156
$mounts = $this->getMountsFromProvider($provider, $user, $this->loader);
115157
$firstMounts = array_merge($firstMounts, $mounts);
@@ -151,7 +193,7 @@ public function getHomeMountForUser(IUser $user): IMountPoint {
151193
* Add a provider for mount points
152194
*/
153195
public function registerProvider(IMountProvider $provider): void {
154-
$this->providers[] = $provider;
196+
$this->providers[get_class($provider)] = $provider;
155197

156198
$this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
157199
}
@@ -229,7 +271,7 @@ public function clearProviders(): void {
229271
* @return list<IMountProvider>
230272
*/
231273
public function getProviders(): array {
232-
return $this->providers;
274+
return array_values($this->providers);
233275
}
234276

235277
/**

0 commit comments

Comments
 (0)