[ https://issues.apache.org/jira/browse/MRESOLVER-325?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17693545#comment-17693545 ]
Michael Osipov commented on MRESOLVER-325: ------------------------------------------ OK, I cracked it. This is purely a Windows problem, any system which adheres to POSIX is supposed to implement {{rename(2)}} atomic: https://pubs.opengroup.org/onlinepubs/000095399/functions/rename.html. Now, the code for Windows does this: https://github.com/openjdk/jdk17u-dev/blob/aa11a935373686bf5d67afb89368931c995824f6/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java#L307-L320 {{MoveFileEx}} does not mention anything about atomic. Interesting read: https://github.com/python/cpython/issues/53074. My testing even with single thread leads to the assumption that {{MoveFileEx}} is executed delayed and fails under high/fast load which means that the target file is blocked while the next operation is already trying to overwrite it again and it fails. So {{MoveFileEx}} returns although the move isn't complete. To verify this I have applied the following patch: {noformat} diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/FileUtils.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/FileUtils.java index f12d5b82..8b4a1960 100644 --- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/FileUtils.java +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/FileUtils.java @@ -26,6 +26,10 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.concurrent.ThreadLocalRandom; +import com.sun.jna.platform.win32.Kernel32; +import com.sun.jna.platform.win32.WinBase; +import com.sun.jna.platform.win32.WinDef.DWORD; + import static java.util.Objects.requireNonNull; /** @@ -118,7 +122,8 @@ public final class FileUtils @Override public void move() throws IOException { - Files.move( tempFile, file, StandardCopyOption.ATOMIC_MOVE ); + Kernel32.INSTANCE.MoveFileEx( tempFile.toAbsolutePath().toString(), file.toAbsolutePath().toString(), + new DWORD( WinBase.MOVEFILE_REPLACE_EXISTING | WinBase.MOVEFILE_WRITE_THROUGH ) ); } @Override {noformat} {{MOVEFILE_WRITE_THROUGH}} guarantees that the method does *not* exit before the operation is complete. Which is actually what we need. With that patch single thread and multi thread executions ran multiple times without issues. So, [~laeubi], nothing is wrong with Tycho. the Java implementation is just CRAP. What now? Well, I replaced ATOMIC with REPLACE_EXISTING, now if you look at that code in JDK it will delete the target which might be subject to move from a previous run and then use again {{MoveFileEx}} without any flags which is again non-blocking and we are back to the previous problem causing a chicken and egg problem. Again, this is under high volume like here. This fails with exceptions as well. Why actually gson? Well, gson JAR AND gson sources JAR are downloaded with a diff of a few hundred milliseconds and Windows cannot handle this. WHAT A JOKE. While the additional flag won't make fully atomic, there is another function for this, it reduces the possible failure to a minimum. Thoughts? PS: This needs to be reported with the OpenJDK team. Many others have suffered from this because of the missing flags. > [REGRESSION] Suddenly seeing I/O errors under windows aborting the build > ------------------------------------------------------------------------ > > Key: MRESOLVER-325 > URL: https://issues.apache.org/jira/browse/MRESOLVER-325 > Project: Maven Resolver > Issue Type: Bug > Components: Resolver > Affects Versions: 1.9.4 > Reporter: Christoph Läubrich > Priority: Major > Fix For: 1.9.6 > > > If one runs a build that otherwise works fine on 3.8.x with 3.9 we now get > the following exception (full output can be found here > https://github.com/eclipse-platform/eclipse.platform/actions/runs/4211467991/jobs/7309831666): > {code:java} > Error: 5.889 [ERROR] Internal error: java.io.UncheckedIOException: > java.nio.file.AccessDeniedException: > C:\Users\runneradmin\.m2\repository\com\google\code\gson\gson\2.10.1\_remote.repositories.15650462061630955031.tmp > -> > C:\Users\runneradmin\.m2\repository\com\google\code\gson\gson\2.10.1\_remote.repositories > -> [Help 1] > org.apache.maven.InternalErrorException: Internal error: > java.io.UncheckedIOException: java.nio.file.AccessDeniedException: > C:\Users\runneradmin\.m2\repository\com\google\code\gson\gson\2.10.1\_remote.repositories.15650462061630955031.tmp > -> > C:\Users\runneradmin\.m2\repository\com\google\code\gson\gson\2.10.1\_remote.repositories > at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:108) > at org.apache.maven.cli.MavenCli.execute (MavenCli.java:821) > at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:270) > at org.apache.maven.cli.MavenCli.main (MavenCli.java:192) > at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method) > at jdk.internal.reflect.NativeMethodAccessorImpl.invoke > (NativeMethodAccessorImpl.java:77) > at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke > (DelegatingMethodAccessorImpl.java:43) > at java.lang.reflect.Method.invoke (Method.java:568) > at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced > (Launcher.java:282) > at org.codehaus.plexus.classworlds.launcher.Launcher.launch > (Launcher.java:225) > at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode > (Launcher.java:406) > at org.codehaus.plexus.classworlds.launcher.Launcher.main > (Launcher.java:347) > Caused by: java.io.UncheckedIOException: java.nio.file.AccessDeniedException: > C:\Users\runneradmin\.m2\repository\com\google\code\gson\gson\2.10.1\_remote.repositories.15650462061630955031.tmp > -> > C:\Users\runneradmin\.m2\repository\com\google\code\gson\gson\2.10.1\_remote.repositories > at org.eclipse.aether.internal.impl.DefaultTrackingFileManager.update > (DefaultTrackingFileManager.java:121) > at > org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManager.addRepo > (EnhancedLocalRepositoryManager.java:274) > at > org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManager.addArtifact > (EnhancedLocalRepositoryManager.java:252) > at org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManager.add > (EnhancedLocalRepositoryManager.java:225) > at > org.eclipse.aether.internal.impl.DefaultArtifactResolver.evaluateDownloads > (DefaultArtifactResolver.java:680) > at > org.eclipse.aether.internal.impl.DefaultArtifactResolver.performDownloads > (DefaultArtifactResolver.java:592) > at org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolve > (DefaultArtifactResolver.java:478) > at > org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifacts > (DefaultArtifactResolver.java:278) > at > org.eclipse.aether.internal.impl.DefaultArtifactResolver.resolveArtifact > (DefaultArtifactResolver.java:255) > at > org.eclipse.aether.internal.impl.DefaultRepositorySystem.resolveArtifact > (DefaultRepositorySystem.java:296) > at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolve > (DefaultArtifactResolver.java:197) > at org.apache.maven.artifact.resolver.DefaultArtifactResolver.resolve > (DefaultArtifactResolver.java:413) > at org.apache.maven.repository.legacy.LegacyRepositorySystem.resolve > (LegacyRepositorySystem.java:332) > at > org.eclipse.tycho.osgi.configuration.MavenDependenciesResolverConfigurer.resolve > (MavenDependenciesResolverConfigurer.java:104) > at org.eclipse.tycho.core.shared.MavenDependenciesResolver.resolve > (MavenDependenciesResolver.java:60) > at org.eclipse.tycho.core.resolver.MavenTargetDefinitionContent.<init> > (MavenTargetDefinitionContent.java:262) > at > org.eclipse.tycho.p2resolver.TargetDefinitionResolver.resolveContentWithExceptions > (TargetDefinitionResolver.java:179) > at org.eclipse.tycho.p2resolver.TargetDefinitionResolver.resolveContent > (TargetDefinitionResolver.java:110) > at > org.eclipse.tycho.p2resolver.TargetDefinitionResolverService.resolveFromArguments > (TargetDefinitionResolverService.java:90) > at java.util.concurrent.ConcurrentHashMap.computeIfAbsent > (ConcurrentHashMap.java:1708) > at > org.eclipse.tycho.p2resolver.TargetDefinitionResolverService.getTargetDefinitionContent > (TargetDefinitionResolverService.java:65) > at > org.eclipse.tycho.p2resolver.TargetPlatformFactoryImpl.resolveTargetDefinitions > (TargetPlatformFactoryImpl.java:214) > at > org.eclipse.tycho.p2resolver.TargetPlatformFactoryImpl.createTargetPlatform > (TargetPlatformFactoryImpl.java:164) > at > org.eclipse.tycho.p2resolver.TargetPlatformFactoryImpl.createTargetPlatform > (TargetPlatformFactoryImpl.java:137) > at > org.eclipse.tycho.p2resolver.TargetPlatformFactoryImpl.createTargetPlatform > (TargetPlatformFactoryImpl.java:88) > at > org.eclipse.tycho.p2resolver.ReactorRepositoryManagerImpl.computePreliminaryTargetPlatform > (ReactorRepositoryManagerImpl.java:61) > at > org.eclipse.tycho.p2resolver.P2DependencyResolver.computePreliminaryTargetPlatform > (P2DependencyResolver.java:202) > at org.eclipse.tycho.core.resolver.DefaultTychoResolver.resolveProject > (DefaultTychoResolver.java:130) > at > org.eclipse.tycho.core.maven.TychoMavenLifecycleParticipant.lambda$resolveProjects$2 > (TychoMavenLifecycleParticipant.java:256) > at java.util.stream.ForEachOps$ForEachOp$OfRef.accept > (ForEachOps.java:183) > at java.util.stream.SpinedBuffer$1Splitr.forEachRemaining > (SpinedBuffer.java:364) > at java.util.stream.AbstractPipeline.copyInto (AbstractPipeline.java:509) > at java.util.stream.ForEachOps$ForEachTask.compute (ForEachOps.java:290) > at java.util.concurrent.CountedCompleter.exec (CountedCompleter.java:754) > at java.util.concurrent.ForkJoinTask.doExec (ForkJoinTask.java:373) > at java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec > (ForkJoinPool.java:1182) > at java.util.concurrent.ForkJoinPool.scan (ForkJoinPool.java:1655) > at java.util.concurrent.ForkJoinPool.runWorker (ForkJoinPool.java:1622) > at java.util.concurrent.ForkJoinWorkerThread.run > (ForkJoinWorkerThread.java:165) > {code} -- This message was sent by Atlassian Jira (v8.20.10#820010)