FULL PRODUCT VERSION :
java version "1.5.0_11"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_11-b03)
Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_11-b03, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux xldn2364dap 2.6.18-8.1.1.el5 #1 SMP Mon Feb 26 20:37:57 EST 2007 x86_64
A DESCRIPTION OF THE PROBLEM :
I believe the cause of the problem is;
- the disk runs out of space in the middle of writing to a file.
- the underlying stream throws an exception.
- this leaves the CharsetEncoder in an inconsistent state.
- the exception thrown is swallowed by the Writer so you don't see it.
- however the writer/encoder is now in an unrecoverable state, even if
space is now made available.
This is difficult to reproduce as the disk system must run out space at
a certain stage in the encoding. E.g. in the middle of writing a
mult-byte character.
* I feel this is a design flaw in the encoders as it should have finally
{ } blocks to ensure the system is always in a consistent state.
* The Writer shouldn't absorb the exception unless it is going to handle
it correctly.
* Java should have a means of detecting when space is about to run out.
(In Java 5!)
* Log4j should use this to prevent the file from hitting the space
limit.
* Ideally the writer should have a mode where it blocks if no free space
is available. (As it would for other streaming devices like Sockets)
The work around I put in place is as follows;
This is clunky as it
- waits for the IllegalStateException rather than trapping the actual
IOException raised.
- there is no clean/efficient way to detect the free disk space in Java
5.
- it writes out a file to test the disk space. If there are multiple
appenders this could cause other log file to run out of space. :(
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING
at java.nio.charset.CharsetEncoder.throwIllegalStateException(Unknown Source)
at java.nio.charset.CharsetEncoder.encode(Unknown Source)
at sun.nio.cs.StreamEncoder$CharsetSE.implWrite(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.OutputStreamWriter.write(Unknown Source)
at java.io.Writer.write(Unknown Source)
at org.apache.log4j.helpers.CountingQuietWriter.write(CountingQuietWriter.java:45)
at org.apache.log4j.WriterAppender.subAppend(WriterAppender.java:302)
at org.apache.log4j.RollingFileAppender.subAppend(RollingFileAppender.java:263)
at org.apache.log4j.WriterAppender.append(WriterAppender.java:160)
at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251)
at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:66)
at org.apache.log4j.Category.callAppenders(Category.java:206)
at org.apache.log4j.Category.forcedLog(Category.java:391)
at org.apache.log4j.Category.info(Category.java:666)
---------- BEGIN SOURCE ----------
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class RollingFileAppender extends
org.apache.log4j.RollingFileAppender {
public RollingFileAppender() {
super();
}
public RollingFileAppender(Layout layout, String filename, boolean
append) throws IOException {
super(layout, filename, append);
}
public RollingFileAppender(Layout layout, String filename) throws
IOException {
super(layout, filename);
}
public void append(LoggingEvent event) {
boolean diskOkay = true;
while (true) {
if (diskOkay)
try {
super.append(event);
return;
} catch (IllegalStateException e) {
if (Thread.currentThread().isInterrupted())
throw e;
e.printStackTrace();
}
diskOkay = waitForFreeSpace();
}
}
private boolean waitForFreeSpace() {
System.err.println("WARN: Checking free disk space after failing
to write to log file " + fileName);
File testFile = new File(fileName + ".test");
FileOutputStream fos = null;
boolean diskOkay = false;
try {
fos = new FileOutputStream(testFile);
int tenMB = 10 * 1000 * 1000;
int size = maxFileSize > tenMB ? tenMB : (int) maxFileSize;
fos.write(new byte[size]);
fos.close();
super.rollOver();
return true;
} catch (FileNotFoundException e) {
throw new AssertionError(e);
} catch (IOException e) {
System.err.println("ERROR: Log directory out of disk space "
+ fileName + " retrying in 30 seconds.");
e.printStackTrace();
} finally {
LifecycleUtils.close(fos);
testFile.delete();
}
Threads.sleep(30 * 1000);
return false;
}
}
---------- END SOURCE ----------
REPRODUCIBILITY :
This bug can be reproduced rarely.
java version "1.5.0_11"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_11-b03)
Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_11-b03, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux xldn2364dap 2.6.18-8.1.1.el5 #1 SMP Mon Feb 26 20:37:57 EST 2007 x86_64
A DESCRIPTION OF THE PROBLEM :
I believe the cause of the problem is;
- the disk runs out of space in the middle of writing to a file.
- the underlying stream throws an exception.
- this leaves the CharsetEncoder in an inconsistent state.
- the exception thrown is swallowed by the Writer so you don't see it.
- however the writer/encoder is now in an unrecoverable state, even if
space is now made available.
This is difficult to reproduce as the disk system must run out space at
a certain stage in the encoding. E.g. in the middle of writing a
mult-byte character.
* I feel this is a design flaw in the encoders as it should have finally
{ } blocks to ensure the system is always in a consistent state.
* The Writer shouldn't absorb the exception unless it is going to handle
it correctly.
* Java should have a means of detecting when space is about to run out.
(In Java 5!)
* Log4j should use this to prevent the file from hitting the space
limit.
* Ideally the writer should have a mode where it blocks if no free space
is available. (As it would for other streaming devices like Sockets)
The work around I put in place is as follows;
This is clunky as it
- waits for the IllegalStateException rather than trapping the actual
IOException raised.
- there is no clean/efficient way to detect the free disk space in Java
5.
- it writes out a file to test the disk space. If there are multiple
appenders this could cause other log file to run out of space. :(
ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING
at java.nio.charset.CharsetEncoder.throwIllegalStateException(Unknown Source)
at java.nio.charset.CharsetEncoder.encode(Unknown Source)
at sun.nio.cs.StreamEncoder$CharsetSE.implWrite(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.OutputStreamWriter.write(Unknown Source)
at java.io.Writer.write(Unknown Source)
at org.apache.log4j.helpers.CountingQuietWriter.write(CountingQuietWriter.java:45)
at org.apache.log4j.WriterAppender.subAppend(WriterAppender.java:302)
at org.apache.log4j.RollingFileAppender.subAppend(RollingFileAppender.java:263)
at org.apache.log4j.WriterAppender.append(WriterAppender.java:160)
at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251)
at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:66)
at org.apache.log4j.Category.callAppenders(Category.java:206)
at org.apache.log4j.Category.forcedLog(Category.java:391)
at org.apache.log4j.Category.info(Category.java:666)
---------- BEGIN SOURCE ----------
import org.apache.log4j.Layout;
import org.apache.log4j.spi.LoggingEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class RollingFileAppender extends
org.apache.log4j.RollingFileAppender {
public RollingFileAppender() {
super();
}
public RollingFileAppender(Layout layout, String filename, boolean
append) throws IOException {
super(layout, filename, append);
}
public RollingFileAppender(Layout layout, String filename) throws
IOException {
super(layout, filename);
}
public void append(LoggingEvent event) {
boolean diskOkay = true;
while (true) {
if (diskOkay)
try {
super.append(event);
return;
} catch (IllegalStateException e) {
if (Thread.currentThread().isInterrupted())
throw e;
e.printStackTrace();
}
diskOkay = waitForFreeSpace();
}
}
private boolean waitForFreeSpace() {
System.err.println("WARN: Checking free disk space after failing
to write to log file " + fileName);
File testFile = new File(fileName + ".test");
FileOutputStream fos = null;
boolean diskOkay = false;
try {
fos = new FileOutputStream(testFile);
int tenMB = 10 * 1000 * 1000;
int size = maxFileSize > tenMB ? tenMB : (int) maxFileSize;
fos.write(new byte[size]);
fos.close();
super.rollOver();
return true;
} catch (FileNotFoundException e) {
throw new AssertionError(e);
} catch (IOException e) {
System.err.println("ERROR: Log directory out of disk space "
+ fileName + " retrying in 30 seconds.");
e.printStackTrace();
} finally {
LifecycleUtils.close(fos);
testFile.delete();
}
Threads.sleep(30 * 1000);
return false;
}
}
---------- END SOURCE ----------
REPRODUCIBILITY :
This bug can be reproduced rarely.
- duplicates
-
JDK-5005426 Buffered stream data is discarded by IllegalStateException in 1.4.2 and Tiger
- Resolved