Passed
Push — master ( f3baab...36c944 )
by Blizzz
15:44 queued 12s
created
lib/private/Files/Config/UserMountCache.php 2 patches
Indentation   +388 added lines, -388 removed lines patch added patch discarded remove patch
@@ -47,392 +47,392 @@
 block discarded – undo
47 47
  * Cache mounts points per user in the cache so we can easilly look them up
48 48
  */
49 49
 class UserMountCache implements IUserMountCache {
50
-	/**
51
-	 * @var IDBConnection
52
-	 */
53
-	private $connection;
54
-
55
-	/**
56
-	 * @var IUserManager
57
-	 */
58
-	private $userManager;
59
-
60
-	/**
61
-	 * Cached mount info.
62
-	 * Map of $userId to ICachedMountInfo.
63
-	 *
64
-	 * @var ICache
65
-	 **/
66
-	private $mountsForUsers;
67
-
68
-	/**
69
-	 * @var ILogger
70
-	 */
71
-	private $logger;
72
-
73
-	/**
74
-	 * @var ICache
75
-	 */
76
-	private $cacheInfoCache;
77
-
78
-	/**
79
-	 * UserMountCache constructor.
80
-	 *
81
-	 * @param IDBConnection $connection
82
-	 * @param IUserManager $userManager
83
-	 * @param ILogger $logger
84
-	 */
85
-	public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
86
-		$this->connection = $connection;
87
-		$this->userManager = $userManager;
88
-		$this->logger = $logger;
89
-		$this->cacheInfoCache = new CappedMemoryCache();
90
-		$this->mountsForUsers = new CappedMemoryCache();
91
-	}
92
-
93
-	public function registerMounts(IUser $user, array $mounts) {
94
-		// filter out non-proper storages coming from unit tests
95
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
96
-			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
97
-		});
98
-		/** @var ICachedMountInfo[] $newMounts */
99
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
100
-			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
101
-			if ($mount->getStorageRootId() === -1) {
102
-				return null;
103
-			} else {
104
-				return new LazyStorageMountInfo($user, $mount);
105
-			}
106
-		}, $mounts);
107
-		$newMounts = array_values(array_filter($newMounts));
108
-		$newMountRootIds = array_map(function (ICachedMountInfo $mount) {
109
-			return $mount->getRootId();
110
-		}, $newMounts);
111
-		$newMounts = array_combine($newMountRootIds, $newMounts);
112
-
113
-		$cachedMounts = $this->getMountsForUser($user);
114
-		$cachedMountRootIds = array_map(function (ICachedMountInfo $mount) {
115
-			return $mount->getRootId();
116
-		}, $cachedMounts);
117
-		$cachedMounts = array_combine($cachedMountRootIds, $cachedMounts);
118
-
119
-		$addedMounts = [];
120
-		$removedMounts = [];
121
-
122
-		foreach ($newMounts as $rootId => $newMount) {
123
-			if (!isset($cachedMounts[$rootId])) {
124
-				$addedMounts[] = $newMount;
125
-			}
126
-		}
127
-
128
-		foreach ($cachedMounts as $rootId => $cachedMount) {
129
-			if (!isset($newMounts[$rootId])) {
130
-				$removedMounts[] = $cachedMount;
131
-			}
132
-		}
133
-
134
-		$changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
135
-
136
-		foreach ($addedMounts as $mount) {
137
-			$this->addToCache($mount);
138
-			$this->mountsForUsers[$user->getUID()][] = $mount;
139
-		}
140
-		foreach ($removedMounts as $mount) {
141
-			$this->removeFromCache($mount);
142
-			$index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
143
-			unset($this->mountsForUsers[$user->getUID()][$index]);
144
-		}
145
-		foreach ($changedMounts as $mount) {
146
-			$this->updateCachedMount($mount);
147
-		}
148
-	}
149
-
150
-	/**
151
-	 * @param ICachedMountInfo[] $newMounts
152
-	 * @param ICachedMountInfo[] $cachedMounts
153
-	 * @return ICachedMountInfo[]
154
-	 */
155
-	private function findChangedMounts(array $newMounts, array $cachedMounts) {
156
-		$new = [];
157
-		foreach ($newMounts as $mount) {
158
-			$new[$mount->getRootId()] = $mount;
159
-		}
160
-		$changed = [];
161
-		foreach ($cachedMounts as $cachedMount) {
162
-			$rootId = $cachedMount->getRootId();
163
-			if (isset($new[$rootId])) {
164
-				$newMount = $new[$rootId];
165
-				if (
166
-					$newMount->getMountPoint() !== $cachedMount->getMountPoint() ||
167
-					$newMount->getStorageId() !== $cachedMount->getStorageId() ||
168
-					$newMount->getMountId() !== $cachedMount->getMountId()
169
-				) {
170
-					$changed[] = $newMount;
171
-				}
172
-			}
173
-		}
174
-		return $changed;
175
-	}
176
-
177
-	private function addToCache(ICachedMountInfo $mount) {
178
-		if ($mount->getStorageId() !== -1) {
179
-			$this->connection->insertIfNotExist('*PREFIX*mounts', [
180
-				'storage_id' => $mount->getStorageId(),
181
-				'root_id' => $mount->getRootId(),
182
-				'user_id' => $mount->getUser()->getUID(),
183
-				'mount_point' => $mount->getMountPoint(),
184
-				'mount_id' => $mount->getMountId()
185
-			], ['root_id', 'user_id']);
186
-		} else {
187
-			// in some cases this is legitimate, like orphaned shares
188
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
189
-		}
190
-	}
191
-
192
-	private function updateCachedMount(ICachedMountInfo $mount) {
193
-		$builder = $this->connection->getQueryBuilder();
194
-
195
-		$query = $builder->update('mounts')
196
-			->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
197
-			->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
198
-			->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
199
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
200
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
201
-
202
-		$query->execute();
203
-	}
204
-
205
-	private function removeFromCache(ICachedMountInfo $mount) {
206
-		$builder = $this->connection->getQueryBuilder();
207
-
208
-		$query = $builder->delete('mounts')
209
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
210
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
211
-		$query->execute();
212
-	}
213
-
214
-	private function dbRowToMountInfo(array $row) {
215
-		$user = $this->userManager->get($row['user_id']);
216
-		if (is_null($user)) {
217
-			return null;
218
-		}
219
-		$mount_id = $row['mount_id'];
220
-		if (!is_null($mount_id)) {
221
-			$mount_id = (int)$mount_id;
222
-		}
223
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
224
-	}
225
-
226
-	/**
227
-	 * @param IUser $user
228
-	 * @return ICachedMountInfo[]
229
-	 */
230
-	public function getMountsForUser(IUser $user) {
231
-		if (!isset($this->mountsForUsers[$user->getUID()])) {
232
-			$builder = $this->connection->getQueryBuilder();
233
-			$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
234
-				->from('mounts', 'm')
235
-				->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
236
-				->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
237
-
238
-			$result = $query->execute();
239
-			$rows = $result->fetchAll();
240
-			$result->closeCursor();
241
-
242
-			$this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
243
-		}
244
-		return $this->mountsForUsers[$user->getUID()];
245
-	}
246
-
247
-	/**
248
-	 * @param int $numericStorageId
249
-	 * @param string|null $user limit the results to a single user
250
-	 * @return CachedMountInfo[]
251
-	 */
252
-	public function getMountsForStorageId($numericStorageId, $user = null) {
253
-		$builder = $this->connection->getQueryBuilder();
254
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
255
-			->from('mounts', 'm')
256
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
257
-			->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
258
-
259
-		if ($user) {
260
-			$query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
261
-		}
262
-
263
-		$result = $query->execute();
264
-		$rows = $result->fetchAll();
265
-		$result->closeCursor();
266
-
267
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
268
-	}
269
-
270
-	/**
271
-	 * @param int $rootFileId
272
-	 * @return CachedMountInfo[]
273
-	 */
274
-	public function getMountsForRootId($rootFileId) {
275
-		$builder = $this->connection->getQueryBuilder();
276
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
277
-			->from('mounts', 'm')
278
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
279
-			->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
280
-
281
-		$result = $query->execute();
282
-		$rows = $result->fetchAll();
283
-		$result->closeCursor();
284
-
285
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
286
-	}
287
-
288
-	/**
289
-	 * @param $fileId
290
-	 * @return array
291
-	 * @throws \OCP\Files\NotFoundException
292
-	 */
293
-	private function getCacheInfoFromFileId($fileId) {
294
-		if (!isset($this->cacheInfoCache[$fileId])) {
295
-			$builder = $this->connection->getQueryBuilder();
296
-			$query = $builder->select('storage', 'path', 'mimetype')
297
-				->from('filecache')
298
-				->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
299
-
300
-			$result = $query->execute();
301
-			$row = $result->fetch();
302
-			$result->closeCursor();
303
-
304
-			if (is_array($row)) {
305
-				$this->cacheInfoCache[$fileId] = [
306
-					(int)$row['storage'],
307
-					$row['path'],
308
-					(int)$row['mimetype']
309
-				];
310
-			} else {
311
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
312
-			}
313
-		}
314
-		return $this->cacheInfoCache[$fileId];
315
-	}
316
-
317
-	/**
318
-	 * @param int $fileId
319
-	 * @param string|null $user optionally restrict the results to a single user
320
-	 * @return ICachedMountFileInfo[]
321
-	 * @since 9.0.0
322
-	 */
323
-	public function getMountsForFileId($fileId, $user = null) {
324
-		try {
325
-			[$storageId, $internalPath] = $this->getCacheInfoFromFileId($fileId);
326
-		} catch (NotFoundException $e) {
327
-			return [];
328
-		}
329
-		$builder = $this->connection->getQueryBuilder();
330
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
331
-			->from('mounts', 'm')
332
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
333
-			->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($storageId, IQueryBuilder::PARAM_INT)));
334
-
335
-		if ($user) {
336
-			$query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
337
-		}
338
-
339
-		$result = $query->execute();
340
-		$rows = $result->fetchAll();
341
-		$result->closeCursor();
342
-		// filter mounts that are from the same storage but a different directory
343
-		$filteredMounts = array_filter($rows, function (array $row) use ($internalPath, $fileId) {
344
-			if ($fileId === (int)$row['root_id']) {
345
-				return true;
346
-			}
347
-			$internalMountPath = isset($row['path']) ? $row['path'] : '';
348
-
349
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
350
-		});
351
-
352
-		$filteredMounts = array_filter(array_map([$this, 'dbRowToMountInfo'], $filteredMounts));
353
-		return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
354
-			return new CachedMountFileInfo(
355
-				$mount->getUser(),
356
-				$mount->getStorageId(),
357
-				$mount->getRootId(),
358
-				$mount->getMountPoint(),
359
-				$mount->getMountId(),
360
-				$mount->getRootInternalPath(),
361
-				$internalPath
362
-			);
363
-		}, $filteredMounts);
364
-	}
365
-
366
-	/**
367
-	 * Remove all cached mounts for a user
368
-	 *
369
-	 * @param IUser $user
370
-	 */
371
-	public function removeUserMounts(IUser $user) {
372
-		$builder = $this->connection->getQueryBuilder();
373
-
374
-		$query = $builder->delete('mounts')
375
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
376
-		$query->execute();
377
-	}
378
-
379
-	public function removeUserStorageMount($storageId, $userId) {
380
-		$builder = $this->connection->getQueryBuilder();
381
-
382
-		$query = $builder->delete('mounts')
383
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
384
-			->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
385
-		$query->execute();
386
-	}
387
-
388
-	public function remoteStorageMounts($storageId) {
389
-		$builder = $this->connection->getQueryBuilder();
390
-
391
-		$query = $builder->delete('mounts')
392
-			->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
393
-		$query->execute();
394
-	}
395
-
396
-	/**
397
-	 * @param array $users
398
-	 * @return array
399
-	 */
400
-	public function getUsedSpaceForUsers(array $users) {
401
-		$builder = $this->connection->getQueryBuilder();
402
-
403
-		$slash = $builder->createNamedParameter('/');
404
-
405
-		$mountPoint = $builder->func()->concat(
406
-			$builder->func()->concat($slash, 'user_id'),
407
-			$slash
408
-		);
409
-
410
-		$userIds = array_map(function (IUser $user) {
411
-			return $user->getUID();
412
-		}, $users);
413
-
414
-		$query = $builder->select('m.user_id', 'f.size')
415
-			->from('mounts', 'm')
416
-			->innerJoin('m', 'filecache', 'f',
417
-				$builder->expr()->andX(
418
-					$builder->expr()->eq('m.storage_id', 'f.storage'),
419
-					$builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
420
-				))
421
-			->where($builder->expr()->eq('m.mount_point', $mountPoint))
422
-			->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
423
-
424
-		$result = $query->execute();
425
-
426
-		$results = [];
427
-		while ($row = $result->fetch()) {
428
-			$results[$row['user_id']] = $row['size'];
429
-		}
430
-		$result->closeCursor();
431
-		return $results;
432
-	}
433
-
434
-	public function clear(): void {
435
-		$this->cacheInfoCache = new CappedMemoryCache();
436
-		$this->mountsForUsers = new CappedMemoryCache();
437
-	}
50
+    /**
51
+     * @var IDBConnection
52
+     */
53
+    private $connection;
54
+
55
+    /**
56
+     * @var IUserManager
57
+     */
58
+    private $userManager;
59
+
60
+    /**
61
+     * Cached mount info.
62
+     * Map of $userId to ICachedMountInfo.
63
+     *
64
+     * @var ICache
65
+     **/
66
+    private $mountsForUsers;
67
+
68
+    /**
69
+     * @var ILogger
70
+     */
71
+    private $logger;
72
+
73
+    /**
74
+     * @var ICache
75
+     */
76
+    private $cacheInfoCache;
77
+
78
+    /**
79
+     * UserMountCache constructor.
80
+     *
81
+     * @param IDBConnection $connection
82
+     * @param IUserManager $userManager
83
+     * @param ILogger $logger
84
+     */
85
+    public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
86
+        $this->connection = $connection;
87
+        $this->userManager = $userManager;
88
+        $this->logger = $logger;
89
+        $this->cacheInfoCache = new CappedMemoryCache();
90
+        $this->mountsForUsers = new CappedMemoryCache();
91
+    }
92
+
93
+    public function registerMounts(IUser $user, array $mounts) {
94
+        // filter out non-proper storages coming from unit tests
95
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
96
+            return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
97
+        });
98
+        /** @var ICachedMountInfo[] $newMounts */
99
+        $newMounts = array_map(function (IMountPoint $mount) use ($user) {
100
+            // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
101
+            if ($mount->getStorageRootId() === -1) {
102
+                return null;
103
+            } else {
104
+                return new LazyStorageMountInfo($user, $mount);
105
+            }
106
+        }, $mounts);
107
+        $newMounts = array_values(array_filter($newMounts));
108
+        $newMountRootIds = array_map(function (ICachedMountInfo $mount) {
109
+            return $mount->getRootId();
110
+        }, $newMounts);
111
+        $newMounts = array_combine($newMountRootIds, $newMounts);
112
+
113
+        $cachedMounts = $this->getMountsForUser($user);
114
+        $cachedMountRootIds = array_map(function (ICachedMountInfo $mount) {
115
+            return $mount->getRootId();
116
+        }, $cachedMounts);
117
+        $cachedMounts = array_combine($cachedMountRootIds, $cachedMounts);
118
+
119
+        $addedMounts = [];
120
+        $removedMounts = [];
121
+
122
+        foreach ($newMounts as $rootId => $newMount) {
123
+            if (!isset($cachedMounts[$rootId])) {
124
+                $addedMounts[] = $newMount;
125
+            }
126
+        }
127
+
128
+        foreach ($cachedMounts as $rootId => $cachedMount) {
129
+            if (!isset($newMounts[$rootId])) {
130
+                $removedMounts[] = $cachedMount;
131
+            }
132
+        }
133
+
134
+        $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
135
+
136
+        foreach ($addedMounts as $mount) {
137
+            $this->addToCache($mount);
138
+            $this->mountsForUsers[$user->getUID()][] = $mount;
139
+        }
140
+        foreach ($removedMounts as $mount) {
141
+            $this->removeFromCache($mount);
142
+            $index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
143
+            unset($this->mountsForUsers[$user->getUID()][$index]);
144
+        }
145
+        foreach ($changedMounts as $mount) {
146
+            $this->updateCachedMount($mount);
147
+        }
148
+    }
149
+
150
+    /**
151
+     * @param ICachedMountInfo[] $newMounts
152
+     * @param ICachedMountInfo[] $cachedMounts
153
+     * @return ICachedMountInfo[]
154
+     */
155
+    private function findChangedMounts(array $newMounts, array $cachedMounts) {
156
+        $new = [];
157
+        foreach ($newMounts as $mount) {
158
+            $new[$mount->getRootId()] = $mount;
159
+        }
160
+        $changed = [];
161
+        foreach ($cachedMounts as $cachedMount) {
162
+            $rootId = $cachedMount->getRootId();
163
+            if (isset($new[$rootId])) {
164
+                $newMount = $new[$rootId];
165
+                if (
166
+                    $newMount->getMountPoint() !== $cachedMount->getMountPoint() ||
167
+                    $newMount->getStorageId() !== $cachedMount->getStorageId() ||
168
+                    $newMount->getMountId() !== $cachedMount->getMountId()
169
+                ) {
170
+                    $changed[] = $newMount;
171
+                }
172
+            }
173
+        }
174
+        return $changed;
175
+    }
176
+
177
+    private function addToCache(ICachedMountInfo $mount) {
178
+        if ($mount->getStorageId() !== -1) {
179
+            $this->connection->insertIfNotExist('*PREFIX*mounts', [
180
+                'storage_id' => $mount->getStorageId(),
181
+                'root_id' => $mount->getRootId(),
182
+                'user_id' => $mount->getUser()->getUID(),
183
+                'mount_point' => $mount->getMountPoint(),
184
+                'mount_id' => $mount->getMountId()
185
+            ], ['root_id', 'user_id']);
186
+        } else {
187
+            // in some cases this is legitimate, like orphaned shares
188
+            $this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
189
+        }
190
+    }
191
+
192
+    private function updateCachedMount(ICachedMountInfo $mount) {
193
+        $builder = $this->connection->getQueryBuilder();
194
+
195
+        $query = $builder->update('mounts')
196
+            ->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
197
+            ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
198
+            ->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
199
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
200
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
201
+
202
+        $query->execute();
203
+    }
204
+
205
+    private function removeFromCache(ICachedMountInfo $mount) {
206
+        $builder = $this->connection->getQueryBuilder();
207
+
208
+        $query = $builder->delete('mounts')
209
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
210
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
211
+        $query->execute();
212
+    }
213
+
214
+    private function dbRowToMountInfo(array $row) {
215
+        $user = $this->userManager->get($row['user_id']);
216
+        if (is_null($user)) {
217
+            return null;
218
+        }
219
+        $mount_id = $row['mount_id'];
220
+        if (!is_null($mount_id)) {
221
+            $mount_id = (int)$mount_id;
222
+        }
223
+        return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
224
+    }
225
+
226
+    /**
227
+     * @param IUser $user
228
+     * @return ICachedMountInfo[]
229
+     */
230
+    public function getMountsForUser(IUser $user) {
231
+        if (!isset($this->mountsForUsers[$user->getUID()])) {
232
+            $builder = $this->connection->getQueryBuilder();
233
+            $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
234
+                ->from('mounts', 'm')
235
+                ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
236
+                ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
237
+
238
+            $result = $query->execute();
239
+            $rows = $result->fetchAll();
240
+            $result->closeCursor();
241
+
242
+            $this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
243
+        }
244
+        return $this->mountsForUsers[$user->getUID()];
245
+    }
246
+
247
+    /**
248
+     * @param int $numericStorageId
249
+     * @param string|null $user limit the results to a single user
250
+     * @return CachedMountInfo[]
251
+     */
252
+    public function getMountsForStorageId($numericStorageId, $user = null) {
253
+        $builder = $this->connection->getQueryBuilder();
254
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
255
+            ->from('mounts', 'm')
256
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
257
+            ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
258
+
259
+        if ($user) {
260
+            $query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
261
+        }
262
+
263
+        $result = $query->execute();
264
+        $rows = $result->fetchAll();
265
+        $result->closeCursor();
266
+
267
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
268
+    }
269
+
270
+    /**
271
+     * @param int $rootFileId
272
+     * @return CachedMountInfo[]
273
+     */
274
+    public function getMountsForRootId($rootFileId) {
275
+        $builder = $this->connection->getQueryBuilder();
276
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
277
+            ->from('mounts', 'm')
278
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
279
+            ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
280
+
281
+        $result = $query->execute();
282
+        $rows = $result->fetchAll();
283
+        $result->closeCursor();
284
+
285
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
286
+    }
287
+
288
+    /**
289
+     * @param $fileId
290
+     * @return array
291
+     * @throws \OCP\Files\NotFoundException
292
+     */
293
+    private function getCacheInfoFromFileId($fileId) {
294
+        if (!isset($this->cacheInfoCache[$fileId])) {
295
+            $builder = $this->connection->getQueryBuilder();
296
+            $query = $builder->select('storage', 'path', 'mimetype')
297
+                ->from('filecache')
298
+                ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
299
+
300
+            $result = $query->execute();
301
+            $row = $result->fetch();
302
+            $result->closeCursor();
303
+
304
+            if (is_array($row)) {
305
+                $this->cacheInfoCache[$fileId] = [
306
+                    (int)$row['storage'],
307
+                    $row['path'],
308
+                    (int)$row['mimetype']
309
+                ];
310
+            } else {
311
+                throw new NotFoundException('File with id "' . $fileId . '" not found');
312
+            }
313
+        }
314
+        return $this->cacheInfoCache[$fileId];
315
+    }
316
+
317
+    /**
318
+     * @param int $fileId
319
+     * @param string|null $user optionally restrict the results to a single user
320
+     * @return ICachedMountFileInfo[]
321
+     * @since 9.0.0
322
+     */
323
+    public function getMountsForFileId($fileId, $user = null) {
324
+        try {
325
+            [$storageId, $internalPath] = $this->getCacheInfoFromFileId($fileId);
326
+        } catch (NotFoundException $e) {
327
+            return [];
328
+        }
329
+        $builder = $this->connection->getQueryBuilder();
330
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
331
+            ->from('mounts', 'm')
332
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
333
+            ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($storageId, IQueryBuilder::PARAM_INT)));
334
+
335
+        if ($user) {
336
+            $query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
337
+        }
338
+
339
+        $result = $query->execute();
340
+        $rows = $result->fetchAll();
341
+        $result->closeCursor();
342
+        // filter mounts that are from the same storage but a different directory
343
+        $filteredMounts = array_filter($rows, function (array $row) use ($internalPath, $fileId) {
344
+            if ($fileId === (int)$row['root_id']) {
345
+                return true;
346
+            }
347
+            $internalMountPath = isset($row['path']) ? $row['path'] : '';
348
+
349
+            return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
350
+        });
351
+
352
+        $filteredMounts = array_filter(array_map([$this, 'dbRowToMountInfo'], $filteredMounts));
353
+        return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
354
+            return new CachedMountFileInfo(
355
+                $mount->getUser(),
356
+                $mount->getStorageId(),
357
+                $mount->getRootId(),
358
+                $mount->getMountPoint(),
359
+                $mount->getMountId(),
360
+                $mount->getRootInternalPath(),
361
+                $internalPath
362
+            );
363
+        }, $filteredMounts);
364
+    }
365
+
366
+    /**
367
+     * Remove all cached mounts for a user
368
+     *
369
+     * @param IUser $user
370
+     */
371
+    public function removeUserMounts(IUser $user) {
372
+        $builder = $this->connection->getQueryBuilder();
373
+
374
+        $query = $builder->delete('mounts')
375
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
376
+        $query->execute();
377
+    }
378
+
379
+    public function removeUserStorageMount($storageId, $userId) {
380
+        $builder = $this->connection->getQueryBuilder();
381
+
382
+        $query = $builder->delete('mounts')
383
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
384
+            ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
385
+        $query->execute();
386
+    }
387
+
388
+    public function remoteStorageMounts($storageId) {
389
+        $builder = $this->connection->getQueryBuilder();
390
+
391
+        $query = $builder->delete('mounts')
392
+            ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
393
+        $query->execute();
394
+    }
395
+
396
+    /**
397
+     * @param array $users
398
+     * @return array
399
+     */
400
+    public function getUsedSpaceForUsers(array $users) {
401
+        $builder = $this->connection->getQueryBuilder();
402
+
403
+        $slash = $builder->createNamedParameter('/');
404
+
405
+        $mountPoint = $builder->func()->concat(
406
+            $builder->func()->concat($slash, 'user_id'),
407
+            $slash
408
+        );
409
+
410
+        $userIds = array_map(function (IUser $user) {
411
+            return $user->getUID();
412
+        }, $users);
413
+
414
+        $query = $builder->select('m.user_id', 'f.size')
415
+            ->from('mounts', 'm')
416
+            ->innerJoin('m', 'filecache', 'f',
417
+                $builder->expr()->andX(
418
+                    $builder->expr()->eq('m.storage_id', 'f.storage'),
419
+                    $builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
420
+                ))
421
+            ->where($builder->expr()->eq('m.mount_point', $mountPoint))
422
+            ->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
423
+
424
+        $result = $query->execute();
425
+
426
+        $results = [];
427
+        while ($row = $result->fetch()) {
428
+            $results[$row['user_id']] = $row['size'];
429
+        }
430
+        $result->closeCursor();
431
+        return $results;
432
+    }
433
+
434
+    public function clear(): void {
435
+        $this->cacheInfoCache = new CappedMemoryCache();
436
+        $this->mountsForUsers = new CappedMemoryCache();
437
+    }
438 438
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -92,11 +92,11 @@  discard block
 block discarded – undo
