VfsUtil.markDirtyAndRefresh() seems flaky in recent builds (2019.1+)


My plugin has several processes that run behind-the-scenes to populate portions of the filesystem. After these processes complete, I've always called VfsUtil.markDirtyAndRefresh(false, true, true, sharedRootDir) to force the IDE to update its notion of these files. That's always worked reliably...until very recently.

Now I can have one of these processes run to populate a temp directory (not under a content root), then do the following:

File ioTempDir = ExternalProcess.populateTempDir(...);
VirtualFile tempDir = VfsUtil.findFileByIoFile(ioTempDir, true);
VfsUtil.markDirtyAndRefresh(false, true, true, tempDir);
List<VirtualFile> tempFiles = VfsUtil.collectChildrenRecursively(tempDir);

and more often than not, the resulting list of files doesn't reflect the actual contents of the temporary directory on disk. I can set a breakpoint in the debugger between the last two lines and refresh a couple of additional times after which things seem to be correct, but I'm running markDirtyAndRefresh() with async=false assuming/hoping that by the time that call returns, the VFS will be up-to-date...or at least will read through to the correct state.

Again, I've implemented this pattern a few times in the past without issue, and there's really no difference in what I'm doing now other than that I'm seeing this behavior.

It's worth nothing that I see what may be related behavior as a user of the IDE in recent builds where sometimes the VCS indicators seem behind until I an explicit File>Synchronize, or files are added to my project's content roots and that's sometimes not picked up when the window gets focus...though sometimes things work fine.

It just seems like something is broken here in recent builds. Does this sound familiar to anyone else? Any thoughts on something I might do short of refreshing/collecting files in a loop until the count of returned files stabilizes?


Yeah, something is definitely wrong here. I can regularly (but not 100% reliably) reproduce the following behavior:

  1. My plugin uses FileUtil.createTempDirectory() to create a temporary directory and runs an external process with the path to that temp directory.
  2. The external process places a file in that temp directory containing the string "System.PageReference". I can see this by opening the file in an editor outside of the IDE. NOTE: This file has the exact same name as a file under one of the open project's content/source roots! I believe that comes into play below.
  3. Within the IDE my plugin runs VfsUtil.markDirtyAndRefresh() as described above on the temporary directory, both synchronously and recursively.
  4. Within the IDE my plugin then uses FileUtil.getFileContents(virtualFile.getInputStream()) to load the bytes of the file placed in step 2.
  5. In the debugger I evaluate the expression new String(fileContents) and copy them into an external editor window. The contents are different from those viewed in step 2 but identical to the contents of the same-named file under the open project's content/source roots. It's like the VFS cache is resolving the wrong file by name. NOTE: In the debugger I can see the path of the file that is being manipulated and it is 100% the one under the temporary directory. The one managed by the project is never even referenced in the active stack frame.

Again, if I repeatedly force a VFS refresh using either VfsUtil.markDirtyAndRefresh() or VirtualFile.refresh(), the correct file contents are ultimately resolved. This really does seem to be some kind of stale caching issue, and I'm definitely concerned that there's a potentially bad bug with VFS caching here. I'll keep hacking away at it to see if I can figure out a definitive pattern.


I filed a ticket here since this seems to be a plugin SDK issue: