8054480: Test java/util/logging/TestLoggerBundleSync.java fails: Unexpected bundle name: null
This is due to a race condition in the test where one GetRB thread can receive a stale LogRecord comming from another GetRB thread. Reviewed-by: dholmes
This commit is contained in:
parent
84a2ad0372
commit
15a875a7a5
@ -58,6 +58,7 @@ import java.util.logging.Logger;
|
|||||||
*/
|
*/
|
||||||
public class TestLoggerBundleSync {
|
public class TestLoggerBundleSync {
|
||||||
|
|
||||||
|
static final boolean VERBOSE = false;
|
||||||
static volatile Exception thrown = null;
|
static volatile Exception thrown = null;
|
||||||
static volatile boolean goOn = true;
|
static volatile boolean goOn = true;
|
||||||
|
|
||||||
@ -65,6 +66,7 @@ public class TestLoggerBundleSync {
|
|||||||
static final long TIME = 4 * 1000; // 4 sec.
|
static final long TIME = 4 * 1000; // 4 sec.
|
||||||
static final long STEP = 1 * 1000; // message every 1 sec.
|
static final long STEP = 1 * 1000; // message every 1 sec.
|
||||||
static final int LCOUNT = 50; // change bundle 50 times...
|
static final int LCOUNT = 50; // change bundle 50 times...
|
||||||
|
static final AtomicLong ignoreLogCount = new AtomicLong(0);
|
||||||
static final AtomicLong setRBcount = new AtomicLong(0);
|
static final AtomicLong setRBcount = new AtomicLong(0);
|
||||||
static final AtomicLong setRBNameCount = new AtomicLong(0);
|
static final AtomicLong setRBNameCount = new AtomicLong(0);
|
||||||
static final AtomicLong getRBcount = new AtomicLong(0);
|
static final AtomicLong getRBcount = new AtomicLong(0);
|
||||||
@ -150,6 +152,7 @@ public class TestLoggerBundleSync {
|
|||||||
long sSetRBNameCount = setRBNameCount.get();
|
long sSetRBNameCount = setRBNameCount.get();
|
||||||
long sCheckCount = checkCount.get();
|
long sCheckCount = checkCount.get();
|
||||||
long sNextLong = nextLong.get();
|
long sNextLong = nextLong.get();
|
||||||
|
long sIgnoreLogCount = ignoreLogCount.get();
|
||||||
List<Thread> threads = new ArrayList<>();
|
List<Thread> threads = new ArrayList<>();
|
||||||
for (Class<? extends ResourceBundle> type : classes) {
|
for (Class<? extends ResourceBundle> type : classes) {
|
||||||
threads.add(new SetRB(type));
|
threads.add(new SetRB(type));
|
||||||
@ -181,21 +184,58 @@ public class TestLoggerBundleSync {
|
|||||||
+ " resource bundles set by " + classes.size() + " Thread(s),");
|
+ " resource bundles set by " + classes.size() + " Thread(s),");
|
||||||
System.out.println("\t " + (setRBNameCount.get() - sSetRBNameCount)
|
System.out.println("\t " + (setRBNameCount.get() - sSetRBNameCount)
|
||||||
+ " resource bundle names set by " + classes.size() + " Thread(s),");
|
+ " resource bundle names set by " + classes.size() + " Thread(s),");
|
||||||
|
System.out.println("\t " + (ignoreLogCount.get() - sIgnoreLogCount)
|
||||||
|
+ " log messages emitted by other GetRB threads were ignored"
|
||||||
|
+ " to ensure MT test consistency,");
|
||||||
System.out.println("\t ThreadMXBean.findDeadlockedThreads called "
|
System.out.println("\t ThreadMXBean.findDeadlockedThreads called "
|
||||||
+ (checkCount.get() -sCheckCount) + " times by 1 Thread.");
|
+ (checkCount.get() -sCheckCount) + " times by 1 Thread.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final static class GetRB extends Thread {
|
final static class GetRB extends Thread {
|
||||||
final static class MyHandler extends Handler {
|
final class MyHandler extends Handler {
|
||||||
volatile ResourceBundle rb;
|
volatile ResourceBundle rb;
|
||||||
volatile String rbName;
|
volatile String rbName;
|
||||||
volatile int count = 0;
|
volatile int count = 0;
|
||||||
@Override
|
@Override
|
||||||
public synchronized void publish(LogRecord record) {
|
public synchronized void publish(LogRecord record) {
|
||||||
|
Object[] params = record.getParameters();
|
||||||
|
// Each GetRB thread has its own handler, but since they
|
||||||
|
// log into the same logger, each handler may receive
|
||||||
|
// messages emitted by other threads.
|
||||||
|
// This means that GetRB#2.handler may receive a message
|
||||||
|
// emitted by GetRB#1 at a time where the resource bundle
|
||||||
|
// was still null.
|
||||||
|
// To avoid falling into this trap, the GetRB thread passes
|
||||||
|
// 'this' as argument to the messages it logs - which does
|
||||||
|
// allow us here to ignore messages that where not emitted
|
||||||
|
// by our own GetRB.this thread...
|
||||||
|
if (params.length == 1) {
|
||||||
|
if (params[0] == GetRB.this) {
|
||||||
|
// The message was emitted by our thread.
|
||||||
count++;
|
count++;
|
||||||
rb = record.getResourceBundle();
|
rb = record.getResourceBundle();
|
||||||
rbName = record.getResourceBundleName();
|
rbName = record.getResourceBundleName();
|
||||||
|
} else {
|
||||||
|
// The message was emitted by another thread: just
|
||||||
|
// ignore it, as it may have been emitted at a time
|
||||||
|
// where the resource bundle was still null, and
|
||||||
|
// processing it may overwrite the 'rb' and 'rbName'
|
||||||
|
// recorded from the message emitted by our own thread.
|
||||||
|
if (VERBOSE) {
|
||||||
|
System.out.println("Ignoring message logged by " + params[0]);
|
||||||
|
}
|
||||||
|
ignoreLogCount.incrementAndGet();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ignoreLogCount.incrementAndGet();
|
||||||
|
System.err.println("Unexpected message received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
rbName = null;
|
||||||
|
rb = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -207,6 +247,7 @@ public class TestLoggerBundleSync {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
final MyHandler handler = new MyHandler();
|
final MyHandler handler = new MyHandler();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@ -234,9 +275,10 @@ public class TestLoggerBundleSync {
|
|||||||
+ handler.getLevel());
|
+ handler.getLevel());
|
||||||
}
|
}
|
||||||
final int countBefore = handler.count;
|
final int countBefore = handler.count;
|
||||||
|
handler.reset();
|
||||||
ll.setLevel(Level.FINEST);
|
ll.setLevel(Level.FINEST);
|
||||||
ll.addHandler(handler);
|
ll.addHandler(handler);
|
||||||
ll.fine("dummy");
|
ll.log(Level.FINE, "dummy {0}", this);
|
||||||
ll.removeHandler(handler);
|
ll.removeHandler(handler);
|
||||||
final int countAfter = handler.count;
|
final int countAfter = handler.count;
|
||||||
if (countBefore == countAfter) {
|
if (countBefore == countAfter) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user