From 3e168ff4f358ccf972af06137fc3c4b22bd36c57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1a=20=C5=BDivkov?= Date: Mon, 11 Mar 2024 13:23:11 +0100 Subject: Prevent ConcurrentModificationException for PushOne.refBatchesToPush The PushOne.refBatchesToPush was a plain HashSet but r/w access to it wasn't synchronized. Under some circumstances, traversing a stream created on refBatchesToPush threw ConcurrentModificationException [1] which caused the thread to die. As a side effect of the thread-death, the replication task would never reschedule itself but would remain in the pending tasks and all follow-up replications to the same URI would be consolidated into that pending task which would never run. Only a restart of the replication plugin would resolve the issue. [1] ERROR com.google.gerrit.server.git.WorkQueue : WorkQueue thread ReplicateTo-some-uri-2 threw exception java.util.ConcurrentModificationException at java.base/java.util.HashMap$KeySpliterator.tryAdvance(HashMap.java:1730) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) at com.googlesource.gerrit.plugins.replication.PushOne.getLimitedRefs(PushOne.java:255) at com.googlesource.gerrit.plugins.replication.PushOne.toString(PushOne.java:221) at com.google.gerrit.server.git.WorkQueue$ProjectTask.toString(WorkQueue.java:760) at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453) at com.google.gerrit.server.git.WorkQueue$Task.run(WorkQueue.java:678) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:840) Change-Id: I3f29779fd150868412e4994d307303d1dd8bde7b --- src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java index ed84087..c25f375 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/PushOne.java @@ -122,7 +122,7 @@ class PushOne implements ProjectRunnable, CanceledWhileRunning, UriUpdates { private final Project.NameKey projectName; private final URIish uri; - private final Set> refBatchesToPush = Sets.newHashSetWithExpectedSize(4); + private final Set> refBatchesToPush = Sets.newConcurrentHashSet(); private boolean pushAllRefs; private Repository git; private boolean isCollision; -- cgit v1.2.3