LoggerContextConcurrentResetTest.java
/*
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2026, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v2.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package ch.qos.logback.classic;
import java.util.concurrent.CyclicBarrier;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import ch.qos.logback.core.testUtil.AbstractMultiThreadedHarness;
import ch.qos.logback.core.testUtil.RunnableWithCounterAndDone;
import ch.qos.logback.core.status.testUtil.StatusChecker;
import org.junit.jupiter.api.Timeout;
@Disabled
public class LoggerContextConcurrentResetTest {
static int CONCURRENT_RESET_THREAD_COUNT = 10;
// see http://jira.qos.ch/browse/LOGBACK-397
@Test
@Timeout(value = 1)
public void concurrentReset() throws InterruptedException {
LoggerContext loggerContext = new LoggerContext();
CyclicBarrier cyclicBarrier = new CyclicBarrier(CONCURRENT_RESET_THREAD_COUNT);
StatusChecker statusChecker = new StatusChecker(loggerContext);
int desiredResetCount = 100;
RunnableWithCounterAndDone[] runnableArray = buildRunnableArray(loggerContext, cyclicBarrier);
Harness harness = new Harness((Resetter) runnableArray[0], desiredResetCount);
harness.execute(runnableArray);
statusChecker.assertIsErrorFree();
}
class Harness extends AbstractMultiThreadedHarness {
int desiredResetCount;
Resetter resetter;
Harness(Resetter resetter, int desiredResetCount) {
this.resetter = resetter;
this.desiredResetCount = desiredResetCount;
}
public void waitUntilEndCondition() throws InterruptedException {
while (resetter.getCounter() < desiredResetCount) {
Thread.yield();
}
}
}
static class GetLoggerRunnable extends RunnableWithCounterAndDone {
final int burstLength = 30;
LoggerContext loggerContext;
CyclicBarrier cyclicBarrier;
String nameSuffix;
GetLoggerRunnable(LoggerContext loggerContext, CyclicBarrier cyclicBarrier, String nameSuffix) {
this.loggerContext = loggerContext;
this.cyclicBarrier = cyclicBarrier;
this.nameSuffix = nameSuffix;
}
public void run() {
try {
cyclicBarrier.await();
} catch (Exception e) {
}
while (!isDone()) {
long i = counter % burstLength;
loggerContext.getLogger("org.bla." + nameSuffix + ".x" + i);
counter++;
if (i == 0) {
Thread.yield();
}
}
}
}
static class Resetter extends RunnableWithCounterAndDone {
LoggerContext loggerContext;
CyclicBarrier cyclicBarrier;
public int resetCount = 0;
Resetter(LoggerContext loggerContext, CyclicBarrier cyclicBarrier) {
this.loggerContext = loggerContext;
this.cyclicBarrier = cyclicBarrier;
}
public void run() {
try {
cyclicBarrier.await();
} catch (Exception e) {
}
while (!isDone()) {
loggerContext.reset();
counter++;
Thread.yield();
}
}
}
private RunnableWithCounterAndDone[] buildRunnableArray(LoggerContext loggerContext, CyclicBarrier cyclicBarrier) {
RunnableWithCounterAndDone[] rArray = new RunnableWithCounterAndDone[CONCURRENT_RESET_THREAD_COUNT];
rArray[0] = new Resetter(loggerContext, cyclicBarrier);
for (int i = 1; i < CONCURRENT_RESET_THREAD_COUNT; i++) {
rArray[i] = new GetLoggerRunnable(loggerContext, cyclicBarrier, "mouse-" + i);
}
return rArray;
}
}