-
Notifications
You must be signed in to change notification settings - Fork 21
FileZipArchive not closing file handles #9632
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
Comments
Imported From: https://issues.scala-lang.org/browse/SI-9632?orig=1 |
@retronym said: I agree the current IO layer used by the compiler is really shabby. I started a refactoring a while back to replace it all with java.nio, but it was too tangled to make quick progress and I shelved that work. |
Hamish Dickson (hamish.dickson-at-gmail.com) said: Also, given what you've said about java.nio (something I agree with btw..) is it worth making a fix to this before that refactor has happened? |
@retronym said (edited on Jan 29, 2016 12:29:33 AM UTC):
This was enough to auto-close in a direct "unit test" of this class: ⚡ qscala -nc -Dscala.classpath.closezip
Welcome to Scala 2.12.0-20160127-203009-3f0bf2517e (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_71).
Type in expressions for evaluation. Or try :help.
scala> val f = new java.io.File("/Users/jason/.ivy2/cache/org.apache.commons/commons-math3/jars/commons-math3-3.0.jar")
f: java.io.File = /Users/jason/.ivy2/cache/org.apache.commons/commons-math3/jars/commons-math3-3.0.jar
scala> new scala.reflect.io.FileZipArchive(f)
opening: commons-math3-3.0.jar
closed: commons-math3-3.0.jar
res0: scala.reflect.io.FileZipArchive = /Users/jason/.ivy2/cache/org.apache.commons/commons-math3/jars/commons-math3-3.0.jar
scala> res0.allDirs.head._2.toList.head.toByteArray
opening: commons-math3-3.0.jar
closed: commons-math3-3.0.jar
res15: Array[Byte] = Array(-54, -2, -70, -66, 0, 0, 0, 49, 0, 36, 10, 0, 6, 0, 23, 10, 0, 24, 0, 25, 7, 0, 26, 10, 0, 3, 0, 29, 7, 0, 30, 7, 0, 31, 7, 0, 32, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 50, 76, 111, 114, 103, 47, 97, 112, 97, 99, 104, 101, 47, 99, 111, 109, 109, 111, 110, 115, 47, 109, 97, 116, 104, 51, 47, 97, 110, 97, 108, 121, 115, 105, 115, 47, 102, 117, 110, 99, 116, 105, 111, 110, 47, 65, 116, 97, 110, 104, 59, 1, 0, 5, 118, 97, 108, 117, 101, 1, 0, 4, 40, 68, 41, 68, 1, 0, 1, 120, 1, 0, 1, 68, 1, 0, 10, 100, 101, 114, 105,...
scala> :quit I confirmed with However, when I tried:
Hopefully this gives you a starting point. I think this ticket is a duplicate of #5207. I'm going to close that one as a duplicate of this one. |
@retronym said: |
Samuel Halliday (fommil) said: I will still have to come up with a workaround for now, though. Do you think it would be possible for me to inject my own implementation of the zip readers into the interactive compiler's classpath? This could all be futile... there is every possibility that ENSIME's java interactive compiler is doing the same thing, which will mean I'll definitely have to copy the files (which sounds like a massive and horrible hack). Why, oh why, Windows, must you put us through this? |
Samuel Halliday (fommil) said: |
@retronym said: You can always put your own version of |
@retronym said: |
Hamish Dickson (hamish.dickson-at-gmail.com) said (edited on Jan 29, 2016 10:44:12 AM UTC): Your code seems pretty sensible, but I'm a bit confused by |
Hamish Dickson (hamish.dickson-at-gmail.com) said (edited on Jan 31, 2016 3:10:35 PM UTC): Does anyone have any advice on how to check if a file is open in general? I know it's one of those annoying java problems, but expected to find something clever in the tests around io.Source (which I can't). Right now I'm assuming that's because they ran into exactly this problem and decided it had to be tested manually. I'll keep working on this over the next day or so, but so you can see roughly what I'm trying to add to @Test
def closeFile: Unit = {
System.setProperty("scala.classpath.closezip", "true")
val f = createTempZipFile
val fza = new FileZipArchive(createTempZipFile)
fza.iterator
System.clearProperty("scala.classpath.closezip")
assertTrue(f.canWrite) // ie File is closed (on Windows)
f.delete
}
@Test
def leaveFileOpen: Unit = {
val f = createTempZipFile
val fza = new FileZipArchive(f)
fza.iterator
assertFalse(f.canWrite) // ie File is still open (on Windows anyway)
}
def createTempZipFile = {
val f = JFile.createTempFile("test", ".zip")
val zf = new ZipOutputStream(new FileOutputStream(f))
zf.putNextEntry(new ZipEntry("data"))
zf.close()
f
} |
Samuel Halliday (fommil) said: |
Samuel Halliday (fommil) said: |
Samuel Halliday (fommil) said: The bad news is that sbt appears to be holding references as well (probably the actual compiler, not the interactive compiler) so I might have to monkey patch there as well. I might get away with it if Windows allows me to delete files from within the same process that holds the reference. |
Hamish Dickson (hamish.dickson-at-gmail.com) said: I know you need this fix now, so it doesn't help you today - but I have pretty much this change in a branch (along with a very simple test) here: https://github.com/hamishdickson/scala/tree/SI-9632-FileZipArchive-not-closing-file-handles I'll raise a pull request as soon as I'm 100% convinced about the tests |
Samuel Halliday (fommil) said: |
Samuel Halliday (fommil) said: |
Samuel Halliday (fommil) said: A serious problem from this is that sbt could be failing to produce new jar files when exportJars is used and the user would be left (silently?) with stale jars :-/ |
@retronym said: |
Samuel Halliday (fommil) said: |
Hamish Dickson (hamish.dickson-at-gmail.com) said: |
Samuel Halliday (fommil) said: |
Hamish Dickson (hamish.dickson-at-gmail.com) said: Well kind of great - sorry you're still having so many other issues |
Samuel Halliday (fommil) said: |
Samuel Halliday (fommil) said: |
Samuel Halliday (fommil) said: |
The implementation of the ZipArchive abstract file backend
https://github.com/scala/scala/blob/2.12.x/src/reflect/scala/reflect/io/ZipArchive.scala
never releases the streams to jar files that it is opening as part of providing the classpath to the compiler and (more importantly) interactive compiler.
This is not so bad on Linux, it's just wasteful, but on Windows it can be really bad as the OS locks the file and does not allow it to be deleted.
The effect is that if the user's IDE (or in my case ENSIME) is using the user's jars as the classpath definition, then the build tool (in my case, sbt in exportJars mode) cannot delete / replace the jars. The result to the end user is that the build tool is a no-op.
The problem can be fixed by releasing references to the jar file.
I am currently looking for a workaround that we can implement within ENSIME to alleviate the problem now for our users.
The text was updated successfully, but these errors were encountered: