Improve delay in accessing WebDAV folders on external storage
- Resolves: #
Summary
Issue: loading time while open an external directory increases with the number of children (files, folders). Root cause: profind function has been called for each child to fetch metadata/permissions and it seem unneccessary. Update:
- Caching the profind response of children while calling function opendir. Then, we don't need to call profind function for each child anymore.
- Optimize propfind caching to prevent duplicate call
Before: calling of profind function for each child increases loading time; propfind duplicate call for parent dir
After: calling profind function reduced since profind response has been cached while calling opendir; no duplicate propfind call
TODO
- [ ] ...
Checklist
- Code is properly formatted
- Sign-off message is added to all commits
- [ ] Tests (unit, integration, api and/or acceptance) are included
- [ ] Screenshots before/after for front-end changes
- [ ] Documentation (manuals or wiki) has been updated or is not required
- [ ] Backports requested where applicable (ex: critical bugfixes)
@juliushaertl Please check again, thanks.
Since you're at it, maybe you can also look into saving the remaining duplicate request that is still left:
@juliushaertl I've updated PR & description, please check.
Can you double check that? When I was testing it the propfind was still duplicate as the second one didn't read the cached response from anywhere.
I think it would make sense to reuse the internal profind method in https://github.com/nextcloud/server/pull/38418/files#diff-53ee4c908f9ae3a27e45d03c57ac5ed83c5916d7260561a03f279880671f6155R240 instead of directly calling the $this->client->propFind
Can you double check that? When I was testing it the propfind was still duplicate as the second one didn't read the cached response from anywhere.
You are right, I updated the screenshot again.
I think it would make sense to reuse the internal profind method in https://github.com/nextcloud/server/pull/38418/files#diff-53ee4c908f9ae3a27e45d03c57ac5ed83c5916d7260561a03f279880671f6155R240 instead of directly calling the $this->client->propFind
As I know, we have to use $this->client->propFind() since the target item (file, folder) is an external dir. The internal propFind is only for internal item (file,folder)
I've pushed a small fixup commit to address an encoding issue with files with spaces, but otherwise this seemed good.
Note that I'll revoke my initial question for reusing the first propfind as i think this one is intentional only done on the root without children (depth=0) as it would also get requested when listing the parent folder of the external storage mount. In this case it might be wise to only request relevant information.
In case we want to optimize that this could easily be done through the following patch
diff --git a/lib/private/Files/Storage/DAV.php b/lib/private/Files/Storage/DAV.php
index 267f32a0e5b..cf031ac8c00 100644
--- a/lib/private/Files/Storage/DAV.php
+++ b/lib/private/Files/Storage/DAV.php
@@ -314,9 +314,11 @@ class DAV extends Common {
'{DAV:}getetag',
'{DAV:}quota-available-bytes',
]
- );
+ , 1);
$this->statCache->set($path, $response);
- $this->propfindCache->set($path, $response);
+ foreach ($response as $file => $responseData) {
+ $this->propfindCache->set($file, $responseData);
+ }
} catch (ClientHttpException $e) {
if ($e->getHttpStatus() === 404 || $e->getHttpStatus() === 405) {
$this->statCache->clear($path . '/');
I'm a bit hesitant (but not fully against) adding extra caching layers.
The issue shown in the OP should also be solvable by implementing a more optimized version of IStorage::getDirectoryContent for Dav.
The default implementation that is currently inherited is doing the "stat every file in the folder" that seems to be causing the issue. Changing it to "load the folder once and the metadata for each item" should give the same speedup in that case.
I'm a bit hesitant (but not fully against) adding extra caching layers.
The issue shown in the OP should also be solvable by implementing a more optimized version of
IStorage::getDirectoryContentforDav.The default implementation that is currently inherited is doing the "stat every file in the folder" that seems to be causing the issue. Changing it to "load the folder once and the metadata for each item" should give the same speedup in that case.
But the caching may help with other operations as well no?
I think the caching here makes sense for all cases here also if it is not just about iterating over the directory content. It especially helps as the previous code called a propfind on any call that would obtain file metadata like the getPermission which is likely to be called in a few other places, so I think caching in an ArrayCache for the scope of the current request is still the most sane approach here.
Don´t know if its because of your commits, but i was testing your PR and checked the logs.
I get some strange absolute urls there.
Example log:
{"reqId":"jXHhrkauwfkRmocMZ0C5","level":0,"time":"2023-06-19T11:03:05+00:00","remoteAddr":"","user":"--","app":"dav","method":"","url":"--","message":"sending dav PROPFIND request to external storage: http://localhosthttps://www.mycloud.com/remote.php/webdav/Backups/Android/Download/DCIM/OpenCamera/IMG_20210313_100632.jpg","userAgent":"--","version":"26.0.2.1","data":{"app":"dav"}}
Should be: "https://www.mycloud.com/remote.php/webdav/Backups/Android/Download/DCIM/OpenCamera/IMG_20210313_100632.jpg"
Is: "http://localhosthttps://www.mycloud.com/remote.php/webdav/Backups/Android/Download/DCIM/OpenCamera/IMG_20210313_100632.jpg"
So "$request->getAbsoluteUrl()" is returning something strange.
There is also a different propfind cache already which this is duplicating
https://github.com/nextcloud/server/pull/38945 implements getDirectoryContent and ensures that the existing statcache is better used
Let's close this then as https://github.com/nextcloud/server/pull/38945 was merged