Skip to content

Conversation

@salmart-dev
Copy link
Contributor

@salmart-dev salmart-dev commented Jul 30, 2025

Summary

Plugins should avoid querying properties per-file and rather eager load them per directory to avoid doing too many round-trips to the database, which cost time.

To ease troubleshooting, this PR adds logging that triggers when loading properties runs queries for every node it scans.

Implementation

At the moment, loading properties from the DB happens when each node is serialized into XML to respond to the client, unless pre-loaded. For this reason, detection is implemented as a wrapper for the on/once methods in our Server connector, for the propFind event. This event is triggered at least once for every node returned in the response.

Note: due to the fact that propFind is called at least once per node, the detection of how many nodes have caused a read from the DB is not the same to the unique number of nodes treated by the propfind. For example: CorePlugin registers three on handlers for the propFind event and, if they all read properties from the DB, will count each node three times.

Checklist

@salmart-dev salmart-dev force-pushed the feat/54114/reportSlowPropfinds branch 2 times, most recently from 539302e to 68c9c6b Compare August 4, 2025 10:36
@salmart-dev salmart-dev self-assigned this Aug 4, 2025
@salmart-dev salmart-dev force-pushed the feat/54114/reportSlowPropfinds branch from 68c9c6b to 53486c0 Compare August 4, 2025 10:39
@salmart-dev salmart-dev marked this pull request as ready for review August 4, 2025 11:09
@salmart-dev salmart-dev requested a review from a team as a code owner August 4, 2025 11:09
@salmart-dev salmart-dev requested review from come-nc, icewind1991 and leftybournes and removed request for a team August 4, 2025 11:09
Copy link
Contributor

@come-nc come-nc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, be careful that the sabre server is built in several places, especially there is a ServerFactory, does the plugin need to be added there as well?

@salmart-dev
Copy link
Contributor Author

Also, be careful that the sabre server is built in several places, especially there is a ServerFactory, does the plugin need to be added there as well?

My IDE was configured to exclude the appinfo directory, so I didn't see the usages. Thanks for the catch!
I added it to the factory and in another server class, the other uses don't seem to be relevant.

@salmart-dev salmart-dev force-pushed the feat/54114/reportSlowPropfinds branch 2 times, most recently from a86009a to c62a214 Compare August 7, 2025 16:03
@salmart-dev salmart-dev force-pushed the feat/54114/reportSlowPropfinds branch from 1395d1c to b936ef2 Compare August 13, 2025 08:18
@salmart-dev salmart-dev enabled auto-merge August 13, 2025 08:22
@salmart-dev salmart-dev force-pushed the feat/54114/reportSlowPropfinds branch from b936ef2 to ec176a9 Compare August 13, 2025 17:46
@salmart-dev salmart-dev merged commit 50c9c7e into master Aug 14, 2025
302 of 319 checks passed
@salmart-dev salmart-dev deleted the feat/54114/reportSlowPropfinds branch August 14, 2025 11:40
@st3iny
Copy link
Member

st3iny commented Aug 18, 2025

@salmart-dev I believe we have to revert this PR. It currently breaks creating invitations and possibly more things in the CalDAV backend (read: you can't invite anyone on master in Calendar events).

My only idea would be to make an exemption for the ACL plugin so that it will never be wrapped.

Problem

TL;DR: Inside Sabre, event listeners are sometimes removed. However, this won't work anymore as the actual event listener is wrapped inside an anonymous function/closure and the Sabre code checks for the identity of the listener ($listener === $callback).

In \Sabre\CalDAV\Schedule\Plugin:

$aclPlugin = $this->server->getPlugin('acl');
// [...]
$this->server->removeListener('propFind', [$aclPlugin, 'propFind']);

It disables the ACLs for a short period in order to access the invitee's properties to get their default schedule calendar URL. However, the line above won't work if the "real" listener is wrapped inside a closure. As a result, the listener is not removed anymore and the ACL checks still run and fail.

@st3iny
Copy link
Member

st3iny commented Aug 18, 2025

In case excluding the plugin is acceptable: #54485

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Monitor and report apps doing per-file propfind discovery

5 participants