Skip to content

Commit fb33980

Browse files
committed
fix(UserMountCache): Add back unique index for oc_mounts and use normal insert
Signed-off-by: provokateurin <[email protected]>
1 parent fe6b4f1 commit fb33980

File tree

7 files changed

+90
-35
lines changed

7 files changed

+90
-35
lines changed

core/Application.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,6 @@ public function __construct() {
218218
'mounts_class_index',
219219
['mount_provider_class']
220220
);
221-
$event->addMissingIndex(
222-
'mounts',
223-
'mounts_user_root_path_index',
224-
['user_id', 'root_id', 'mount_point'],
225-
['lengths' => [null, null, 128]]
226-
);
227221

228222
$event->addMissingIndex(
229223
'systemtag_object_mapping',
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OC\Core\Migrations;
11+
12+
use Closure;
13+
use OCP\DB\ISchemaWrapper;
14+
use OCP\DB\Types;
15+
use OCP\IDBConnection;
16+
use OCP\Migration\IOutput;
17+
use OCP\Migration\SimpleMigrationStep;
18+
use Override;
19+
20+
class Version33000Date20251209123503 extends SimpleMigrationStep {
21+
public function __construct(
22+
private readonly IDBConnection $connection,
23+
) {
24+
}
25+
26+
#[Override]
27+
public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
28+
$this->connection->truncateTable('mounts', false);
29+
}
30+
31+
#[Override]
32+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
33+
/** @var ISchemaWrapper $schema */
34+
$schema = $schemaClosure();
35+
36+
$table = $schema->getTable('mounts');
37+
if (!$table->hasColumn('mount_point_hash')) {
38+
$table->addColumn('mount_point_hash', Types::STRING, [
39+
'notnull' => true,
40+
'length' => 32, // xxh128
41+
]);
42+
$table->dropIndex('mounts_user_root_path_index');
43+
$table->addUniqueIndex(['user_id', 'root_id', 'mount_point_hash'], 'mounts_user_root_path_index');
44+
return $schema;
45+
}
46+
47+
return null;
48+
}
49+
}

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,7 @@
14711471
'OC\\Core\\Migrations\\Version31000Date20250213102442' => $baseDir . '/core/Migrations/Version31000Date20250213102442.php',
14721472
'OC\\Core\\Migrations\\Version31000Date20250731062008' => $baseDir . '/core/Migrations/Version31000Date20250731062008.php',
14731473
'OC\\Core\\Migrations\\Version32000Date20250620081925' => $baseDir . '/core/Migrations/Version32000Date20250620081925.php',
1474+
'OC\\Core\\Migrations\\Version33000Date20251209123503' => $baseDir . '/core/Migrations/Version33000Date20251209123503.php',
14741475
'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php',
14751476
'OC\\Core\\ResponseDefinitions' => $baseDir . '/core/ResponseDefinitions.php',
14761477
'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php',

lib/composer/composer/autoload_static.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
1717
'OC\\' => 3,
1818
'OCP\\' => 4,
1919
),
20-
'N' =>
20+
'N' =>
2121
array (
2222
'NCU\\' => 4,
2323
),
24-
'B' =>
24+
'B' =>
2525
array (
2626
'Bamarni\\Composer\\Bin\\' => 21,
2727
),
@@ -40,11 +40,11 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
4040
array (
4141
0 => __DIR__ . '/../../..' . '/lib/public',
4242
),
43-
'NCU\\' =>
43+
'NCU\\' =>
4444
array (
4545
0 => __DIR__ . '/../../..' . '/lib/unstable',
4646
),
47-
'Bamarni\\Composer\\Bin\\' =>
47+
'Bamarni\\Composer\\Bin\\' =>
4848
array (
4949
0 => __DIR__ . '/..' . '/bamarni/composer-bin-plugin/src',
5050
),
@@ -1520,6 +1520,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
15201520
'OC\\Core\\Migrations\\Version31000Date20250213102442' => __DIR__ . '/../../..' . '/core/Migrations/Version31000Date20250213102442.php',
15211521
'OC\\Core\\Migrations\\Version31000Date20250731062008' => __DIR__ . '/../../..' . '/core/Migrations/Version31000Date20250731062008.php',
15221522
'OC\\Core\\Migrations\\Version32000Date20250620081925' => __DIR__ . '/../../..' . '/core/Migrations/Version32000Date20250620081925.php',
1523+
'OC\\Core\\Migrations\\Version33000Date20251209123503' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251209123503.php',
15231524
'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php',
15241525
'OC\\Core\\ResponseDefinitions' => __DIR__ . '/../../..' . '/core/ResponseDefinitions.php',
15251526
'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php',