92 92
 
93 93
 	public function registerMounts(IUser $user, array $mounts) {
94 94
 		// filter out non-proper storages coming from unit tests
95
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
95
+		$mounts = array_filter($mounts, function(IMountPoint $mount) {
96 96
 			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
97 97
 		});
98 98
 		/** @var ICachedMountInfo[] $newMounts */
99
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
99
+		$newMounts = array_map(function(IMountPoint $mount) use ($user) {
100 100
 			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
101 101
 			if ($mount->getStorageRootId() === -1) {
102 102
 				return null;
@@ -105,13 +105,13 @@  discard block
 block discarded – undo
105 105
 			}
106 106
 		}, $mounts);
107 107
 		$newMounts = array_values(array_filter($newMounts));
108
-		$newMountRootIds = array_map(function (ICachedMountInfo $mount) {
108
+		$newMountRootIds = array_map(function(ICachedMountInfo $mount) {
109 109
 			return $mount->getRootId();
110 110
 		}, $newMounts);
111 111
 		$newMounts = array_combine($newMountRootIds, $newMounts);
112 112
 
113 113
 		$cachedMounts = $this->getMountsForUser($user);
114
-		$cachedMountRootIds = array_map(function (ICachedMountInfo $mount) {
114
+		$cachedMountRootIds = array_map(function(ICachedMountInfo $mount) {
115 115
 			return $mount->getRootId();
116 116
 		}, $cachedMounts);
117 117
 		$cachedMounts = array_combine($cachedMountRootIds, $cachedMounts);
@@ -185,7 +185,7 @@  discard block
 block discarded – undo
185 185
 			], ['root_id', 'user_id']);
186 186
 		} else {
187 187
 			// in some cases this is legitimate, like orphaned shares
188
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
188
+			$this->logger->debug('Could not get storage info for mount at '.$mount->getMountPoint());
189 189
 		}
190 190
 	}
191 191
 
@@ -218,9 +218,9 @@  discard block
 block discarded – undo
218 218
 		}
219 219
 		$mount_id = $row['mount_id'];
220 220
 		if (!is_null($mount_id)) {
221
-			$mount_id = (int)$mount_id;
221
+			$mount_id = (int) $mount_id;
222 222
 		}
223
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
223
+		return new CachedMountInfo($user, (int) $row['storage_id'], (int) $row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
224 224
 	}
225 225
 
226 226
 	/**
@@ -303,12 +303,12 @@  discard block
 block discarded – undo
303 303
 
304 304
 			if (is_array($row)) {
305 305
 				$this->cacheInfoCache[$fileId] = [
306
-					(int)$row['storage'],
306
+					(int) $row['storage'],
307 307
 					$row['path'],
308
-					(int)$row['mimetype']
308
+					(int) $row['mimetype']
309 309
 				];
310 310
 			} else {
311
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
311
+				throw new NotFoundException('File with id "'.$fileId.'" not found');
312 312
 			}
313 313
 		}
314 314
 		return $this->cacheInfoCache[$fileId];
@@ -340,17 +340,17 @@  discard block
 block discarded – undo
340 340
 		$rows = $result->fetchAll();
341 341
 		$result->closeCursor();
342 342
 		// filter mounts that are from the same storage but a different directory
343
-		$filteredMounts = array_filter($rows, function (array $row) use ($internalPath, $fileId) {
344
-			if ($fileId === (int)$row['root_id']) {
343
+		$filteredMounts = array_filter($rows, function(array $row) use ($internalPath, $fileId) {
344
+			if ($fileId === (int) $row['root_id']) {
345 345
 				return true;
346 346
 			}
347 347
 			$internalMountPath = isset($row['path']) ? $row['path'] : '';
348 348
 
349
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
349
+			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath.'/';
350 350
 		});
351 351
 
352 352
 		$filteredMounts = array_filter(array_map([$this, 'dbRowToMountInfo'], $filteredMounts));
353
-		return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
353
+		return array_map(function(ICachedMountInfo $mount) use ($internalPath) {
354 354
 			return new CachedMountFileInfo(
355 355
 				$mount->getUser(),
356 356
 				$mount->getStorageId(),
@@ -407,7 +407,7 @@  discard block
 block discarded – undo
407 407
 			$slash
408 408
 		);
409 409
 
410
-		$userIds = array_map(function (IUser $user) {
410
+		$userIds = array_map(function(IUser $user) {
411 411
 			return $user->getUID();
412 412
 		}, $users);
413 413
 
Please login to merge, or discard this patch.