[VFS] Optimize FTP directory existence to use CWD instead of parent LIST#759
[VFS] Optimize FTP directory existence to use CWD instead of parent LIST#759ilang wants to merge 1 commit intoapache:masterfrom
Conversation
0ec1a6e to
c0cec45
Compare
garydgregory
left a comment
There was a problem hiding this comment.
Hello @ilang
Please rebase on git master and review my comments.
Isn't it possible that LIST would work when CDW could fail due to access restrictions?
TY!
| * @param relPath The pathname of the directory to change to. | ||
| * @return true if successfully completed, false if not. | ||
| * @throws IOException If an I/O error occurs. | ||
| * @since 2.10.1 |
There was a problem hiding this comment.
The next feature version will be 2.11.0 as you can see in the POM. How did you get to 2.10.1? Is this AI generated?
There was a problem hiding this comment.
Sorry for the wrong version, I do work with AI, but I closely review it, and make sure there are tests in place. I guess I missed the version here.
| * @param relPath The pathname to test. | ||
| * @return true if the path is an existing directory, false otherwise. | ||
| * @throws IOException If an I/O error occurs. | ||
| * @since 2.10.1 |
There was a problem hiding this comment.
The next feature version will be 2.11.0 as you can see in the POM. How did you get to 2.10.1? Is this AI generated?
There was a problem hiding this comment.
Sorry for the wrong version, I do work with AI, but I closely review it, and make sure there are tests in place. I guess I missed the version here.
| manager.init(); | ||
| final FileObject dir = manager.resolveFile( | ||
| FtpProviderTest.getConnectionUri() + "/cwdOptDir/nested", createOptions()); | ||
| Assertions.assertTrue(dir.exists(), "Nested directory should exist"); |
There was a problem hiding this comment.
Please use static imports but only for JUnit.
Thanks, @garydgregory Good point, had too look it up myself. and yes, CWD could fail due to access restrictions while LIST on the parent would still work. in FTPFileObject : private void setFTPFile(final boolean flush) throws IOException { The only time we don't fall back is when this is a root directory, however the root case is also covered: the factory already CWDs to the root directory during connection setup. |
|
Hi @garydgregory, I am going to rebase and commit, I also added a very small optimization, to save one cwd command when it is the "." folder. |
For directory existence checks, CWD is a lightweight control-channel command with no data transfer, while LIST opens a data channel and transfers the entire directory contents. When CWD succeeds (path is a directory), the expensive parent LIST is skipped entirely. When CWD fails (path is a file, symlink, non-existent, or access-restricted), falls back to the original parent LIST behavior. Add FtpClient.isDirectory() with PWD save/restore in FTPClientWrapper to avoid changing the working directory when probing non-root paths. Skip save/restore for CWD "." (root check) since it does not change the working directory. Rename verifyRootDirectory() to verifyDirectory() as it now serves both root and non-root paths. Fix NPE in getTimestampMillis() for CWD-resolved directories: the synthetic FTPFile has no timestamp, so lazily fetch the real FTPFile via parent LIST when timestamp is first requested. Review fixes: - Fix @SInCE 2.10.1 to @SInCE 2.11.0 to match POM version. - Use static imports for JUnit assertions.
c0cec45 to
2ed521d
Compare
|
I may be missing something here, but why not use the FTP command MLST [1] to return just the details for a single file/directory? |
Thanks @sebbASF I will check it, I moved this pull request to be a draft, to check more stuff, and while I am dealing with my pervious PR that needs fixing. |
Summary
setFTPFile()now tries CWD before falling back to parent LIST for directory existence checksFtpClient.isDirectory()with PWD save/restore to avoid changing the working directorySymlink note
CWD follows symlinks transparently, so a symlink-to-directory is classified as a plain directory via the CWD fast path. This is acceptable because FTP symlink behavior in VFS is provider-internal —
doGetType()resolves symlinks to their target type, andisSymbolicLink()always returnsfalsefor FTP (the FTP provider does not overridedoIsSymbolicLink()). The embedded MINA FTP server also cannot report symlinks in LIST output (it uses the oldjava.io.FileAPI which follows symlinks transparently).Depends on
This PR depends on #757 (root exists on disconnect fix). Please merge #757 first.
Test plan
FtpCwdOptimizationTestwith 5 tests: