fix(LocalStorage): Clear realpath cache on fopen failure and re-try access - #63101
fix(LocalStorage): Clear realpath cache on fopen failure and re-try access#63101DerDreschner wants to merge 1 commit into
Conversation
|
/backport to stable34 |
|
/backport to stable33 |
|
/backport to stable32 |
|
/backport to stable31 |
|
/backport to stable30 |
|
/backport to stable29 |
|
Backport down to stable29 is to stabilize our CI runs. |
joshtrichards
left a comment
There was a problem hiding this comment.
Some of the comments may be better represented by (or at least in) the regression tests. 🤷
| // realpath_cache_ttl expires, this process still has it cached as a file, and | ||
| // because fopen() resolves through that cache, it refuses to look inside and | ||
| // fails as if the file did not exist. Dropping the stale entries and opening | ||
| // again is what fixes that. The retry deliberately stays unsuppressed, so the |
There was a problem hiding this comment.
I'm all for making troubleshooting clues not invisible, but this is an API contract change. Not sure...
| $this->unlink($path); | ||
| } | ||
| $result = @fopen($sourcePath, $mode); | ||
| if ($result === false) { |
There was a problem hiding this comment.
Any non-cache-related failures worth ignoring? (Not even sure it's possible).
|
+1 to an official php.net docs clarification in this area. ;-) I wander.if this is relevant for any other |
…ccess Assisted-by: ClaudeCode:claude-opus-5 Signed-off-by: David Dreschner <david.dreschner@nextcloud.com>
deec1b8 to
ceca32a
Compare
Summary
PHP resolves the path of every
fopen()through its realpath cache, which stores per path component whether that component is a directory. That cache is per process, and entries live forrealpath_cache_ttl(120s by default). If one process has a path cached as a file and another process replaces it with a directory, the first process keeps refusing to descend into it andfopen()fails as if the file were missing - whilestat()/file_exists()bypass that cache and keep reporting the file. The file looks perfectly present and is still unreadable, for up to two minutes.That is why the
filesdropintegration tests fail intermittently: the suite recycles the same user and paths, one scenario storesdrop/Alice/folderas a file, the next needs it as a directory, and the dev server runs several worker processes (PHP_CLI_SERVER_WORKERS=2), so the worker serving the download is usually not the one that created the directory (example run: …). It is not CI-specific: php-fpm workers keep the same cache, so a user who deletes a fileX, creates a folderX, and downloadsX/y.txtvia another worker gets a 503 for up torealpath_cache_ttl.This is being fixed by this PR, which in this case walks up the parents, clears their cache entry and re-tries to access the path.
Checklist
3. to review, feature component)stable32)AI (if applicable)