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

Make jib-core a parent-first dependency #34873

Closed
wants to merge 1 commit into from
Closed

Conversation

geoand
Copy link
Contributor

@geoand geoand commented Jul 20, 2023

Done in order to avoid problems with Jib's use of
lock classes which have no effect when the lock
class is loaded from different ClassLoaders

Fixes: #11903

Done in order to avoid problems with Jib's use of
lock classes which have no effect when the lock
class is loaded from different ClassLoaders

Fixes: quarkusio#11903
@famod
Copy link
Member

famod commented Jul 26, 2023

FTR, I have not forgotten about this but other things got/are getting in the way.

@geoand
Copy link
Contributor Author

geoand commented Jul 26, 2023

No worries, whenever you have time

@famod
Copy link
Member

famod commented Jul 27, 2023

I'm sorry but I have to report that this change is not fixing the OverlappingFileLockException in a multi-threaded Maven build.

I might be totally wrong here but AFAICS, if there is not also a "vanilla" lock in jib (synchronized or some java.util.concurrent.locks.Lock), then I don't see how limiting the classloaders involved can prevent OverlappingFileLockException in the first place.
E.g. you should be able to provoke this issue in a totally flat classloader hierarchy (or single CL) just by kicking off two threads that try to lock the same file via FileChannel.lock().
If my assumption is right, then either jib should add a "vanilla" lock upstream or Quarkus could add one around the jib invocation. The latter would be less efficient/more coarse grained as the entire jib execution would run inside the lock.

@geoand
Copy link
Contributor Author

geoand commented Jul 27, 2023

I didn't really look at what the Jib code does, I just assumed that it was using a class lock, hence the proposed change.

In any case, thanks for checking, I'll close this and we should probably implement your suggestion about running our Jib code in a lock (definitely not great, but I don't see what else we can do...)

@geoand geoand closed this Jul 27, 2023
@quarkus-bot quarkus-bot bot added the triage/invalid This doesn't seem right label Jul 27, 2023
@famod
Copy link
Member

famod commented Jul 27, 2023

@famod
Copy link
Member

famod commented Jul 27, 2023

Btw, I'm currently testing a very primitive synchronized in JibProcessor.

PS: Doesn't work, which is not that surprising.

@famod
Copy link
Member

famod commented Jul 27, 2023

Even with parent-first, I can see that com.google.cloud.tools.jib.api.JibContainer is loaded in three different QuarkusClassLoader:Augmentation Class Loader: PROD@* CLs (with 3 concurrent Maven modules building a Quarkus app via jib). Their parent CL is the same though.

@geoand
Copy link
Contributor Author

geoand commented Jul 27, 2023

That shouldn't happen, I'll have to actually run it.

Do you have a sample multi-module application I can use?

@famod
Copy link
Member

famod commented Jul 27, 2023

I'm afraid no, I'm testing with my actual corporate & closed-source project.

@geoand
Copy link
Contributor Author

geoand commented Jul 27, 2023

🆗

@famod
Copy link
Member

famod commented Jul 28, 2023

@geoand got something for you: q_jib-parallel.zip
Run it in a loop:
time while mvn -q package -T2 -Dquarkus.container-image.build=true; do echo ----; rm -rf /tmp/jib-core-application-layers-cache; done

Should fail very quickly.

PS: I had to add that cache cleanup while testing my actual app build in the same kind of loop because after a while I got "no space left on device" (Ubuntu 22). Looks like another issue to me.

@geoand
Copy link
Contributor Author

geoand commented Jul 28, 2023

Nice!

@geoand
Copy link
Contributor Author

geoand commented Jul 31, 2023

So the reason why my parent-first change didn't do anything is because parentFirst artifacts are for the runtime classloaders, not the build time.

@geoand
Copy link
Contributor Author

geoand commented Jul 31, 2023

Btw, I'm currently testing a very primitive synchronized in JibProcessor.

How did this go?

@famod
Copy link
Member

famod commented Jul 31, 2023

It didn't work for the same classloading reasons.
I used JibContainer.class as the lock object though. I think it should work when locking on the parent classloader, but that seems kind of dirty?

@geoand
Copy link
Contributor Author

geoand commented Jul 31, 2023

I used JibContainer.class as the lock object though. I think it should work when locking on the parent classloader, but that seems kind of dirty?

Yeah, that would, but so would just using any JDK class :)

@famod
Copy link
Member

famod commented Aug 1, 2023

@geoand In case we'd find a "suitable" Quarkus class to lock (that was loaded by the common CL), would that be an acceptable workaround for you?

@geoand
Copy link
Contributor Author

geoand commented Aug 1, 2023

Sure, but given that Quarkus ClassLoaders are created for each Maven build, I don't see how that could work.

@famod
Copy link
Member

famod commented Aug 1, 2023

@geoand this quick hack in JibProcessor works:

Object lockObj;
try {
    lockObj = getClass().getClassLoader().getParent().loadClass("io.quarkus.deployment.GlobalLock");
} catch (Throwable t) {
    throw new RuntimeException(t);
}
JibContainer container;
synchronized (lockObj) {
    container = jibContainerBuilder.containerize(containerizer);
}

This GlobalLock (preliminary naming) is located in core-deployment and it could provide convenience methods to hide this ugly classloading detour and to support multiple different locks, not only for Jib (though I hope it is and will stay the only case). It probably also needs some safeguards and checks as well.

Not pretty at all, but WDYT?

PS: Someone would need to check Gradle, too.

@geoand
Copy link
Contributor Author

geoand commented Aug 1, 2023

Yeah, I think we can live with that hack.

I'd rather not have any util methods though and keep this only to Jib for now and hope we never need it anywhere else

@geoand
Copy link
Contributor Author

geoand commented Aug 1, 2023

Was going to ask about Gradle, but I see you already did 😁

@famod
Copy link
Member

famod commented Aug 1, 2023

I'd rather not have any util methods though and keep this only to Jib for now and hope we never need it anywhere else

Ok, but how? The parent CL doesn't know about the jib-deployment module. That was my first attempt, btw. 😉

@geoand
Copy link
Contributor Author

geoand commented Aug 1, 2023

I'd just use (semi)some random class in the deployment module

@famod
Copy link
Member

famod commented Aug 2, 2023

@geoand

I'd just use (semi)some random class in the deployment module

You mean core-deployment, right?

@geoand
Copy link
Contributor Author

geoand commented Aug 2, 2023

Correct

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Gradle multimodule project + quarkus-container-image-jib: OverlappingFileLockException
2 participants