lib/private/Files/Config/UserMountCache.php

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use OC\User\LazyUser;
1111
use OCP\Cache\CappedMemoryCache;
12+
use OCP\DB\Exception;
1213
use OCP\DB\QueryBuilder\IQueryBuilder;
1314
use OCP\Diagnostics\IEventLogger;
1415
use OCP\EventDispatcher\IEventDispatcher;
@@ -160,14 +161,25 @@ private function findChangedMounts(array $newMounts, array $cachedMounts): array
160161

161162
private function addToCache(ICachedMountInfo $mount) {
162163
if ($mount->getStorageId() !== -1) {
163-
$this->connection->insertIfNotExist('*PREFIX*mounts', [
164-
'storage_id' => $mount->getStorageId(),
165-
'root_id' => $mount->getRootId(),
166-
'user_id' => $mount->getUser()->getUID(),
167-
'mount_point' => $mount->getMountPoint(),
168-
'mount_id' => $mount->getMountId(),
169-
'mount_provider_class' => $mount->getMountProvider(),
170-
], ['root_id', 'user_id', 'mount_point']);
164+
$qb = $this->connection->getQueryBuilder();
165+
$qb
166+
->insert('mounts')
167+
->values([
168+
'storage_id' => $qb->createNamedParameter($mount->getStorageId(), IQueryBuilder::PARAM_INT),
169+
'root_id' => $qb->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT),
170+
'user_id' => $qb->createNamedParameter($mount->getUser()->getUID()),
171+
'mount_point' => $qb->createNamedParameter($mount->getMountPoint()),
172+
'mount_point_hash' => $qb->createNamedParameter(hash('xxh128', $mount->getMountPoint())),
173+
'mount_id' => $qb->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT),
174+
'mount_provider_class' => $qb->createNamedParameter($mount->getMountProvider()),
175+
]);
176+
try {
177+
$qb->executeStatement();
178+
} catch (Exception $e) {
179+
if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
180+
throw $e;
181+
}
182+
}
171183
} else {
172184
// in some cases this is legitimate, like orphaned shares
173185
$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
@@ -180,6 +192,7 @@ private function updateCachedMount(ICachedMountInfo $mount) {
180192
$query = $builder->update('mounts')
181193
->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
182194
->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
195+
->set('mount_point_hash', $builder->createNamedParameter(hash('xxh128', $mount->getMountPoint())))
183196
->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
184197
->set('mount_provider_class', $builder->createNamedParameter($mount->getMountProvider()))
185198
->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
@@ -194,7 +207,7 @@ private function removeFromCache(ICachedMountInfo $mount) {
194207
$query = $builder->delete('mounts')
195208
->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
196209
->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)))
197-
->andWhere($builder->expr()->eq('mount_point', $builder->createNamedParameter($mount->getMountPoint())));
210+
->andWhere($builder->expr()->eq('mount_point_hash', $builder->createNamedParameter(hash('xxh128', $mount->getMountPoint()))));
198211
$query->executeStatement();
199212
}
200213

