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

NIO Path support #304

Merged
merged 17 commits into from
Oct 8, 2021
Merged

NIO Path support #304

merged 17 commits into from
Oct 8, 2021

Conversation

tbrunsch
Copy link

@tbrunsch tbrunsch commented Oct 1, 2021

jHDF makes intensive use of NIO internally and HdfFile provides constructors for Path and URI. However, these constructors convert Path and URI to File (before converting it back to Path again). In this branch, all internal usages of File have been replaced with Path.

Remarks:

  • The test NioPathTest demonstrates that all provided test files can be loaded correctly from within a ZipFileSystem.
  • I did not want to break with the API, so I had to add a method Node.getFileAsPath() as an alternative to Node.getFile() that returns a Path instance rather than a File instance. (Unfortunately, the name "getPath" was already in use.)
  • I had to implement a fallback strategy in HdfFileChannel when memory mapping is not supported by the file system, which is the case for all non-default file systems I am aware of. This fallback only works if the requested buffer size does not exceed Integer.MAX_VALUE.

Copy link
Owner

@jamesmudd jamesmudd left a comment

Choose a reason for hiding this comment

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

This looks good. When you point it out, it is odd that I converted to FIle this cleans that up nicely and allows support for other file systems so that's nice. Do you have a use case for this change?

It seems there are a few failing tests hopefully mostly where a File is now compared to a Path could you take a look and see if you can fix those?

About the API i'm not too attached to it ATM I know of quite a few users, but if you have a strong proposal to change it, and keep it simple I would be happy to do so. Then again the solution proposed here doesn't break it so maybe that's nicer.

Think there are also some minor CI checkstyle issues would be great if you can take a look.

Comment on lines 79 to 103
// many file systems do not support memory mapping
int lengthAsInt = (int) length;
if (lengthAsInt != length) {
// length must be representable by an int such that we can allocate a ByteBuffer manually
throw e;
}
ByteBuffer buffer = ByteBuffer.allocate(lengthAsInt);
long oldPosition = fc.position();
fc.position(address);
try {
int totalNumberOfBytesRead = 0;
while (totalNumberOfBytesRead < lengthAsInt) {
int numberOfBytesRead = fc.read(buffer);
if (numberOfBytesRead < 0) {
throw new IOException("Trying to read more bytes than available");
}
totalNumberOfBytesRead += numberOfBytesRead;
}
}
finally {
// reset file channel to old position
fc.position(oldPosition);
}
buffer.flip();
return buffer;
Copy link
Owner

Choose a reason for hiding this comment

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

Think maybe this is a cleaner impl

ByteBuffer buffer = ByteBuffer.allocate(Math.toIntExact(length));
int bytesRead = fc.read(buffer, address);
if(bytesRead != length) {
	throw new IOException("Incorrect bytes read");
}
buffer.flip();
return buffer;

What do you think?

Copy link
Author

Choose a reason for hiding this comment

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

Regarding Math.toIntExact(length): If this conversion fails, then the caller will get an ArithmeticException. This might be a bit surprising, so I tried to handle this case individually. However, since HdfInMemoryByteBuffer.mapNoOffset() also uses this method, I think that it is consistent to use it here as well.

Regarding your suggestion to remove the loop for reading data into the ByteBuffer: FileChannel.read() does not guarantee to fill the whole buffer. It might even return 0 although there is still more data to read. Maybe this case occurs when data is transferred via the network and it is known that there is more data, but it has not arrived yet. This is why I think it is safer to read the data in a loop.

Regarding resetting the position: I tried to avoid side effects, so I decided to reset the position after reading the data. If you think that this side effect is uncritical, then we could remove this behavior to make the code simpler. What do you think?

* </li>
* </ol>
*/
class NioPathTest
Copy link
Owner

Choose a reason for hiding this comment

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

Test looks great really thorough. Would it be possible to convert to Hamcrest style assetThat assertions. I think there more readable and have generally nicer errors. Not a blocker though can be merged anyway and changed later.

Copy link
Author

Choose a reason for hiding this comment

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

I changed the test to Hamcrest style to be consistent with the other tests. Unlike the other tests, I used Matchers.is() as a shortcut for Matchers.is(Matchers.equalTo()). If you find is(equalTo()) more expressive in the code, then I can also use the longer version.

@tbrunsch
Copy link
Author

tbrunsch commented Oct 4, 2021

Our company has developed a distributed file system tailored to measurement data. We have custom FileSystem and Path implementations to access the files there. Additionally, many cloud provides have an NIO-based Java API.

I am sorry for the failing tests. I do not know why I forgot to run all tests before creating the pull request...

@jamesmudd
Copy link
Owner

Think this just need this adding 9fc4021 then the tests will pass and think this can be merged.

@sonarcloud
Copy link

sonarcloud bot commented Oct 8, 2021

SonarCloud Quality Gate failed.    Quality Gate failed

Bug C 3 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 1 Code Smell

81.0% 81.0% Coverage
0.0% 0.0% Duplication

@jamesmudd jamesmudd merged commit 892afb1 into jamesmudd:master Oct 8, 2021
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.

None yet

2 participants