-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Description
Presumably due to a1dfa85 my application throws an error when loggers get changed from multiple threads.
This is likely because InternalLoggerRegistry#getLoggers does not return a thread-safe stream.
Streams are by nature evaluated on the fly, thus still using the values of loggerRefByNameByMessageFactory after readLock was unlocked.
When multiple threads modify loggerRefByNameByMessageFactory, sometimes it errors with the attached error.
This happens inconsistently because it's a race condition, but I've been able to get this error a few times.
Configuration
Version: 2.24.2
Operating system: Windows
JDK: openjdk version "21.0.4" 2024-07-16 LTS
Logs
java.util.ConcurrentModificationException: null
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1792) ~[?:?]
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) ~[?:?]
at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:276) ~[?:?]
at java.base/java.util.WeakHashMap$ValueSpliterator.forEachRemaining(WeakHashMap.java:1223) ~[?:?]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[?:?]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[?:?]
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) ~[?:?]
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) ~[?:?]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) ~[?:?]
at org.apache.logging.log4j.core.LoggerContext.updateLoggers(LoggerContext.java:776) ~[?:?]
at org.apache.logging.log4j.core.LoggerContext.updateLoggers(LoggerContext.java:766) ~[?:?]
at org.apache.logging.log4j.core.config.Configurator.setLevel(Configurator.java:379) ~[?:?]
at org.apache.logging.log4j.core.config.Configurator.setLevel(Configurator.java:414) ~[?:?]
at com.soulfiremc.server.SoulFireServer.setupLogging(SoulFireServer.java:213) ~[?:?]
at com.soulfiremc.server.SoulFireServer.setupLoggingAndVia(SoulFireServer.java:208) ~[?:?]
at com.soulfiremc.server.InstanceManager.start(InstanceManager.java:194) ~[?:?]
at com.soulfiremc.server.SoulFireScheduler.lambda$wrapFuture$6(SoulFireScheduler.java:140) ~[?:?]
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1804) ~[?:?]
at com.soulfiremc.server.SoulFireScheduler.runCommand(SoulFireScheduler.java:154) ~[?:?]
at com.soulfiremc.server.SoulFireScheduler.lambda$schedule$2(SoulFireScheduler.java:79) ~[?:?]
at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1423) ~[?:?]
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387) ~[?:?]
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312) ~[?:?]
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843) ~[?:?]
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808) ~[?:?]
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188) ~[?:?]
This shows the stream being collected due to the forEach call in LoggerContext#updateLoggers, but there being no read lock, therefore causing this race condition.
Reproduction
I unfortunately cannot provide an example because I do not have much experience with reproducing race conditions.