Thomas Wolf created SSHD-1220:
---------------------------------

             Summary: SFTP: too many LSTAT calls
                 Key: SSHD-1220
                 URL: https://issues.apache.org/jira/browse/SSHD-1220
             Project: MINA SSHD
          Issue Type: Improvement
    Affects Versions: 2.7.0
            Reporter: Thomas Wolf


While looking at an alternate solution for SSHD-1217 I noticed that the 
{{AbstractSftpSubsystemHelper}} makes several LSTAT calls for a single 
{{FileSystem.readAttributes()}} invocation.

Basically it makes one LSTAT call per supported attributes view; only to 
collect the returned items then in one single map anyway.

This doesn't make any sense. SFTP file attributes are a single, defined 
structure. If {{AbstractSftpSubsystemHelper.getAttributes()}} needs to collect 
all these different views ({{BasicFileAttributes}}, {{PosixFileAttributes}}, 
and so on) on these underlying SFTP attributes, then all these views should 
build upon the same single {{SftpClient.Attributes}} gotten exactly _once_.

This could be solved with careful temporary caching of SFTP attributes on the 
{{SftpPath}} once read while in {{AbstractSftpSubsystemHelper.getAttributes()}} 
and clearing that cache at the end.

The problem is more general, though. The code in several places makes up-front 
checks whether a file exists, is a directory, and so on. This is a questionable 
pattern anyway, since the result of a {{Files.exists()}} is outdated 
immediately; one cannot rely on the file being still there on the next access. 
With an {{SftpPath}}, this {{exists()}} call is an (L)STAT remote call getting 
the attributes. Now look at 
{{AbstractSftpSubsystemHelper.resolveFileAttributes}}: here getting the 
attributes themselves is so guarded, so it makes at least _two_ LSTAT calls.

This should be improved. A solution might be not checking for existence, 
isDirectory(), and such up front but translating {{SftpExceptions}} at the 
{{FileSystem}} boundary into more standard exceptions if possible and then just 
doing the operations. For instance, 
{{AbstractSftpSubsystemHelper.resolveFileAttributes}} currently is

{code:java}
    protected NavigableMap<String, Object> resolveFileAttributes(
            Path file, int flags, LinkOption... options)
            throws IOException {
        Boolean status = IoUtils.checkFileExists(file, options);
        if (status == null) {
            return handleUnknownStatusFileAttributes(file, flags, options);
        } else if (!status) {
            throw new NoSuchFileException(file.toString(), file.toString(), 
"Attributes N/A for target");
        } else {
            return getAttributes(file, flags, options);
        }
    }
{code}

The {{getAttributes()}} call will call {{java.nio.file.Files.getAttributes()}}, 
which calls {{SftpFileSystemProvider.readAttributes()}}. That function is at 
the {{FileSystem}} API boundary, and should translate an {{SftpException}} with 
subcode SH_FX_NO_SUCH_FILE into a {{java.nio.file.NoSuchFileException}}. (And a 
few others.)

The {{handleUnknownStatusFileAttributes}} mechanism is invoked if the file 
neither {{Files.exists()}} nor {{Files.notExists()}}. IMO that whole case would 
just disappear. There is no need for up-front checking in many cases; here 
either {{getAttributes()}} succeeds or throws an appropriate exception.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@mina.apache.org
For additional commands, e-mail: dev-h...@mina.apache.org

Reply via email to