Skip to content

GH-3076: Add file existence check #3077

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

Merged
merged 8 commits into from
Oct 17, 2019

Conversation

EmmanuelRoux
Copy link
Contributor

Fixes #3076

  • Add file existence check: throw a FileNotFoundException when trying to get a lock for a non-existent file

Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

@EmmanuelRoux ,

Thank you for contribution. Looks good, but any chances to have a unit test covering such a behavior?

@EmmanuelRoux
Copy link
Contributor Author

@artembilan Maybe we should discuss about modifying NioFileLocker too, as it's the only usage of FileChannelCache

With my first suggestion, the FileNotFoundException will be wrapped in a MessagingException by NioFileLocker (line 54).

I suggest NioFileLocker.lock(File) should instead return false in that case. That would result in both:

  • DefaultDirectoryScanner.tryClaim(File) also returning false
  • FileReadingMessageSource.doReceive() skipping non-existent (or removed) scanned files being kept in internal toBeReceived cache if scanEachPoll is false (the default)

@artembilan
Copy link
Member

Sounds like a plan, @EmmanuelRoux !

Although I'd like to see some unit tests anyway.

Thank you for your effort!

@EmmanuelRoux EmmanuelRoux force-pushed the GH-3076 branch 3 times, most recently from 59d0f51 to 187483b Compare October 17, 2019 07:00
Copy link
Member

@artembilan artembilan left a comment

Choose a reason for hiding this comment

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

Please, find my review.
It might be slight nit-picking, but we develop here Open Source and our code should be in high quality 😉

Also, consider in the future not squashing commits for PR. First of all we get a notification about new commits. Secondly it is much easier to review a historical flow. We squash them during merge anyway.

Thanks for undertstanding

* <p>
* Locks acquired through this method should be passed back to #closeChannelFor to prevent memory leaks.
* <p>
* Thread safe.
*/
public static FileLock tryLockFor(File fileToLock) throws IOException {
if (!fileToLock.exists()) {
throw new FileNotFoundException("Unable to get lock for non-existent file: " + fileToLock.getAbsolutePath());
Copy link
Member

Choose a reason for hiding this comment

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

Wouldn't return null instead of this exception enough for the method contract?
As you see in the NioFileLocker, you just suppress such an exception any way.

So, let's make a return null; here, add a @Nullable for method return and so on!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's what I suggested as an alternative in #3076. In my mind, the semantics were different between a lock that failed because the file was already locked (or any other filesystem-related reason), and an attempt to lock a file that does not exist.

Anyway, I will push a new version returning null 😉

Copy link
Member

Choose a reason for hiding this comment

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

Well, if there is nothing to lock, then we definitely not locked. Seems for me that's the point of that contract.
So, let's live with null for non-existing file as well!

public TemporaryFolder temp = new TemporaryFolder() {

@Override
public void create() throws IOException {
Copy link
Member

Choose a reason for hiding this comment

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

I don't see reason in such extra logic.
It looks like temp.newFile("test0"); is fully enough against a default public TemporaryFolder temp = new TemporaryFolder();

Although I would insist on JUnit 5 already in the tests.
I'll back-port it to JUnit 4 for version 4.3.x on merge

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reason is that TemporaryFolder.newFile(String) calls File.createNewFile() which is not what is desired for test case of a non-existent file

Copy link
Member

Choose a reason for hiding this comment

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

Well, you can do then this.temp.getRoot() for a new File().
My point is: do not over-engineer a TemporaryFolder if we really can rely on its default public API.
With JUnit 5 we definitely don't have a luxury to extend extensions on the fly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right, let's go for that

}
};

@Test(expected = FileNotFoundException.class)
Copy link
Member

Choose a reason for hiding this comment

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

It is much cleaner to use an Assertions.assertThatExceptionOfType() in the code instead.
Although when we agree about null instead, this will go away anyway.

@artembilan artembilan merged commit c420c41 into spring-projects:master Oct 17, 2019
@artembilan
Copy link
Member

... and cherry-picked to 5.1.x.

Back-ported to 4.3.x after removing @Nullable and AssertJ constructions.

Will clean up code a little bit and fix AssertJ on 5.1.x branch as well.

Thank you very much for contribution; looking forward for more!

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.

FileChannelCache.tryLockFor creates empty files
2 participants