Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-3370: Remove synchronized from RemoteFileUtils #3380

Merged
merged 4 commits into from Sep 10, 2020

Conversation

artembilan
Copy link
Member

Fixes #3370

The synchronized on the RemoteFileUtils.makeDirectories() makes an application too
slow, especially when we deal with different paths in different sessions

  • Remove the synchronized from that method and rework SftpSession.mkdir()
    to return false when "A file cannot be created if it already exists" exception
    is thrown from the server.
    Essentially make an exists() call to be sure that an exception is really related
    to "file-already-exists" answer from the server

Cherry-pick to 5.3.x, 5.2.x & 4.3.x

Fixes spring-projects#3370

The `synchronized` on the `RemoteFileUtils.makeDirectories()` makes an application too
 slow, especially when we deal with different paths in different sessions

* Remove the `synchronized` from that method and rework `SftpSession.mkdir()`
to return `false` when "A file cannot be created if it already exists" exception
is thrown from the server.
Essentially make an `exists()` call to be sure that an exception is really related
to "file-already-exists" answer from the server

**Cherry-pick to 5.3.x, 5.2.x & 4.3.x**
throw new NestedIOException("failed to create remote directory '" + remoteDirectory + "'.", e);
catch (SftpException ex) {
if (ex.id == ChannelSftp.SSH_FX_FAILURE && exists(remoteDirectory)) {
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should return true since it was a race condition. RFU currently discards the result; I think it should check it and throw an exception if false - see FtpSession where we simply delegate to the client.

when error code is not `4` or remote dir does not exist
@garyrussell
Copy link
Contributor

I still think we need to check the result in RFU (for the FTP case).

@artembilan
Copy link
Member Author

I still think we need to check the result in RFU

Hm. Probably that true/false contract is not good. I may guess that Session API was designed after that FTPClient, so we blindly got a boolean result which confuses us now: what really could be the case when we got false reply, but not an exception?..

I think for now I'll just go with your suggestion to make a minimal breaking change and I'll throw some exception from the RFU to align with the sftpSession when it throws an exception instead of false return.

`RemoteFileUtils` to throw an `IOException` when `false`
@garyrussell
Copy link
Contributor

a minimal breaking change

It's not really a breaking change, we will just detect the problem earlier - some downstream operation would have failed if the mkdir was not successful.

@artembilan
Copy link
Member Author

OK. I just mean that the FtpSession contract is not the same as an SftpSession one. So, it is not clear when should return false for SFTP case, or throw an exception for FTP to align them.
Right now we match both contracts in that RFU, but still have a difference in mkdir() behavior. That's what I don't want to break at the moment.

@garyrussell
Copy link
Contributor

FtpSession contract is not the same as an SftpSession

I don't think that matters - FTP can throw an exception too.

@garyrussell
Copy link
Contributor

RemoteFileOutboundGatewayTests > testMoveWithMkDirs FAILED
    org.springframework.messaging.MessagingException at RemoteFileOutboundGatewayTests.java:304
        Caused by: java.io.IOException at RemoteFileOutboundGatewayTests.java:304

@garyrussell garyrussell merged commit 47cae46 into spring-projects:master Sep 10, 2020
garyrussell pushed a commit that referenced this pull request Sep 10, 2020
* GH-3370: Remove synchronized from RemoteFileUtils

Fixes #3370

The `synchronized` on the `RemoteFileUtils.makeDirectories()` makes an application too
 slow, especially when we deal with different paths in different sessions

* Remove the `synchronized` from that method and rework `SftpSession.mkdir()`
to return `false` when "A file cannot be created if it already exists" exception
is thrown from the server.
Essentially make an `exists()` call to be sure that an exception is really related
to "file-already-exists" answer from the server

**Cherry-pick to 5.3.x, 5.2.x & 4.3.x**

* * Re-throw an exception in the `SftpSession.mkdir()`
when error code is not `4` or remote dir does not exist

* * Check `session.mkdir()` result in the
`RemoteFileUtils` to throw an `IOException` when `false`

* * Fix mock test to return `true` for `mkdir` instead of `null`
garyrussell pushed a commit that referenced this pull request Sep 10, 2020
* GH-3370: Remove synchronized from RemoteFileUtils

Fixes #3370

The `synchronized` on the `RemoteFileUtils.makeDirectories()` makes an application too
 slow, especially when we deal with different paths in different sessions

* Remove the `synchronized` from that method and rework `SftpSession.mkdir()`
to return `false` when "A file cannot be created if it already exists" exception
is thrown from the server.
Essentially make an `exists()` call to be sure that an exception is really related
to "file-already-exists" answer from the server

**Cherry-pick to 5.3.x, 5.2.x & 4.3.x**

* * Re-throw an exception in the `SftpSession.mkdir()`
when error code is not `4` or remote dir does not exist

* * Check `session.mkdir()` result in the
`RemoteFileUtils` to throw an `IOException` when `false`

* * Fix mock test to return `true` for `mkdir` instead of `null`
@garyrussell
Copy link
Contributor

Cherry-picked to 5.3.x, 5.2.x - 4.3.x needs a back-port.

artembilan added a commit that referenced this pull request Sep 10, 2020
* GH-3370: Remove synchronized from RemoteFileUtils

Fixes #3370

The `synchronized` on the `RemoteFileUtils.makeDirectories()` makes an application too
 slow, especially when we deal with different paths in different sessions

* Remove the `synchronized` from that method and rework `SftpSession.mkdir()`
to return `false` when "A file cannot be created if it already exists" exception
is thrown from the server.
Essentially make an `exists()` call to be sure that an exception is really related
to "file-already-exists" answer from the server

**Cherry-pick to 5.3.x, 5.2.x & 4.3.x**

* * Re-throw an exception in the `SftpSession.mkdir()`
when error code is not `4` or remote dir does not exist

* * Check `session.mkdir()` result in the
`RemoteFileUtils` to throw an `IOException` when `false`

* * Fix mock test to return `true` for `mkdir` instead of `null`
# Conflicts:
#	spring-integration-file/src/main/java/org/springframework/integration/file/remote/RemoteFileUtils.java
#	spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java
#	spring-integration-file/src/test/java/org/springframework/integration/file/remote/gateway/RemoteFileOutboundGatewayTests.java
#	spring-integration-sftp/src/test/java/org/springframework/integration/sftp/outbound/SftpOutboundTests.java
@artembilan
Copy link
Member Author

Back-ported to 4.3.x as 9019676 after fixing conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Don't make RemoteFileUtils.makeDirectories syncronized
2 participants