Skip to content

Conversation

@jovanstevanovic
Copy link
Member

@jovanstevanovic jovanstevanovic commented Mar 29, 2021

Task and high-level overview (#3326)

PROGRESS:

  • First step toward creating a custom filesystem with a TODO list is committed.

@graalvmbot
Copy link
Collaborator

Hello jovanstevanovic, thanks for contributing a PR to our project!

We use the Oracle Contributor Agreement to make the copyright of contributions clear. We don't have a record of you having signed this yet, based on your email address jovan -(dot)- stevanovic1 -(at)- outlook -(dot)- com. You can sign it at that link.

If you think you've already signed it, please comment below and we'll check.

Copy link

@christianwimmer christianwimmer left a comment

Choose a reason for hiding this comment

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

So this PR removes some substitutions that are not necessary because the JDK code eventually calls a method that remains substituted. I'm curious - where is the actual "root" in the JDK that remains substituted?

private static URL findResource(String mn, String name) {
return ClassLoader.getSystemClassLoader().getResource(name);
}
@AnnotateOriginal

Choose a reason for hiding this comment

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

What is the AnnotateOriginal for? You are not adding any annotations, so this is not going to do anything

@graalvmbot
Copy link
Collaborator

Hello Jovan Stevanovic, thanks for contributing a PR to our project!

We use the Oracle Contributor Agreement to make the copyright of contributions clear. We don't have a record of you having signed this yet, based on your email address 44313413+jovanstevanovic -(at)- users -(dot)- noreply -(dot)- github -(dot)- com. You can sign it at that link.

If you think you've already signed it, please comment below and we'll check.

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ByteArrayChannel implements SeekableByteChannel {
Copy link
Member

Choose a reason for hiding this comment

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

Can we simply ignore the JDK 8 implementation? Would it still work for the set of programs that worked before this PR?

import java.net.URL;
import java.net.URLConnection;

public class JDKVersionSpecificResourceBuilder {
Copy link
Member

Choose a reason for hiding this comment

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

Then we could skip all of this as well.

return isDirectory;
}

public void setDirectory(boolean directory) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This and setData don't seem to be used - I would remove them

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree.

* </p>
*
* <p>
* ResourceFileSystemProvider exposes methods for creating a new file system, getting existing one
Copy link
Contributor

Choose a reason for hiding this comment

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

I would tweak this comment a bit:

The {@link NativeImageResourceFileSystemProvider} provides most of the functionality of a {@link FileSystem}. It is an in-memory file system that upon creation contains a copy of the resources included in the native-image.
Note that changes to files do not affect actual resources returned by resource manipulation methods like  `Class.getResource`. Upon being closed, all changes are discarded.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

* </p>
*
* <p>
* Most of operations mentioned above aren't accessed directly i.e. by calling methods from this
Copy link
Contributor

Choose a reason for hiding this comment

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

I would tweak this one as well:

As with other file system providers, these methods provide a low-level interface and are not meant for direct usage - see {@link java.nio.file.Files}

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

new HashSet<>(Arrays.asList("basic", "resource")));

private final Set<InputStream> streams = Collections.synchronizedSet(new HashSet<>());
private final Set<Path> tmpPaths = Collections.synchronizedSet(new HashSet<Path>());
Copy link
Contributor

Choose a reason for hiding this comment

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

<Path> is redundant here -> <>

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

* <p>
* Some parts of code from this class are copied from jdk.nio.zipfs.ZipFileSystem with small tweaks.
* The main reason why we cannot reuse this class (without any code copying) is that we cannot
* extend jdk.nio.zipfs.ZipPath which is central class in Zip file system.
Copy link
Contributor

Choose a reason for hiding this comment

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

is central class in Zip file system -> is the central class in the Zip file system

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

private final long size;

ResourceFileStoreAttributes(NativeImageResourceFileStore fileStore) throws IOException {
Path path = FileSystems.getDefault().getPath(fileStore.name());
Copy link
Contributor

Choose a reason for hiding this comment

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

If I understood correctly, a NativeImageResourceFileStore is bound to a path inside of the native-image file system. However, here we seem to be resolving that path in the default file system - I may have missed something, but it seems like this file isn't connected to the native-image file system and the information here, provided that such a path exists, most likely isn't what we're looking to return

private static native void initSystemClassLoader();

@Substitute
private URL getResource(String name) {
Copy link
Contributor

Choose a reason for hiding this comment

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

To make sure I understand these correctly, we've pushed these substitutions to the appropriate class loaders - we now respect the class loader hierarchy when looking up resources

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct. That was the idea at some point, but due to a lack of module support, I was forced to return almost all substitutions. Once we get full module support, we will surely push substitutions to appropriate class loaders.

} else {
checkParents(dst);
}
Entry target = new Entry(eSrc, Entry.COPY); // Copy eSrc entry.
Copy link
Contributor

Choose a reason for hiding this comment

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

When we do a copy of the entry, we may either create a copy of the original entry's bytes, or, if the previous entry is getting deleted, take the original entry's bytes directly. In both cases, however, copyOnWrite remains false - if we attempt to write data to this entry (using getBytes), it seems like we will accidentally reload the entry - should we also flip the copyOnWrite flag to true here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice catch. That could cause a bug in the future.

if (!isTrue(env, "create")) {
throw new FileSystemNotFoundException(resourcePath.toString());
}
this.useTempFile = isTrue(env, "useTempFile");
Copy link
Contributor

Choose a reason for hiding this comment

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

If I understood it correctly, this option allows us to create temporary files when modifying a file system entry?
Would such a flag be required? This seems to only be used when attempting to create new output streams, but it may help reduce complexity if we remove it and keep everything in memory

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct. No, it's not required, we can get rid of this flag and simplify the operation of creating a new output stream and keep everything in memory.

} else {
os = new ByteArrayOutputStream((e.size > 0) ? e.size : 8192);
}
return new EntryOutputStream(e, os);
Copy link
Contributor

Choose a reason for hiding this comment

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

If we keep everything in memory, would it make sense to also close the output streams when closing the file system?

Copy link
Member Author

Choose a reason for hiding this comment

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

Agree. I overlooked it. We are keeping all information about opened input streams, so we should do the same thing for output streams.

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.

5 participants