Quantcast
Channel: Scratch Where It's Itching
Viewing all articles
Browse latest Browse all 73

Why don't I know my disk is full?

$
0
0
We had this interesting problem lately, that an application had a corrupted file after a disk got full. The strange thing was that the app did not know that the disk was full. We were expecting an IOException, but no trace of it nowhere. Moreover, the app went on running, and resumed writing in the file when someone deleted a big file from the disk.

While looking on the net for how to know when a disk is full, we got this code strip on StackOverflow:

  FileOutputStream fos = ...;
  fos.write("hello".getBytes());
  fos.getFD().sync();
  fos.close();

This forces the OS to force synchronization of the file with its internal buffer, and throws a SyncFailedException when the disk is full. However, this has horrible performance. So we kept looking for our IOException. After a bit of investigation, we found out the culprit: PrintWriter.

The PrintWriter class can be very useful, since it wraps common print methods around a stream. Also, it automatically creates a BufferedWriter, as you can see in this constructor:

public PrintWriter(File file) throws FileNotFoundException {this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
             false);
    }

Another features of the PrintWriter, and now we get to the problem, is that most of its methods do not throw any Exception. Here is an example of a typical PrintWriter method:

publicvoid write(char buf[], int off, int len) {try {synchronized (lock) {
                ensureOpen();
                out.write(buf, off, len);
            } 
        } catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }catch (IOException x) {
            trouble = true;
        } 
    } 

You can see that all IOExceptions are caught, and a boolean is set to true. The only way to know that something went wrong is to call the method checkError(). This only tells you that something went amiss, but not what, since you lost the exception.

publicboolean checkError() {if (out != null) {
            flush();
        } if (out instanceof java.io.PrintWriter) {
            PrintWriter pw = (PrintWriter) out;return pw.checkError();
        }  elseif (psOut != null) {return psOut.checkError();
        } return trouble;
    } 

Notice how it checks if it wraps another PrintWriter or a PrintOutputStream, because it knows that they swallow the Exception.

At the end, we replaced the PrintWriter with a simple FileWriter, because we did not need the PrintWriter in our case. We only needed a Writer to give to our CSV exporter library, which already wrapped it in a BufferedWriter. Now, IOExceptions are nicely bubbling up, and we know when our disk is full.


Viewing all articles
Browse latest Browse all 73

Trending Articles