eclipse-archived / ceylon

The Ceylon compiler, language module, and command line tools
http://ceylon-lang.org
Apache License 2.0
395 stars 62 forks source link

compiler: Remove existing output .car files before writing new ones #7410

Open xkr47 opened 5 years ago

xkr47 commented 5 years ago

I'm running a reverse proxy implemented in ceylon that is the entry point for our 20+ domains.

I just happened to notice that if I recompile the module while it is running (and I never really update version numbers) then I can get NoClassDefFoundError thrown in the running proxy.

This turned out to be because java loads classes dynamically from the car file as they are needed. This has happened to me earlier with Java as well. Because the file is just overwritten (and assuming the byte offsets of individual classes in the file changes just a little), then it can fail to load classes that are not currently loaded into memory.

At least in posix systems (I believe this is the criterion), the solution is to remove the .car files before recompiling. The files will remain accessible to the JVM for as long as they are kept open (and that's what the JVM does), but the new .car file will conceptually be a different file instead, thus not overwriting the contents of the old one.

I think it could be a good idea to at least in posix systems to remove the .car files before writing the new ones. I don't know about Windows; but I would perhaps guess the files are locked by the JVM and thus not even overwritable while the program is running. I don't have a possibility to test this right now.. Anyway iff this is hypothesis is true, writing the .car files will fail and trying to remove it first will fail just the same, so it doesn't get worse.

I guess a simple test program would be one that sleeps 30 seconds and then accesses another class for the first time so that it gets loaded at that point.

OlafTitz commented 5 years ago

Yes, under Windows the JAR files are kept open and can neither be rewritten, nor removed, nor renamed. (At least if accessed via a URLClassLoader, and the files are kept open until the URLClassLoader is closed.) In this case a different approach to hot redeployment is needed, but "rewriting the binary then restarting the app" sounds rather hackish anyway.

jvasileff commented 5 years ago

Just to confirm - the inode of the car file renames the same after ceylon compile. IMO, it should not be this way for non-incremental compiles (full compiles should create fresh archives).

$ ceylon compile && ls -ali modules/simple/1.0.0/simple-1.0.0.car
Note: Created module simple/1.0.0
11267733 -rw-r--r--  1 jvasileff  staff  4278 Oct 11 19:50 modules/simple/1.0.0/simple-1.0.0.car
$ ceylon compile && ls -ali modules/simple/1.0.0/simple-1.0.0.car
Note: Created module simple/1.0.0
11267733 -rw-r--r--  1 jvasileff  staff  4278 Oct 11 19:51 modules/simple/1.0.0/simple-1.0.0.car