83 lines
2.1 KiB
PHP
83 lines
2.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types = 1);
|
|
|
|
/**
|
|
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
namespace OCA\DAV\Connector\Sabre;
|
|
|
|
use Sabre\DAV\Server as SabreServer;
|
|
use Sabre\DAV\ServerPlugin;
|
|
use Sabre\HTTP\RequestInterface;
|
|
use Sabre\HTTP\ResponseInterface;
|
|
|
|
/**
|
|
* This plugin runs after requests and logs an error if a plugin is detected
|
|
* to be doing too many SQL requests.
|
|
*/
|
|
class PropFindMonitorPlugin extends ServerPlugin {
|
|
|
|
/**
|
|
* A Plugin can scan up to this amount of nodes without an error being
|
|
* reported.
|
|
*/
|
|
public const THRESHOLD_NODES = 50;
|
|
|
|
/**
|
|
* A plugin can use up to this amount of queries per node.
|
|
*/
|
|
public const THRESHOLD_QUERY_FACTOR = 1;
|
|
|
|
private SabreServer $server;
|
|
|
|
public function initialize(SabreServer $server): void {
|
|
$this->server = $server;
|
|
$this->server->on('afterResponse', [$this, 'afterResponse']);
|
|
}
|
|
|
|
public function afterResponse(
|
|
RequestInterface $request,
|
|
ResponseInterface $response): void {
|
|
if (!$this->server instanceof Server) {
|
|
return;
|
|
}
|
|
|
|
$pluginQueries = $this->server->getPluginQueries();
|
|
if (empty($pluginQueries)) {
|
|
return;
|
|
}
|
|
|
|
$logger = $this->server->getLogger();
|
|
foreach ($pluginQueries as $eventName => $eventQueries) {
|
|
$maxDepth = max(0, ...array_keys($eventQueries));
|
|
// entries at the top are usually not interesting
|
|
unset($eventQueries[$maxDepth]);
|
|
foreach ($eventQueries as $depth => $propFinds) {
|
|
foreach ($propFinds as $pluginName => $propFind) {
|
|
[
|
|
'queries' => $queries,
|
|
'nodes' => $nodes
|
|
] = $propFind;
|
|
if ($queries === 0 || $nodes > $queries || $nodes < self::THRESHOLD_NODES
|
|
|| $queries < $nodes * self::THRESHOLD_QUERY_FACTOR) {
|
|
continue;
|
|
}
|
|
$logger->error(
|
|
'{name}:{event} scanned {scans} nodes with {count} queries in depth {depth}/{maxDepth}. This is bad for performance, please report to the plugin developer!',
|
|
[
|
|
'name' => $pluginName,
|
|
'scans' => $nodes,
|
|
'count' => $queries,
|
|
'depth' => $depth,
|
|
'maxDepth' => $maxDepth,
|
|
'event' => $eventName,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|