RFR: 8054480: Test java/util/logging/TestLoggerBundleSync.java fails: Unexpected bundle name: null

David Holmes david.holmes at oracle.com
Thu Aug 14 10:44:13 UTC 2014


Hi Daniel,

This change seems quite reasonable to me.

Thanks,
David

On 13/08/2014 3:01 AM, Daniel Fuchs wrote:
> Hi,
>
> Please find below a fix for:
>
> 8054480: Test java/util/logging/TestLoggerBundleSync.java fails:
>           Unexpected bundle name: null
>
> This test has been reported to fail from time to time with the
> following stack:
>
> java.lang.RuntimeException: Unexpected bundle name: null
>      at TestLoggerBundleSync$GetRB.run(TestLoggerBundleSync.java:257)
>
> The issue here is due to a race condition in the test code.
> The comments in the fix explains the fix & the issue.
>
> http://cr.openjdk.java.net/~dfuchs/webrev_8054480/webrev.00/
>
> --
>
> The test creates several GetRB threads which 'read' the resource
> bundle that will be used by loggers. It does that by publishing
> a dummy message in a child logger, and checking the resource
> bundle name stored in the associated LogRecord.
>
> The test also creates several SetRB/SetRBName threads which attempts to
> set the resource bundle on loggers, in parallel with the GetRB threads.
>
> The race condition occurs because although each GetRB thread
> has its own Handler that it uses to get at the ResourceBundle in
> the  LogRecord, it can receive LogRecords that were emitted by
> other GetRB threads - which (because of thread scheduling) might
> have been prepared at an earlier time and may contain stale
> information.
>
> What it means is that the following logic from
> GetRB is flawed:
>
>   a. gets ResourceBundle from parent logger
>   b. register handler with child logger
>   c. emit dummy message through child logger
>   d. remove handler registered in b.
>   f. check resource bundle that was passed in LogRecord,
>      comparing it with the resource bundle obtained in a.
>      The expectation is that if a. is not null, then
>      the resource bundle name obtained by the handler should
>      not be null, and should be equal to the name obtained
>      in a.
>
> This logic is flawed and prone to race conditions, because
> the following may sometime happens:
>
>   GetRB#1 logs a message, but gets interrupted after LogRecord
>           is created but before publish() is called. At this
>           point the ResourceBundle has not been set yet, so the
>           record has a null ResourceBundle.
>   SetRB#? sets resource bundle on parent logger
>   GetRB#2 sees the new resource bundle, emit a dummy message, but is
>           interrupted before it removes its handler.
>           At this point the handler has the correct resource bundle
>           and resource bundle name that it found in the LogRecord
>           emitted by GetRB#2 in step c.
>   GetRB#1 is resumed. LogRecord gets published - but since the
>           handler from thread #2 is still present, the 'old'
>           LogRecord from GetRB#1 gets forwarded to GetRB#2's handler
>           where it erases the information previously recorded by the
>           message that was emitted by GetRB#2
>   GetRB#2 is resumed, and sees the rbName/rb that was present in
>           the old LogRecord emitted by GetRB#1 instead of seeing
>           the newer information that was in the LogRecord emitted
>           by GetRB#2.
>
>   => the exception gets raised.
>
> The fix is relatively simple: the Handler registered by each
> GetRB thread need simply to ignore messages that were not emitted by
> its own thread - we do this now by passing 'this' as parameter to
> the dummy logged message - and by comparing GetRB.this
> with LogRecord.getParameters()[0];
>
> best regards,
>
> -- daniel



More information about the core-libs-dev mailing list