@@ -426,16 +439,8 @@ public function remoteStorageMounts($storageId) {
426439
public function getUsedSpaceForUsers(array $users) {
427440
$builder = $this->connection->getQueryBuilder();
428441

429-
$slash = $builder->createNamedParameter('/');
430-
431-
$mountPoint = $builder->func()->concat(
432-
$builder->func()->concat($slash, 'user_id'),
433-
$slash
434-
);
435-
436-
$userIds = array_map(function (IUser $user) {
437-
return $user->getUID();
438-
}, $users);
442+
$mountPointHashes = array_map(static fn (IUser $user) => hash('xxh128', '/' . $user->getUID() . '/'), $users);
443+
$userIds = array_map(static fn (IUser $user) => $user->getUID(), $users);
439444

440445
$query = $builder->select('m.user_id', 'f.size')
441446
->from('mounts', 'm')
@@ -444,7 +449,7 @@ public function getUsedSpaceForUsers(array $users) {
444449
$builder->expr()->eq('m.storage_id', 'f.storage'),
445450
$builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
446451
))
447-
->where($builder->expr()->eq('m.mount_point', $mountPoint))
452+
->where($builder->expr()->in('m.mount_point_hash', $builder->createNamedParameter($mountPointHashes, IQueryBuilder::PARAM_STR_ARRAY)))
448453
->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
449454

450455
$result = $query->executeQuery();

tests/lib/DB/QueryBuilder/Partitioned/PartitionedQueryBuilderTest.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ private function setupFileCache(): void {
8686
'storage_id' => $query->createNamedParameter(1001001, IQueryBuilder::PARAM_INT),
8787
'user_id' => $query->createNamedParameter('partitioned_test'),
8888
'mount_point' => $query->createNamedParameter('/mount/point'),
89+
'mount_point_hash' => $query->createNamedParameter(hash('xxh128', '/mount/point')),
8990
'mount_provider_class' => $query->createNamedParameter('test'),
9091
'root_id' => $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT),
9192
]);
@@ -134,7 +135,7 @@ public function testSimplePartitionedQuery(): void {
134135
$builder->addPartition(new PartitionSplit('filecache', ['filecache']));
135136

136137
// query borrowed from UserMountCache
137-
$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class')
138+
$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_point_hash', 'mount_id', 'f.path', 'mount_provider_class')
138139
->from('mounts', 'm')
139140
->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
140141
->where($builder->expr()->eq('storage_id', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT)));
@@ -147,6 +148,7 @@ public function testSimplePartitionedQuery(): void {
147148
$this->assertCount(1, $results);
148149
$this->assertEquals($results[0]['user_id'], 'partitioned_test');
149150
$this->assertEquals($results[0]['mount_point'], '/mount/point');
151+
$this->assertEquals($results[0]['mount_point_hash'], hash('xxh128', '/mount/point'));
150152
$this->assertEquals($results[0]['mount_provider_class'], 'test');
151153
$this->assertEquals($results[0]['path'], 'file1');
152154
}
@@ -155,7 +157,7 @@ public function testMultiTablePartitionedQuery(): void {
155157
$builder = $this->getQueryBuilder();
156158
$builder->addPartition(new PartitionSplit('filecache', ['filecache', 'filecache_extended']));
157159

158-
$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class', 'fe.upload_time')
160+
$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_point_hash', 'mount_id', 'f.path', 'mount_provider_class', 'fe.upload_time')
159161
->from('mounts', 'm')
160162
->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
161163
->innerJoin('f', 'filecache_extended', 'fe', $builder->expr()->eq('f.fileid', 'fe.fileid'))
@@ -169,6 +171,7 @@ public function testMultiTablePartitionedQuery(): void {
169171
$this->assertCount(1, $results);
170172
$this->assertEquals($results[0]['user_id'], 'partitioned_test');
171173
$this->assertEquals($results[0]['mount_point'], '/mount/point');
174+
$this->assertEquals($results[0]['mount_point_hash'], hash('xxh128', '/mount/point'));
172175
$this->assertEquals($results[0]['mount_provider_class'], 'test');
173176
$this->assertEquals($results[0]['path'], 'file1');
174177
$this->assertEquals($results[0]['upload_time'], 1234);
@@ -178,7 +181,7 @@ public function testPartitionedQueryFromSplit(): void {
178181
$builder = $this->getQueryBuilder();
179182
$builder->addPartition(new PartitionSplit('filecache', ['filecache']));
180183

181-
$query = $builder->select('storage', 'm.root_id', 'm.user_id', 'm.mount_point', 'm.mount_id', 'path', 'm.mount_provider_class')
184+
$query = $builder->select('storage', 'm.root_id', 'm.user_id', 'm.mount_point', 'm.mount_point_hash', 'm.mount_id', 'path', 'm.mount_provider_class')
182185
->from('filecache', 'f')
183186
->innerJoin('f', 'mounts', 'm', $builder->expr()->eq('m.root_id', 'f.fileid'));
184187
$query->where($builder->expr()->eq('storage', $builder->createNamedParameter(1001001, IQueryBuilder::PARAM_INT)));
@@ -191,6 +194,7 @@ public function testPartitionedQueryFromSplit(): void {
191194
$this->assertCount(1, $results);
192195
$this->assertEquals($results[0]['user_id'], 'partitioned_test');
193196
$this->assertEquals($results[0]['mount_point'], '/mount/point');
197+
$this->assertEquals($results[0]['mount_point_hash'], hash('xxh128', '/mount/point'));
194198
$this->assertEquals($results[0]['mount_provider_class'], 'test');
195199
$this->assertEquals($results[0]['path'], 'file1');
196200
}
@@ -200,7 +204,7 @@ public function testMultiJoinPartitionedQuery(): void {
200204
$builder->addPartition(new PartitionSplit('filecache', ['filecache']));
201205

202206
// query borrowed from UserMountCache
203-
$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class')
207+
$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_point_hash', 'mount_id', 'f.path', 'mount_provider_class')
204208
->selectAlias('s.id', 'storage_string_id')
205209
->from('mounts', 'm')
206210
->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
@@ -215,6 +219,7 @@ public function testMultiJoinPartitionedQuery(): void {
215219
$this->assertCount(1, $results);
216220
$this->assertEquals($results[0]['user_id'], 'partitioned_test');
217221
$this->assertEquals($results[0]['mount_point'], '/mount/point');
222+
$this->assertEquals($results[0]['mount_point_hash'], hash('xxh128', '/mount/point'));
218223
$this->assertEquals($results[0]['mount_provider_class'], 'test');
219224
$this->assertEquals($results[0]['path'], 'file1');
220225
$this->assertEquals($results[0]['storage_string_id'], 'test1');

version.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patch level
1010
// when updating major/minor version number.
1111

12-
$OC_Version = [31, 0, 12, 3];
12+
$OC_Version = [31, 0, 12, 4];
1313

1414
// The human-readable string
1515
$OC_VersionString = '31.0.12';

0 commit comments

Comments
 (0)