From 3a2e2e34d3c49c0b342498df18a3336f892cbc9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Fri, 22 Mar 2024 12:32:17 +0100 Subject: [PATCH] Prevent ConcurrentModificationException in PomInstallableUnitStore In some rare cases it is possible that a ConcurrentModificationException occurs in the PomInstallableUnitStore when projects are build in parallel and as part of this artifacts are attached. This adds a new safeCopy method to retry the copy operation in such case and checks for possible null values because of concurrent removals. --- .../p2resolver/PomInstallableUnitStore.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/PomInstallableUnitStore.java b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/PomInstallableUnitStore.java index 833f07ce0c..b7424c2902 100644 --- a/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/PomInstallableUnitStore.java +++ b/tycho-core/src/main/java/org/eclipse/tycho/p2resolver/PomInstallableUnitStore.java @@ -18,8 +18,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -221,13 +223,34 @@ private Stream getArtifactStream(Artifact artifact, IArtifactFacade fa MavenProject mavenProject = projectFacade.getReactorProject().adapt(MavenProject.class); if (mavenProject != null) { return Stream.concat(Stream.of(mavenProject.getArtifact()), - mavenProject.getAttachedArtifacts().stream()); + safeCopy(mavenProject.getAttachedArtifacts()).stream()); } } return Stream.of(artifact); } + private List safeCopy(List list) { + while (true) { + //in parallel execution mode it is possible that items are added to the attached artifacts what will throw ConcurrentModificationException so we must make a quite unusual copy here + //we can not only use one of the List.copyOf(), ArrayList(...) and so on e.g. they often just copy the data but a concurrent copy can lead to data corruption or null values + try { + List copyList = new ArrayList<>(); + for (Iterator iterator = list.iterator(); iterator.hasNext();) { + Artifact a = iterator.next(); + if (a != null) { + copyList.add(a); + } + } + return copyList; + } catch (ConcurrentModificationException e) { + //retry... + Thread.yield(); + } + } + + } + void addPomDependencyConsumer(Consumer consumer) { gatheredDependencies.forEach(consumer); dependencyConsumer.add(consumer);